Files
DeskcommCRM/docker-compose.npm.yml
rootandClaude Sonnet 5 652abef325 fix(proxy): app não perde a rede do NPM numa atualização
Incidente real em 2026-09-11: uma instalação atrás de Nginx Proxy Manager
tinha a rede do `app` plugada à mão (`docker network connect`). A primeira
recriação do contêiner (deploy, `update.sh`) perdeu essa conexão e o domínio
voltou a responder 502, com o app `healthy` — o healthcheck é TCP interno e
não sabe nada de roteamento.

docker-compose.npm.yml (novo) faz pro NPM o que docker-compose.traefik.yml já
fazia pro Traefik: fixa o `app` na rede/IP que o Proxy Host espera e desliga
o Caddy por profile. docker-compose.yml (WAHA local) entra na mesma rede
compartilhada, já que nesta VPS o dashboard do WAHA também sai pelo NPM.

Faltava o fio até o kit: REVERSE_PROXY=npm agora é um terceiro valor de
primeira classe em dc()/dc_files() (install.sh e _common.sh, gêmeas), com
guarda de rede ausente em garantir_rede_do_proxy (mesmo cuidado que o Traefik
já tinha) e sem o bug de reativar o Caddy por engano que o force-recreate por
nome já causava pro Traefik — sem isso REVERSE_PROXY=npm silenciosamente
caía no branch do Caddy em ambos os pontos, reproduzindo o incidente na
primeira atualização.

Testado com sabotagem: revertida a mudança em _common.sh/update.sh, 4 dos 8
casos novos de test-validators.sh caíram nos pontos exatos (dc_files, guarda
de rede, integração de rede sumida, guarda do Caddy), confirmando que os
testes vigiam o comportamento e não só a presença do símbolo. Suíte restaurada
e verde (bash hostgator-setup-kit/test-validators.sh + os 6 demais scripts de
tests/shell/, que compõem pnpm test:shell).

Configuração inicial (REVERSE_PROXY=npm, PROXY_NETWORK_NAME, PROXY_NETWORK_APP_IP)
continua manual — NPM não fala por labels como o Traefik — documentada no
cabeçalho de docker-compose.npm.yml.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Ja8SghdefMR1UqtT3TePw
2026-09-12 00:20:12 -03:00

52 lines
2.3 KiB
YAML

# docker-compose.npm.yml — override para VPS que já tem Nginx Proxy Manager (ou
# proxy equivalente que NÃO lê labels Docker, ao contrário do Traefik) ocupando
# as portas 80/443.
#
# docker compose -f docker-compose.prod.yml -f docker-compose.npm.yml --env-file .env up -d
#
# QUANDO USAR
# -----------
# O `docker-compose.traefik.yml` já existente resolve o caso de um Traefik na
# frente (lê labels). O NPM não lê labels — o roteamento é configurado na UI
# dele (porta 81), num "Proxy Host" que aponta pro app por IP fixo dentro de
# uma rede Docker compartilhada. Este arquivo faz só a parte que falta nesse
# cenário: garantir que o `app` SEMPRE entre nessa rede, no MESMO IP que o
# Proxy Host espera.
#
# Sem isto, qualquer recriação do container `app` (deploy, `--force-recreate`,
# atualização de imagem) derruba o roteamento e o domínio volta a responder
# 502 — foi exatamente o que aconteceu no incidente de 2026-09-11: alguém
# tinha plugado a rede manualmente com `docker network connect`, o app foi
# recriado, a conexão manual se perdeu e o NPM ficou apontando pro vácuo.
#
# CONFIGURAR PRA OUTRA INSTALAÇÃO
# --------------------------------
# Ajuste PROXY_NETWORK_NAME e PROXY_NETWORK_APP_IP no .env se a rede ou o IP
# do seu Proxy Host forem outros. Pra descobrir os valores atuais: Nginx Proxy
# Manager > Proxy Hosts > <domínio> > Edit > Forward Hostname / IP, e a rede é
# a que o container do próprio NPM já está conectado (`docker inspect
# <container-do-npm> --format '{{json .NetworkSettings.Networks}}'`).
#
# O `caddy` deste projeto nunca deve subir aqui: as portas 80/443 já são do
# NPM, e o `docker-compose.prod.yml` sozinho tenta criá-lo mesmo assim (fica
# em `Created`, falhando o bind — inofensivo, mas suja o `docker ps`). Mesmo
# truque de profile do `docker-compose.traefik.yml`.
services:
app:
networks:
internal: {}
npm:
ipv4_address: ${PROXY_NETWORK_APP_IP:-172.18.0.3}
caddy:
profiles: ["caddy-nao-usado-com-proxy-externo"]
# `external: true` = quem cria esta rede não é este compose — é o stack do NPM
# (ou de quem hospeda o proxy). Rede ausente é recusada ANTES de criar
# qualquer coisa: "network X declared as external, but could not be found".
networks:
npm:
external: true
name: ${PROXY_NETWORK_NAME:-proxy_network}