diff --git a/docker-compose.yml b/docker-compose.yml index bedcf2a..ae6cf68 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,15 +12,15 @@ services: # - "122:122/tcp" # SSH volumes: # Volumes para Configurações (Persistência Interna) - - ../sites-ativos/nginx.conf:/etc/nginx/nginx.conf:ro - - ../sites-ativos/conf.d:/etc/nginx/conf.d - - ../sites-ativos/snippets:/etc/nginx/snippets - - ../sites-ativos/modsec/main.conf:/etc/nginx/modsec/main.conf:ro + - ./sites-ativos/nginx.conf:/etc/nginx/nginx.conf:ro + - ./sites-ativos/conf.d:/etc/nginx/conf.d + - ./sites-ativos/snippets:/etc/nginx/snippets + - ./sites-ativos/modsec/main.conf:/etc/nginx/modsec/main.conf:ro # Persistência de Dados e Certificados - ./ssl:/etc/nginx/ssl - ./certbot:/etc/letsencrypt - - ../sites-ativos/logs:/var/log/nginx + - ./sites-ativos/logs:/var/log/nginx # Customização do Shell - ./.bashrc:/root/.bashrc:ro @@ -36,9 +36,9 @@ services: - NET_RAW restart: always volumes: - - ../sites-ativos/logs:/var/log/nginx:ro # Monitora os logs do Nginx + - ./sites-ativos/logs:/var/log/nginx:ro # Monitora os logs do Nginx - ./fail2ban/data:/config # Configurações do F2B - - ../sites-ativos/snippets:/etc/nginx/snippets # Onde ele gera o blacklist.conf + - ./sites-ativos/snippets:/etc/nginx/snippets # Onde ele gera o blacklist.conf - /var/run/docker.sock:/var/run/docker.sock # Para reload do Nginx user: root # Necessário para interagir com o socket environment: diff --git a/sites-ativos/.gitignore b/sites-ativos/.gitignore new file mode 100644 index 0000000..dda8ec9 --- /dev/null +++ b/sites-ativos/.gitignore @@ -0,0 +1,35 @@ +# Logs and debug files +*.log +debug_logs*.txt +nginx_test*.log + +# Environment files +.env +.env.local + +# Docker +docker-compose.override.yml + +# SSL certificates (sensitive - should be managed separately) +ssl/*.key +ssl/*.crt +ssl/*.pem + +# Editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.bak + +# Disabled configs +*.disabled +.gemini/ \ No newline at end of file diff --git a/sites-ativos/README.md b/sites-ativos/README.md new file mode 100644 index 0000000..89053c4 --- /dev/null +++ b/sites-ativos/README.md @@ -0,0 +1,47 @@ +# Nginx Pathfinder - Sites e Configurações + +Este diretório é o cérebro operacional do Proxy. Aqui ficam as definições de domínios, snippets de configuração e persistência de logs/segurança. + +## 🧠 O que este repositório faz: +* **Gerenciamento de Sites:** Definição de VHosts em `conf.d/`. +* **Snippets Reutilizáveis:** Componentes de configuração (SSL, Proxy, WAF, ACME). +* **Segurança Dinâmica:** Gerenciamento da `blacklist.conf` alimentada pelo Fail2Ban. +* **Análise de Dados:** Logs detalhados em formato JSON (`detailed_proxy`). +* **Certificados:** Persistência de SSL via Certbot. + +## 📂 Estrutura de Pastas +```text +. +├── nginx.conf # Configuração mestre (Global) +├── conf.d/ # Arquivos de site (Ex: dominio.com.br.conf) +├── snippets/ # Peças modulares (SSL, ModSec, Proxy, Blacklist) +├── modsec/ # Regras do WAF e OWASP CRS +└── logs/ # Logs JSON para análise e Fail2Ban +``` + +## 🛠️ Como Adicionar um Site +1. Crie o arquivo em `conf.d/meusite.conf`. +2. Utilize os snippets para manter o padrão: +```nginx +server { + listen 443 quic reuseport; # HTTP3 + listen 443 ssl; + server_name meusite.com.br; + + include snippets/ssl_params.conf; + include snippets/proxy_params.conf; + include snippets/modsecurity.conf; + + location / { + proxy_pass http://ip_interno:porta; + } +} +``` +3. Valide e aplique as mudanças usando o script na pasta de produção: +`../producao/safe-deploy.sh` + +--- + +> [!NOTE] +> **Gestão do Motor:** Para atualizar a imagem docker, portas ou o Fail2Ban, utilize o repositório: +> [NGINX Pathfinder - Infraestrutura](../producao) diff --git a/sites-ativos/conf.d/README.md b/sites-ativos/conf.d/README.md new file mode 100644 index 0000000..9569eeb --- /dev/null +++ b/sites-ativos/conf.d/README.md @@ -0,0 +1,13 @@ +# Site Configurations +Put your server blocks (vhosts) in this directory. +Example: `my-site.conf` + +```nginx +server { + listen 80; + server_name example.com; + location / { + proxy_pass http://internal:8080; + } +} +``` diff --git a/sites-ativos/conf.d/ferreirareal.com.br.conf b/sites-ativos/conf.d/ferreirareal.com.br.conf new file mode 100644 index 0000000..40d491b --- /dev/null +++ b/sites-ativos/conf.d/ferreirareal.com.br.conf @@ -0,0 +1,67 @@ +upstream ferreirareal_backend { + server 172.112.1.2:8081; +} + +server { + listen 80; + server_name ferreirareal.com.br www.ferreirareal.com.br; + include snippets/acme_challenge.conf; + location / { + return 301 https://ferreirareal.com.br$request_uri; + } +} + +server { + listen 443 quic; + listen 443 ssl; + server_name www.ferreirareal.com.br; + include snippets/ssl_params.conf; + ssl_certificate /etc/letsencrypt/live/ferreirareal.com.br/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/ferreirareal.com.br/privkey.pem; + return 301 https://ferreirareal.com.br$request_uri; +} + +server { + listen 443 quic reuseport; + listen 443 ssl; + server_name ferreirareal.com.br; + + access_log /var/log/nginx/ferreirareal.com.br.access.log detailed_proxy; + error_log /var/log/nginx/ferreirareal.com.br.error.log warn; + + include snippets/ssl_params.conf; + include snippets/proxy_params.conf; + include snippets/modsecurity.conf; + # modsecurity_rules_file /etc/nginx/modsec/main.conf; + include snippets/well_known.conf; + include snippets/security_actions.conf; + + ssl_certificate /etc/letsencrypt/live/ferreirareal.com.br/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/ferreirareal.com.br/privkey.pem; + + proxy_cache dynamic_cache; + set $upstream_proto http; + set $upstream_app ferreirareal_backend; + + location = /Contatos.html { + proxy_cache_bypass 1; + proxy_no_cache 1; + proxy_pass http://ferreirareal_backend; + } + + location ~* \.(webp|avif|heic|apng|jpg|jpeg|gif|png|ico|svg|mjs|js|ts|wasm|json|woff2?|ttf|otf|eot|css|less|scss)$ { + include snippets/cache_optimizer.conf; + add_header Cache-Control $cache_control_header; + proxy_cache_valid 200 1d; + proxy_pass http://ferreirareal_backend; + limit_req zone=global_limit burst=50 nodelay; + limit_req zone=punishment_limit burst=5 nodelay; + access_log off; + } + + location / { + expires 15m; + proxy_cache_valid 200 15m; + proxy_pass http://ferreirareal_backend; + } +} diff --git a/sites-ativos/conf.d/test.local.conf b/sites-ativos/conf.d/test.local.conf new file mode 100644 index 0000000..a064afc --- /dev/null +++ b/sites-ativos/conf.d/test.local.conf @@ -0,0 +1,29 @@ +upstream test_backend { + server 127.0.0.1:8080; + keepalive 32; +} + +server { + listen 80; + server_name test.local; + + access_log /var/log/nginx/test.local.access.log detailed_proxy; + error_log /var/log/nginx/test.local.error.log warn; + + include snippets/well_known.conf; + include snippets/security_actions.conf; + + location / { + proxy_pass http://test_backend; + include snippets/proxy_params.conf; + limit_req zone=global_limit burst=20 nodelay; + limit_req zone=punishment_limit burst=5 nodelay; + } + + location ~* \.(webp|avif|heic|apng|jpg|jpeg|gif|png|ico|svg|mjs|js|ts|wasm|json|woff2?|ttf|otf|eot|css|less|scss)$ { + include snippets/cache_optimizer.conf; + add_header Cache-Control $cache_control_header; + proxy_cache_valid 200 1d; + proxy_pass http://test_backend; + } +} diff --git a/sites-ativos/modsec/empty.conf b/sites-ativos/modsec/empty.conf new file mode 100644 index 0000000..9cab844 --- /dev/null +++ b/sites-ativos/modsec/empty.conf @@ -0,0 +1 @@ +# Empty rules diff --git a/sites-ativos/modsec/main.conf b/sites-ativos/modsec/main.conf new file mode 100644 index 0000000..5bd12d1 --- /dev/null +++ b/sites-ativos/modsec/main.conf @@ -0,0 +1,11 @@ +# ModSecurity Main Configuration File + +# Include base configuration +Include /etc/nginx/modsec/modsecurity.conf-recommended + +# Configure OWASP Core Rule Set +Include /etc/nginx/modsec/owasp-crs/crs-setup.conf +Include /etc/nginx/modsec/owasp-crs/rules/*.conf + +# Include Custom Rules +# include /etc/nginx/modsec/custom_rules.conf diff --git a/sites-ativos/nginx.conf b/sites-ativos/nginx.conf new file mode 100644 index 0000000..fcf8fa1 --- /dev/null +++ b/sites-ativos/nginx.conf @@ -0,0 +1,62 @@ +# NGINX Master Configuration - Pathfinder Proxy + +# Load essential modules +# load_module modules/ngx_http_modsecurity_module.so; # Se compilado dinamicamente +# load_module modules/ngx_http_brotli_filter_module.so; +# load_module modules/ngx_http_brotli_static_module.so; + +user nginx; +worker_processes auto; +worker_rlimit_nofile 65535; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 16384; + multi_accept on; +} + +http { + # modsecurity_rules_file /etc/nginx/modsec/main.conf; + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Performance + sendfile on; + tcp_nopush on; + tcp_nodelay on; + server_tokens off; + proxy_headers_hash_bucket_size 512; + client_max_body_size 0; + keepalive_timeout 65; + + # Compression (Brotli + Gzip) + include /etc/nginx/snippets/compression.conf; + + # Logging JSON (Detailed) + include /etc/nginx/snippets/log_formats.conf; + access_log /var/log/nginx/access.log detailed_proxy; + + # SSL Settings (Global) + ssl_session_cache shared:SSL:50m; + ssl_session_timeout 1d; + ssl_session_tickets off; + + # Shared Cache Zone (Pseudo-CDN) + proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=dynamic_cache:50m max_size=10g inactive=60m use_temp_path=off; + + # DNS Resolver (SSL Stapling & Upstreams) + resolver 8.8.8.8 8.8.4.4 valid=300s; + resolver_timeout 5s; + + # Security Snippets + include /etc/nginx/snippets/security_maps.conf; + include /etc/nginx/snippets/rate_limit.conf; + + # Ativação Global da Blacklist + include /etc/nginx/snippets/blacklist.conf; + + # Site Configurations + include /etc/nginx/conf.d/*.conf; +} diff --git a/sites-ativos/snippets/acme_challenge.conf b/sites-ativos/snippets/acme_challenge.conf new file mode 100644 index 0000000..0c99c7b --- /dev/null +++ b/sites-ativos/snippets/acme_challenge.conf @@ -0,0 +1,7 @@ +# ACME Challenge for Certbot +location ^~ /.well-known/acme-challenge/ { + allow all; + root /var/lib/letsencrypt/; + default_type "text/plain"; + try_files $uri =404; +} diff --git a/sites-ativos/snippets/ads_disallow.conf b/sites-ativos/snippets/ads_disallow.conf new file mode 100644 index 0000000..aa90637 --- /dev/null +++ b/sites-ativos/snippets/ads_disallow.conf @@ -0,0 +1,8 @@ +# ads_disallow.conf - Bloquear Todos os Vendedores de Anúncios +# Função: Indica que nenhum vendedor está autorizado, prevenindo anúncios não autorizados. +location = /ads.txt { + allow all; + log_not_found off; + access_log off; + return 200 "contact=suporte@itguys.com.br\n"; +} diff --git a/sites-ativos/snippets/blacklist.conf b/sites-ativos/snippets/blacklist.conf new file mode 100644 index 0000000..af0e7ee --- /dev/null +++ b/sites-ativos/snippets/blacklist.conf @@ -0,0 +1,2 @@ +# Arquivo gerado automaticamente pelo Fail2Ban +# IPs bloqueados aparecerão aqui como: deny 1.2.3.4; diff --git a/sites-ativos/snippets/cache_optimizer.conf b/sites-ativos/snippets/cache_optimizer.conf new file mode 100644 index 0000000..b17970c --- /dev/null +++ b/sites-ativos/snippets/cache_optimizer.conf @@ -0,0 +1,10 @@ +# --- Pathfinder Smart Cache Optimization --- + +# 1. Stale-While-Revalidate (SWR) Global +# Serve conteúdo antigo enquanto atualiza em background (Ultra rápido) +proxy_cache_revalidate on; +proxy_cache_background_update on; +proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + +# 2. Configuracoes de Cache-Control por Tipo de Arquivo +add_header X-Cache-Status $upstream_cache_status; diff --git a/sites-ativos/snippets/cache_proxy_params.conf b/sites-ativos/snippets/cache_proxy_params.conf new file mode 100644 index 0000000..18185f2 --- /dev/null +++ b/sites-ativos/snippets/cache_proxy_params.conf @@ -0,0 +1,7 @@ +# Standard Proxy Cache Settings +# Include this inside server blocks that use proxy_cache + +proxy_cache_revalidate on; +proxy_cache_lock on; +proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; +add_header X-Proxy-Cache $upstream_cache_status; diff --git a/sites-ativos/snippets/cache_zones.conf b/sites-ativos/snippets/cache_zones.conf new file mode 100644 index 0000000..77b6fcb --- /dev/null +++ b/sites-ativos/snippets/cache_zones.conf @@ -0,0 +1,8 @@ +# Universal Dynamic Cache Zone +# Uma única zona robusta que atende a todos os sites dinamicamente. +# O isolamento é garantido pela 'proxy_cache_key' que inclui o $host. +proxy_cache_path /var/cache/nginx/dynamic_cache levels=1:2 keys_zone=dynamic_cache:100m max_size=20g inactive=7d use_temp_path=off; + +# Default Cache Key (Inteligente: Isolada por Host ou Global para CDN) +# Definida dinamicamente no security_maps.conf +proxy_cache_key $pathfinder_cache_key; diff --git a/sites-ativos/snippets/compression.conf b/sites-ativos/snippets/compression.conf new file mode 100644 index 0000000..fb73d42 --- /dev/null +++ b/sites-ativos/snippets/compression.conf @@ -0,0 +1,53 @@ +# --- Pathfinder Modern Compression Stack --- + +# 1. Gzip (Fallback e Compatibilidade) +gzip on; +gzip_static on; # Serve .gz se existir no disco (Ganho de CPU) +gzip_vary on; +gzip_proxied any; +gzip_comp_level 6; +gzip_min_length 256; +gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/x-javascript + application/json + application/xml + application/rss+xml + application/atom+xml + application/ld+json + application/manifest+json + application/wasm + application/vnd.ms-fontobject + application/x-font-ttf + font/opentype + image/svg+xml + image/x-icon; + +# 2. Google Brotli (Próxima Geração) +brotli on; +brotli_static on; # Serve .br se existir no disco (Alta Performance) +brotli_comp_level 6; +brotli_min_length 256; +brotli_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/x-javascript + application/json + application/xml + application/rss+xml + application/atom+xml + application/ld+json + application/manifest+json + application/wasm + application/vnd.ms-fontobject + application/x-font-ttf + font/opentype + image/svg+xml + image/x-icon; diff --git a/sites-ativos/snippets/humans.txt.conf b/sites-ativos/snippets/humans.txt.conf new file mode 100644 index 0000000..fb3e3af --- /dev/null +++ b/sites-ativos/snippets/humans.txt.conf @@ -0,0 +1,8 @@ +# Humans.txt - Créditos e Tecnologias +# Função: Um arquivo para humanos que lista quem construiu o site e as ferramentas usadas. +location = /humans.txt { + allow all; + log_not_found off; + access_log off; + try_files /humans.txt =404; +} diff --git a/sites-ativos/snippets/log_formats.conf b/sites-ativos/snippets/log_formats.conf new file mode 100644 index 0000000..b97507f --- /dev/null +++ b/sites-ativos/snippets/log_formats.conf @@ -0,0 +1,80 @@ +# Log Format Definitions +# Include this file in nginx.conf http block + +log_format detailed_proxy escape=json +'{' +# Timestamps e Identificadores +'"@timestamp":"$time_iso8601",' +'"time_local":"$time_local",' +'"msec":"$msec",' +'"request_id":"$request_id",' +'"hostname":"$hostname",' +'"worker_pid":$pid,' + +# Informações de Conexão e Cliente +'"remote_addr":"$remote_addr",' +'"remote_port":$remote_port,' +'"server_addr":"$server_addr",' +'"server_port":"$server_port",' +'"real_ip":"$http_x_forwarded_for",' +'"http_x_real_ip":"$http_x_real_ip",' +'"remote_user":"$remote_user",' + +# Detalhes da Requisição HTTP +'"request":"$request",' +'"request_method":"$request_method",' +'"scheme":"$scheme",' +'"server_protocol":"$server_protocol",' +'"host_header":"$host",' +'"request_uri":"$request_uri",' +'"uri":"$uri",' +'"document_uri":"$document_uri",' +'"args":"$args",' +'"query_string":"$query_string",' +'"request_length":$request_length,' + +# Headers da Requisição +'"http_referer":"$http_referer",' +'"http_user_agent":"$http_user_agent",' +'"http_accept_encoding":"$http_accept_encoding",' +'"http_accept_language":"$http_accept_language",' + +# Detalhes da Resposta +'"status":$status,' +'"body_bytes_sent":$body_bytes_sent,' +'"bytes_sent":$bytes_sent,' +'"sent_http_content_type":"$sent_http_content_type",' +'"sent_http_cache_control":"$sent_http_cache_control",' + +# Performance e Conexão +'"request_time":$request_time,' +'"connection":"$connection",' +'"connection_requests":$connection_requests,' + +# SSL/TLS +'"ssl_protocol":"$ssl_protocol",' +'"ssl_cipher":"$ssl_cipher",' +'"ssl_session_reused":"$ssl_session_reused",' + +# Upstream +'"upstream_addr":"$upstream_addr",' +'"upstream_status":"$upstream_status",' +'"upstream_connect_time":"$upstream_connect_time",' +'"upstream_header_time":"$upstream_header_time",' +'"upstream_response_time":"$upstream_response_time",' +'"upstream_cache_status":"$upstream_cache_status",' + +# Compressão e Performance Modernos +'"content_encoding":"$sent_http_content_encoding",' +'"compression_ratio":"$gzip_ratio",' +'"is_global_asset":"$is_global_asset",' +'"cache_key":"$pathfinder_cache_key",' + +# Variáveis Customizadas de Segurança +'"is_bad_bot":"$is_bad_bot",' +'"is_suspicious_uri":"$is_suspicious_uri",' +'"block_request":"$block_request",' +'"risk_level":"$risk_level",' +'"security_score":"$security_score",' +'"is_internal_ip":"$is_internal"' +'}'; diff --git a/sites-ativos/snippets/modsecurity.conf b/sites-ativos/snippets/modsecurity.conf new file mode 100644 index 0000000..13698f3 --- /dev/null +++ b/sites-ativos/snippets/modsecurity.conf @@ -0,0 +1,5 @@ +# ModSecurity Engine Configuration +modsecurity on; + +# Inclusão da Blacklist Dinâmica do Fail2Ban +include /etc/nginx/snippets/blacklist.conf; diff --git a/sites-ativos/snippets/proxy_params.conf b/sites-ativos/snippets/proxy_params.conf new file mode 100644 index 0000000..44ac451 --- /dev/null +++ b/sites-ativos/snippets/proxy_params.conf @@ -0,0 +1,15 @@ +proxy_set_header Host $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 $scheme; +proxy_set_header X-Forwarded-Host $host; +proxy_set_header X-Forwarded-Port $server_port; + +# Buffers +proxy_buffers 32 4k; +proxy_buffer_size 8k; + +# Timeouts +proxy_connect_timeout 60s; +proxy_send_timeout 60s; +proxy_read_timeout 60s; diff --git a/sites-ativos/snippets/rate_limit.conf b/sites-ativos/snippets/rate_limit.conf new file mode 100644 index 0000000..43ea3a5 --- /dev/null +++ b/sites-ativos/snippets/rate_limit.conf @@ -0,0 +1,8 @@ +# Rate Limit Zones +# Include this file in nginx.conf http block + +# Smart rate limiting - IPs internos são ignorados ($limit_key = "") +limit_req_zone $limit_key zone=global_limit:20m rate=20r/s; + +# Zona de Penalidade (Heavy Limit) - Para quem tem Score de Risco > 0 +limit_req_zone $heavy_limit_key zone=punishment_limit:10m rate=1r/s; diff --git a/sites-ativos/snippets/robots_allow.conf b/sites-ativos/snippets/robots_allow.conf new file mode 100644 index 0000000..dd0bc7b --- /dev/null +++ b/sites-ativos/snippets/robots_allow.conf @@ -0,0 +1,8 @@ +# robots_allow.conf - Permitir Tudo +# Função: Indica que todos os robôs podem indexar todo o site. +location = /robots.txt { + allow all; + log_not_found off; + access_log off; + return 200 "User-agent: *\nAllow: /\n"; +} diff --git a/sites-ativos/snippets/robots_disallow.conf b/sites-ativos/snippets/robots_disallow.conf new file mode 100644 index 0000000..30c5654 --- /dev/null +++ b/sites-ativos/snippets/robots_disallow.conf @@ -0,0 +1,8 @@ +# robots_disallow.conf - Bloquear Tudo +# Função: Indica que nenhum robô deve indexar o site. +location = /robots.txt { + allow all; + log_not_found off; + access_log off; + return 200 "User-agent: *\nDisallow: /\n"; +} diff --git a/sites-ativos/snippets/security.txt.conf b/sites-ativos/snippets/security.txt.conf new file mode 100644 index 0000000..1c3fbaf --- /dev/null +++ b/sites-ativos/snippets/security.txt.conf @@ -0,0 +1,8 @@ +# Security.txt - Reporte de Vulnerabilidades +# Função: Padroniza como pesquisadores de segurança devem contatar o responsável pelo site. +location = /.well-known/security.txt { + allow all; + log_not_found off; + access_log off; + return 200 "Contact: mailto:suporte@itguys.com.br\nPreferred-Languages: pt, en\n"; +} diff --git a/sites-ativos/snippets/security_actions.conf b/sites-ativos/snippets/security_actions.conf new file mode 100644 index 0000000..9805e05 --- /dev/null +++ b/sites-ativos/snippets/security_actions.conf @@ -0,0 +1,5 @@ +# Security Actions +# Bloqueio imediato baseado no security_maps.conf +if ($block_request) { + return 444; # Fecha a conexão sem resposta (mais agressivo) ou 403/404 +} diff --git a/sites-ativos/snippets/security_maps.conf b/sites-ativos/snippets/security_maps.conf new file mode 100644 index 0000000..9e576ab --- /dev/null +++ b/sites-ativos/snippets/security_maps.conf @@ -0,0 +1,175 @@ +# Security Maps and Variables +# Include this file in nginx.conf http block + +# Bad Bot Detection +map $http_user_agent $is_bad_bot { + default 0; + # Scanners, Exploracao e Reconhecimento de Rede (RECON) + "~*(nikto|sqlmap|wpscan|gobuster|dirbuster|feroxbuster|nessus|nmap|curl|wget|python|php|perl|ruby|java)" 1; + "~*(Acunetix|Netsparker|AppScan|Zgrab|Masscan|OpenVAS|Scanbot|ZmEu|Morfeus|Jorgee|Havij|Nuclei|Tsunami)" 1; + "~*(Shodan|Censys|ZoomEye|BinaryEdge|Smap|N-Stealth|N-Sentinel|ScanAlert)" 1; + + # Crawlers Agressivos e Scrapers de Conteudo + "~*(HTTrack|ia_archiver|mj12bot|AhrefsBot|DotBot|SemrushBot|MJ12bot|DataForSeoBot|PetalBot|QuerySeekerSpider)" 1; + "~*(SEO-Crawler|SEOstats|SpyFu|Lighthouse|PageSpeed|SiteAudit|Screaming|MegaIndex|ZoominfoBot)" 1; + "~*(BLEXBot|WinHTTP|Xenu|Scrap|extract|grab|Crawlspace|WebCopier|TeleportPro|OfflineExplorer)" 1; + + # Bibliotecas de Scraping e Automacao (MCPs, Frameworks) + "~*(Scrapy|BeautifulSoup|selenium|puppeteer|playwright|phantomjs|HeadlessChrome|headless)" 1; + "~*(GuzzleHttp|axios|requests|urllib|libwww-perl|WinHTTP|Go-http-client|node-fetch|Faraday|Typhoeus)" 1; + + # Bloqueio Total de IA Crawlers (Treinamento e Coleta) + "~*(GPTBot|ChatGPT-User|OAI-SearchBot|anthropic-ai|ClaudeBot|Claude-Web|Claude-User|Claude-SearchBot)" 1; + "~*(Google-Extended|Google-CloudVertexBot|Bard-Ai|Gemini-Ai|GoogleAgent-Mariner)" 1; + "~*(FacebookBot|Meta-ExternalAgent|meta-webindexer|Applebot-Extended|Amazonbot|Applebot)" 1; + "~*(PerplexityBot|Perplexity-User|Bytespider|CCBot|Diffbot|Cohere-Ai|DeepseekBot|Youbot)" 1; + "~*(Omgilibot|Omgili|webzio-extended|HuggingFace-Bot|Brightbot|FirecrawlAgent|Seekr|Sentibot)" 1; +} + +# Suspicious URI Detection (Bloqueio de Borda / Fast-Fail) +# Atua antes do ModSecurity para economizar processamento do WAF em ataques óbvios. +map $request_uri $is_suspicious_uri { + default 0; + + # Cloud & Infrastructure Metadata (SSRF/Recon) + "~*(169\.254\.169\.254|/latest/meta-data/|/v1/metadata/|/metadata-flavor)" 1; + "~*(docker-compose\.ya?ml|Dockerfile|kubernetes\.s?yaml)" 1; + + # Arquivos de Configuracao, Credenciais e Segredos (Deep leaking) + "~*(\.env(\..+)?|\.git|\.aws|\.ssh|\.docker|\.config|config\.php|wp-config\.php)" 1; + "~*(composer\.(json|lock)|package(-lock)?\.json|yarn\.lock|pnpm-lock\.yaml)" 1; + "~*(web\.config|appsettings\.json|settings\.py|local_settings\.py)" 1; + + # Backups, Dumps e Arquivos Temporarios + "~*(\.(bak|old|orig|save|sql|db|sqlite|tar\.gz|zip|swp|rar|7z)$|/autobackup/)" 1; + + # Framework Debugging & Admin Endpoints (Fast-Fail) + "~*(/_ignition/|/_profiler/|/_telescope/|/actuator/|/eureka/|/api-docs)" 1; + "~*(/phpmyadmin|/wp-admin/setup-config\.php|/rails/info/properties)" 1; + + # Webshells e Exploracao Ativa Conhecida + "~*(/shell\.php|/cmd\.php|/eval-stdin\.php|/xmlrpc\.php|/setup\.php|/install\.php)" 1; +} + +# --- Pathfinder Security Decision Engine (PSDE) --- + +# 1. Detecção de Métodos HTTP Incomuns/Perigosos +map $request_method $is_suspicious_method { + default 0; + ~*(TRACE|TRACK|CONNECT|DEBUG) 1; +} + +# 2. Security Scoring System (Concatenado) +# Padrão: [Bot][URI][Method] -> Ex: "110" (Bot detectado + URI suspeita + Método normal) +map $is_bad_bot$is_suspicious_uri$is_suspicious_method $security_score { + "000" 0; # Tudo limpo + "100" 1; # Apenas Bot (Bloqueio Simples) + "010" 1; # Apenas URI Suspeita (Bloqueio Simples) + "110" 2; # Bot + URI Suspeita (Risco Alto) + "111" 3; # Bot + URI Suspeita + Método Malicioso (Ataque Crítico) + "001" 1; # Apenas Método Malicioso + default 1; # Por segurança, qualquer outra combinação bloqueia +} + +# 3. Nível de Risco para Auditoria (Verboso em Português) +map $security_score $risk_level { + 0 "TRAFEGO_LIMPO_ACESSO_LEGITIMO"; + 1 "SUSPEITO_COMPORTAMENTO_ANOMALO"; + 2 "PERIGO_ALTO_RISCO_TENTATIVA_VAZAMENTO"; + 3 "ATAQUE_CRITICO_BLOQUEIO_DE_EXPLORACAO"; +} + +# 4. Decisão de Bloqueio Final +# 0 = Passa | 1 = Bloqueia +map $security_score $block_request { + 0 0; + default 1; +} + +# Internal IP Detection +geo $is_internal { + default 0; + 10.10.0.0/16 1; 10.11.0.0/16 1; 10.12.0.0/16 1; 172.16.0.0/16 1; + 45.169.73.155 1; 201.73.213.130 1; 177.74.160.17 1; 177.74.160.18 1; + 177.74.160.19 1; 177.74.160.20 1; 177.74.160.21 1; 177.74.160.22 1; + 177.74.160.23 1; 45.169.87.168 1; 45.169.87.169 1; 45.169.87.170 1; + 45.169.87.171 1; 45.169.87.172 1; 45.169.87.173 1; 45.169.87.174 1; + 45.169.87.175 1; 45.169.73.154 1; 201.73.213.129 1; +} + +# --- modern Rate Limiting & Performance Maps --- + +# 1. Chave Unificada de Rate Limit com Penalidade +# IPs internos são liberados, IPs suspeitos (score > 0) caem em zonas de limitação mais agressivas. +map $is_internal$security_score $limit_key { + ~^1. 0; # Whitelist para IPs Internos (independente de score) + "00" $binary_remote_addr; # Tráfego Limpo + default $binary_remote_addr; # Qualquer outra coisa (Suspeitos) +} + +# 2. Chave de "Castigo" para Bots e Ataques (Tarpit / Delay) +map $security_score $heavy_limit_key { + 0 ""; + default $binary_remote_addr; # Apenas quem tem pontuação de risco entra aqui +} + +# 3. Cache Asset TTL - Suporte Total 2026 (Modern Web) +# No proxy_cache usamos um tempo curto, o Cache-Control (Browser) é que decide o tempo longo. +map $request_uri $cache_asset_ttl { + # 1. Assets Versionados (?v= ou .v1.) -> Cache Longo no Proxy (1 mes) + "~*(\?v=|\?id=|\.v[0-9]|\.[0-9a-f]{8,})" 30d; + + # 2. Imagens e Mídia (Sem versão) -> 1 dia + ~*\.(webp|avif|heic|apng|jpg|jpeg|gif|png|ico|svg)$ 1d; + + # 3. Scripts e Estilos (Sem versão) -> 6 horas + ~*\.(mjs|js|ts|wasm|json|css|less|scss)$ 6h; + + # 4. Fontes -> 7 dias + ~*\.(woff2?|ttf|otf|eot)$ 7d; + + # Padrão: Sem Cache (Documentos como PDF entram aqui por segurança) + default off; +} + +# --- Pathfinder Pseudo-CDN Engine --- + +# 1. Identificação de Assets Globais (Idênticos em todos os sistemas) +map $request_uri $is_global_asset { + default 0; + # Bibliotecas Comuns (Fingerprinted ou Versão Fixa) - Front-end Power Pack 2026 + ~*(jquery|bootstrap|fontawesome|axios|vue|react|alpine|htmx|inter|roboto).*\.(js|css|woff2?|ttf|otf)$ 1; + ~*(tailwind|shadcn|lucide|radix|framer|next|lodash|moment|dayjs).*\.(js|css|woff2?|ttf|otf)$ 1; + ~*(chart|leaflet|mapbox|slick|swiper|videojs).*\.(js|css|woff2?|ttf|otf)$ 1; + # Fontes Populares (Web Fonts Compartilhadas) + ~*(montserrat|open-sans|lato|poppins|oswald|playfair|merriweather|nunito|ubuntu|raleway|outfit|plus-jakarta).*\.(woff2?|ttf|otf)$ 1; + # Pastas de Ativos Compartilhados (Convenção interna) + ~*(/cdn/|/shared/|/common/) 1; +} + +# 2. Chave de Cache Inteligente (Isolation vs Sharing) +# Se for Asset Global -> Chave sem $host (Efeito CDN) +# Se for Normal -> Chave com $host (Isolamento total) +map $is_global_asset $pathfinder_cache_key { + 0 "$scheme$request_method$host$request_uri"; + 1 "$scheme$request_method$request_uri"; +} + +# --- Pathfinder Smart Cache Optimization Maps --- +# Trata a politica de Cache do Navegador baseado na URI e Versao +map $request_uri $cache_control_header { + # 1. Assets Versionados -> Imutaveis (1 ano) + "~*(\?v=|\?id=|\.v[0-9]|\.[0-9a-f]{8,})" "public, max-age=31536000, immutable"; + + # 2. Assets Comuns (Imagens, Fontes) -> Revalidacao obrigatoria (curto) + "~*\.(webp|avif|heic|apng|jpg|jpeg|gif|png|ico|svg|woff2?|ttf|otf|eot)$" "public, max-age=86400, must-revalidate"; + + # 3. Scripts e Estilos (Sem versao) -> Revalidacao agressiva (curto) + "~*\.(mjs|js|ts|wasm|json|css|less|scss)$" "public, max-age=3600, must-revalidate"; + + # 4. HTML e APIs -> Nunca cachear no navegador sem revalidar + "~*(\.html|\/api\/)" "no-cache, must-revalidate"; + + # Padrao: Seguranca Maxima (Documentos, PDFs, etc. nao sao cacheados) + default "no-cache, no-store, must-revalidate"; +} diff --git a/sites-ativos/snippets/ssl_params.conf b/sites-ativos/snippets/ssl_params.conf new file mode 100644 index 0000000..c8e1ec1 --- /dev/null +++ b/sites-ativos/snippets/ssl_params.conf @@ -0,0 +1,15 @@ +# SSL/TLS Params - Requisitos: Nginx com HTTP/3 +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers off; + +# HSTS +add_header Strict-Transport-Security "max-age=63072000" always; + +# HTTP/3 (QUIC) Alt-Svc +add_header Alt-Svc 'h3=":443"; ma=86400'; + +# OCSP Stapling +ssl_stapling on; +ssl_stapling_verify on; +resolver 1.1.1.1 8.8.8.8 valid=300s; +resolver_timeout 5s; diff --git a/sites-ativos/snippets/well_known.conf b/sites-ativos/snippets/well_known.conf new file mode 100644 index 0000000..4db5b3b --- /dev/null +++ b/sites-ativos/snippets/well_known.conf @@ -0,0 +1,7 @@ +# Agregador de Arquivos de Identificação e Controle (Well-Known / Root Files) +# Função: Inclui todos os snippets padrão de identificação em um único comando. + +include snippets/robots_disallow.conf; +include snippets/security.txt.conf; +include snippets/humans.txt.conf; +include snippets/ads_disallow.conf;