Docker · 13 min read · Oct 05, 2025

Cómo configurar un registro privado de Docker en Ubuntu 22.04

Si trabajas para una organización y deseas mantener tus imágenes de Docker en casa para un despliegue rápido, entonces alojar un repositorio privado de Docker es perfecto. Tener un registro privado de Docker te permite poseer tu canal de distribución de imágenes y tener un control más estricto sobre el almacenamiento y la distribución de imágenes. Puedes integrar tu registro con tu sistema CI/CD mejorando tu flujo de trabajo.

Este tutorial te enseñará cómo configurar y usar un registro privado de Docker en un servidor Ubuntu 22.04 utilizando Amazon S3 como ubicación de almacenamiento.

Prerrequisitos

  • Dos servidores Linux con Ubuntu 22.04. Un servidor actuará como el host del registro, mientras que el otro se utilizará como cliente para enviar solicitudes y recibir imágenes del host.
  • Un nombre de dominio registrado apuntando al servidor host. Usaremos registry.example.com para nuestro tutorial.
  • Un usuario no root con privilegios de sudo en ambas máquinas.
  • Asegúrate de que todo esté actualizado. $ sudo apt update $ sudo apt upgrade
  • Algunos paquetes que tu sistema necesita. $ sudo apt install wget curl nano software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y Algunos de estos paquetes pueden ya estar instalados en tu sistema.

Paso 1 - Configurar el Firewall

El primer paso es configurar el firewall. Ubuntu viene con ufw (Uncomplicated Firewall) por defecto.

Verifica si el firewall está en funcionamiento.

$ sudo ufw status

Deberías obtener la siguiente salida.

Estado: inactivo

Permite el puerto SSH para que el firewall no interrumpa la conexión actual al habilitarlo.

$ sudo ufw allow OpenSSH

Permite también los puertos HTTP y HTTPS.

$ sudo ufw allow http
$ sudo ufw allow https

Habilita el Firewall

$ sudo ufw enable
El comando puede interrumpir conexiones ssh existentes. ¿Proceder con la operación (y|n)? y
El firewall está activo y habilitado en el inicio del sistema

Verifica el estado del firewall nuevamente.

$ sudo ufw status

Deberías ver una salida similar.

Estado: activo

Para                         Acción      Desde
--                         ------      ----
OpenSSH                    PERMITIR    En cualquier lugar
80/tcp                     PERMITIR    En cualquier lugar
443                        PERMITIR    En cualquier lugar
OpenSSH (v6)               PERMITIR    En cualquier lugar (v6)
80/tcp (v6)                PERMITIR    En cualquier lugar (v6)
443 (v6)                   PERMITIR    En cualquier lugar (v6)

Paso 2 - Instalar Docker y Docker Compose

Este paso es necesario en ambas máquinas, el servidor y el cliente.

Ubuntu 22.04 viene con una versión más antigua de Docker. Para instalar la última versión, primero, importa la clave GPG de Docker.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Crea un archivo de repositorio de Docker.

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Actualiza la lista de repositorios del sistema.

$ sudo apt update

Instala la última versión de Docker.

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Verifica que esté en funcionamiento.

$ sudo systemctl status docker
? docker.service - Docker Application Container Engine
     Cargado: cargado (/lib/systemd/system/docker.service; habilitado; preset del proveedor: habilitado)
     Activo: activo (en ejecución) desde jue 2023-04-13 09:37:09 UTC; hace 3min 47s
TriggeredBy: ? docker.socket
       Docs: https://docs.docker.com
   Main PID: 2106 (dockerd)
      Tareas: 7
     Memoria: 26.0M
        CPU: 267ms
     CGroup: /system.slice/docker.service
             ??2106 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Por defecto, Docker requiere privilegios de root. Si deseas evitar usar sudo cada vez que ejecutes el comando docker, agrega tu nombre de usuario al grupo docker.

$ sudo usermod -aG docker $(whoami)

Necesitarás cerrar sesión en el servidor y volver a iniciar sesión como el mismo usuario para habilitar este cambio o usar el siguiente comando.

