⚡ AutomationsAI|Portal de Cursos →

Verificando acesso...

TRILHA 6

🚀 Deploy & Produção

Do código rodando local até um sistema em produção que aguenta porrada: VPS, Docker Compose, HTTPS automático, reverse proxy, monitoramento, backup testado e segurança operacional. O último passo do MkBlogs — onde tudo vira infra real.

4
Módulos
24
Tópicos
~3h
Duração
Avançado
Nível

Mapa da trilha

Conteúdo detalhado

6.1 ~40 min

🖥️ Servidor e Docker

Escolher VPS, hardening básico do Ubuntu, Docker + Compose e o arquivo docker-compose.prod.yml que vai pra produção.

O que é:

Servidor virtual privado (VPS) com IP público fixo, onde a stack inteira do MkBlogs vai rodar 24/7. Hetzner CX22 (2 vCPU, 4GB RAM, 40GB SSD) na Alemanha custa ~€4,51/mês e cobre tranquilamente Postiz + Postgres + Redis + uma app NestJS.

Por que aprender:

Render, Railway e Fly.io ficam caros rápido quando você precisa de banco persistente, fila e worker. Uma VPS de €4 entrega 5x mais recurso pela mesma faixa de preço — e você aprende infra de verdade. Hetzner, OVH, Contabo e DigitalOcean são opções sérias; AWS Lightsail funciona mas é o mais caro.

Conceitos-chave:

vCPU vs CPU dedicada; RAM mínima 2GB pra Postgres + Redis + Node; localização do data center (latência pra Brasil: Ashburn/EUA ~120ms, Hetzner Falkenstein ~200ms); IPv4 dedicado; snapshot/imagem de backup.

O que é:

Hardening básico do Ubuntu 24.04 LTS recém-provisionado: usuário não-root com sudo, login SSH só por chave (PasswordAuthentication no), ufw liberando apenas 22/80/443 e fail2ban banindo IPs que tentam força bruta no SSH.

Por que aprender:

Uma VPS sem hardening recebe milhares de tentativas de login por dia em 1h após subir. Sem fail2ban e firewall, é questão de tempo até alguém entrar. Esses 4 passos básicos eliminam 99% dos ataques automatizados.

Conceitos-chave:

Princípio do menor privilégio; chave SSH ed25519 (não RSA); ufw default deny incoming; jaula de fail2ban (maxretry, bantime, findtime); unattended-upgrades pra patches de segurança automáticos.

O que é:

Instalação do Docker Engine + plugin Compose v2 via repositório oficial do Docker (download.docker.com), não pelo apt do Ubuntu que entrega versão velha. Compose v2 vem como subcomando: docker compose up, sem hífen.

Por que aprender:

O docker.io do apt pode ter 1-2 anos de atraso e bugs já corrigidos. O repositório oficial garante a versão atual, suporte a buildx, networking moderno e o Compose v2 nativo. Adicionar seu usuário ao grupo docker evita ter que usar sudo a cada comando.

Conceitos-chave:

Docker Engine vs Docker Desktop (desktop é só pra dev); grupo docker = root equivalente (cuidado); docker compose vs docker-compose; daemon.json pra log driver e storage driver; docker system prune pra limpar lixo.

O que é:

Arquivo Compose dedicado à produção: imagens fixadas por tag (não :latest), variáveis vindas de .env, sem bind mounts de código, sem portas expostas direto (só via Caddy), restart: unless-stopped e limites de recursos (mem_limit, cpus).

Por que aprender:

Compose de dev e prod são animais diferentes: dev quer hot reload e ports expostas; prod quer reprodutibilidade, segurança e estabilidade. Misturar os dois leva a "funciona no meu PC" e portas 5432 do Postgres expostas na internet — receita pra invasão.

Conceitos-chave:

Override files (-f compose.yml -f compose.prod.yml); networks internas vs externas; expose vs ports; secrets via .env com permissão 600; pin de versão de imagem (ghcr.io/postiz/postiz-app:v1.30.0).

O que é:

Named volumes do Docker (postgres_data, redis_data, postiz_uploads) que vivem em /var/lib/docker/volumes/ e sobrevivem a docker compose down. Ou bind mounts pra /srv/mkblogs/data quando você quer ver os arquivos direto no host.

