todos

Backup e Segurança do homelab

Ativo
Progresso geral0 / 0 tarefas (0%)

Backup e Segurança do Homelab Dark n Black

Guia operacional para proteger, copiar, restaurar e auditar os projetos rodando no servidor local da Dark n Black.

Última atualização: 2026-10-11
Servidor: dnb-local
IP LAN: 192.168.50.99
Usuário Linux usado nos exemplos: dwoond
Base principal: /srv/homelab
Documento complementar: documentacao-homelab-dnb-servidor-projetos.md


1. Objetivo deste documento

Este documento existe para responder três perguntas:

  1. O que precisa ser protegido?
  2. Como fazer backup de forma consistente?
  3. Como recuperar o servidor/projeto se algo quebrar?

Ele também define regras mínimas de segurança para evitar perda de dados, vazamento de secrets, exposição indevida de serviços e quebras acidentais em stacks que já estão funcionando.


2. Estado atual considerado

Estrutura-base do homelab:

/srv/homelab
├── apps
│   ├── atlas
│   ├── ledger
│   └── hub-metrics
│
├── supabase
│   ├── atlas
│   │   └── docker
│   ├── ledger
│   │   └── docker
│   └── hub-metrics
│       └── docker
│
├── proxy
│   ├── docker-compose.yml
│   └── Caddyfile
│
├── infra
│   └── cloudflared
│       ├── docker-compose.yml
│       └── .env
│
├── monitoring
├── backups
├── scripts
└── logs

Serviços atuais mais importantes:

ÁreaCaminhoObservação
Apps Next.js/srv/homelab/apps/<projeto>Código, Dockerfile, compose e env de app
Supabase por projeto/srv/homelab/supabase/<projeto>/dockerBanco, Auth, Storage, Studio e APIs daquele projeto
Proxy/srv/homelab/proxyCaddy e roteamento central
Tunnel/srv/homelab/infra/cloudflaredCloudflare Tunnel para acesso externo
Backups/srv/homelab/backupsDestino local de dumps e pacotes
Scripts/srv/homelab/scriptsAutomatizações de backup, restore e auditoria
Logs/srv/homelab/logsLogs operacionais do homelab

Regra de arquitetura:

Internet → Cloudflare Tunnel → Caddy → apps/Supabase

Evitar:

Internet → app direto
Internet → Supabase direto
Internet → Postgres direto

3. O que precisa de backup

Nem tudo tem o mesmo valor. A ordem de prioridade é esta:

PrioridadeItemPrecisa backup?Por quê
Crítica.env, secrets, senhas, JWT, service roleSim, criptografadoSem isso, a restauração pode ficar impossível ou insegura
CríticaBanco Postgres de cada SupabaseSimDados reais do projeto
AltaStorage do SupabaseSim, quando usadoUploads, arquivos, imagens e documentos
AltaCaddyfile e compose do proxySimRotas, domínios e reverse proxy
AltaConfig do cloudflaredSim, criptografadoTunnel e acesso externo
Altadocker-compose.yml dos apps e SupabaseSimPermite recriar serviços corretamente
MédiaCódigo dos appsGit é a fonte principalBackup local é opcional se estiver tudo no Git
MédiaScripts internosSimAutomatizações e runbooks
BaixaLogsOpcionalÚteis para auditoria, mas podem ser grandes
BaixaImagens DockerNãoPodem ser baixadas/rebuildadas
Baixanode_modules, .next, cachesNãoGerados novamente no build

4. Política de backup recomendada

Usar a regra prática 3-2-1:

3 cópias dos dados importantes
2 tipos de mídia/destino
1 cópia fora do servidor

Para o homelab:

Cópia 1: dados vivos no servidor
Cópia 2: backup local em /srv/homelab/backups
Cópia 3: backup externo/offsite criptografado

4.1. Frequência recomendada

TipoFrequênciaRetenção sugerida
Dump PostgresDiário14 a 30 dias
Backup de .env/configsDiário ou a cada alteração30 a 90 dias
Storage SupabaseDiário, se usado14 a 30 dias
Backup completo antes de updateSempre antes de update grandeManter por 30 dias
Teste de restoreMensalRegistrar resultado
Backup offsiteDiário ou semanal30 a 90 dias

4.2. Regra para secrets

Secrets nunca devem ficar apenas em um lugar.

