Cloud & Infraestrutura • 5 min de leitura

Deploy automático e HTTPS: Nginx com GitHub Actions e Certbot

Deploy automático e HTTPS: Nginx com GitHub Actions e Certbot

Nos artigos anteriores, entendemos como o Nginx funciona e configuramos o servidor do zero. O servidor está rodando, mas ainda faltam duas coisas para uma aplicação de produção real: deploy automatizado e HTTPS.

Neste artigo vamos resolver os dois. Ao final, cada git push na branch main vai:

  1. Enviar os arquivos atualizados para o servidor via SSH
  2. Validar a configuração do Nginx (nginx -t)
  3. Recarregar o Nginx sem derrubar conexões ativas

E o site vai estar servindo HTTPS com certificado gratuito e renovação automática via Certbot.

Parte 1 — Deploy automático com GitHub Actions

A ideia

O arquivo infra/nginx.conf fica no repositório. A cada push, o GitHub Actions envia os arquivos para /var/www/meusite.com/ via rsync (ou scp) e executa nginx -t && systemctl reload nginx remotamente via SSH.

Nenhum acesso manual ao servidor é necessário depois da configuração inicial.

Estrutura do repositório

meusite/
├── infra/
│   └── nginx.conf          # configuração do Nginx versionada
├── html/
│   ├── index.html
│   └── estilo.css
└── .github/
    └── workflows/
        └── deploy.yml

1.1 Criar um usuário dedicado para deploy no servidor

Nunca use root para deploy. Crie um usuário com acesso restrito:

sudo adduser deployuser
sudo mkdir -p /home/deployuser/.ssh
sudo chmod 700 /home/deployuser/.ssh

Dê permissão de escrita apenas no diretório do projeto:

sudo chown -R deployuser:deployuser /var/www/meusite.com

Configure o sudo restrito para os comandos do Nginx:

echo "deployuser ALL=(ALL) NOPASSWD: /usr/sbin/nginx, /bin/systemctl reload nginx" \
  | sudo tee /etc/sudoers.d/nginx-deploy

1.2 Configurar a chave SSH

Na sua máquina local, gere um par de chaves para o deploy:

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key

Adicione a chave pública ao servidor:

sudo -u deployuser bash -c 'cat >> /home/deployuser/.ssh/authorized_keys' < ~/.ssh/deploy_key.pub
sudo chmod 600 /home/deployuser/.ssh/authorized_keys

1.3 Adicionar os secrets no GitHub

No repositório, acesse Settings → Secrets and variables → Actions e adicione:

SecretValor
SERVER_HOSTIP ou domínio do servidor
SERVER_USERdeployuser
SERVER_SSH_KEYConteúdo de ~/.ssh/deploy_key (chave privada)

1.4 Criar o workflow de deploy

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Enviar arquivos para o servidor
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          source: "html/,infra/"
          target: /var/www/meusite.com/
          strip_components: 0

      - name: Validar e recarregar Nginx
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            sudo nginx -t && sudo systemctl reload nginx

Por que nginx -t antes do reload? Se o infra/nginx.conf tiver um erro de sintaxe, o reload falha e o servidor continua rodando com a config anterior. O nginx -t valida antes de tentar recarregar. Se a validação falhar, o workflow para e o problema aparece no log do Actions — sem impacto no site em produção.

1.5 Testar o deploy

Faça uma alteração qualquer no html/index.html, commit e push:

git add .
git commit -m "test: primeiro deploy automático"
git push origin main

Acompanhe a execução em Actions no GitHub. Se tudo correr bem, você verá os dois steps verdes e o site atualizado.

Parte 2 — HTTPS com Certbot

2.1 Instalar o Certbot

sudo apt update
sudo apt install certbot python3-certbot-nginx -y

2.2 Garantir que o domínio está apontando para o servidor

O Certbot vai fazer uma verificação HTTP no domínio antes de emitir o certificado. O DNS precisa estar propagado.

Verifique:

dig +short meusite.com
# deve retornar o IP do seu servidor

2.3 Emitir o certificado

sudo certbot --nginx -d meusite.com -d www.meusite.com

O Certbot vai:

  1. Verificar a propriedade do domínio via HTTP
  2. Emitir o certificado via Let's Encrypt
  3. Modificar automaticamente o nginx.conf do site para adicionar HTTPS e redirecionar HTTP → HTTPS

Após o processo, o arquivo infra/nginx.conf terá sido atualizado pelo Certbot com algo assim:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name meusite.com www.meusite.com;

    ssl_certificate /etc/letsencrypt/live/meusite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/meusite.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root /var/www/meusite.com/html;
    # ... resto da config ...
}

server {
    listen 80;
    listen [::]:80;
    server_name meusite.com www.meusite.com;
    return 301 https://$host$request_uri;
}

Importante: como o Certbot modifica o arquivo no servidor, após esse passo você deve copiar o conteúdo atualizado de volta para o repositório. A partir daí, o arquivo no repo já terá as diretivas SSL e o deploy automático vai mantê-las.

2.4 Verificar a renovação automática

Os certificados do Let's Encrypt expiram em 90 dias. O Certbot instala um timer systemd que renova automaticamente antes do vencimento.

Verifique se o timer está ativo:

sudo systemctl status certbot.timer

Simule uma renovação para confirmar que funciona:

sudo certbot renew --dry-run

Fluxo completo após a configuração

Com tudo configurado, o ciclo de trabalho fica assim:

Edita código ou nginx.conf
         │
         ▼
   git push main
         │
         ▼
  GitHub Actions
  ├── scp: envia html/ e infra/ para /var/www/meusite.com/
  └── ssh: nginx -t && systemctl reload nginx
         │
         ▼
  Site atualizado em produção
  sem acesso manual ao servidor

Checklist final

Antes de considerar o servidor pronto para produção, verifique:

  • [ ] sudo nginx -t retorna syntax ok
  • [ ] Site acessível via HTTPS no navegador
  • [ ] Redirecionamento HTTP → HTTPS funcionando
  • [ ] sudo certbot renew --dry-run sem erros
  • [ ] Deploy automático funcionando (push → Actions verde → site atualizado)
  • [ ] Logs de acesso e erro sendo escritos corretamente
  • [ ] server_tokens off ativo (oculta versão do Nginx)
  • [ ] Usuário deployuser sem acesso root (apenas sudo restrito)

Próximos passos

Com essa base, você pode evoluir para:

  • Rate limiting — protege endpoints de login e APIs contra abuso com limit_req_zone
  • Load balancing — distribui tráfego entre múltiplas instâncias com o bloco upstream
  • Proxy para backend — configura o Nginx como reverse proxy para Node.js, Python ou Go
  • Cabeçalhos de segurança — adiciona X-Frame-Options, Content-Security-Policy e similares

Referências: