Deploy com rsync, SSH e Symlinks Atómicos: Como Atualizar Sites Estáticos no HestiaCP Sem Ficheiros Partidos
A Condição de Corrida nos Deploys Comuns: O Perigo de Copiar Ficheiros Diretos
Acabaste de compilar o teu site estático ultrarrápido em Astro, Hugo ou Next.js. O teu script de build gerou ficheiros HTML otimizados, folhas de estilo e ficheiros JavaScript compactados com hashes criptográficos na pasta dist/.
A seguir, disparas um comando muito comum:
# O ERRO TÍPICO: Escrever diretamente por cima da pasta de produção
rsync -avz --delete ./dist/ utilizador@servidor:/home/utilizador/web/dominio.com/public_html/
À primeira vista, este comando parece inofensivo. No entanto, num servidor em produção com tráfego real, este comando cria uma perigosa condição de corrida.
A CONDIÇÃO DE CORRIDA DURANTE UM DEPLOY COMUM
- O rsync está a gravar 50MB de ficheiros novos (Tempo decorrido: 4 segundos…)
- Ficheiros no disco: [ index.html (NOVO) ] [ app.b8f9.js (A GRAVAR…) ] [ style.css (ANTIGO) ]
- Um Utilizador Entra no Site ao Segundo 2: 1. O Nginx serve o novo index.html → Que pede o ficheiro
app.b8f9.js -
- O browser pede
app.b8f9.js→ Mas o ficheiro ainda só está a meio!
- O browser pede
- Resultado: SyntaxError: Unexpected end of input → ECRÃ BRANCO NO CLIENTE!
Durante os 4 a 8 segundos em que o rsync está a percorrer a árvore de pastas e a substituir ficheiros, a tua pasta pública fica num estado híbrido inconsistente:
- O ficheiro
index.htmljá foi substituído e aponta para os novos blocos de JavaScript. - O browser do teu visitante lê esse HTML e pede imediatamente o ficheiro
chunk-99a2c.js. - Como o
rsyncainda vai a meio da lista, o Nginx responde com 404 Not Found. - O utilizador fica com o site desconfigurado e a consola cheia de erros de execução.
Em produção precisas de atomicidade matemática. Ou o visitante vê a Versão A, ou vê a Versão B. Nunca pode apanhar o sistema a meio da mudança.
Nas soluções que desenvolvemos no nosso serviço de alojamento gerido e na entrega de websites estáticos rápidos, aplicamos sempre a arquitetura de symlinks atómicos para garantir zero falhas e reversões imediatas.
A Arquitetura de Symlinks Atómicos: Pastas Releases, Shared e Current
O padrão de excelência para deploys com paragem zero em servidores sem Docker pesado baseia-se no modelo clássico do Capistrano. Criado no ecossistema Ruby, este método tira partido das regras nativas do sistema de ficheiros em Debian GNU/Linux.
ESTRUTURA DE PASTAS PARA DEPLOY ATÓMICO
- /home/utilizador/web/dominio.com/ releases/
- 20261019_100000/ (Versão Antiga N-2)
- 20261019_120000/ (Versão Anterior N-1)
- 20261019_140000/ (Versão Mais Recente N - Já enviada a 100%)
- shared/ uploads/ (Imagens de utilizadores e ficheiros fixos)
- .env (Variáveis de ambiente)
- public_html → LINK SIMBÓLICO para releases/20261019_140000/
- O Nginx entrega a versão ativa instantaneamente!
Como Funciona Este Mecanismo:
- Cada envio copia os novos ficheiros para uma pasta isolada com o carimbo temporal UTC:
releases/AAAAMMDD_HHMMSS/. - A transferência acontece em segundo plano sem ninguém ver. Os teus visitantes continuam a navegar na versão anterior sem solavancos.
- Se a tua ligação cair ou o
rsyncfalhar a meio, o site ativo não sofre rigorosamente nada. Basta apagares a pasta temporária. - Quando a transferência termina com sucesso, um comando do Linux altera o apontador do link
public_htmlpara a nova diretoria. - No kernel do Linux, alterar um link simbólico através de
rename()é uma operação atómica. Não existe nenhum milissegundo de vazio.
Passo a Passo para Configurar no HestiaCP e Nginx
Vamos preparar o teu servidor Debian 12 com HestiaCP e Nginx para este modelo de trabalho.
1. Prepara as Diretorias no Servidor
Liga-te por SSH ao teu servidor e organiza as pastas do teu domínio:
# Entra na pasta do teu domínio no HestiaCP
cd /home/admin/web/dominio.com
# 1. Guarda a pasta antiga por precaução
mv public_html public_html_antigo
# 2. Cria as pastas de releases e armazenamento partilhado
mkdir -p releases shared/uploads
# 3. Cria uma primeira versão de teste para o Nginx não dar erro
mkdir -p releases/inicial
echo "<h1>Servidor Pronto</h1>" > releases/inicial/index.html
# 4. Cria o link simbólico inicial
ln -sfn /home/admin/web/dominio.com/releases/inicial public_html
Confirma a criação do link com ls -la:
lrwxrwxrwx 1 admin admin 44 Oct 19 14:10 public_html -> /home/admin/web/dominio.com/releases/inicial
O Script Automático de Deploy em Bash
Eis o script que podes correr no teu computador ou integrar no teu sistema de integração contínua (GitHub Actions ou GitLab):
#!/usr/bin/env bash
set -euo pipefail
# Definições do Servidor
UTILIZADOR_SSH="admin"
SERVIDOR_IP="servidor.dominio.com"
CAMINHO_REMOTO="/home/admin/web/dominio.com"
PASTA_BUILD="./dist/"
DATA_HORA=$(date -u +"%Y%m%d_%H%M%S")
PASTA_RELEASE="${CAMINHO_REMOTO}/releases/${DATA_HORA}"
echo "=== A Iniciar Deploy Atómico: ${DATA_HORA} ==="
# 1. Valida se a pasta de build existe localmente
if [ ! -d "${PASTA_BUILD}" ]; then
echo "Erro: A pasta local de compilação ${PASTA_BUILD} não existe!"
exit 1
fi
# 2. Cria a nova pasta de versão no servidor
ssh "${UTILIZADOR_SSH}@${SERVIDOR_IP}" "mkdir -p ${PASTA_RELEASE}"
# 3. Transfere os ficheiros com rsync
echo "A transferir ficheiros com rsync..."
rsync -avz --checksum --no-perms --no-owner --no-group \
"${PASTA_BUILD}" "${UTILIZADOR_SSH}@${SERVIDOR_IP}:${PASTA_RELEASE}/"
# 4. Troca o symlink de forma atómica e apaga versões velhas
echo "A trocar o link simbólico e a limpar versões antigas..."
ssh "${UTILIZADOR_SSH}@${SERVIDOR_IP}" bash -c "'
set -euo pipefail
# Cria o symlink temporário e faz a troca imediata
ln -sfn \"${PASTA_RELEASE}\" \"${CAMINHO_REMOTO}/public_html_tmp\"
mv -Tf \"${CAMINHO_REMOTO}/public_html_tmp\" \"${CAMINHO_REMOTO}/public_html\"
# Mantém apenas as 5 versões mais recentes e apaga as restantes
cd \"${CAMINHO_REMOTO}/releases\"
ls -dt */ | tail -n +6 | xargs rm -rf 2>/dev/null || true
'"
echo "=== Deploy Concluído com Sucesso! Versão ativa: ${DATA_HORA} ==="
- A TROCA ATÓMICA COM mv -Tf NO KERNEL
- Passo A: Criação do link temporário: public_html_tmp → releases/20261019_140000/ public_html → releases/20261019_120000/ (Ativo)
- Passo B: Chamada atómica de rename (mv -Tf): public_html → releases/20261019_140000/ (Ativo!)
- O kernel substitui o ponteiro instantaneamente sem quebras de serviço.
A combinação de criar um link temporário e movê-lo com mv -Tf é a chave de todo o processo. O parâmetro -T trata o destino como um ficheiro normal em vez de tentar mover o link para dentro da pasta, acionando a chamada de sistema rename(). Mesmo que o teu site receba centenas de pedidos por segundo nesse instante, todos os clientes recebem ficheiros válidos.
Recuperação Imediata: Como Fazer Rollback em Menos de 1 Segundo
Imagina que um erro grave de código passou despercebido nos testes e chegou a produção. Num deploy vulgar com rsync terias de esperar que o teu sistema voltasse a compilar o código anterior, demorando minutos enquanto os clientes se queixam.
Com lançamentos atómicos, reverter o site para a versão anterior demora menos de um segundo:
# Script de Reversão de Emergência (Rollback)
ssh admin@servidor.dominio.com bash -c "'
cd /home/admin/web/dominio.com/releases
# Descobre qual é a pasta da versão imediatamente anterior
VERSAO_ANTERIOR=\$(ls -dt */ | sed -n 2p | tr -d /)
if [ -z \"\$VERSAO_ANTERIOR\" ]; then
echo \"Não foi encontrada nenhuma versão anterior para reverter!\"
exit 1
fi
echo \"A reverter para releases/\$VERSAO_ANTERIOR...\"
ln -sfn \"/home/admin/web/dominio.com/releases/\$VERSAO_ANTERIOR\" \"/home/admin/web/dominio.com/public_html_tmp\"
mv -Tf \"/home/admin/web/dominio.com/public_html_tmp\" \"/home/admin/web/dominio.com/public_html\"
echo \"Reversão concluída com sucesso em milissegundos!\"
'"
Ao guardares as últimas 5 versões no teu disco, garantes um cinto de segurança infalível. Se algo correr mal, disparas este comando e o site bom volta ao ar em 200 milissegundos.
Aliando esta estratégia aos princípios de anti-over-engineering, consegues fiabilidade e rapidez dignas de grandes infraestruturas sem precisares de ferramentas pesadas e dispendiosas para gerir os teus sites estáticos.
No terreno, em conjunto com a experiência acumulada na Webxtek Studio, aplicamos exatamente estes padrões operacionais em setores exigentes como especialistas em devops e arquitetura cloud e saas empresarial b2b. Quando alinhas a tua estrutura através de alojamento gerido para websites e aplicações e anti-over-engineering, transformas boas práticas técnicas numa vantagem competitiva real e mensurável para o teu negócio.
[+] [ INDEX_DIRECTORY ] 15 tópicos ▼
- A Condição de Corrida nos Deploys Comuns: O Perigo de Copiar Ficheiros Diretos
- A Arquitetura de Symlinks Atómicos: Pastas Releases, Shared e Current
- Como Funciona Este Mecanismo:
- Passo a Passo para Configurar no HestiaCP e Nginx
- 1. Prepara as Diretorias no Servidor
- O Script Automático de Deploy em Bash
- Recuperação Imediata: Como Fazer Rollback em Menos de 1 Segundo
- Autor
- Perguntas Frequentes
- Porque é que fazer rsync diretamente para a pasta public_html quebra o site durante o envio?
- Como é que o kernel do Linux garante que a troca de um symlink é 100% atómica?
- Como configuras a estrutura de pastas no HestiaCP mantendo a pasta public_html?
- Quantas versões antigas deves guardar no servidor e como limpas as restantes?
- Nós Relacionados
- Sequência do Caminho
Perguntas Frequentes
Porque é que fazer rsync diretamente para a pasta public_html quebra o site durante o envio?
Quando transferes ficheiros diretamente para a pasta ativa de produção, a operação demora vários segundos. Se um visitante ou motor de busca aceder à página a meio do processo, vai receber um ficheiro HTML atualizado que tenta carregar ficheiros JavaScript ou CSS que ainda não acabaram de ser gravados no disco, provocando erros 404 e ecrãs em branco.
Como é que o kernel do Linux garante que a troca de um symlink é 100% atómica?
Ao utilizares comandos como `ln -sfn` combinado com `mv -Tf`, o sistema operativo executa a chamada de sistema `rename()` do padrão POSIX. O kernel troca o apontador da diretoria numa única instrução de processador, garantindo que nenhum pedido HTTP vê uma pasta vazia ou a meio da transição.
Como configuras a estrutura de pastas no HestiaCP mantendo a pasta public_html?
O HestiaCP espera que os ficheiros do domínio fiquem em `/home/
Quantas versões antigas deves guardar no servidor e como limpas as restantes?
A recomendação ideal é manteres entre 3 e 5 versões anteriores no disco. Isto permite-te reverter um deploy com problemas em menos de 1 segundo. Podes automatizar a limpeza no final do teu script com uma linha em bash (`ls -dt releases/* | tail -n +6 | xargs rm -rf`).
[ RELATED_NODES ]
> INICIAR_PROJETO
Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.