Itens que precisam de cópia segura:

POSTGRES_PASSWORD
JWT_SECRET
ANON_KEY
SERVICE_ROLE_KEY
DASHBOARD_PASSWORD
CRON_SECRET
Tokens do Cloudflare
Tokens de GitHub runner
Chaves de APIs externas
.env.production.local dos apps
.env dos Supabases

Regra:

Secrets podem ficar no servidor em produção.
Secrets podem ficar em backup criptografado.
Secrets não podem ir para Git.
Secrets não devem ser colados em chats, issues ou logs.

5. Estrutura recomendada para backups

Criar estrutura:

sudo mkdir -p /srv/homelab/backups/{local,offsite-staging,restore-tests,logs}
sudo mkdir -p /srv/homelab/scripts
sudo mkdir -p /srv/homelab/logs
sudo chown -R dwoond:dwoond /srv/homelab/backups /srv/homelab/scripts /srv/homelab/logs
chmod 700 /srv/homelab/backups
chmod 700 /srv/homelab/scripts

Estrutura final:

/srv/homelab/backups
├── local
│   ├── atlas
│   ├── ledger
│   ├── hub-metrics
│   ├── proxy
│   └── infra
│
├── offsite-staging
├── restore-tests
└── logs

6. Backup manual de um Supabase

Exemplo usando hub-metrics.

6.1. Entrar na stack

cd /srv/homelab/supabase/hub-metrics/docker

6.2. Verificar saúde antes do backup

docker compose ps

O ideal é que db, auth, rest, kong, storage, studio, meta e pooler estejam healthy ou up.

6.3. Criar pasta do backup

PROJECT="hub-metrics"
DATE="$(date +%Y%m%d-%H%M%S)"
OUT="/srv/homelab/backups/local/$PROJECT/$DATE"
mkdir -p "$OUT"
chmod 700 "$OUT"

6.4. Fazer dump do banco Postgres

Formato recomendado: custom (.dump), pois é melhor para restore com pg_restore.

docker compose exec -T db bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -h 127.0.0.1 -U postgres -d postgres -Fc --no-owner --no-privileges' > "$OUT/postgres.dump"

Verificar tamanho:

ls -lh "$OUT/postgres.dump"

Se o arquivo tiver poucos bytes ou tamanho zero, o backup falhou.

6.5. Backup de configs do Supabase

O .env contém secrets. Então existem duas opções:

Opção A — backup local protegido por permissão

tar -czf "$OUT/supabase-config.tar.gz" \
  docker-compose.yml \
  .env \
  volumes \
  --exclude='volumes/db/data' \
  --exclude='volumes/storage'

chmod 600 "$OUT/supabase-config.tar.gz"

Opção B — backup criptografado com GPG simétrico

tar -czf - \
  docker-compose.yml \
  .env \
  volumes \
  --exclude='volumes/db/data' \
  --exclude='volumes/storage' \
| gpg --symmetric --cipher-algo AES256 -o "$OUT/supabase-config.tar.gz.gpg"

chmod 600 "$OUT/supabase-config.tar.gz.gpg"

Use a opção criptografada para qualquer cópia que saia do servidor.

6.6. Backup do Storage

Primeiro verifique se existe storage local:

ls -la volumes/storage 2>/dev/null || true

Se existir e tiver arquivos:

tar -czf "$OUT/storage.tar.gz" volumes/storage
chmod 600 "$OUT/storage.tar.gz"

Se o storage estiver em outro volume Docker, descubra com:

docker compose config | grep -n "storage\|volumes" -A5 -B5

7. Script de backup dos Supabases

Criar arquivo:

nano /srv/homelab/scripts/backup-supabase-project.sh

Conteúdo:

#!/usr/bin/env bash
set -euo pipefail

PROJECT="${1:-}"

if [ -z "$PROJECT" ]; then
  echo "Uso: $0 <projeto>"
  echo "Exemplo: $0 hub-metrics"
  exit 1
fi

BASE="/srv/homelab"
STACK_DIR="$BASE/supabase/$PROJECT/docker"
DATE="$(date +%Y%m%d-%H%M%S)"
OUT="$BASE/backups/local/$PROJECT/$DATE"
LOG_DIR="$BASE/logs"

if [ ! -d "$STACK_DIR" ]; then
  echo "Stack não encontrada: $STACK_DIR"
  exit 1
