Como Hospedar um Registry Privado Docker na VPS

11 min de leitura Docker
Como Hospedar um Registry Privado Docker na VPS

Introdução ao Registry Privado na VPS

A gestão de imagens Docker é um pilar fundamental para o desenvolvimento moderno e a operação de infraestrutura como código. Embora repositórios públicos como o Docker Hub sejam convenientes para bibliotecas oficiais, eles não atendem às necessidades de segurança e privacidade exigidas por aplicações proprietárias. Empresas frequentemente necessitam armazenar suas próprias imagens contendo configurações específicas, credenciais (embora isso deva ser evitado) ou lógica de negócio compilada.

Neste tutorial, demonstraremos como configurar um registry privado docker em uma VPS Linux, utilizando o stack oficial da Docker Inc. A solução será orquestrada via docker compose, garantindo persistência de dados e facilidade de manutenção. Além disso, implementaremos camadas críticas de segurança e usabilidade: um reverse proxy com Traefik para roteamento inteligente, certificados SSL automáticos via Let's Encrypt para criptografia em trânsito, e o Watchtower para atualização automática dos containers.

Este guia é destinado a sysadmins e desenvolvedores que buscam controle total sobre seu ciclo de vida de imagens. Ao final, você terá um serviço robusto, seguro e escalável, pronto para receber as builds do seu pipeline CI/CD.

Pré-requisitos e Preparação do Ambiente

Antes de iniciar a implementação, certifique-se de que sua VPS atenda aos seguintes requisitos mínimos:

  • Sistema operacional Linux (Ubuntu 20.04/22.04 ou Debian 11/12 recomendados).
  • Acesso root ou usuário com privilégios sudo.
  • Docker e Docker Compose instalados na máquina.
  • Um domínio registrado apontando para o IP da sua VPS (ex: registry.seudominio.com).
  • Pasta de armazenamento persistente criada no sistema de arquivos local ou em volume montado.

Para garantir que seu ambiente esteja atualizado, execute os comandos abaixo. Isso previne conflitos de dependências e garante a instalação das versões mais recentes do Docker Engine.

sudo apt update && sudo apt upgrade -y
sudo apt install docker.io docker-compose-plugin -y
sudo systemctl enable docker
sudo systemctl start docker

Se você ainda não possui o Traefik em execução na mesma VPS, recomendamos que ele seja o primeiro serviço a ser configurado, pois o Registry dependerá dele para gerenciar os certificados SSL e o roteamento HTTP/HTTPS. O foco deste tutorial, contudo, é a configuração específica do serviço de registry dentro da stack existente.

Estrutura de Diretórios e Arquivos de Configuração

A organização dos arquivos é crucial para a manutenibilidade. Crie um diretório dedicado para o projeto do Registry. Isso facilitará backups e migrações futuras.

mkdir -p ~/docker/registry/data
mkdir -p ~/docker/registry/config

Dentro da pasta config, criaremos o arquivo de configuração do Docker Registry, o config.yml. Este arquivo define onde as imagens serão armazenadas fisicamente e como a autenticação funcionará. Para este tutorial, utilizaremos autenticação básica com senha em texto simples (hash) para fins didáticos, mas em produção, considere integrar com LDAP ou OAuth.

nano ~/docker/registry/config/config.yml

Cole o seguinte conteúdo no arquivo:

version: 0.1
log:
  fields:
    service: registry
storage:
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
auth:
  htpasswd:
    realm: "Restricted Registry"
    path: /etc/docker/registry/auth.htpasswd

Em seguida, precisamos gerar as credenciais de acesso. Instale a ferramenta apache2-utils para utilizar o comando htpasswd.

sudo apt install apache2-utils -y
htpasswd -nbB admin senha_forte_aqui > ~/docker/registry/config/auth.htpasswd

Este comando gera um hash seguro e salva no arquivo auth.htpasswd. Substitua senha_forte_aqui por uma senha complexa. Mantenha este arquivo em segredo absoluto.

Configuração do Docker Compose para o Registry

