Conhecimento / Arquivo Técnico / ARC-001
Do git push à produção: como este site é construído e publicado
Um pipeline sem portas abertas e sem segredos no repositório, e uma lista honesta do que ele ainda não faz.
ARC-001Concluído2026-10-30DevSecOpsGitHub ActionsDockerCloudflare TunnelWatchtower
Publicar uma postagem neste site é um git push. Tudo o que vem depois é automático. Esta página descreve como isso funciona, as decisões de segurança por trás e, no final, o que ainda não está coberto.
O fluxo
git push
-> o GitHub Actions constrói uma imagem Docker
-> a imagem é guardada em um registro privado
-> o Watchtower no servidor baixa a imagem nova
-> o contêiner do site é recriado
-> um Cloudflare Tunnel o serve por HTTPS
Build: uma imagem pequena que roda como usuário comum
- Um Dockerfile em múltiplos estágios separa dependências, build e execução. O estágio final só tem o necessário para servir o site: a saída standalone do Next.js, os arquivos estáticos, os assets públicos e a pasta de conteúdo.
- O processo roda como usuário não root.
- Arquivos de desenvolvimento, o briefing do projeto e arquivos
.envficam fora do contexto de build. - A imagem tem um health check.
CI: o GitHub Actions publica a imagem
- O workflow roda a cada push na
main. - Ele faz login no GitHub Container Registry com o token que o GitHub cria para cada job. Esse token só existe enquanto o job roda, e o workflow o limita a ler o código e escrever pacotes. Nenhuma credencial de longa duração é guardada para o build.
- Cada imagem recebe duas etiquetas:
lateste o SHA do commit. Uma versão ruim pode ser revertida fixando o SHA. - O cache de camadas deixa os builds seguintes rápidos. O primeiro build levou cerca de seis minutos, e o seguinte cerca de trinta segundos.
Deploy: três contêineres e nenhuma porta de entrada
webé o site. Ele é publicado só na interface de loopback do servidor, então nada o alcança diretamente pela rede.cloudflaredabre um túnel de saída para a Cloudflare. O roteador não tem portas abertas, o IP de casa não fica exposto, e o HTTPS termina na Cloudflare.watchtowerconsulta o registro a cada cinco minutos. Ele só mexe nos contêineres que aderiram por uma etiqueta, e a versão dele está fixada. Quando aparece uma imagem nova, recria o contêiner.
Segredos
- Nada sensível está no git. Varri todo o histórico atrás de padrões de credenciais e não achei nenhum, e os arquivos
.envsão ignorados. - A credencial do túnel fica só em um arquivo
.envno servidor, legível apenas pelo dono, e o Compose se recusa a subir se ela faltar. - O servidor baixa a imagem privada com um token de acesso pessoal limitado a
read:packages, com data de expiração. - O pacote no registro é privado.
Decisões e trade-offs
- Atualização por pull, em vez de webhook de deploy ou SSH. O servidor não expõe nenhum endpoint de deploy, e o sistema de CI não guarda credenciais do servidor.
- Túnel em vez de redirecionamento de portas. Funciona atrás de um roteador residencial e mantém o IP de casa fora do DNS.
- Versão do Watchtower fixada. O projeto original estava arquivado e incompatível com versões recentes do Docker, então migrei para um fork mantido. Conferi a versão atual no Docker Hub em vez de confiar em um artigo, porque o artigo estava desatualizado.
O que ele ainda não faz
Esta é a parte honesta. O pipeline é útil e também é incompleto:
- O Watchtower precisa de acesso ao socket do Docker, o que na prática equivale a root no host. Um proxy de socket que limite o que ele pode chamar reduziria esse risco.
- As atualizações são confiadas pela etiqueta: o que for enviado para
latesté publicado. As imagens não são assinadas, e nada verifica uma assinatura. - Não há varredura de vulnerabilidades da imagem nem das dependências no CI, e também não há lista de materiais de software (SBOM).
- Algumas imagens usam etiqueta flutuante (o
cloudflaredusalatest), e nenhuma está fixada por digest. - A credencial do registro fica no servidor, no arquivo de configuração do Docker, que apenas a codifica.
- O rollback é manual.
Próximos passos
- Adicionar varredura de imagem e dependências (Trivy) e de segredos (gitleaks) ao workflow.
- Fixar imagens base e demais contêineres por digest.
- Assinar as imagens (cosign) e verificá-las antes do deploy.
- Colocar um proxy de socket do Docker na frente do Watchtower.