Un registry mirror funciona como una caché intermedia entre Docker Engine y Docker Hub. La primera vez que un cliente solicita una imagen, el mirror descarga sus capas desde Docker Hub, las almacena y las entrega al cliente. En solicitudes posteriores, las capas disponibles se sirven desde el almacenamiento local.


Los cuatro pasos: configurar daemon.json, validarlo con dockerd --validate, reiniciar Docker y comprobar con docker info y un pull de prueba

Esto reduce descargas repetidas y mejora el tiempo de aprovisionamiento cuando varios servidores utilizan las mismas imágenes. No convierte el servicio en un registry privado: solo actúa como caché de Docker Hub y no admite operaciones docker push. Tampoco puede utilizarse para replicar otros registries privados. Docker Docs, CNCF Distribution.

Arquitectura

La solución tendrá dos componentes:

  • Un servidor mirror con Distribution Registry y almacenamiento persistente.
  • Uno o más clientes Docker Engine configurados para consultar https://mirror.ejemplo.com.

Aunque una imagen esté almacenada en caché, una solicitud basada en una etiqueta como latest puede consultar Docker Hub para comprobar si existe una versión nueva. Las capas que no cambiaron se sirven localmente.

Requisitos previos

  • Un servidor Ubuntu 24.04 LTS con Docker Engine y el complemento Docker Compose.
  • Un dominio, por ejemplo mirror.ejemplo.com, apuntando al servidor.
  • Un certificado TLS válido para ese dominio.
  • Puerto TCP 443 accesible desde los clientes autorizados.
  • Espacio en disco suficiente para /srv/registry-mirror/data.
  • Acceso mediante sudo tanto al mirror como a los clientes.
En producción, limita el acceso mediante la red del proveedor, una VPN o reglas en la cadena DOCKER-USER. Los puertos publicados por Docker pueden no respetar como se espera las reglas habituales de UFW. Instalación de Docker Engine en Ubuntu.

La primera descarga pasa por el mirror hasta Docker Hub, y el pull repetido se resuelve desde la caché local sin salir a internet
pasos para registry



Paso 1: registrar el estado actual

En el servidor mirror y en cada cliente, registra las versiones antes de modificar la configuración:

docker version
docker info
sudo systemctl is-active docker

Confirma que Docker esté activo y resuelve cualquier error previo antes de continuar.

Paso 2: preparar el servidor mirror

Crea las rutas de configuración, certificados y datos:

sudo install -d -m 0750 \
  /srv/registry-mirror/data \
  /srv/registry-mirror/certs
cd /srv/registry-mirror

Copia el certificado y la clave privada como certs/fullchain.pem y certs/privkey.pem. La clave debe quedar restringida:

sudo chmod 0644 certs/fullchain.pem
sudo chmod 0600 certs/privkey.pem

No expongas la clave privada en capturas, repositorios ni historiales de comandos.

Paso 3: configurar el pull-through cache

Crea /srv/registry-mirror/config.yml:

version: 0.1

log:
  level: info

storage:
  delete:
    enabled: true
  filesystem:
    rootdirectory: /var/lib/registry

http:
  addr: 0.0.0.0:5000
  tls:
    certificate: /certs/fullchain.pem
    key: /certs/privkey.pem

proxy:
  remoteurl: https://registry-1.docker.io
  ttl: 168h

El backend filesystem es el recomendado para garantizar el funcionamiento correcto de la caché. delete.enabled permite que el programador elimine contenido vencido, mientras que ttl establece la vigencia de las entradas. Configuración de Distribution.

Esta configuración utiliza imágenes públicas. Agregar credenciales de Docker Hub podría hacer accesibles mediante el mirror los repositorios privados permitidos para esa cuenta. No las incorpores sin proteger antes el servicio con autenticación y control de acceso.

Paso 4: crear y validar el servicio

Crea /srv/registry-mirror/compose.yaml:

services:
  registry:
    image: registry:3
    container_name: registry-mirror
    restart: unless-stopped
    ports:
      - "443:5000"
    environment:
      OTEL_TRACES_EXPORTER: none
    volumes:
      - ./config.yml:/etc/distribution/config.yml:ro
      - ./certs:/certs:ro
      - ./data:/var/lib/registry
    security_opt:
      - no-new-privileges:true

En producción, sustituye registry:3 por un digest aprobado para evitar cambios inesperados. Valida el archivo antes de iniciar el contenedor:

sudo docker compose config

