Refactor: Migrate from Nginx/ModSec to Caddy Proxy

This commit is contained in:
João Pedro Toledo Goncalves 2026-01-27 10:12:13 -03:00
parent 5a73c9a116
commit f1445a7609
30 changed files with 93 additions and 99 deletions

25
Caddyfile Normal file
View File

@ -0,0 +1,25 @@
{
# Global Options
email admin@oestepan.com.br
# Enable Admin API for the watcher to trigger reloads
admin :2019
}
# Import dynamic sites
import sites/*
# Default Site: Traccar GPS
gps.oestepan.com.br {
# Reverse Proxy to the backend service
reverse_proxy host.docker.internal:8083 {
# Trust original IPs
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
# Enable logging
log {
output file /var/log/caddy/gps.access.log
}
}

49
TODO.md Normal file
View File

@ -0,0 +1,49 @@
# Relatório de Diagnóstico e Pontos de Dor (Pain Points)
Este documento sumariza os problemas arquiteturais e técnicos identificados durante a tentativa de estabilizar o stack `nginx-pathfinder-proxy`. O objetivo é fornecer um contexto claro para um futuro Agente de IA simplificar a solução.
## 1. Arquitetura Excessivamente Complexa (Split Container)
Atualmente, temos dois containers NGINX separados:
1. **Frontend (`modsecurity`)**: Recebe a internet, faz WAF, termina SSL.
2. **Backend (`nginx-proxy`)**: Recebe do WAF, faz roteamento, gerencia certificados (Certbot), roda scripts.
**Problemas Causados:**
- **Inferno de Permissões (Permission Hell):** O Backend (onde roda o Certbot) gera certificados no volume compartilhado como `root`. O Frontend tenta ler esses arquivos e falha com `Permission denied` porque roda com outro UID/GID. Tentar corrigir com `chmod` é frágil e inseguro.
- **Configuração Duplicada:** É preciso configurar o Nginx duas vezes. Uma no Frontend (para saber onde estão os certs) e uma no Backend (para saber como tratar a requisição na porta 8080).
- **SSL "Ping-Pong":** O Backend gerencia a renovação, mas o Frontend é quem *usa* o certificado. Isso exige reload sincronizado em dois containers diferentes.
## 2. Problema do "Ovo e a Galinha" (SSL Bootstrap)
- O NGINX **não sobe** se o arquivo de certificado não existir.
- O Certbot **não gera** o certificado se o NGINX não estiver rodando (para responder o desafio HTTP-01).
- **Solução Atual (Gambiarra):** Criamos um script complexo (`pre-flight.sh` + `renew_ssl.sh`) que gera certificados falsos (self-signed) só para o NGINX subir, e depois tenta baixar os reais. Isso adiciona muita lógica propensa a falhas.
## 3. Fragilidade de Deploy (Portainer / Docker)
- **Mount Error:** O Portainer falha ao tentar montar arquivos de configuração (`modsec_conf/...`) que ainda não foram baixados pelo git no host.
- **Solução Atual:** Tivemos que "assar" (bake) as configurações dentro da imagem Docker (`COPY conf.d ...`). Isso tira a agilidade de alterar uma config no git e dar deploy rápido; agora exige rebuild da imagem.
## 4. Scripts de Automação Frágeis
- O script `pre-flight.sh` tenta fazer `git clone/pull` dentro do container. Isso gera erros de "Resource busy" quando tenta limpar pastas montadas via volume.
- Lógica de `sed/grep` para ler arquivos `.conf` e achar domínios é suscetível a erros de sintaxe no arquivo de config.
---
# Recomendação de Simplificação (Para o Próximo Agente)
### Opção A: Single "Super" Container (Recomendada)
Unificar tudo em um único container.
- **Base:** Usar a imagem oficial com ModSecurity já compilado (ou compilar num multi-stage build).
- **Benefício:** Resolve problemas de permissão (mesmo processo lê e escreve). Resolve problema de setup (um único serviço). Remove complexidade de rede (sem proxy pass interno desnecessário).
### Opção B: Caddy Server (Radical)
Substituir NGINX + Certbot por **Caddy**.
- **Benefício:** Caddy tem HTTPS automático (resolve o problema do Ovo/Galinha nativamente).
- **WAF:** Existe plugin de WAF para Caddy (Coraza), mas exige validação se atende os requisitos de segurança do Oestepan.
### Opção C: NGINX Proxy Manager (GUI)
Usar uma solução pronta como NGINX Proxy Manager.
- Tem interface web.
- Gerencia SSL sozinho.
- Pode ser difícil integrar ModSecurity customizado.
### Resumo do Pedido de Refatoração
> "Simplificar a infraestrutura eliminando a separação Frontend/Backend. Criar um container único que faça WAF + Proxy + SSL Management, eliminando scripts complexos de bootstrap e problemas de permissão de volume."

View File

@ -1,22 +1,15 @@
#!/bin/bash #!/bin/bash
set -e set -e
echo "Detecting Public IP..." echo "Deploying Caddy Proxy..."
CURRENT_IP=$(curl -s https://ifconfig.me)
if [ -z "$CURRENT_IP" ]; then # Pull latest code
echo "Error: Could not detect Public IP." git pull
exit 1
fi
echo "Public IP detected: $CURRENT_IP" # Ensure containers are up
echo "HOST_PUBLIC_IP=$CURRENT_IP" > .env
echo "Building and testing..."
docker compose build
docker compose run --rm nginx-proxy nginx -t
echo "Deploying..."
docker compose up -d docker compose up -d
echo "Done! Proxy is running." # Force a reload just in case
docker compose exec caddy caddy reload
echo "Deployment Complete."

View File

@ -1,94 +1,21 @@
services: services:
# ============================================ caddy:
# ModSecurity WAF (Frente do NGINX) image: caddy:latest
# ============================================ container_name: proxy_caddy
modsecurity:
build:
context: .
dockerfile: Dockerfile.modsec
container_name: modsecurity-waf
restart: always restart: always
ports: ports:
- "80:80" - "80:80"
- "443:443" - "443:443"
environment:
# - BACKEND=http://nginx-proxy:8080 # Replaced by static config mount
- PARANOIA=1
- ANOMALY_INBOUND=5
- ANOMALY_OUTBOUND=4
volumes: volumes:
- ssl_data:/etc/nginx/ssl:ro - ./Caddyfile:/etc/caddy/Caddyfile
- modsec_logs:/var/log/modsecurity - ./sites:/etc/caddy/sites
depends_on: - caddy_data:/data
- nginx-proxy - caddy_config:/config
- caddy_logs:/var/log/caddy
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
- "srvproxy001.itguys.com.br:172.16.254.1"
- "srvproxy001:172.16.254.1"
- "zammad.itguys.com.br:172.16.254.59"
- "zammad:172.16.254.59"
- "cloud.grupopralog.com.br:172.16.253.12"
- "business.itguys.com.br:172.16.121.13"
- "verbocloud.itguys.com.br:172.16.253.13"
- "srvoffice001.itguys.com.br:172.16.253.101"
- "srvoffice001:172.16.253.101"
# ============================================
# NGINX Proxy (Backend do ModSecurity)
# ============================================
nginx-proxy:
build: .
container_name: nginx-proxy
restart: always
expose:
- "8080"
environment:
- HOST_PUBLIC_IP=${HOST_PUBLIC_IP}
volumes:
- ssl_data:/etc/nginx/ssl
- nginx_cache:/var/cache/nginx
- nginx_logs:/var/log/nginx
- certbot_data_conf:/etc/letsencrypt
- certbot_data_www:/var/www/certbot
- repo_data:/opt/repo
extra_hosts:
- "host.docker.internal:host-gateway"
- "server-254:10.10.253.254"
- "srvproxy001.itguys.com.br:172.16.254.1"
- "srvproxy001:172.16.254.1"
- "zammad.itguys.com.br:172.16.254.59"
- "zammad:172.16.254.59"
- "cloud.grupopralog.com.br:172.16.253.12"
- "business.itguys.com.br:172.16.121.13"
- "verbocloud.itguys.com.br:172.16.253.13"
- "srvoffice001.itguys.com.br:172.16.253.101"
- "srvoffice001:172.16.253.101"
# ============================================
# Fail2ban (Lê logs e bane IPs)
# ============================================
fail2ban:
build:
context: .
dockerfile: Dockerfile.fail2ban
container_name: fail2ban
restart: always
network_mode: host
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- nginx_logs:/var/log/nginx:ro
- modsec_logs:/var/log/modsecurity:ro
volumes: volumes:
nginx_cache: caddy_data:
nginx_logs: caddy_config:
modsec_logs: caddy_logs:
ssl_data:
certbot_data_conf:
certbot_data_www:
repo_data:

Binary file not shown.