$ su - ${USER}

Confirma que tu usuario ha sido agregado al grupo Docker.

$ groups
navjot wheel docker

Paso 3 - Configurar el Registro de Docker

Crear directorios de usuario

Crea un directorio para la configuración del registro.

$ mkdir ~/docker-registry

Cambia al directorio docker-registry.

$ cd ~/docker-registry

Crea un directorio para almacenar la contraseña de autenticación HTTP, archivos de configuración de Nginx y certificados SSL.

$ mkdir auth

Crea otro directorio para almacenar los registros de Nginx.

$ mkdir logs

Crear un Bucket de Amazon S3

Puedes almacenar los datos del registro y las imágenes en tu servidor o usar un servicio de alojamiento en la nube. Para nuestro tutorial, utilizaremos el servicio en la nube de Amazon S3.

El siguiente paso es configurar el archivo de configuración con algunos ajustes importantes. Estos ajustes también se pueden definir en el archivo docker-compose.yml, pero tener un archivo separado es mucho mejor.

Crea un bucket con los siguientes ajustes.

  • ACL debe estar deshabilitado.
  • El acceso público al bucket debe estar deshabilitado.
  • La versión del bucket debe estar deshabilitada.
  • Habilitar la encriptación del bucket utilizando claves gestionadas por Amazon S3. (SSE-S3)
  • El bloqueo de objetos debe estar deshabilitado.

Crea un usuario IAM con la siguiente política.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketLocation",
        "s3:ListBucketMultipartUploads"
      ],
      "Resource": "arn:aws:s3:::S3_BUCKET_NAME"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListMultipartUploadParts",
        "s3:AbortMultipartUpload"
      ],
      "Resource": "arn:aws:s3:::S3_BUCKET_NAME/*"
    }
  ]
}

Reemplaza S3_BUCKET_NAME con el nombre de tu bucket S3.

Anota la clave secreta, el valor secreto y la región del bucket para usarlos más tarde.

Crear Archivo de Docker Compose

Crea el archivo docker-compose.yml y ábrelo para editar.

$ nano docker-compose.yml

Pega el siguiente código en él.

services:
  registry:
    image: registry:2
    restart: always
    environment:
      - REGISTRY_STORAGE=s3
      - REGISTRY_STORAGE_S3_REGION=us-west-2
      - REGISTRY_STORAGE_S3_BUCKET=hf-docker-registry
      - REGISTRY_STORAGE_S3_ENCRYPT=true
      - REGISTRY_STORAGE_S3_CHUNKSIZE=5242880
      - REGISTRY_STORAGE_S3_SECURE=true
      - REGISTRY_STORAGE_S3_ACCESSKEY=AKIA3FIG4NVFNXKQXMSJ
      - REGISTRY_STORAGE_S3_SECRETKEY=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
      - REGISTRY_STORAGE_S3_V4AUTH=true
      - REGISTRY_STORAGE_S3_ROOTDIRECTORY=/image-registry
      - REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
      - REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false
  nginx:
    image: "nginx:alpine"
    ports:
      - 443:443
    links:
      - registry:registry
    volumes:
      - ./auth:/etc/nginx/conf.d
      - ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./logs:/var/log/nginx
      - /etc/letsencrypt:/etc/letsencrypt

Guarda el archivo presionando Ctrl + X y entrando Y cuando se te pida.