Por que aprender:

Container sem volume = dado evaporado no primeiro docker compose down -v. Volume mal configurado = backup quebrado porque você está fazendo dump de pasta vazia. Saber exatamente onde cada dado mora é pré-requisito pra dormir tranquilo.

Conceitos-chave:

Named volume vs bind mount vs tmpfs; docker volume ls, inspect, prune; nunca usar volume pra banco em prod sem backup; UID/GID consistente entre host e container; cuidado com NFS pra Postgres (lock issues).

O que é:

restart: unless-stopped faz o Docker subir o container de volta se ele crashar ou se a VPS reiniciar. healthcheck define como o Docker sabe que o container está saudável (HTTP /health, pg_isready, redis-cli ping) — e depends_on: condition: service_healthy faz o app só subir depois do banco estar pronto.

Por que aprender:

Sem restart policy, um OOM-kill no meio da madrugada deixa o site fora do ar até alguém perceber. Sem healthcheck, o Caddy roteia requisições pra um app que ainda está bootando e devolve 502. Esses dois ajustes resolvem 80% dos "caiu durante a noite".

Conceitos-chave:

Policies: no, on-failure, always, unless-stopped (esse é o certo); interval/timeout/retries/start_period do healthcheck; loop de restart (CrashLoopBackOff); diferença entre liveness e readiness.

6.2 ~40 min

🔒 Domínio, HTTPS, reverse proxy

Apontar DNS, escolher reverse proxy, configurar Caddyfile com auto-HTTPS, subdomínios e headers de segurança.

O que é:

Criar registro A em mkblogs.com apontando pro IPv4 da VPS, AAAA pro IPv6, e CNAMEs pros subdomínios (api., app.) apontando pro domínio raiz. Cloudflare grátis na frente (modo DNS-only, nuvem cinza) facilita gerenciar.

Por que aprender:

Sem DNS apontando certo, Caddy não consegue validar Let's Encrypt e fica sem HTTPS. TTL alto (24h) atrapalha quando você precisa mudar IP. Subdomínios facilitam separar API, painel e status sem precisar de novos certificados.

Conceitos-chave:

A vs AAAA vs CNAME; TTL (use 300s durante mudanças, 3600s depois); propagação (dig +trace); Cloudflare proxy desligado pra Let's Encrypt HTTP-01 funcionar; wildcard *.mkblogs.com exige validação DNS-01.

O que é:

Reverse proxy é a porta de entrada HTTPS que termina TLS, roteia por hostname e fala HTTP pros containers internos. Caddy (Go) tem auto-HTTPS no Caddyfile com 3 linhas. Traefik é mais flexível mas YAML/labels complexas. nginx-proxy + acme-companion é o jeito antigo, ainda funciona.

Por que aprender:

Pra MkBlogs (1-3 serviços HTTP), Caddy é a escolha óbvia: Caddyfile cabe em 10 linhas, certificado automático, renovação automática, HTTP/3 ligado por padrão. Traefik ganha se você tem 10+ serviços e quer descobrir por labels do Docker.

Conceitos-chave:

Termination TLS; SNI; upstream HTTP interno; service discovery (labels Docker, etcd, file); ACME provider; admin API do Caddy na porta 2019 (não expor!); reload sem downtime.

O que é:

Arquivo Caddyfile no formato: app.mkblogs.com { reverse_proxy postiz:3000 }. Caddy sozinho resolve ACME challenge HTTP-01, pega certificado Let's Encrypt, instala, configura HSTS e redireciona 80 → 443.

Por que aprender:

É literalmente a configuração mais simples de HTTPS em produção que existe hoje. Comparado ao nginx + certbot + cronjob de renovação + reload, são 3 linhas vs 50. Erro humano cai drasticamente.

Conceitos-chave:

Site block; matcher (@api host api.mkblogs.com); reverse_proxy com health check; encode gzip zstd; volume caddy_data persistente (guarda os certificados!); tls internal pra dev local.

O que é:

Separar superfícies por subdomínio: app.mkblogs.com (painel Postiz), api.mkblogs.com (sua API NestJS), status.mkblogs.com (status page), grafana.mkblogs.com (métricas). Cada um vira um site block no Caddyfile.

