diff --git a/fail2ban/data/action.d/nginx-blacklist.conf b/fail2ban/data/action.d/nginx-blacklist.conf deleted file mode 100644 index bd61514..0000000 --- a/fail2ban/data/action.d/nginx-blacklist.conf +++ /dev/null @@ -1,6 +0,0 @@ -[Definition] -actionstart = touch /etc/nginx/snippets/blacklist.conf -actionstop = -actioncheck = -actionban = echo "deny ;" >> /etc/nginx/dynamic/blacklist.conf && docker exec nginx-proxy nginx -s reload -actionunban = sed -i "/deny ;/d" /etc/nginx/dynamic/blacklist.conf && docker exec nginx-proxy nginx -s reload diff --git a/fail2ban/data/fail2ban/jail.d/nginx-pathfinder-jail.conf b/fail2ban/data/fail2ban/jail.d/nginx-pathfinder-jail.conf index 5e04b7a..61224de 100644 --- a/fail2ban/data/fail2ban/jail.d/nginx-pathfinder-jail.conf +++ b/fail2ban/data/fail2ban/jail.d/nginx-pathfinder-jail.conf @@ -9,7 +9,8 @@ enabled = true port = http,https filter = nginx-pathfinder-filter action = nginx-pathfinder-action -logpath = /var/log/nginx/access_json.log +logpath = /var/log/nginx/*access.log + /var/log/nginx/access_json.log backend = auto # --- Política de Tolerância Zero --- diff --git a/fail2ban/data/fail2ban/jail.local b/fail2ban/data/fail2ban/jail.local new file mode 100644 index 0000000..58902fa --- /dev/null +++ b/fail2ban/data/fail2ban/jail.local @@ -0,0 +1,19 @@ +[INCLUDES] +before = paths-debian.conf + +[DEFAULT] +# Ignora IPs locais e da rede interna +ignoreip = 127.0.0.1/8 ::1 172.16.0.0/12 10.0.0.0/8 192.168.0.0/16 + +# Backend padrao para Ubuntu/Debian +backend = systemd + +# Logpath padrao +var_log_path = /var/log + +# Email de destino +destemail = root@localhost +sender = root@ + +# Acao padrao +banaction = iptables-multiport diff --git a/fail2ban/data/filter.d/nginx-modsec.conf b/fail2ban/data/filter.d/nginx-modsec.conf deleted file mode 100644 index bbe7452..0000000 --- a/fail2ban/data/filter.d/nginx-modsec.conf +++ /dev/null @@ -1,4 +0,0 @@ -[Definition] -failregex = ^.*"remote_addr":"".*"block_request":"1".*$ - ^.*"remote_addr":"".*"status":403.*$ - ^.*"remote_addr":"".*"status":404.*$ diff --git a/fail2ban/data/jail.d/nginx-modsec.local b/fail2ban/data/jail.d/nginx-modsec.local deleted file mode 100644 index cb1816d..0000000 --- a/fail2ban/data/jail.d/nginx-modsec.local +++ /dev/null @@ -1,9 +0,0 @@ -[nginx-modsec] -enabled = true -port = http,https -filter = nginx-modsec -logpath = /var/log/nginx/access_json.log -maxretry = 3 -bantime = 3600 -findtime = 600 -action = nginx-blacklist diff --git a/nginx/conf.d/atendimento.grupopralog.com.br.conf b/nginx/conf.d/atendimento.grupopralog.com.br.conf new file mode 100644 index 0000000..4545849 --- /dev/null +++ b/nginx/conf.d/atendimento.grupopralog.com.br.conf @@ -0,0 +1,65 @@ +upstream chatwoot_pralog_backend { + server 172.17.0.3:8082; +} + +server { + listen 80; + server_name atendimento.grupopralog.com.br; + include snippets/acme_challenge.conf; + location / { + return 301 https://atendimento.grupopralog.com.br$request_uri; + } +} + +server { + listen 443 quic; + listen 443 ssl; + server_name atendimento.grupopralog.com.br; + + # Certificados (Ajustar apos geracao via Certbot se necessario) + ssl_certificate /etc/letsencrypt/live/atendimento.grupopralog.com.br/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/atendimento.grupopralog.com.br/privkey.pem; + + access_log /var/log/nginx/atendimento.grupopralog.com.br.access.log detailed_proxy; + error_log /var/log/nginx/atendimento.grupopralog.com.br.error.log warn; + + include snippets/ssl_params.conf; + include snippets/proxy_params.conf; + include snippets/modsecurity.conf; + include snippets/well_known.conf; + include snippets/security_actions.conf; + + proxy_cache dynamic_cache; + set $upstream_proto http; + set $upstream_app chatwoot_pralog_backend; + + # Recomendacao Chatwoot/Twilio: Permitir underscores em headers para webhooks + underscores_in_headers on; + + location / { + expires 15m; + proxy_cache_valid 200 15m; + proxy_pass http://chatwoot_pralog_backend; + + # Force HTTPS for Rails + include snippets/proxy_params.conf; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-Port 443; + } + + # Configuracao obrigatoria para Real-time (WebSockets) + location /cable { + proxy_pass http://chatwoot_pralog_backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + access_log off; + } +} diff --git a/nginx/nginx.conf b/nginx/nginx.conf index fb947c6..635e174 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -63,7 +63,7 @@ http { # --- HTTP/2 Hardening (CVE-2025-8671: MadeYouReset Mitigation) --- http2_max_concurrent_streams 64; - http2_idle_timeout 3m; + keepalive_requests 500; # 2. Conexões & Timeouts diff --git a/scripts/deploy_pathfinder.py b/scripts/deploy_pathfinder.py index 6bf1570..faa64b5 100644 --- a/scripts/deploy_pathfinder.py +++ b/scripts/deploy_pathfinder.py @@ -203,9 +203,11 @@ def windows_deploy(args): print(f"[!] Erro: Não encontrei a pasta 'nginx' em {prod_dir}") sys.exit(1) + fail2ban_dir = os.path.join(prod_dir, "fail2ban") + # 2. Empacotar arquivos tar_name = "pathfinder_deploy.tar.gz" - create_tarball([nginx_dir, scripts_dir], tar_name) + create_tarball([nginx_dir, scripts_dir, fail2ban_dir], tar_name) # 3. Conexão SSH print(f"[*] Conectando em {SERVER_HOST} como {SERVER_USER}...") @@ -310,6 +312,10 @@ def sync_all(): return False run_sudo(['systemctl', 'reload', 'nginx']) + + # Sincroniza Fail2Ban também + sync_fail2ban() + print("[+] Sincronização total concluída com sucesso.") return True @@ -452,6 +458,60 @@ def site_remove(domain): else: rollback_all() +# ============================================================================== +# FAIL2BAN LOGIC +# ============================================================================== + +def sync_fail2ban(): + """Sincroniza configurações do Fail2Ban.""" + # Definição do source (Dual mode: /tmp/fail2ban direto ou TMP_SYNC_BASE) + # A estrutura do tarball é fail2ban/data/fail2ban/... + src_base_1 = "/tmp/fail2ban/data/fail2ban" + src_base_2 = os.path.join(TMP_SYNC_BASE, "fail2ban", "data", "fail2ban") + + src = src_base_1 + if not os.path.exists(os.path.join(src, "jail.local")): + # Tenta o segundo caminho (caso não tenha sido extraído do tarball padrão) + # Ou se o tarball foi gerado de forma diferente + if os.path.exists(os.path.join("/tmp/fail2ban", "jail.local")): + src = "/tmp/fail2ban" + else: + src = src_base_2 + + if not os.path.exists(src): + print(f"[!] Diretório fonte do Fail2Ban não encontrado: {src}") + # Tenta achar onde foi parar + print(f" (DEBUG) Procurando em {src_base_1} e {src_base_2}") + return False + + print(f"[*] Sincronizando Fail2Ban de: {src}") + + # Lista de pastas/arquivos a sincronizar para /etc/fail2ban + # Não sobrescrevemos jail.conf para respeitar o mantenedor do pacote + targets = ["jail.local", "jail.d", "filter.d", "action.d", "paths-common.conf", "paths-lsio.conf"] + + for item in targets: + s_item = os.path.join(src, item) + d_item = os.path.join(FAIL2BAN_CONF_DIR, item) + + if os.path.exists(s_item): + log_syslog("SYNC_F2B", "sync_fail2ban", f"Copiando {item}") + if os.path.isdir(s_item): + run_sudo(['cp', '-rf', os.path.join(s_item, "."), d_item]) + else: + run_sudo(['cp', '-f', s_item, d_item]) + else: + print(f" [!] Item não encontrado na origem: {item} (Ignorado)") + + print("[*] Reiniciando serviço Fail2Ban...") + rc, out, err = run_sudo(['systemctl', 'restart', 'fail2ban']) + if rc != 0: + print(f"[!] Erro ao reiniciar Fail2Ban: {err}") + return False + + print("[+] Fail2Ban sincronizado e reiniciado.") + return True + # ============================================================================== # CLI HANDLER # ==============================================================================