Repasemos lo que hemos configurado en nuestro archivo de composición.

  1. El primer paso es obtener la última imagen de la versión 2 del registro de Docker desde el hub. No estamos usando la etiqueta más reciente porque puede causar problemas en caso de una actualización de versión mayor. Configurarlo en 2 te permite obtener todas las actualizaciones 2.x mientras se evita ser actualizado automáticamente a la siguiente versión mayor, que puede introducir cambios incompatibles.
  2. El contenedor del registro está configurado para reiniciarse siempre en caso de fallo o apagado inesperado.
  3. Hemos establecido varias variables de entorno para el almacenamiento de Amazon S3. Repasemos rápidamente. - REGISTRY_STORAGE establece el tipo de almacenamiento. Hemos seleccionado s3 ya que estamos utilizando Amazon S3.
  • REGISTRY_STORAGE_S3_REGION establece la región de tu bucket S3.
  • REGISTRY_STORAGE_S3_BUCKET establece el nombre de tu bucket S3.
  • REGISTRY_STORAGE_S3_ENCRYPT - configúralo en true si has habilitado la encriptación del bucket.
  • REGISTRY_STORAGE_S3_CHUNKSIZE establece el tamaño de los fragmentos de carga. Debe ser mayor de 5MB (5 1024 1024).
  • REGISTRY_STORAGE_S3_SECURE - configúralo en true si vas a usar HTTPS.
  • REGISTRY_STORAGE_S3_ACCESSKEY y REGISTRY_STORAGE_S3_SECRETKEY - Credenciales de usuario que obtuviste después de crear tu usuario IAM.
  • REGISTRY_STORAGE_S3_V4AUTH - configúralo en true si usas v4 de la autenticación de AWS. Si estás obteniendo errores relacionados con el inicio de sesión en S3, configúralo en false.
  • REGISTRY_STORAGE_S3_ROOTDIRECTORY - establece el directorio raíz en tu bucket bajo el cual se almacenarán los datos de tu registro.
  • REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR - establece la ubicación para la caché. En nuestro caso, lo estamos almacenando en memoria. También puedes configurarlo para usar Redis.
  • REGISTRY_HEALTH_STORAGEDRIVER_ENABLED - configúralo en false para deshabilitar el servicio de verificación de salud del almacenamiento del registro. Hay un error con el registro que puede causar problemas si no lo configuras en false.
  1. El registro de Docker se comunica a través del puerto 5000, que es lo que hemos expuesto en nuestro servidor al docker.
  2. ./auth:/etc/nginx/conf.d asegura que todas las configuraciones de Nginx estén disponibles en el contenedor.
  3. ./auth/nginx.conf:/etc/nginx/nginx.conf:ro mapea el archivo de configuración de Nginx del sistema a uno en el contenedor en modo de solo lectura.
  4. ./logs:/var/log/nginx permite el acceso a los registros de Nginx en el sistema mapeando al directorio de registros de Nginx en el contenedor.
  5. La configuración del registro de Docker se almacena en el archivo /etc/docker/registry/config.yml en el contenedor, y lo hemos mapeado al archivo config.yml en el directorio actual, que crearemos en el siguiente paso.

Configurar Autenticación

Para configurar la autenticación HTTP, necesitas instalar el paquete httpd-tools.

$ sudo apt install apache2-utils -y

Crea el archivo de contraseñas en el directorio ~/docker-registry/auth.

$ htpasswd -Bc ~/docker-registry/auth/nginx.htpasswd user1
Nueva contraseña:
Reescribe la nueva contraseña:
Agregando contraseña para el usuario user1

La bandera -c indica al comando que cree un nuevo archivo, y la bandera -B es para usar el algoritmo bcrypt soportado por Docker. Reemplaza user1 con un nombre de usuario de tu elección.

Si deseas agregar más usuarios, ejecuta el comando nuevamente, pero sin la bandera -c.

$ htpasswd -B ~/docker-registry/auth/registry.password user2

Ahora, el archivo será mapeado al contenedor del registro para la autenticación.

Paso 4 - Instalar SSL

Necesitamos instalar Certbot para generar el certificado SSL. Puedes instalar Certbot usando el repositorio de Ubuntu o obtener la última versión usando la herramienta Snapd. Usaremos la versión de Snapd.

Ubuntu 22.04 viene con Snapd instalado por defecto. Ejecuta los siguientes comandos para asegurarte de que tu versión de Snapd esté actualizada.

$ sudo snap install core && sudo snap refresh core

Instala Certbot.

$ sudo snap install --classic certbot

Usa el siguiente comando para asegurarte de que el comando Certbot pueda ejecutarse creando un enlace simbólico al directorio /usr/bin.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Ejecuta el siguiente comando para generar un certificado SSL.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d registry.example.com

