Ir para o conteúdo

Nginx — Coaching app e documentação

Utiliza estes exemplos como base no mesmo servidor da app (Next.js + pm2) e do site MkDocs em docs.diasantos.com.

Ficheiros no repositório

Os mesmos conteúdos estão em apps/docs/examples/nginx/ para copiares para /etc/nginx/sites-available/ sem passar pelo browser.

Activar um site no nginx (Debian / Ubuntu)

Fluxo típico para cada domínio (substitui docs.diasantos.com pelo nome do ficheiro que quiseres; para a app usa por exemplo coaching.app ou o domínio real).

1. Instalar o nginx (se ainda não existir)

sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx

2. Criar o ficheiro do virtual host

Opção A — copiar o exemplo do repositório (ajusta o caminho do clone):

sudo cp /var/www/coaching/apps/docs/examples/nginx/docs.diasantos.com.conf.example \
  /etc/nginx/sites-available/docs.diasantos.com

Opção B — criar/editar à mão com o editor que preferires:

sudo vim /etc/nginx/sites-available/docs.diasantos.com
# ou: sudo nano /etc/nginx/sites-available/docs.diasantos.com

Cola o conteúdo do exemplo (secções abaixo ou ficheiro .example), grava e sai (:wq no vim, Ctrl+O / Ctrl+X no nano).

Antes do primeiro HTTPS

Se ainda não tens certificados, podes começar só com o bloco listen 80 e server_name, servir o site em HTTP, emitir o certificado com certbot, e só depois acrescentar o bloco listen 443 ssl ou deixar o certbot alterar o ficheiro por ti. Os exemplos assumem que os paths do Let's Encrypt já existem.

O nginx só carrega o que estiver em sites-enabled/. Cria um link para o ficheiro em sites-available/:

sudo ln -sf /etc/nginx/sites-available/docs.diasantos.com \
  /etc/nginx/sites-enabled/docs.diasantos.com
  • -f substitui o link se já existir (útil ao repetir o comando).
  • Repete o mesmo padrão para a app, por exemplo: /etc/nginx/sites-available/coaching.app → sites-enabled/coaching.app.

4. Conflito com o site por defeito (opcional)

Em instalações novas, /etc/nginx/sites-enabled/default pode ocupar a porta 80. Se precisares dessa porta para o teu server_name, desactiva o default:

sudo rm /etc/nginx/sites-enabled/default
# ou: sudo unlink /etc/nginx/sites-enabled/default

5. Validar e aplicar

sudo nginx -t

Se aparecer syntax is ok e test is successful:

sudo systemctl reload nginx

