# Caddy — reverse proxy + HTTPS automático (Let's Encrypt) para o DeskcommCRM. # HTTP→HTTPS e emissão/renovação de certificado são automáticos. { email {$ACME_EMAIL} } {$DOMAIN} { encode gzip # `route` é obrigatório aqui: fora dele o Caddy reordena as diretivas pela # ordem padrão dele, na qual `respond` vem DEPOIS de `reverse_proxy` — o # catch-all atendia primeiro e o 403 abaixo nunca era alcançado (medido: o # POST sem assinatura ainda respondia 200). Dentro de `route`, vale a ordem # escrita. route { # O webhook GLOBAL do WAHA (sem token na URL) não é publicado na internet. # # Nesta stack o WAHA fala com o app pela rede interna do Docker # (http://app:3000/api/v1/webhooks/waha), então essa rota nunca precisou ser # alcançável de fora — e estando aberta, qualquer pessoa que soubesse o # endereço injetava mensagem falsa no CRM, escolhia o remetente e fazia o # WhatsApp do dono responder para um número arbitrário (queimando o # orçamento de IA e arriscando banimento do número). # # Quem roda o WAHA em OUTRO servidor deve usar a rota por tenant, # /api/v1/webhooks/waha/, que carrega um token imprevisível na URL e # continua pública — é a variante canônica para essa topologia. @waha_global path /api/v1/webhooks/waha respond @waha_global 403 # Todo o resto do app. reverse_proxy app:3000 } } # ── Ponto de extensão (#2724) ──────────────────────────────────────────────── # Publicar OUTRO serviço no mesmo VPS (wiki, landing page, n8n) sem editar # este arquivo: solte um arquivo seu em `caddy-sites/` — a pasta local que o # compose monta em /etc/caddy/sites, somente-leitura — e o Caddy publica aquele # serviço em seguida. Exemplo comentado em caddy-sites/README.caddy. # # É assim de propósito: este Caddyfile entra no contêiner por bind mount de um # arquivo e o update.sh troca de versão com `git checkout `; com o arquivo # alterado a atualização para em "parece haver mudanças locais que divergem" — # e quem atualiza pela tela do CRM nem vê o motivo. Ninguém precisa editar nada # versionado para publicar um domínio a mais. # # O caminho tem de ser o MESMO que o bind mount do compose declara; se os dois # divergirem o glob não acha nada e só avisa no log (a régua em # tests/unit/ponto-de-extensao-do-caddy.test.ts acopla os dois). import /etc/caddy/sites/*.caddy