Si la validación informa un error, corrige el YAML antes de continuar.

Paso 5: iniciar y comprobar el mirror

sudo docker compose up -d
sudo docker compose ps
sudo docker compose logs --tail=100 registry

Comprueba la API del registry desde un cliente autorizado:

curl -fsS https://mirror.ejemplo.com/v2/

Una respuesta vacía {} con estado HTTP 200 confirma que el endpoint responde. Esto todavía no demuestra que la caché esté funcionando.

Paso 6: configurar cada cliente Docker Engine

Primero conserva una copia del archivo actual:

sudo install -d -m 0755 /etc/docker

if sudo test -f /etc/docker/daemon.json; then
  sudo cp -a /etc/docker/daemon.json \
    "/etc/docker/daemon.json.bak.$(date +%Y%m%d%H%M%S)"
fi

Edita /etc/docker/daemon.json y agrega registry-mirrors. Si el archivo ya contiene otras opciones, intégralas en el mismo objeto JSON en lugar de sobrescribirlas:

{
  "registry-mirrors": [
    "https://mirror.ejemplo.com"
  ]
}

Valida la configuración antes de reiniciar Docker:

sudo dockerd --validate --config-file=/etc/docker/daemon.json

Continúa únicamente si aparece configuration OK. La opción --validate devuelve un código distinto de cero cuando encuentra directivas inválidas. Referencia de dockerd.

Paso 7: aplicar y verificar

El reinicio de Docker puede afectar temporalmente a los contenedores del host. Realízalo durante una ventana controlada:

sudo systemctl restart docker
sudo systemctl is-active docker
docker info

En la salida de docker info, comprueba que aparezca:

Registry Mirrors:
 https://mirror.ejemplo.com/

Revisa también los mensajes recientes del daemon:

sudo journalctl -u docker --since "5 minutes ago" --no-pager

Paso 8: demostrar el uso de la caché

En el cliente, descarga una imagen pequeña que no esté almacenada localmente:

docker image rm hello-world:latest 2>/dev/null || true
docker pull hello-world:latest

En el servidor mirror, revisa los registros y el espacio utilizado:

cd /srv/registry-mirror
sudo docker compose logs --since 5m registry
sudo du -sh data

El primer pull debe generar actividad contra el origen y crear datos en el volumen. Elimina únicamente la imagen de prueba del cliente y repite la descarga:

docker image rm hello-world:latest
docker pull hello-world:latest

En el segundo intento, las capas ya almacenadas deben servirse desde la caché. El mirror todavía puede consultar Docker Hub para verificar la vigencia de una etiqueta.

Cómo revertir el cambio

Restaura el backup de daemon.json, vuelve a validarlo y reinicia Docker:

sudo cp /etc/docker/daemon.json.bak.FECHA /etc/docker/daemon.json
sudo dockerd --validate --config-file=/etc/docker/daemon.json
sudo systemctl restart docker

Para retirar el servidor mirror sin borrar la caché:

cd /srv/registry-mirror
sudo docker compose down

No agregues --volumes ni elimines data si necesitas conservar las capas almacenadas.

Problemas frecuentes

El cliente informa x509: certificate signed by unknown authority

Comprueba el nombre incluido en el certificado, la cadena completa, su vigencia y la confianza de la CA en el cliente. No soluciones el problema agregando el servicio a insecure-registries en producción.

El mirror no aparece en docker info

Revisa la sintaxis de daemon.json, confirma que modificaste el host correcto y comprueba que Docker se reinició. Busca también opciones de inicio de dockerd que entren en conflicto con el archivo.

La carpeta de datos no crece

El cliente puede estar utilizando su caché local. Elimina solo la imagen de prueba y repite el pull. Confirma además que la imagen provenga de Docker Hub y que el cliente pueda alcanzar el mirror.

Buildx no utiliza el mirror

Los builders con driver docker-container o Kubernetes ejecutan una instancia independiente de BuildKit y pueden necesitar su propia configuración buildkitd.toml. Configuración de BuildKit.

Aparece un error HTTP 429

Los mirrors continúan sujetos a la política de uso y a los límites de descarga de Docker Hub. Una caché reduce la transferencia repetida, pero no elimina necesariamente las comprobaciones remotas. Límites de Docker Hub.


Cloud Servers by Donweb

Ya no dependes de Docker Hub en cada build. El mirror también necesita dónde vivir.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Aloja tu mirror en un Cloud Server