Cómo arreglar pull access denied for minio/mc en tu contenedor createbuckets
Índice de contenidos
- Puntos clave
- ¿Qué significa pull access denied for minio/mc?
- ¿Qué stacks lo usan y por qué se rompieron ahora?
- Arreglo de una línea: cambia minio/mc por pgsty/silo
- Una versión más robusta del servicio createbuckets
- Alternativa con la imagen de Chainguard
- Alternativa sin MinIO: aws-cli o rclone
- Cuánto pesa cada sustituto
- Si tus buckets ya existen, quita el servicio
- Preguntas frecuentes
- ¿Sirve docker login o cambiar a quay.io/minio/mc?
- ¿Tengo que cambiar también el servidor MinIO?
- ¿Funcionan estos sustitutos con otro servidor S3?
- Conclusión
- Fuentes
El error pull access denied for minio/mc aparece porque MinIO borró esa imagen de Docker Hub en septiembre de 2026, y tumba el compose entero aunque solo la use el contenedor que crea los buckets. Cámbiala por pgsty/silo, por la imagen de Chainguard o por aws-cli, o quita el servicio si tus buckets ya existen.
El error pull access denied for minio/mc significa que la imagen del cliente de MinIO ya no existe en Docker Hub, y se arregla cambiando la imagen del contenedor que crea los buckets, o quitándolo si ya hizo su trabajo. MinIO borró minio/mc en septiembre de 2026, y el fallo de esa descarga impide que arranque todo el stack, servidor incluido. Esta guía reproduce el error en un compose típico con un servicio createbuckets y prueba tres sustitutos que crean el bucket y su política de acceso. Lo probé el 18 de octubre de 2026 en Linux arm64 con Docker 29.5.2 y Compose v2.40.3. Tienes la versión en inglés de esta guía.
Puntos clave
- La API de Docker Hub devuelve 404 para
minio/mc, ydocker compose upsale con código 1 sin crear ni un contenedor del proyecto. - El arreglo de una línea es
pgsty/silo:RELEASE.2026-10-15T00-00-00Z: trae/usr/bin/mccomo enlace a su cliente, así que el script original funciona sin tocarlo. cgr.dev/chainguard/minio-client:latest-devtambién vale, pero la etiquetalatestsin-devno tiene shell y no ejecuta un script.aws-clicrea el bucket y su política cons3api;rclonecrea el bucket pero no pone políticas.- Si tus buckets ya existen, quita el servicio y también cada
depends_onque apunte a él, o Compose rechaza el proyecto.
¿Qué significa pull access denied for minio/mc?
Significa que Docker no encuentra un repositorio público llamado minio/mc, y en este caso es literal: MinIO lo borró de Docker Hub junto con minio/minio. El mensaje sugiere docker login porque Docker usa el mismo texto para un repositorio privado y para uno inexistente. Para reproducirlo monté el patrón que copian los tutoriales y las plantillas: un MinIO, un servicio createbuckets con minio/mc y una aplicación que espera a que termine. Este es el servicio que falla:
createbuckets:
image: minio/mc
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
/usr/bin/mc alias set myminio http://minio:9000
$${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD};
/usr/bin/mc mb --ignore-existing myminio/uploads;
/usr/bin/mc anonymous set download myminio/uploads;
exit 0;
"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
El servidor del mismo compose usa cgr.dev/chainguard/minio:latest, que sí se descarga, y la aplicación declara depends_on: createbuckets con condition: service_completed_successfully. Esto es lo que devolvió docker compose up -d:
$ docker compose up -d
createbuckets Pulling
createbuckets Error pull access denied for minio/mc, repository does
not exist or may require 'docker login'
Error response from daemon: pull access denied for minio/mc,
repository does not exist or may require 'docker login'
En tu terminal cada mensaje ocupa una sola línea. El comando salió con código 1 y docker compose ps -a no listó nada: Compose descarga todas las imágenes antes de crear contenedores, así que un contenedor que solo crea un bucket deja parado también el servidor. Si buscas el mismo error con minio/minio, la guía de pull access denied for minio/minio cubre la imagen del servidor.
¿Qué stacks lo usan y por qué se rompieron ahora?
El patrón de un contenedor mc que crea buckets y termina es habitual en plantillas de autoalojamiento, y se rompió cuando Docker Hub dejó de servir minio/mc el 11 de septiembre de 2026. El caso más visible es la plantilla de Supabase de Coolify: la incidencia coolify#11855[1], abierta el 16 de septiembre, cuenta que tanto los despliegues nuevos como los reinicios fallaban en el servicio minio-createbucket. Coolify marcó tres incidencias más como duplicadas (#12000, #12035 y #12052).
El arreglo llegó el 15 de octubre, en el commit d60d3a5, y cambió las imágenes de MinIO de todas las plantillas por pgsty/silo. El mantenedor lo describe como "the maintained MinIO fork with the same data format and API" y avisa de que los servicios ya creados conservan su compose antiguo: tienes que editarlo tú. La misma tanda cerró la incidencia de Plane[2], aunque ahí falla minio/minio, no el cliente.
El compose de Supabase sin Coolify ya no tiene el problema. Su fichero docker-compose.s3.yml[3] usa cgr.dev/chainguard/minio-client:latest-dev desde un commit del 18 de febrero de 2026, siete meses antes del borrado.
Arreglo de una línea: cambia minio/mc por pgsty/silo
Silo es el fork comunitario de MinIO que publica Pigsty, y su imagen trae el cliente en la misma ruta que la oficial. En la etiqueta RELEASE.2026-10-15T00-00-00Z, /usr/bin/mc es un enlace simbólico a /usr/bin/mcli, que se identifica como mc version RELEASE.2026-09-16T00-00-00Z. Por eso cambias la línea image: y dejas el script como estaba:
sed -i 's#image: minio/mc#image: pgsty/silo:RELEASE.2026-10-15T00-00-00Z#' \
compose.yml
docker compose up -d && docker compose logs createbuckets
El sed sustituye la imagen y el segundo comando arranca el stack y muestra la salida del contenedor de inicio. Con el compose anterior obtuve esto:
createbuckets-1 | Added `myminio` successfully.
createbuckets-1 | Bucket created successfully `myminio/uploads`.
createbuckets-1 | Access permission for `myminio/uploads` is set to `download`
Tu entrypoint: sustituye al script de entrada de la imagen, que en Silo antepone silo a los argumentos, así que no interfiere. La imagen corre como root, tiene variante arm64 y amd64 y la etiqueta pgsty/silo:RELEASE.2026-09-16T00-00-00Z también trae el enlace mc. Fija la etiqueta por versión en lugar de latest: es lo que hace Coolify.
Una versión más robusta del servicio createbuckets
El script original termina con exit 0 y sin -e, así que el contenedor acaba "bien" aunque no haya creado nada, y tu aplicación arranca contra un bucket que no existe. Esta variante define el alias con la variable MC_HOST_s3, sale con error en el primer fallo y no necesita alias set:
createbuckets:
image: pgsty/silo:RELEASE.2026-10-15T00-00-00Z
depends_on:
minio:
condition: service_healthy
entrypoint: ["/bin/sh", "-ec"]
command:
- |
mc mb --ignore-existing s3/uploads
mc anonymous set download s3/uploads
environment:
MC_HOST_s3: http://${MINIO_ROOT_USER}:${MINIO_ROOT_PASSWORD}@minio:9000
Compose sustituye las variables desde tu .env al leer el fichero. Si la clave contiene @, : o /, codifícala para URL o vuelve al alias set. Para comprobar el aviso de error, puse una clave equivocada: mc mb falló con The request signature we calculated does not match, el contenedor salió con 1 y docker compose up también, con la aplicación en estado Created sin arrancar. Ese bloqueo es lo que esperas de un contenedor de inicio, como explica la guía de init containers en Docker Compose.
Alternativa con la imagen de Chainguard
cgr.dev/chainguard/minio-client:latest-dev es la sustitución que eligió Supabase, y funciona con el mismo bloque cambiando solo image:. El sufijo -dev es imprescindible: la etiqueta latest no trae shell, y al pedirle sh Docker responde exec: "sh": executable file not found in $PATH. La variante -dev sí la trae.
La imagen corre como el usuario 65532 y su mc se identifica como DEVELOPMENT.GOGET, sin número de versión. En mi prueba creó el bucket uploads, le puso el permiso download y una petición anónima al objeto de prueba devolvió 200. Chainguard no publica etiquetas por versión en su catálogo gratuito, así que fíjala por resumen si quieres builds reproducibles.
Alternativa sin MinIO: aws-cli o rclone
Si prefieres no depender de ningún cliente derivado de MinIO, la interfaz de línea de comandos de AWS (AWS CLI) habla con cualquier servidor S3. Lee el destino de la variable AWS_ENDPOINT_URL, y s3api crea el bucket y escribe su política en JSON:
createbuckets:
image: public.ecr.aws/aws-cli/aws-cli:2.38.1
depends_on:
minio:
condition: service_healthy
entrypoint: ["/bin/sh", "-ec"]
command:
- |
export AWS_ENDPOINT_URL=http://minio:9000
aws s3api head-bucket --bucket uploads 2>/dev/null \
|| aws s3api create-bucket --bucket uploads
aws s3api put-bucket-policy --bucket uploads --policy '{
"Version": "2012-10-17",
"Statement": [{"Effect": "Allow", "Principal": {"AWS": ["*"]},
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::uploads/*"]}]}'
environment:
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER}
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD}
AWS_DEFAULT_REGION: us-east-1
head-bucket hace que el script sea idempotente: la segunda ejecución sobre el mismo volumen salió con 0 sin intentar crear nada. La política equivale a mc anonymous set download, aunque mc anonymous get la muestra como custom; la petición anónima al objeto devolvió 200. La imagen viene de la galería pública de Amazon ECR, así que tampoco depende de Docker Hub.
rclone es la cuarta opción, solo si no necesitas política. Con rclone/rclone:1.75.2, cinco variables RCLONE_CONFIG_S3_* y el comando mkdir s3:uploads, el bucket se creó como privado y la petición anónima devolvió 403, porque rclone no escribe políticas de bucket.
Cuánto pesa cada sustituto
Las cuatro imágenes cumplen la tarea, pero aws-cli pesa casi cinco veces lo que la imagen de Chainguard. Para un contenedor que corre unos segundos en cada arranque, el tamaño solo importa en la primera descarga:
Silo pesa más que el cliente de Chainguard porque incluye también el servidor, de 90 MB. Si ya usas pgsty/silo para el servidor, el contenedor de inicio reutiliza la misma imagen y no descarga nada más.
Si tus buckets ya existen, quita el servicio
Si tu instancia ya arrancó alguna vez con minio/mc, los buckets y sus políticas viven en el volumen de datos del servidor, y el contenedor de inicio ya no tiene trabajo que hacer. Puedes borrar el bloque createbuckets del compose, pero antes busca quién depende de él. En mi prueba, quitar solo el servicio dio este error:
service "app" depends on undefined service "createbuckets": invalid
compose project
La solución es cambiar esa dependencia por la del servidor, o borrarla:
app:
depends_on:
minio:
condition: service_healthy
Después ejecuta docker compose up -d --remove-orphans para eliminar el contenedor antiguo de createbuckets. El bucket uploads siguió con el permiso download tras el cambio. En la plantilla de Supabase de Coolify ningún servicio depende de minio-createbucket, así que ahí borrar el bloque es suficiente; en el compose de Supabase sin Coolify, storage sí depende de él. Si algún día recreas el volumen desde cero, necesitarás de nuevo uno de los sustitutos.
Preguntas frecuentes
¿Sirve docker login o cambiar a quay.io/minio/mc?
No. docker login no recupera un repositorio borrado, y la copia de Quay responde 401 desde el 24 de septiembre de 2026, como documenta la guía de minio/minio. La API de Docker Hub devuelve 404 para minio/mc.
¿Tengo que cambiar también el servidor MinIO?
Si tu servidor usa minio/minio, sí, porque falla igual. Ya que lo cambias, valora salir de MinIO. La migración de MinIO a RustFS conserva versionado y políticas, y la de MinIO a Garage es más ligera pero no tiene políticas de bucket.
¿Funcionan estos sustitutos con otro servidor S3?
aws-cli y rclone sí, porque solo hablan S3. mc anonymous set necesita un servidor que acepte políticas de bucket al estilo de MinIO; contra Garage, que no las tiene, usa solo la creación del bucket.
Conclusión
pull access denied for minio/mc se arregla en la línea image: del contenedor de inicio, no en el registro. Para el cambio mínimo, pon pgsty/silo:RELEASE.2026-10-15T00-00-00Z y tu script seguirá funcionando. Para no depender de MinIO, usa aws-cli. Si tus buckets ya existen, borra el servicio y sus depends_on, y añade -e al script del sustituto que dejes para que un fallo pare el stack en lugar de esconderse.
Fuentes: [1] Coolify, incidencia 11855 sobre minio/mc en Supabase[1], [2] Coolify, incidencia 11975 sobre Plane[2], [3] Coolify, plantilla de Supabase[4], [4] Supabase, docker-compose.s3.yml[3], [5] Pigsty, fork Silo[5], [6] Chainguard, imagen minio-client[6], [7] AWS, puntos de conexión en la interfaz de línea de comandos[7], [8] rclone, configuración por variables de entorno[8], [9] Docker, depends_on en la especificación de Compose[9].
Fuentes
- incidencia coolify#11855
- incidencia de Plane
- fichero docker-compose.s3.yml
- Coolify, plantilla de Supabase
- Pigsty, fork Silo
- Chainguard, imagen minio-client
- AWS, puntos de conexión en la interfaz de línea de comandos
- rclone, configuración por variables de entorno
- Docker, depends_on en la especificación de Compose
Código fuente
Accede a todo el código fuente de este artículo en GitHub.
Ver en GitHub