Confirma no browser (https://docs.diasantos.com) ou com curl -I https://docs.diasantos.com.

6. Ver erros se algo falhar

sudo journalctl -u nginx -n 50 --no-pager

Coaching (reverse proxy para Next.js)

Pressupõe next start ou equivalente em 127.0.0.1:3000 (porta típica do pm2). Ajusta server_name, caminhos dos certificados e a proxy_pass se a porta for outra.

Manutenção durante o deploy

No início do update (UI admin, deploy.sh ou webhook) a app cria /var/www/coaching/.maintenance. Enquanto o ficheiro existir, o nginx deve servir a página estática deploy/maintenance/index.html com 503 — assim os utilizadores vêem manutenção mesmo quando o Next.js está a apagar/reconstruir .next. O ficheiro só é removido no fim com sucesso; se o deploy falhar, o flag mantém-se (mensagem de interrupção) até um deploy bem-sucedido ou remoção manual.

Copia o exemplo actualizado:

sudo cp /var/www/coaching/apps/docs/examples/nginx/coaching.app.conf.example \
  /etc/nginx/sites-available/coaching.app
# ajusta server_name / certificados se necessário
sudo nginx -t && sudo systemctl reload nginx

O ficheiro completo está em apps/docs/examples/nginx/coaching.app.conf.example (inclui o bloco if (-f …/.maintenance), error_page 503, e excepções para /api/admin/deploy e /api/webhook).

A app também envia comentários SSE periódicos durante os passos do deploy para o proxy ver leituras regulares; convém manter proxy_read_timeout alto neste caminho no nginx.

Documentação (MkDocs estático em docs.diasantos.com)

Depois de mkdocs build, o conteúdo fica em apps/docs/site/. O root abaixo deve apontar para essa pasta no servidor.

# Exemplo: site estático MkDocs (saída de: cd apps/docs && mkdocs build).
#
# Uso no servidor Debian/Ubuntu:
#   sudo cp docs.diasantos.com.conf.example /etc/nginx/sites-available/docs.diasantos.com
#   sudo ln -sf /etc/nginx/sites-available/docs.diasantos.com /etc/nginx/sites-enabled/
#   sudo nginx -t && sudo systemctl reload nginx
#
# Ajusta root ao caminho real do clone (APP_DIR/apps/docs/site).
# Certificados: certbot certonly --nginx -d docs.diasantos.com

server {
    listen 80;
    listen [::]:80;
    server_name docs.diasantos.com;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name docs.diasantos.com;

    ssl_certificate     /etc/letsencrypt/live/docs.diasantos.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/docs.diasantos.com/privkey.pem;

    root /var/www/coaching/apps/docs/site;
    index index.html;

    error_page 404 /404.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # Opcional: cache curto para assets estáticos gerados pelo MkDocs
    location ~* \.(?:css|js|woff2?|png|jpg|jpeg|gif|svg|ico|webp)$ {
        try_files $uri =404;
        expires 7d;
        add_header Cache-Control "public, max-age=604800, immutable";
    }
}

Certificados com Certbot (Let's Encrypt)

Usa o plugin nginx do Certbot para emitir e renovar certificados sem parar o servidor de forma desnecessária (desafio via nginx).

Pré-requisitos

  • DNS: registos A (e opcionalmente AAAA) para app.diasantos.com e docs.diasantos.com a apontar para o IP público deste servidor (substitui pelos teus domínios reais).
  • Porta 80 acessível de Internet (Let's Encrypt usa HTTP-01 por defeito com --nginx).
  • Nginx a correr com pelo menos o bloco HTTP (porta 80) e server_name correcto antes de pedires HTTPS — se o ficheiro tiver ssl_certificate para ficheiros que ainda não existem, o nginx -t falha; nesse caso começa só com listen 80 (como no aviso da secção de activação), obtém o certificado, e só depois acrescenta ou descomenta o bloco 443 dos exemplos.

Instalar o Certbot

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

Emitir um certificado por site (recomendado)

Com os dois virtual hosts activos em sites-enabled e HTTP a responder para cada server_name:

# App (reverse proxy Next.js)
sudo certbot --nginx -d app.diasantos.com

# Documentação (MkDocs estático)
sudo certbot --nginx -d docs.diasantos.com

O Certbot pergunta email, aceitação dos termos e se queres redireccionar HTTP→HTTPS (equivalente aos return 301 dos exemplos). No fim, costuma ajustar os teus server { ... } para usar fullchain.pem e privkey.pem em /etc/letsencrypt/live/<domínio>/.

Alinhar com os exemplos desta página

Se já tinhas colado os blocos completos dos exemplos (proxy, root, cabeçalhos), faz backup antes (sudo cp …/sites-available/… /tmp/) e, depois do Certbot, verifica com sudo nginx -t. Se o Certbot simplificar demasiado um bloco (por exemplo perder proxy_set_header na app), recupera essas linhas do backup e mantém os ssl_certificate que o Certbot configurou.

Um único certificado para os dois nomes (opcional)

Útil se quiseres um só certificado SAN para ambos os hosts:

sudo certbot --nginx -d app.diasantos.com -d docs.diasantos.com

Nesse caso ambos os server { … } em HTTPS devem referenciar o mesmo par fullchain.pem / privkey.pem (normalmente o primeiro nome da lista define o directório em /etc/letsencrypt/live/). Os exemplos separados por domínio assumem um certificado por site (um server_name por certificado).

Verificar e recarregar

sudo nginx -t && sudo systemctl reload nginx
sudo certbot certificates

Renovação automática

O pacote instala normalmente um timer systemd que corre certbot renew:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Em Debian/Ubuntu, após renovação bem-sucedida o hook costuma recarregar o nginx; se alterares configuração manualmente, confirma que renew continua a funcionar com o dry-run.

Alternativa: só obter o certificado (sem o plugin alterar o nginx)

Se preferires emitir o certificado e tu editares o nginx à mão:

sudo certbot certonly --nginx -d app.diasantos.com
sudo certbot certonly --nginx -d docs.diasantos.com

Depois define ssl_certificate / ssl_certificate_key como nos exemplos abaixo (paths sob /etc/letsencrypt/live/<domínio>/).

Teste rápido depois de tudo

curl -fsSI https://app.diasantos.com | head -n 5
curl -fsSI https://docs.diasantos.com | head -n 5

Se não usares /var/www/certbot no bloco /.well-known/acme-challenge/ e usares webroot manualmente, alinha root com o webroot que passares ao Certbot.

Ver também