Por que aprender:

Manter tudo em /api, /app, /status no mesmo domínio gera conflito de cookies, CORS confuso e dificulta limites de rate por surface. Subdomínios isolam cookies de sessão e simplificam regras.

Conceitos-chave:

Cookie scope por domínio; CORS cross-subdomain (Access-Control-Allow-Origin); rate-limit por host no Caddy; CSP connect-src; um certificado por subdomínio (Let's Encrypt grátis até 50/semana por domínio raiz).

O que é:

Conjunto de headers HTTP que o reverse proxy adiciona automaticamente: Strict-Transport-Security (HSTS, força HTTPS), X-Frame-Options: DENY (anti-clickjacking), X-Content-Type-Options: nosniff, Referrer-Policy e CSP básica.

Por que aprender:

Pega de graça nota A no securityheaders.com e fecha vetores comuns (clickjacking, MIME sniffing, downgrade HTTPS→HTTP). Custa 6 linhas no Caddyfile e protege contra ataques que existem desde 2010.

Conceitos-chave:

HSTS preload (cuidado, é difícil reverter); CSP report-only antes de enforce; nonce e hash em scripts inline; Permissions-Policy (substitui Feature-Policy); diretiva header do Caddy.

O que é:

Certificados Let's Encrypt duram 90 dias. Caddy renova automaticamente quando faltam ~30 dias, usando o mesmo desafio HTTP-01 (ou DNS-01 se você configurou). Tudo persiste no volume caddy_data em /data.

Por que aprender:

A maioria dos "site fora do ar com cadeado vermelho" é certificado expirado. Com Caddy, isso é problema resolvido — desde que (1) o volume persista, (2) o DNS continue apontando certo e (3) a porta 80 continue acessível pra desafio HTTP-01.

Conceitos-chave:

ACME v2; rate limit de 5 certificados/semana por domínio (cuidado em testes — usar staging); acme_ca https://acme-staging-v02.api.letsencrypt.org/directory; ZeroSSL como fallback; alerta em UptimeRobot pra expiração (cinto e suspensório).

6.3 ~35 min

📊 Monitoramento e logs

Centralizar logs (Loki/Better Stack), uptime, métricas no Grafana, alertas, Sentry pra erros de app e status page pública.

O que é:

Coletar logs de todos os containers num lugar pesquisável. Opção self-hosted: Grafana Loki + Promtail/Alloy lendo do Docker socket. Opção SaaS: Better Stack (ex-Logtail) com plano grátis de 1GB/mês.

Por que aprender:

docker logs -f só funciona quando você sabe qual container investigar. Quando o usuário diz "deu erro às 14h32 ontem", você precisa de busca textual com filtros por serviço, tempo e nível — exatamente o que Loki/Better Stack entregam.

Conceitos-chave:

Structured logging (JSON > texto solto); log driver do Docker (json-file padrão, com rotação max-size); LogQL do Loki (similar a PromQL); retention vs custo; PII em logs (não logar token/email cru).

O que é:

Monitor externo (fora da sua VPS!) que faz HTTP GET no /health de cada serviço a cada 5 minutos e alerta quando responde !=200 ou demora demais. UptimeRobot tem 50 monitors grátis; BetterStack Uptime e Healthchecks.io são alternativas.

Por que aprender:

Monitor que roda dentro da própria VPS é inútil — se a VPS cai, o monitor cai junto e silencia. Monitor externo é a primeira linha de defesa contra "tô fora do ar e nem sei". Healthchecks.io ainda monitora cron jobs (pings de heartbeat).

Conceitos-chave:

HTTP check vs ping vs keyword check; intervalo (5min grátis, 1min pago); endpoint /health que valida banco + Redis, não só "200 OK"; dead-man's-switch pra cron (Healthchecks.io); SSL expiration check de brinde.

O que é:

Stack Prometheus + Grafana rodando ao lado da app. node_exporter coleta CPU/RAM/disco da VPS, cadvisor coleta métricas por container, e a app expõe /metrics (latência, fila BullMQ, falhas de OAuth). Grafana desenha gráficos.

Por que aprender:

Sem métricas, você descobre que o disco encheu quando o Postgres trava. Com gráfico de disco e CPU dos últimos 7 dias, você vê a tendência e age antes. Pra MkBlogs, métricas críticas são: profundidade da fila, latência das APIs (X, LinkedIn), erros 5xx, uso de disco em volumes.

Conceitos-chave:

Pull-based (Prometheus) vs push-based; counter/gauge/histogram; labels (cuidado com cardinalidade alta); retention de 15 dias é suficiente; dashboards do Grafana com grafana.com/dashboards (ID 1860 = Node Exporter Full, 893 = cadvisor).

O que é:

Regras no Alertmanager (parte do Prometheus) que disparam quando uma métrica passa do limite (disco > 85%, fila > 1000 jobs, taxa de erro > 5%). Saída pra email SMTP, Telegram (via bot), Discord webhook ou ntfy.sh.

Por que aprender:

Dashboard que ninguém olha não serve. Alerta no celular acorda você. Telegram via @BotFather é grátis, instantâneo e chega no celular sem precisar de SMS pago. Cuidado com alert fatigue: poucos alertas e acionáveis.

Conceitos-chave:

Severity (warning vs critical); for: 5m evita flapping; agrupamento (group_by); silenciamento durante manutenção; runbook URL em cada alerta; ntfy.sh self-hosted como alternativa zero-friction.

O que é:

Sentry captura exceptions não tratadas do Node, agrupa por fingerprint, mostra stack trace, breadcrumbs, request body, user ID e dispara alerta. Tem SaaS com free tier de 5k eventos/mês e versão self-hosted (mais pesada).

Por que aprender:

Logs mostram que deu erro; Sentry mostra por que. Pra app real do MkBlogs, você quer saber: qual user, qual rede social, qual job da fila, qual versão do código (release tag), e ver a tendência (esse erro está crescendo?).

Conceitos-chave:

DSN; tracesSampleRate (performance) vs sampleRate (erros); beforeSend pra remover PII; release tracking + sourcemaps; integração com BullMQ (capturar falhas de job); GlitchTip como alternativa open-source.

O que é:

Página em status.mkblogs.com mostrando estado de cada componente (API, painel, agendamento, OAuth) e histórico de incidentes. Open-source: Uptime Kuma, Statping-ng, Cachet. SaaS: Better Stack, Instatus.

Por que aprender:

Quando algo cai, status page reduz suporte em ~70%: usuário vê "X API está fora" e entende. Também serve de histórico público de SLA — clientes B2B pedem isso. Uptime Kuma sobe em 2 minutos com docker-compose e tem visual decente.

Conceitos-chave:

Componente vs incidente; postmortem público; comunicação durante incidente (4 estágios: investigando → identificado → monitorando → resolvido); status page fora da mesma VPS (senão cai junto); subscribe por email/RSS pra updates.

6.4 ~35 min

💾 Backup e segurança

Dump diário do Postgres, off-site em S3/R2 com restic, teste de restore mensal, rotação de tokens e plano de disaster recovery.

O que é:

Cron job diário (03:00 UTC) que roda docker compose exec -T postgres pg_dump -Fc -U mkblogs mkblogs > /srv/backups/mkblogs-$(date +%F).dump. Formato -Fc (custom) é binário e comprimido, restaurável com pg_restore.

Por que aprender:

Backup é a única coisa que separa "incidente chato" de "fim do negócio". Snapshot da VPS no provider ajuda, mas dump lógico é o que permite restaurar uma tabela específica, migrar de versão de Postgres ou ir pra outro provedor.

Conceitos-chave:

Dump lógico (pg_dump) vs físico (pg_basebackup, snapshot LVM); -Fc custom vs -Fp plain SQL; rotação local (manter últimos 7 dias); flock pra evitar overlap; cron com MAILTO ou Healthchecks.io ping.

O que é:

Mandar o dump pra fora da VPS. restic faz dedupe + criptografia + snapshots e fala com S3/R2/B2 nativamente. rclone é mais simples (rsync pra cloud). Cloudflare R2 tem 10GB grátis e zero egress fee — perfeito pra backup pequeno.

Por que aprender:

Backup que mora só na própria VPS é backup que some junto com a VPS (ransomware, datacenter pegando fogo, conta suspensa). Regra 3-2-1: 3 cópias, 2 mídias diferentes, 1 off-site. R2 + restic resolve isso por ~US$0/mês.

Conceitos-chave:

restic snapshots + forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12; chave de criptografia (guardada FORA da VPS!); S3-compatible (R2, B2, Wasabi, MinIO); egress fee como armadilha (AWS S3 cobra, R2/B2 não); restic check pra validar integridade.

O que é:

Script que mensalmente baixa o último snapshot do R2, sobe um Postgres descartável em container, roda pg_restore, faz SELECT count(*) FROM users e compara com um número esperado. Falhou? Alerta no Telegram.

Por que aprender:

Backup não testado é Schrödinger backup — você não sabe se funciona até precisar. Histórias de empresas que perderam tudo porque o dump estava corrompido há 6 meses são abundantes. Restore mensal automatizado dá confiança real.

Conceitos-chave:

RTO (Recovery Time Objective — quanto tempo até voltar) vs RPO (Recovery Point Objective — quanto dado posso perder); restore em ambiente isolado; smoke test pós-restore (contagens, checksums); pg_restore --jobs pra paralelizar; documentar o procedimento (DR runbook).

O que é:

Trocar regularmente: senha do banco, JWT secret, encryption key dos OAuth tokens, API keys de Sentry/UptimeRobot, chave SSH do deploy, password do admin do Postiz. Calendário trimestral; emergencial se um dev sai do time ou se houver suspeita.

Por que aprender:

Token vazado em log, em commit antigo do Git ou no laptop roubado de um dev continua válido até alguém revogar. Rotação periódica limita a janela de exposição. git history não esquece — tem que usar git-secrets, trufflehog e revogar.

Conceitos-chave:

Inventário de segredos (lista do que existe); rotação com overlap (chave antiga aceita por 24h); .env com permissão 600 e sem comitar; gerenciadores (Doppler, Infisical, 1Password CLI, sops + age); revogar tokens OAuth nas próprias plataformas (X, LinkedIn).

O que é:

Cada componente recebe só a permissão mínima necessária: user do Postgres da app não tem SUPERUSER; container não roda como root (USER node no Dockerfile); chave R2 tem escopo de write-only num bucket específico; deploy SSH usa chave dedicada com command= restrito.

Por que aprender:

Quando (não se) um componente for comprometido, o estrago fica limitado. Container rodando como root + montando /var/run/docker.sock = comprometimento total do host. Chave R2 com s3:* = adversário apaga seus backups.

Conceitos-chave:

Defense in depth; CAP_DROP: ALL e read_only: true em containers que aguentam; network_mode: internal pra Postgres/Redis; IAM policy mínima em R2/S3; SSH PermitRootLogin no; sudoers granular.

O que é:

Documento curto (1-2 páginas) que descreve passo a passo o que fazer quando "a VPS sumiu": (1) provisionar nova VPS, (2) rodar Ansible/script de bootstrap, (3) baixar último snapshot do R2, (4) pg_restore, (5) apontar DNS, (6) revogar tokens da máquina antiga. Tempo-alvo: < 2h.

Por que aprender:

Durante um desastre você tem adrenalina alta e cabeça ruim. Improvisar leva a erros que multiplicam o dano (rodar restore com --clean no banco errado, por exemplo). Runbook escrito com calma, em tempo seco, vira checklist em tempo de chuva.

Conceitos-chave:

Drill anual (fingir que tudo caiu e testar o runbook); contatos de emergência (registrador de domínio, provider, CDN); credenciais de fallback impressas e guardadas físicamente; pre-bootstrap automatizado (Ansible playbook ou Docker image custom da VPS); status page já preparado pra anunciar incidente.

← Trilha 5: Construindo do Zero 🏠 Voltar ao início

🎉 Fim da jornada MkBlogs

Você passou por 6 trilhas: fundamentos, Postiz pronto, OAuth de redes, blogs, construção do zero e agora deploy em produção. A próxima publicação já pode ser sua — em escala.

Mais cursos em AutomationsAI →