Crear registry Docker privado con autenticación y mirror en VPS: tutorial paso a paso
Docker & Containers · Por Kevin Marcondes · Publicado el · Actualizado el · 8 min de lectura
En este tutorial —crear un registry Docker privado con autenticación y mirror en VPS— vas a desplegar un Docker Registry con htpasswd, habilitar el pull‑through cache del Docker Hub y protegerlo con HTTPS mediante un reverse proxy. Al final, tus clientes Docker usarán el mirror y podrán hacer push de imágenes privadas con seguridad.
1. Requisitos previos y arquitectura que vamos a montar
Necesitas una VPS Linux actualizada, un dominio (p. ej.: registry.example.com) apuntando al servidor y los puertos 80/443 abiertos. Será necesario acceso root o sudo.
Usaremos Docker + Compose para desplegar: (1) un registry privado con autenticación htpasswd; (2) pull‑through cache para el Docker Hub; (3) un reverse proxy con HTTPS automático.
Si aún no lo tienes instalado, sigue la guía cómo instalar Docker y Docker Compose en Linux. Haz el hardening con el checklist de seguridad para VPS Linux y abre los puertos en el firewall; consulta cómo configurar UFW.
- VPS con CPU/RAM/disco compatibles con tu volumen de imágenes.
- DNS A/AAAA para registry.example.com apuntando a la VPS.
- Docker y Docker Compose instalados.
- Puertos 80/443 y 5000 abiertos en el firewall.
2. Crear directorios y archivo de contraseñas (htpasswd)
Crea la estructura de datos y genera el htpasswd. Usaremos la imagen httpd solo para generar el archivo de contraseñas. Cambia el usuario y la contraseña por valores fuertes y guárdalos de forma segura.
sudo mkdir -p /opt/registry/{data,auth}
# Gere um usuário e senha para acessar o registry
# Substitua registryuser e a senha por valores fortes
docker run --rm --entrypoint htpasswd httpd:2 -Bbn registryuser 'S3nh@F0rte' \
> /opt/registry/auth/htpasswd
# Revise permissões conforme sua política de segurança
sudo chmod 640 /opt/registry/auth/htpasswd
sudo chown root:root /opt/registry/auth/htpasswd
3. Levantar el Docker Registry con autenticación (puerto 5000)
Vamos iniciar el registry con autentificación htpasswd. En esta etapa lo ejecutaremos sin TLS, ya que HTTPS se gestionará con el reverse proxy más adelante. Restringe el acceso en el firewall hasta configurar HTTPS.
# docker-compose.yml
version: "3.9"
services:
registry:
image: registry:2
container_name: registry
restart: unless-stopped
ports:
- "5000:5000"
environment:
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
- REGISTRY_STORAGE_DELETE_ENABLED=true
volumes:
- /opt/registry/data:/var/lib/registry
- /opt/registry/auth:/auth
# Suba o serviço (na mesma pasta do docker-compose.yml)
# Compose v2:
docker compose up -d registry
4. Activar pull-through cache (mirror) del Docker Hub
Para reducir latencia y ahorrar ancho de banda, activa el espejado. El registry hará cache de imágenes públicas del Docker Hub conforme sean solicitadas por los clientes. No es un mirror completo; solo cachea lo que se solicite.
- Mantiene capas en disco local, acelerando pulls repetidos.
- Respeta el rate limit del Docker Hub; opcionalmente puedes usar credenciales propias.
# Edite docker-compose.yml e adicione a variável de proxy
services:
registry:
environment:
- REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io
# Opcional: para límites do Hub, defina usuário/senha do Hub
# - REGISTRY_PROXY_USERNAME=seu_usuario
# - REGISTRY_PROXY_PASSWORD=sua_senha
# Recrie o serviço
docker compose up -d registry
# Verifique logs
docker logs -f registry
5. HTTPS con reverse proxy (Caddy) y dominio propio
Vamos poner el registry detrás de Caddy para obtener HTTPS automático. Asegúrate de que el DNS resuelva hacia la VPS y de que los puertos 80/443 estén abiertos, ya que ACME necesita validar el dominio.
Si prefieres Traefik o Nginx, compara las opciones en Traefik vs Caddy para HTTPS en Docker y elige la que mejor encaje en tu stack.
- TLS automático y renovación transparente.
- Reverse proxy sencillo de configurar con Caddy.
# Adicione o Caddy ao docker-compose.yml
services:
caddy:
image: caddy:2
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- registry
volumes:
caddy_data:
caddy_config:
---
# Crie o arquivo Caddyfile na mesma pasta
# Substitua registry.example.com pelo seu domínio
registry.example.com {
encode gzip
reverse_proxy registry:5000
}
# Suba/recrie tudo
docker compose up -d
6. Configurar clientes Docker para usar el mirror y el registry
En los clientes (máquinas de desarrollo, servidores de CI), apunta el mirror y reinicia el daemon. Reiniciar Docker puede interrumpir contenedores en ejecución. Después, haz login para las operaciones de push en tu dominio.
- El mirror acelera pulls de imágenes públicas del Docker Hub.
- Push/pull de imágenes privadas usa tu dominio con login.
# Linux (systemd): configure o mirror e reinicie o Docker
sudo tee /etc/docker/daemon.json >/dev/null <<'JSON'
{
"registry-mirrors": ["https://registry.example.com"],
"insecure-registries": [],
"log-driver": "json-file",
"log-opts": {"max-size": "10m", "max-file": "3"}
}
JSON
sudo systemctl restart docker
# Verifique
docker info | grep -A2 'Registry Mirrors'
7. Publicar y consumir imágenes privadas; probar el mirror
Después de configurar el cliente, autentícate y sube una imagen a tu registry. También validaremos el mirror tirando de una imagen pública común tras configurar el registry‑mirror.
# Faça login no seu registry
docker login registry.example.com
# Marque e envie sua imagem
# Exemplo: container local "myapp:1.0"
docker tag myapp:1.0 registry.example.com/minhaorg/myapp:1.0
docker push registry.example.com/minhaorg/myapp:1.0
# Teste pull privado
docker pull registry.example.com/minhaorg/myapp:1.0
# Teste o mirror (imagem pública do Hub)
docker pull nginx:alpine # deve ser servido via mirror após primeiro pull
8. Verificación y solución de problemas comunes
Confirma el acceso y revisa los logs. Ante fallos de HTTPS, verifica DNS y firewall. Para ahorrar espacio, considera limpiar tags y ejecutar garbage‑collect en el registry. Ejecutar garbage‑collect elimina capas huérfanas; haz backup antes.
- Prueba la API del registry: catálogo y tags.
- Revisa los logs del contenedor registry y del proxy.
- Errores de certificado: confirma dominio y puertos.
- Rate limit en el Hub: considera credenciales en el proxy.
# Testes rápidos (ajuste domínio/credenciais)
curl -u registryuser:S3nh@F0rte -fsSL https://registry.example.com/v2/_catalog | jq .
# Listar tags de um repositório
curl -u registryuser:S3nh@F0rte -fsSL https://registry.example.com/v2/minhaorg/myapp/tags/list | jq .
# Logs
docker logs --tail=100 registry
# (Opcional) Garbage collect — pare o serviço antes
# docker compose stop registry
# docker run --rm -v /opt/registry/data:/var/lib/registry \
# -v /opt/registry/auth:/auth registry:2 \
# garbage-collect /etc/docker/registry/config.yml
Preguntas frecuentes
¿Cuál es la diferencia entre registry privado y mirror (pull‑through cache)?
El registry privado almacena tus imágenes bajo tu dominio y control. El mirror actúa como caché para imágenes públicas del Docker Hub: las descarga bajo demanda, las guarda en disco y acelera pulls futuros. Puedes usar el mismo servicio para ambas funciones, con autenticación.
¿Necesito autenticación para usar el mirror?
Para pulls de imágenes públicas, el mirror puede estar accesible sin autenticación si lo expones así en el proxy. No obstante, es recomendable exigir autenticación para todo el acceso. Para pushes de imágenes privadas, la autenticación con docker login es obligatoria.
¿Dónde se almacenan las capas en caché?
Las capas se guardan en el directorio configurado del registry, en el volumen montado en /var/lib/registry. Asegura espacio en disco suficiente y sitúa el volumen en un disco rápido. Haz backups periódicos si las imágenes son críticas.
¿Cómo limpiar espacio en disco en el registry?
Elimina tags no usadas y ejecuta la recolección de basura (garbage‑collect) del registry con el servicio parado. Esto elimina capas huérfanas. Haz copia de seguridad antes, ya que la operación es destructiva para blobs no referenciados. Programa mantenimiento para evitar indisponibilidad.
¿Puedo usar un certificado TLS propio en lugar de ACME?
Sí. En Caddy o en tu proxy, desactiva la gestión automática y apunta a tus archivos de certificado y clave. Distribuye la cadena completa a los clientes. Si usas una CA interna, añade el certificado raíz al trust store de los hosts clientes.
¿El mirror acelera imágenes privadas de otros registries?
No. El pull‑through cache descrito aquí es para el Docker Hub público. Pulls de registries privados de terceros no pasan por el mirror. Para esos casos, autentícate y haz pull directamente desde el registry de origen.
¿Necesitas ayuda para adaptar el setup a tu entorno?
Si quieres revisar la topología, políticas de acceso, automatización de TLS o integración con CI/CD, podemos conversar sobre opciones y riesgos comunes.
Hablar sobre tu escenarioVer también
- Tutorial: implementar Canary releases con Traefik en Docker Compose usando headers y weighted routing para despliegues graduales de aplicaciones PHP
- Tutorial: configurar HAProxy con Let's Encrypt y healthchecks para balanceo de tráfico entre contenedores Docker en VPS (paso a paso)
- Tutorial práctico: implementar mTLS entre Nginx y microservicios usando smallstep CA en Docker Compose
- Tutorial: configurar cgroup v2 y systemd ResourceControl para limitar CPU, memoria e I/O de contenedores Docker en Debian