fi

mkdir -p "$OUT" "$LOG_DIR"
chmod 700 "$OUT"

cd "$STACK_DIR"

echo "[$(date -Is)] Iniciando backup do Supabase: $PROJECT"

echo "[$(date -Is)] Verificando containers..."
docker compose ps > "$OUT/docker-compose-ps.txt"

echo "[$(date -Is)] Backup do Postgres..."
docker compose exec -T db bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -h 127.0.0.1 -U postgres -d postgres -Fc --no-owner --no-privileges' > "$OUT/postgres.dump"

if [ ! -s "$OUT/postgres.dump" ]; then
  echo "ERRO: postgres.dump vazio ou inexistente"
  exit 1
fi

echo "[$(date -Is)] Backup de configurações..."
tar -czf "$OUT/supabase-config.tar.gz" \
  docker-compose.yml \
  .env \
  volumes \
  --exclude='volumes/db/data' \
  --exclude='volumes/storage' \
  2>/dev/null || true

chmod 600 "$OUT/supabase-config.tar.gz" || true

if [ -d "volumes/storage" ]; then
  echo "[$(date -Is)] Backup do Storage..."
  tar -czf "$OUT/storage.tar.gz" volumes/storage
  chmod 600 "$OUT/storage.tar.gz"
fi

sha256sum "$OUT"/* > "$OUT/SHA256SUMS.txt" 2>/dev/null || true

cat > "$OUT/README.txt" <<EOF_README
Projeto: $PROJECT
Data: $DATE
Stack: $STACK_DIR
Conteúdo:
- postgres.dump: dump custom do Postgres
- supabase-config.tar.gz: docker-compose.yml, .env e volumes de configuração sem data dir
- storage.tar.gz: storage local, se existir
- docker-compose-ps.txt: estado dos containers no momento do backup
- SHA256SUMS.txt: checksums dos arquivos
EOF_README

echo "[$(date -Is)] Backup concluído: $OUT"

Permissão:

chmod +x /srv/homelab/scripts/backup-supabase-project.sh

Teste:

/srv/homelab/scripts/backup-supabase-project.sh hub-metrics

Para Atlas e Ledger:

/srv/homelab/scripts/backup-supabase-project.sh atlas
/srv/homelab/scripts/backup-supabase-project.sh ledger

8. Script de backup de apps, proxy e infra

Este script salva arquivos operacionais importantes, incluindo envs dos apps.

Criar:

nano /srv/homelab/scripts/backup-homelab-configs.sh

Conteúdo:

#!/usr/bin/env bash
set -euo pipefail

BASE="/srv/homelab"
DATE="$(date +%Y%m%d-%H%M%S)"
OUT="$BASE/backups/local/configs/$DATE"

mkdir -p "$OUT"
chmod 700 "$OUT"

cd "$BASE"

echo "[$(date -Is)] Backup de configs do homelab..."

tar -czf "$OUT/apps-configs.tar.gz" \
  apps \
  --exclude='apps/*/.next' \
  --exclude='apps/*/node_modules' \
  --exclude='apps/*/.git' \
  --exclude='apps/*/dist' \
  --exclude='apps/*/build' \
  2>/dev/null || true

if [ -d "$BASE/proxy" ]; then
  tar -czf "$OUT/proxy.tar.gz" proxy
fi

if [ -d "$BASE/infra" ]; then
  tar -czf "$OUT/infra.tar.gz" infra
fi

if [ -d "$BASE/scripts" ]; then
  tar -czf "$OUT/scripts.tar.gz" scripts
fi