El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/registry.example.com en tu servidor.

Genera un certificado de grupo Diffie-Hellman.

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

Verifica el servicio programador de renovación de Certbot.

$ sudo systemctl list-timers

Encontrarás snap.certbot.renew.service como uno de los servicios programados para ejecutarse.

NEXT                        LEFT          LAST                        PASSED        UNIT                      ACTIVATES
.....
Dom 2023-04-14 00:00:00 UTC 19min left    Sab 2023-02-25 18:04:05 UTC n/a          snap.certbot.renew.timer  snap.certbot.renew.service
Dom 2023-04-14 00:00:20 UTC 19min left    Sab 2023-02-25 10:49:23 UTC 14h ago      apt-daily-upgrade.timer   apt-daily-upgrade.service
Dom 2023-04-14 00:44:06 UTC 3h 22min left Sab 2023-02-25 20:58:06 UTC 7h ago       apt-daily.timer           apt-daily.service

Realiza una prueba del proceso para verificar si la renovación de SSL está funcionando correctamente.

$ sudo certbot renew --dry-run

Si no ves errores, estás listo. Tu certificado se renovará automáticamente.

Copiar el archivo Dhparam al contenedor

Copia el certificado de grupo Diffie-Hellman al directorio ~/docker-registry/auth, que será mapeado al contenedor.

$ sudo cp /etc/ssl/certs/dhparam.pem ~/docker-registry/auth

Paso 5 - Configurar Nginx

El siguiente paso implica configurar el servidor Nginx como un proxy frontal para el servidor de registro de Docker. El registro de Docker viene con un servidor incorporado que opera en el puerto 5000. Lo pondremos detrás de Nginx.

Crea y abre el archivo ~/docker-registry/auth/nginx.conf para editar.

$ sudo nano ~/docker-registry/auth/nginx.conf

Pega el siguiente código en él.

events {
    worker_connections  1024;
}

http {

  upstream docker-registry {
    server registry:5000;
  }

  ## Establecer una variable para ayudarnos a decidir si necesitamos agregar el
  ## encabezado 'Docker-Distribution-Api-Version'.
  ## El registro siempre establece este encabezado.
  ## En el caso de que nginx realice la autenticación, el encabezado no se establece
  ## ya que nginx está autenticando antes de hacer el proxy.
  map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
    '' 'registry/2.0';
  }

  server {
    listen 443 ssl http2;
    server_name registry.example.com;

    # SSL
    ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/registry.example.com/chain.pem;

    access_log  /var/log/nginx/registry.access.log;
    error_log   /var/log/nginx/registry.error.log;

    # Recomendaciones de https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers on;
    ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/nginx/conf.d/dhparam.pem;
    resolver 8.8.8.8;

    # deshabilitar cualquier límite para evitar HTTP 413 para cargas de imágenes grandes
    client_max_body_size 0;

    # requerido para evitar HTTP 411: ver el Problema #1486 (https://github.com/moby/moby/issues/1486)
    chunked_transfer_encoding on;

    location /v2/ {
      # No permitir conexiones desde docker 1.5 y anteriores
      # docker pre-1.6.0 no estableció correctamente el agente de usuario en ping, atrapa "Go *" agentes de usuario
      if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
        return 404;
      }

      # Para agregar autenticación básica a v2 usa la configuración auth_basic.
      auth_basic "Realm del Registro";
      auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;

      ## Si $docker_distribution_api_version está vacío, el encabezado no se agrega.
      ## Ver la directiva map arriba donde se define esta variable.
      add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;

      proxy_pass                          http://docker-registry;
      proxy_set_header  Host              $http_host;   # requerido por el cliente de docker
      proxy_set_header  X-Real-IP         $remote_addr; # pasar la IP real del cliente
      proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Proto $scheme;
      proxy_read_timeout                  900;
    }
  }
}

Guarda el archivo presionando Ctrl + X y entrando Y cuando se te pida una vez que hayas terminado.

Paso 6 - Lanzar el Registro de Docker

Cambia al directorio del Registro de Docker.

$ cd ~/docker-registry