Agora, criaremos o arquivo docker-compose.yml na raiz do diretório ~/docker/registry. Este arquivo define o serviço do registry e suas dependências implícitas de rede com o Traefik.

nano ~/docker/registry/docker-compose.yml

O conteúdo deve seguir a estrutura abaixo, que integra o serviço ao reverse proxy Traefik:

version: '3.8'

services:
  registry:
    image: registry:2
    container_name: private-registry
    restart: always
    environment:
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
    volumes:
      - ./config/config.yml:/etc/docker/registry/config.yml:ro
      - ./data:/var/lib/registry
      - ./config/auth.htpasswd:/etc/docker/registry/auth.htpasswd:ro
    networks:
      - web
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.registry.rule=Host(`registry.seudominio.com`)"
      - "traefik.http.services.registry.loadbalancer.server.port=5000"
      - "traefik.http.middlewares.registry-auth.basicauth.usersfile=/etc/docker/registry/auth.htpasswd"
      - "traefik.http.routers.registry.middlewares=registry-auth@docker"

networks:
  web:
    external: true

Observe as diretivas labels do Traefik. Elas são essenciais para que o serviço seja exposto corretamente via HTTPS e protegido por autenticação. O label traefik.http.middlewares.registry-auth.basicauth.usersfile aponta para o arquivo gerado anteriormente, permitindo que o proxy valide as credenciais antes de encaminhar a requisição ao container do registry.

A rede web: external: true indica que o container deve se conectar à rede externa definida pelo seu stack principal do Traefik. Certifique-se de que essa rede exista no seu ambiente.

Implantação e Validação dos Serviços

Com os arquivos configurados, inicie o serviço usando o Docker Compose. O comando abaixo baixará a imagem oficial, criará os volumes e iniciará o container.

cd ~/docker/registry
docker compose up -d

Aguarde alguns instantes para que o Traefik gere os certificados SSL via Let's Encrypt. Você pode verificar o status dos containers com:

docker ps

Se tudo estiver correto, você verá o container private-registry em estado "Up". Para confirmar que o SSL está ativo, acesse via navegador ou curl:

curl -k https://registry.seudominio.com/v2/

O retorno deve ser um objeto JSON vazio {}, indicando que o endpoint API está acessível e seguro. O uso de -k ignora a verificação local do certificado, mas como estamos usando Let's Encrypt confiável, em ambientes reais você pode remover essa flag se o certificado estiver instalado no host.

Configuração do Host Docker para Push e Pull

Aqui reside um dos pontos de troubleshooting containers mais comuns: o Docker daemon no seu computador local (ou em outras VPS) não confiará automaticamente em um registry HTTPS com certificado autoassinado ou interno. Como estamos usando SSL público, isso deve funcionar, mas precisamos dizer ao Docker onde encontrar nosso registry.

No servidor que enviará as imagens (build server ou sua máquina local), edite o arquivo /etc/docker/daemon.json. Se o arquivo não existir, crie-o.

nano /etc/docker/daemon.json

Adicione a URL do seu registry à lista de insecure-registries apenas se você estiver usando HTTP ou certificado inválido. Como estamos usando HTTPS válido, tecnicamente não é necessário adicionar ao insecure-registries, mas muitos administradores adicionam o domínio para facilitar a resolução. No entanto, a prática recomendada para SSL público é confiar no sistema de certificados do OS.

Importante: Se você estiver em uma rede interna sem DNS público confiável ou usando autowrapping local, pode ser necessário adicionar ao insecure-registries. Para este cenário de VPS pública com SSL:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Não adicione ao insecure se o SSL for válido. O Docker confiará no CA raiz do sistema operacional.

Testando Push e Pull de Imagens

Agora, teste a funcionalidade completa. Vamos fazer login, enviar uma imagem leve (como alpine) e baixá-la em outro lugar.

No terminal do cliente:

docker login registry.seudominio.com

Insira o usuário admin e a senha definida anteriormente. Se o login for bem-sucedido, você verá "Login Succeeded".

Para enviar uma imagem:

docker pull alpine:latest
docker tag alpine:latest registry.seudominio.com/admin/alpine:latest
docker push registry.seudominio.com/admin/alpine:latest