chmod 600 "$OUT"/*.tar.gz 2>/dev/null || true
sha256sum "$OUT"/* > "$OUT/SHA256SUMS.txt" 2>/dev/null || true

echo "[$(date -Is)] Backup de configs concluído: $OUT"

Permissão:

chmod +x /srv/homelab/scripts/backup-homelab-configs.sh

Teste:

/srv/homelab/scripts/backup-homelab-configs.sh

9. Script geral de backup diário

Criar:

nano /srv/homelab/scripts/backup-homelab-daily.sh

Conteúdo:

#!/usr/bin/env bash
set -euo pipefail

BASE="/srv/homelab"
LOG="$BASE/logs/backup-daily.log"

mkdir -p "$BASE/logs"

echo "==============================" >> "$LOG"
echo "[$(date -Is)] Início backup diário" >> "$LOG"

PROJECTS=("atlas" "ledger" "hub-metrics")

for PROJECT in "${PROJECTS[@]}"; do
  if [ -d "$BASE/supabase/$PROJECT/docker" ]; then
    echo "[$(date -Is)] Backup Supabase: $PROJECT" >> "$LOG"
    "$BASE/scripts/backup-supabase-project.sh" "$PROJECT" >> "$LOG" 2>&1 || {
      echo "[$(date -Is)] ERRO no backup do projeto: $PROJECT" >> "$LOG"
    }
  else
    echo "[$(date -Is)] Ignorando projeto sem stack: $PROJECT" >> "$LOG"
  fi
done

echo "[$(date -Is)] Backup configs" >> "$LOG"
"$BASE/scripts/backup-homelab-configs.sh" >> "$LOG" 2>&1 || {
  echo "[$(date -Is)] ERRO no backup de configs" >> "$LOG"
}

echo "[$(date -Is)] Fim backup diário" >> "$LOG"

Permissão:

chmod +x /srv/homelab/scripts/backup-homelab-daily.sh

Teste:

/srv/homelab/scripts/backup-homelab-daily.sh

Ver log:

tail -120 /srv/homelab/logs/backup-daily.log

10. Agendar backup com cron

Editar cron do usuário dwoond:

crontab -e

Adicionar:

0 3 * * * /srv/homelab/scripts/backup-homelab-daily.sh >> /srv/homelab/logs/cron-backup.log 2>&1

Isso roda diariamente às 03:00.

Verificar cron instalado:

crontab -l

Conferir logs no dia seguinte:

tail -120 /srv/homelab/logs/backup-daily.log
tail -120 /srv/homelab/logs/cron-backup.log

11. Retenção e limpeza de backups antigos

Antes de apagar, sempre faça dry-run.

11.1. Ver o que seria apagado

find /srv/homelab/backups/local -type f -mtime +30 -print

11.2. Apagar arquivos com mais de 30 dias

find /srv/homelab/backups/local -type f -mtime +30 -delete

11.3. Remover pastas vazias

find /srv/homelab/backups/local -type d -empty -delete

11.4. Script de retenção

Criar:

nano /srv/homelab/scripts/backup-retention.sh

Conteúdo:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/srv/homelab/backups/local"
LOG="/srv/homelab/logs/backup-retention.log"
RETENTION_DAYS="30"

echo "[$(date -Is)] Limpando backups com mais de $RETENTION_DAYS dias" >> "$LOG"

find "$BACKUP_DIR" -type f -mtime +"$RETENTION_DAYS" -print -delete >> "$LOG" 2>&1
find "$BACKUP_DIR" -type d -empty -delete >> "$LOG" 2>&1

echo "[$(date -Is)] Limpeza concluída" >> "$LOG"

Permissão:

chmod +x /srv/homelab/scripts/backup-retention.sh

Cron semanal:

30 3 * * 0 /srv/homelab/scripts/backup-retention.sh >> /srv/homelab/logs/cron-retention.log 2>&1

12. Backup offsite

Backup local não basta. Se o notebook/SSD morrer, o backup local morre junto.

Destinos possíveis:

Google Drive
Dropbox
Backblaze B2
Cloudflare R2
Outro servidor via SSH/rsync
HD externo criptografado

12.1. Regra para offsite

Nunca envie para offsite sem uma destas proteções:

1. Criptografia no arquivo antes do upload
2. Rclone crypt
3. Bucket com criptografia forte + acesso restrito + secrets fora do repo

12.2. Staging para offsite

Usar:

/srv/homelab/backups/offsite-staging

Exemplo:

DATE="$(date +%Y%m%d-%H%M%S)"
SRC="/srv/homelab/backups/local"
DEST="/srv/homelab/backups/offsite-staging/homelab-backup-$DATE.tar.gz"

tar -czf "$DEST" -C "$SRC" .
chmod 600 "$DEST"

Criptografar com GPG simétrico:

gpg --symmetric --cipher-algo AES256 "$DEST"
rm -f "$DEST"

Resultado:

homelab-backup-YYYYMMDD-HHMMSS.tar.gz.gpg

Esse arquivo pode ir para Google Drive, R2, B2, HD externo etc.


13. Restore: banco Supabase

Atenção: restore sobrescreve dados. Antes de restaurar, faça um backup novo do estado atual.

13.1. Entrar na stack

cd /srv/homelab/supabase/hub-metrics/docker

13.2. Fazer backup de segurança antes do restore

/srv/homelab/scripts/backup-supabase-project.sh hub-metrics

13.3. Parar app que usa esse Supabase

cd /srv/homelab/apps/hub-metrics
docker compose stop hub-metrics

13.4. Restaurar dump

Voltar para a stack Supabase:

cd /srv/homelab/supabase/hub-metrics/docker

Restaurar:

BACKUP_FILE="/srv/homelab/backups/local/hub-metrics/COLE_A_DATA/postgres.dump"

docker compose exec -T db bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" pg_restore -h 127.0.0.1 -U postgres -d postgres --clean --if-exists --no-owner --no-privileges' < "$BACKUP_FILE"

13.5. Reiniciar stack e app

cd /srv/homelab/supabase/hub-metrics/docker
docker compose up -d

docker compose ps

Depois:

cd /srv/homelab/apps/hub-metrics
docker compose up -d

13.6. Testar

curl -I http://127.0.0.1:8003
curl -I -H "Host: metrics.darknblack.com" http://127.0.0.1

14. Restore: configs e secrets

14.1. Restaurar config do Supabase

Se backup não criptografado:

cd /srv/homelab/supabase/hub-metrics/docker

tar -xzf /srv/homelab/backups/local/hub-metrics/COLE_A_DATA/supabase-config.tar.gz -C /tmp/restore-supabase-config

Compare antes de substituir:

diff -u .env /tmp/restore-supabase-config/.env || true
diff -u docker-compose.yml /tmp/restore-supabase-config/docker-compose.yml || true

Nunca sobrescreva .env sem comparar.

14.2. Restaurar backup criptografado

gpg -d supabase-config.tar.gz.gpg > supabase-config.tar.gz

Depois extraia e compare.


15. Restore: app Next.js

Código deve vir do Git:

cd /srv/homelab/apps

git clone git@github.com:SEU_USUARIO/hub-metrics.git hub-metrics

Restaurar .env.production.local do backup de configs:

cd /srv/homelab/apps/hub-metrics
cp /CAMINHO/RESTAURADO/apps/hub-metrics/.env.production.local .env.production.local
ln -sf .env.production.local .env
chmod 600 .env.production.local

Subir:

docker compose up -d --build

16. Segurança: regra geral de exposição

16.1. O que pode ser público

Pode ser público, via Cloudflare Tunnel e Caddy:

metrics.darknblack.com → app público
api-metrics.darknblack.com → API Supabase necessária ao app

16.2. O que deve ficar protegido

Preferencialmente protegido por Cloudflare Access, VPN ou rede local:

Supabase Studio
Netdata
Dashboards internos
Rotas administrativas
Endpoints de cron
Painéis de deploy

16.3. O que não deve ser público

Nunca expor diretamente:

Postgres
Docker socket
SSH aberto para a internet
Portainer sem proteção forte
Arquivos .env
Backups
Diretórios /srv/homelab
Painéis admin sem autenticação forte

17. Segurança: SSH

17.1. Verificar serviço SSH

sudo systemctl status ssh

17.2. Recomendado

Usar chave SSH e evitar senha.

Arquivo:

sudo nano /etc/ssh/sshd_config

Recomendações:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Antes de aplicar PasswordAuthentication no, confirme que o login por chave está funcionando.

Reiniciar SSH:

sudo systemctl restart ssh

Teste em outro terminal antes de fechar o atual:

ssh dwoond@192.168.50.99

18. Segurança: firewall local

Se usar Cloudflare Tunnel para entrada pública, o servidor não precisa abrir portas no roteador.

Ver status:

sudo ufw status verbose

Política segura inicial:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Permitir SSH pela LAN:

sudo ufw allow from 192.168.50.0/24 to any port 22 proto tcp

Permitir HTTP pela LAN para Caddy local:

sudo ufw allow from 192.168.50.0/24 to any port 80 proto tcp

Se usar Tailscale:

sudo ufw allow in on tailscale0

Ativar:

sudo ufw enable
sudo ufw status verbose

Atenção: aplique firewall com cuidado. Não faça isso sem acesso físico ou sem uma sessão SSH alternativa aberta.


19. Segurança: Docker

Regras:

Não montar /var/run/docker.sock em apps comuns.
Não usar privileged: true sem necessidade extrema.
Não publicar ports nos apps; usar expose + Caddy.
Não colocar secrets no Dockerfile.
Não commitar .env.
Não usar latest em serviços críticos quando possível.
Manter cada projeto em compose próprio.

Ver containers com portas publicadas:

docker ps --format "table {{.Names}}\t{{.Ports}}"

Idealmente, apps Next.js devem aparecer só com:

3000/tcp

E não:

0.0.0.0:3000->3000/tcp

Supabase publica portas específicas por stack:

Atlas:       8001, 8444, Postgres conforme stack
Ledger:      8002, 8445, 54322, 6544
Hub Metrics: 8003, 8446, 54323, 6545

Essas portas devem ficar restritas à LAN/host, não abertas no roteador.


20. Segurança: Caddy

Bloco global atual recomendado:

{
  auto_https off

  servers {
    trusted_proxies static private_ranges
  }
}

Esse bloco precisa ser o primeiro do Caddyfile.

Validação:

cd /srv/homelab/proxy
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile

Reload:

docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile

20.1. Headers de segurança para apps

Para apps públicos, considerar:

metrics.darknblack.com {
  header {
    X-Content-Type-Options nosniff
    X-Frame-Options DENY
    Referrer-Policy strict-origin-when-cross-origin
    Permissions-Policy "geolocation=(), microphone=(), camera=()"
  }

  reverse_proxy hub-metrics:3000
}

Cuidado com Content-Security-Policy: pode quebrar Next.js, Supabase Auth, fontes, imagens e scripts externos se aplicada sem teste.

20.2. Proteger painéis admin

Para Studio, Netdata e painéis internos, preferir Cloudflare Access no domínio público ou manter apenas local.

Exemplos de domínios que devem ser protegidos:

studio-hub-metrics.local
monitor.local
studio.darknblack.com, se existir

21. Segurança: Cloudflare Tunnel

Princípio:

Tunnel aponta para Caddy.
Caddy decide para onde cada domínio vai.

Não apontar o tunnel diretamente para Postgres, Docker, Netdata ou painel admin sem proteção.

21.1. Domínios públicos esperados do Hub Metrics

metrics.darknblack.com      → Caddy → hub-metrics:3000
api-metrics.darknblack.com  → Caddy → host.docker.internal:8003

21.2. Regras recomendadas no Cloudflare

Para app público:

HTTPS ativo
WAF básico
Bot fight/challenges com cuidado
Cache desativado para rotas dinâmicas sensíveis

Para admin:

Cloudflare Access obrigatório
Login por e-mail permitido apenas para você/equipe
MFA habilitado na conta Cloudflare

21.3. Tokens do Cloudflare

Tokens do tunnel e API tokens:

Não colocar no Git
Não colocar no Caddyfile
Guardar em /srv/homelab/infra/cloudflared/.env com chmod 600
Backup apenas criptografado
Rotacionar se houver suspeita de vazamento

22. Segurança: Supabase

22.1. Desabilitar signup público quando necessário

No Supabase do projeto:

cd /srv/homelab/supabase/hub-metrics/docker

Ver variável usada:

grep -Rni "SIGNUP\|DISABLE_SIGNUP\|ENABLE.*SIGNUP\|GOTRUE.*SIGNUP" .env docker-compose.yml volumes 2>/dev/null

Se existir DISABLE_SIGNUP:

grep -q '^DISABLE_SIGNUP=' .env \
  && sed -i 's|^DISABLE_SIGNUP=.*|DISABLE_SIGNUP=true|' .env \
  || echo 'DISABLE_SIGNUP=true' >> .env

Se existir ENABLE_EMAIL_SIGNUP:

grep -q '^ENABLE_EMAIL_SIGNUP=' .env \
  && sed -i 's|^ENABLE_EMAIL_SIGNUP=.*|ENABLE_EMAIL_SIGNUP=false|' .env \
  || echo 'ENABLE_EMAIL_SIGNUP=false' >> .env

Aplicar:

docker compose up -d auth

22.2. URLs públicas do Hub Metrics

No Supabase Hub Metrics:

SUPABASE_PUBLIC_URL=https://api-metrics.darknblack.com
API_EXTERNAL_URL=https://api-metrics.darknblack.com/auth/v1
SITE_URL=https://metrics.darknblack.com

Aplicar sem nano:

cd /srv/homelab/supabase/hub-metrics/docker

cp .env ".env.bak-public-urls-$(date +%Y%m%d-%H%M%S)"

sed -i 's|^SUPABASE_PUBLIC_URL=.*|SUPABASE_PUBLIC_URL=https://api-metrics.darknblack.com|' .env
sed -i 's|^API_EXTERNAL_URL=.*|API_EXTERNAL_URL=https://api-metrics.darknblack.com/auth/v1|' .env
sed -i 's|^SITE_URL=.*|SITE_URL=https://metrics.darknblack.com|' .env

grep -n "SUPABASE_PUBLIC_URL\|API_EXTERNAL_URL\|SITE_URL" .env

docker compose up -d

22.3. Service role

A SERVICE_ROLE_KEY nunca deve ser usada no browser.

Pode ficar em:

.env.production.local do app, se usada apenas server-side
backend interno
scripts de manutenção

Não pode ficar em:

NEXT_PUBLIC_*
frontend/browser
código commitado
logs
prints públicos

23. Segurança: apps Next.js

Arquivo real de produção:

/srv/homelab/apps/hub-metrics/.env.production.local

Link para Compose:

/srv/homelab/apps/hub-metrics/.env -> .env.production.local

Variáveis públicas:

NEXT_PUBLIC_*

Essas podem ir para o bundle do frontend. Não colocar secrets nelas.

Variáveis privadas:

SUPABASE_SERVICE_ROLE_KEY
CRON_SECRET
API_SECRET
WEBHOOK_SECRET

Essas só podem ser usadas no server-side.

23.1. Verificar envs dentro do container

docker exec -it hub-metrics sh
printenv | sort
exit

Não use esse comando em gravações/prints públicos porque ele pode exibir secrets.

23.2. Cron endpoints

Endpoints de cron devem exigir segredo:

Authorization: Bearer <CRON_SECRET>

ou header próprio:

x-cron-secret: <CRON_SECRET>

Nunca deixar /api/cron/* aberto sem proteção.


24. Atualizações seguras

Antes de atualizar qualquer stack importante:

/srv/homelab/scripts/backup-homelab-daily.sh

Depois verificar:

tail -120 /srv/homelab/logs/backup-daily.log

24.1. Atualizar app Next.js

cd /srv/homelab/apps/hub-metrics

git pull
docker compose config > /tmp/hub-metrics-app-compose-check.yml
docker compose up -d --build
docker compose ps
docker compose logs --tail=120 hub-metrics

24.2. Atualizar Supabase

Antes:

/srv/homelab/scripts/backup-supabase-project.sh hub-metrics

Nunca rodar comandos destrutivos sem backup:

Evitar: docker compose down -v
Evitar: rm -rf volumes/db/data
Evitar: reset.sh em stack com dados reais

docker compose down -v só deve ser usado em stack nova, descartável, sem dados reais.


25. Auditoria rápida semanal

Rodar 1 vez por semana:

# Espaço em disco
df -h

# Containers
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# Backups recentes
find /srv/homelab/backups/local -type f -mtime -2 -print

# Logs de backup
tail -120 /srv/homelab/logs/backup-daily.log

# Caddy válido
cd /srv/homelab/proxy && docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile

# Portas abertas no host
ss -ltnp

Checklist:

[ ] Backups rodaram nas últimas 24h
[ ] Dumps não estão vazios
[ ] Disco não passou de 80%
[ ] Nenhum container crítico está restartando
[ ] Caddy valida sem erro
[ ] Cloudflare Tunnel está online
[ ] Nenhum app publicou porta indevida no host
[ ] Nenhum .env foi commitado

26. Auditoria mensal de restore

Backup sem restore testado é só uma promessa.

Mensalmente:

  1. Escolher um backup recente.
  2. Criar uma stack temporária ou ambiente de teste.
  3. Restaurar o dump.
  4. Validar tabelas principais.
  5. Registrar resultado.

Registro sugerido:

Data:
Projeto:
Backup usado:
Restore funcionou? Sim/Não
Tempo de restore:
Problemas encontrados:
Ações corretivas:

Salvar em:

/srv/homelab/backups/restore-tests/restore-log.md

27. Plano de desastre

27.1. Se o app quebrou, mas servidor está ok

cd /srv/homelab/apps/hub-metrics

docker compose logs --tail=120 hub-metrics
docker compose ps

git status
git log --oneline -5

Ações:

1. Reverter último commit se foi deploy ruim.
2. Restaurar .env.production.local se foi alteração de env.
3. Rebuildar container.
4. Se banco foi afetado, restaurar dump.

27.2. Se Supabase quebrou

cd /srv/homelab/supabase/hub-metrics/docker

docker compose ps
docker compose logs --tail=120 db
docker compose logs --tail=120 auth
docker compose logs --tail=120 kong

Ações:

1. Não rodar down -v.
2. Fazer backup do estado atual.
3. Identificar serviço quebrado.
4. Restaurar .env/docker-compose se alteração de config.
5. Restaurar dump apenas se dados foram corrompidos.

27.3. Se servidor morreu e precisa recriar

Ordem:

1. Instalar Ubuntu/Docker/Git.
2. Recriar /srv/homelab.
3. Restaurar /srv/homelab/proxy.
4. Restaurar /srv/homelab/infra/cloudflared.
5. Restaurar stacks Supabase.
6. Restaurar dumps dos bancos.
7. Clonar apps pelo Git.
8. Restaurar .env.production.local dos apps.
9. Subir Caddy.
10. Subir Supabase.
11. Subir apps.
12. Validar Cloudflare Tunnel.

28. Comandos críticos de verificação

28.1. Hub Metrics app

cd /srv/homelab/apps/hub-metrics

docker compose ps
docker compose logs --tail=120 hub-metrics
docker compose config > /tmp/hub-metrics-app-compose-check.yml

28.2. Hub Metrics Supabase

cd /srv/homelab/supabase/hub-metrics/docker

docker compose ps
docker compose logs --tail=120 kong
docker compose logs --tail=120 auth
docker compose logs --tail=120 db
curl -I http://127.0.0.1:8003

28.3. Caddy

cd /srv/homelab/proxy

docker compose ps
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
docker compose logs --tail=120 caddy

28.4. Cloudflare Tunnel

cd /srv/homelab/infra/cloudflared

docker compose ps
docker compose logs --tail=120 cloudflared

29. O que nunca fazer sem backup

Nunca rodar docker compose down -v em stack com dados reais.
Nunca apagar /srv/homelab/supabase/<projeto>/docker/volumes/db/data sem backup.
Nunca trocar POSTGRES_PASSWORD de stack existente sem plano de migração.
Nunca commitar .env.
Nunca deixar service role em NEXT_PUBLIC_*.
Nunca expor Postgres na internet.
Nunca expor Docker socket.
Nunca atualizar Supabase sem backup do banco.
Nunca confiar em backup que nunca foi restaurado.

30. Checklist rápido para novo projeto seguro

Ao criar um novo projeto:

[ ] Criar /srv/homelab/apps/<projeto>
[ ] Criar /srv/homelab/supabase/<projeto>/docker, se precisar de Supabase próprio
[ ] Garantir portas únicas para Kong/Postgres/Pooler
[ ] Criar .env do Supabase e guardar backup criptografado
[ ] Criar .env.production.local do app e .env symlink
[ ] Garantir .env e .env.production.local no .gitignore
[ ] Adicionar app ao Caddy
[ ] Proteger admin/studio com Cloudflare Access ou manter local
[ ] Adicionar projeto ao script backup-homelab-daily.sh
[ ] Rodar backup manual inicial
[ ] Testar restore do dump inicial

31. Referências oficiais úteis


32. Resumo operacional

Para rotina diária:

/srv/homelab/scripts/backup-homelab-daily.sh

Para backup manual de um projeto:

/srv/homelab/scripts/backup-supabase-project.sh hub-metrics

Para validar Caddy:

cd /srv/homelab/proxy
docker compose exec caddy caddy validate --config /etc/caddy/Caddyfile

Para ver backups recentes:

find /srv/homelab/backups/local -type f -mtime -2 -print

Para regra mental:

Código fica no Git.
Dados ficam no Postgres/Storage.
Secrets ficam no .env e em backup criptografado.
Caddy roteia tudo.
Cloudflare Tunnel entra pelo Caddy.
Backup só vale depois de restore testado.