Lanza el contenedor de docker.

$ docker compose up -d

Verifica el estado de los contenedores.

$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                      NAMES
3328b7e36bb2   nginx:alpine   "/docker-entrypoint.…"   Hace un minuto       En ejecución hace 3 segundos        80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   docker-registry-nginx-1
bf7cdfc0e013   registry:2     "/entrypoint.sh /etc…"   Hace un minuto       En ejecución hace aproximadamente un minuto   5000/tcp                                 docker-registry-registry-1

Inicia sesión en el registro de Docker.

$ docker login -u=user1 -p=password https://registry.example.com

Obtendrás la siguiente salida.

¡ADVERTENCIA! Usar --password a través de la CLI no es seguro. Usa --password-stdin.
¡ADVERTENCIA! Tu contraseña se almacenará sin encriptar en /home/username/.docker/config.json.
Configura un ayudante de credenciales para eliminar esta advertencia. Ver
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Inicio de sesión exitoso

También puedes abrir la URL https://registry.example.com/v2/ en tu navegador, y te pedirá un nombre de usuario y contraseña. Deberías ver una página vacía con {} en ella.

Puedes verificar la URL en la terminal usando curl.

$ curl -u user1 -X GET https://registry.example.com/v2/
Ingresa la contraseña del host para el usuario 'user1':
{}

Descarga la última imagen de Ubuntu.

$ docker pull ubuntu:latest

Etiqueta esta imagen para el registro privado.

$ docker tag ubuntu:latest registry.example.com/ubuntu2204

Envía la imagen al registro.

$ docker push registry.example.com/ubuntu2204

Prueba si el envío ha sido exitoso.

$ curl -u user1 -X GET https://registry.example.com/v2/_catalog
Ingresa la contraseña del host para el usuario 'user1':
{"repositories":["ubuntu2204"]}

Ingresa tu contraseña de autenticación de Nginx cuando se te pida, y verás la lista de repositorios disponibles a través del registro.

Cierra sesión usando la terminal para borrar las credenciales.

$ docker logout https://registry.example.com
Eliminando credenciales de inicio de sesión para registry.example.com

Verifica la lista de imágenes de Docker actualmente disponibles para su uso.

$ docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
registry                             2         8db46f9d7550   hace 2 semanas   24.2MB
nginx                                alpine    8e75cbc5b25c   hace 2 semanas   41MB
ubuntu                               latest    08d22c0ceb15   hace 5 semanas   77.8MB
registry.example.com/ubuntu2204      latest    08d22c0ceb15   hace 5 semanas   77.8MB

Paso 7 - Acceder y usar el registro de Docker desde la máquina cliente

Inicia sesión en tu servidor cliente. En el paso 1, instalamos Docker en la máquina cliente.

Inicia sesión en el registro privado de Docker desde la máquina cliente.

$ docker login -u=user1 -p=password https://registry.example.com

Extrae la imagen de Ubuntu del registro.

$ docker pull registry.example.com/ubuntu2204

Lista todas las imágenes en tu máquina cliente.

$ docker images
REPOSITORY                        TAG        IMAGE ID       CREATED         SIZE
registry.example.com/ubuntu2204   latest     08d22c0ceb15   hace 5 semanas   77.8MB

Crea y lanza un contenedor usando la imagen descargada.

$ docker run -it registry.example.com/ubuntu2204 /bin/bash

Estarás dentro del Shell dentro del contenedor de Ubuntu.

root@647899f255db:

Ejecuta el siguiente comando para verificar la versión de Linux.

root@a2da49fdbea9$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

Ahora, puedes comenzar a usar tu registro de Docker desde tus máquinas cliente.

Conclusión

Esto concluye nuestro tutorial sobre cómo configurar un registro privado de Docker en un servidor Ubuntu 22.04 que utiliza Amazon S3 como almacenamiento. Si tienes alguna pregunta, publícalas en los comentarios a continuación.

Share: X/Twitter LinkedIn

Recibe nuevas publicaciones en tu bandeja de entrada.

No spam. Cancela la suscripción en cualquier momento.