O processo de upload pode demorar alguns segundos dependendo da sua largura de banda. Após o término, verifique se a imagem está listada acessando a interface web do seu registry (se configurada com UI como Portainer ou Registry UI) ou via API:

curl -u admin:senha https://registry.seudominio.com/v2/admin/alpine/tags/list

O retorno deve ser {"name":"admin/alpine","tags":["latest"]}.

Mantendo o Sistema Atualizado com Watchtower

Manter a imagem do container do Registry atualizada é vital para correções de segurança. Em vez de atualizar manualmente, integraremos o Watchtower. Este monitor continua rodando em segundo plano e verifica se há novas versões das imagens configuradas.

Adicione o Watchtower ao seu stack principal (onde está o Traefik) ou crie um compose separado. Aqui assumiremos que ele roda na mesma rede web.

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --cleanup \
  --interval 3600 \
  --label-enable

A flag --label-enable faz com que o Watchtower apenas monitore containers que possuem a label com.centurylinklabs.watchtower.enable=true. Para ativar isso no seu registry, edite o docker-compose.yml do registry e adicione:

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Em seguida, recrie o container:

cd ~/docker/registry
docker compose up -d --force-recreate

Agora, a cada hora (intervalo de 3600 segundos), o Watchtower verificará se uma nova versão da imagem registry:2 foi publicada no Docker Hub. Se houver, ele baixará a nova imagem, parará o container antigo, moverá os dados persistentes (que estão em volume, então não serão perdidos) e iniciará o novo container.

Troubleshooting Comum

Apesar da simplicidade relativa, problemas podem ocorrer. Aqui estão as causas mais frequentes de falhas em um registry privado docker.

1. Erro "http: server gave HTTP response to HTTPS client"

Isso ocorre quando o cliente Docker tenta conectar via HTTPS, mas o serviço responde apenas HTTP, ou vice-versa. Verifique se o Traefik está redirecionando corretamente as portas 80 e 443 para o container do registry na porta 5000. Confirme também que o label traefik.http.services.registry.loadbalancer.server.port=5000 está correto.

2. Falha de SSL / Certificate Expired

O Traefik lida automaticamente com a renovação do Let's Encrypt. Se o certificado expirar, verifique os logs do container do Traefik:

docker logs traefik

Procure por erros de conexão com a API da Let's Encrypt. Frequentemente, firewalls bloqueiam a saída na porta 443 necessária para a validação ACME.

3. Espaço em Disco Cheio

O diretório ./data armazena todas as camadas das imagens. Imagens Docker podem ser grandes. Monitore o uso de disco da sua VPS:

df -h /caminho/para/docker/registry/data

Se o disco encher, o registry entrará em modo apenas-leitura e não aceitará novos pushes. Configure rotacionamento de logs do Docker e monitore o espaço.

4. Erro de Autenticação 401 Unauthorized

Verifique se o arquivo auth.htpasswd está sendo montado corretamente no container. Use docker exec -it private-registry cat /etc/docker/registry/auth.htpasswd para verificar o conteúdo dentro do container. Se estiver vazio, há erro na montagem de volume.

Conclusão e Boas Práticas

A configuração de um registry privado docker em sua VPS oferece controle total sobre suas imagens proprietárias. Ao utilizar docker compose, Traefik para reverse proxy e SSL automático, e Watchtower para manutenção, você estabelece uma infraestrutura resiliente.

Lembre-se de proteger o acesso ao painel administrativo e considerar a implementação de backups regulares do diretório data. Para ambientes de alta disponibilidade, considere replicar os dados para um bucket S3 ou outro armazenamento em nuvem, utilizando drivers de storage alternativos no config.yml.

Com esta base sólida, você está preparado para integrar este registry ao seu pipeline CI/CD, acelerando o ciclo de desenvolvimento com segurança e eficiência.

Compartilhar: Link copiado!
Esse tutorial foi útil?

Comentários (0)

Seja o primeiro a comentar.

Deixe seu comentário

Seu comentário será analisado antes de ser publicado.

0/2000