// infrastructure — reverse proxy sécurisé
nginx Reverse Proxy
REVERSE PROXY · WAF · SSL/TLS · GEOIP2
nginx 1.26
TLSv1.2 · TLSv1.3
CrowdSec AppSec WAF
GeoIP2 · Restriction FR
Rate Limiting · Headers
// démarche — mise en place chronologique
$ cat chronologie.txt
Implémentation en 8 phases successives. Chaque couche est validée avant d'ajouter la suivante.
Approche défense en profondeur.
01
Base nginx
worker_processes
events, gzip
SSL global
server_tokens off
02
SSL/TLS
certbot
TLSv1.2+1.3
HSTS · dhparam
03
Vhosts & Proxy
server blocks
proxy_pass
proxy_set_header
http2
04
En-têtes Sécurité
snippet réutilisable
HSTS · CSP
X-Frame · X-Content
Permissions-Policy
05
Rate Limiting
limit_req_zone
zones par usage
burst nodelay
06
GeoIP2
restriction géo
whitelist admin+LAN
map $geo_blocked
07
CrowdSec AppSec
auth_request
WAF port 7422
snippet appsec.conf
08
Hardening final
Slowloris timeouts
proxy cache API
filtrage méthodes HTTP
// extraits de configuration — générique
$ cat config-snippets.conf
Patterns de configuration réutilisables. Les valeurs entre [CROCHETS] sont à adapter à votre infrastructure.
// SNIPPET 1 — WORKERS & PERFORMANCE
# nginx.conf — bloc principal
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 1024;
multi_accept on;
}
# Gzip
gzip on; gzip_vary on; gzip_comp_level 6;
gzip_types text/plain text/css application/javascript
application/json image/svg+xml font/woff2;
// SNIPPET 2 — EN-TÊTES SÉCURITÉ (SNIPPET RÉUTILISABLE)
# /etc/nginx/snippets/security-headers.conf
add_header Strict-Transport-Security
"max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy
"strict-origin-when-cross-origin" always;
add_header Permissions-Policy
"geolocation=(), camera=(), microphone=()" always;
add_header Content-Security-Policy
"default-src 'self'; script-src 'self';
img-src 'self' data:; frame-ancestors 'none';" always;
// SNIPPET 3 — RATE LIMITING
# Dans http {} de nginx.conf
# Whitelist LAN — bypass rate limiting
geo $geo_whitelist {
default 0;
[LAN_SUBNET] 1; # réseau local
[ADMIN_IP]/32 1; # IP fixe admin
}
map $geo_whitelist $limit_key {
default $binary_remote_addr;
1 ""; # clé vide = pas de limite
}
limit_req_zone $limit_key zone=global:10m rate=120r/m;
limit_req_zone $limit_key zone=contact:10m rate=5r/m;
limit_req_zone $limit_key zone=api:10m rate=10r/m;
# Dans location {} :
# limit_req zone=global burst=100 nodelay;
// SNIPPET 4 — GEOIP2 RESTRICTION GÉOGRAPHIQUE
# Dans http {} — après chargement module ngx_http_geoip2_module
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 1d;
$geoip2_country_code country iso_code;
}
map $geoip2_country_code $geo_country_blocked {
default 1; # tout bloqué par défaut
FR 0; # France autorisée
}
# Résultat : whitelisté OU France = autorisé
map "$geo_whitelist:$geo_country_blocked" $geo_blocked {
default 1;
"~^1:" 0; # whitelisté
"0:0" 0; # France
}
# Dans location {} :
# if ($geo_blocked) { return 403; }
// pattern vhost — structure type
$ cat vhost-pattern.conf
Structure type d'un vhost sécurisé. Le même pattern est appliqué à chaque domaine avec
adaptation du backend et de la CSP.
// VHOST — STRUCTURE COMPLÈTE AVEC TOUTES LES COUCHES
server {
server_name [YOUR_DOMAIN] www.[YOUR_DOMAIN];
# En-têtes sécurité globaux
include /etc/nginx/snippets/security-headers.conf;
# SSL — géré par Certbot
listen 443 ssl; http2 on;
ssl_certificate /etc/letsencrypt/live/[YOUR_DOMAIN]/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/[YOUR_DOMAIN]/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
# Certbot ACME challenge
location /.well-known/acme-challenge/ {
root /var/www/html;
try_files $uri =404;
}
# Fichiers cachés — toujours bloquer
location ~ /\. { deny all; return 404; }
# Proxy principal vers backend
location / {
limit_req zone=global burst=100 nodelay;
if ($geo_blocked) { return 403; }
include /etc/nginx/snippets/security-headers.conf;
include /etc/nginx/snippets/crowdsec-appsec.conf;
proxy_pass http://[BACKEND_IP];
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 10s;
proxy_read_timeout 20s;
}
}
server {
listen 80;
server_name [YOUR_DOMAIN] www.[YOUR_DOMAIN];
return 301 https://$host$request_uri; # redirect HTTP → HTTPS
}
// résultats & validation
$ cat resultats.txt
Validation à chaque étape via nginx -t + systemctl reload nginx.
Tests avec curl -I et outils SSL Labs.
| Test |
Outil |
Résultat attendu |
| Syntaxe config |
nginx -t |
configuration file ... syntax is ok |
| Reload sans coupure |
systemctl reload nginx |
0 downtime, graceful |
| Score SSL/TLS |
SSL Labs / testssl.sh |
A+ / Grade A |
| Headers sécurité |
curl -I https://[domaine] |
HSTS, X-Frame, CSP présents |
| Rate limiting |
ab / wrk |
429 Too Many Requests au seuil |
| Restriction GeoIP |
curl depuis VPN étranger |
403 Forbidden |
| CrowdSec WAF |
test injection SQLi/XSS |
Bloqué avant le backend |
| Backends isolés |
curl direct [BACKEND_IP]:80 |
Non accessible depuis internet |