Registry Docker self-hosted na VPS
Um registry Docker self-hosted armazena suas imagens de container localmente — sem depender do Docker Hub ou GHCR, sem limites de pull, com latência mínima para a VPS que vai fazer o pull. Ideal para ambientes offline, compliance com soberania de dados ou pipelines de alta frequência.
Registry oficial Docker self-hosted
Instalar o registry Docker da distribuição oficial:
# docker-compose.yml — Registry Docker com autenticação básica:
services:
registry:
image: registry:2
restart: always
ports:
- "127.0.0.1:5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: "Docker Registry"
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
# Ativar interface de gerenciamento:
REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin: '["*"]'
volumes:
- registry_data:/data
- ./auth:/auth
volumes:
registry_data:
# Criar arquivo de autenticação htpasswd:
# (instalar: apt install apache2-utils)
mkdir -p auth
htpasswd -Bbn meu-usuario minha-senha > auth/htpasswd
# Expor via Nginx com HTTPS (obrigatório para registry remoto):
# O Docker client exige HTTPS para registry remotos (exceto localhost)Nginx como proxy com HTTPS
Expor o registry com HTTPS e certificado Let's Encrypt:
# /etc/nginx/conf.d/registry.conf:
server {
listen 443 ssl http2;
server_name registry.seudominio.com.br;
ssl_certificate /etc/letsencrypt/live/registry.seudominio.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.seudominio.com.br/privkey.pem;
# Aumentar limite para push de imagens grandes:
client_max_body_size 2G;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
# Login no registry:
docker login registry.seudominio.com.br
# (informar usuário e senha do htpasswd)
# Build e push para o registry self-hosted:
docker build -t registry.seudominio.com.br/minha-org/minha-api:latest .
docker push registry.seudominio.com.br/minha-org/minha-api:latest
# Pull na VPS:
docker pull registry.seudominio.com.br/minha-org/minha-api:latestGitea com Container Registry integrado
Gitea fornece git hosting + container registry em um único serviço:
# docker-compose.yml — Gitea com Container Registry:
services:
gitea:
image: gitea/gitea:latest
restart: always
environment:
USER_UID: 1000
USER_GID: 1000
GITEA__packages__ENABLED: "true" # ativar Container Registry
ports:
- "127.0.0.1:3000:3000"
- "22:22" # SSH para git push
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
volumes:
gitea_data:
# Após criar conta e organização no Gitea:
# Login no Container Registry do Gitea:
docker login gitea.seudominio.com.br
# Usuário: seu usuário do Gitea
# Senha: Personal Access Token (Settings → Applications → Generate Token)
# Push de imagem:
docker tag minha-api gitea.seudominio.com.br/minha-org/minha-api:latest
docker push gitea.seudominio.com.br/minha-org/minha-api:latest
# O package aparece em: Gitea → Packages → ContainerIntegrar registry self-hosted com GitHub Actions
Push para o registry próprio no pipeline de CI/CD:
# .github/workflows/build.yml:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login no registry self-hosted
uses: docker/login-action@v3
with:
registry: registry.seudominio.com.br
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build e push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
registry.seudominio.com.br/minha-org/minha-api:latest
registry.seudominio.com.br/minha-org/minha-api:${{ github.sha }}
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Na VPS — já autenticada no registry local:
docker pull registry.seudominio.com.br/minha-org/minha-api:${{ github.sha }}
cd /opt/minha-api
sed -i 's|:.*|:${{ github.sha }}|' docker-compose.yml
docker compose up -d apiLimpeza automática de imagens antigas
Evitar que o disco encha com imagens não utilizadas:
#!/bin/bash
# /opt/scripts/cleanup-registry.sh
# Deletar manifests de mais de 30 dias via Registry API:
REGISTRY="http://localhost:5000"
AUTH="meu-usuario:minha-senha"
# Listar repositórios:
REPOS=$(curl -s -u "$AUTH" "$REGISTRY/v2/_catalog" | jq -r '.repositories[]')
for REPO in $REPOS; do
# Listar todas as tags:
TAGS=$(curl -s -u "$AUTH" "$REGISTRY/v2/$REPO/tags/list" | jq -r '.tags[]?')
for TAG in $TAGS; do
# Verificar data de criação pelo digest:
DIGEST=$(curl -s -u "$AUTH" -I \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
"$REGISTRY/v2/$REPO/manifests/$TAG" | grep Docker-Content-Digest | awk '{print $2}' | tr -d '\r')
# (lógica de idade da imagem via label ou timestamp)
echo " $REPO:$TAG → $DIGEST"
done
done
# Limpeza mais simples — remover imagens não usadas na VPS:
docker image prune -a --filter "until=720h" -f # imagens com mais de 30 dias
docker volume prune -f # volumes órfãos
docker system df # ver uso de disco do Docker
# Crontab — executar toda semana:
# 0 2 * * 0 root /opt/scripts/cleanup-registry.sh$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS para Docker em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.