Call-Informatique
Call-Informatique
Le média tech
Nginx reverse proxy : configuration avancée et hardening
InformatiqueGuides8 min de lecture

Nginx reverse proxy : configuration avancée et hardening

Configuration complète de Nginx en reverse proxy : load balancing, headers de sécurité, cache, rate limiting et hardening. Guide technique avec fichiers complets.

Nginx reverse proxy : configuration avancée et hardening

Ce guide couvre la configuration production-ready de Nginx comme reverse proxy. On part du principe que vous avez un serveur Ubuntu 22.04/24.04 ou Debian 12, un accès root, et une ou plusieurs applications à exposer derrière Nginx.

On ne va pas se contenter d'un proxy_pass basique. On couvre le hardening, le load balancing, le cache, le rate limiting et les headers de sécurité.

Installation depuis le dépôt officiel Nginx

Les dépôts Ubuntu fournissent souvent une version datée. Pour avoir les dernières fonctionnalités et correctifs de sécurité, ajoutez le dépôt officiel Nginx :

bash
## Installer les prérequis
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring -y

## Importer la clé GPG officielle Nginx
curl https://nginx.org/keys/nginx_signing.key | gpg —dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

## Ajouter le dépôt stable
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/nginx/sources.list.d/nginx.list

## Prioriser le dépôt officiel sur celui d'Ubuntu
echo -e "Package: *\nPin: origin nginx.org\nPin-Priority: 900" | sudo tee /etc/apt/preferences.d/99nginx

## Installer
sudo apt update
sudo apt install nginx -y

## Vérifier la version
nginx -v

Sur Ubuntu 24.04, le paquet des dépôts standard fournit Nginx 1.24.x. Le dépôt officiel vous donne accès aux versions 1.26+ avec les derniers correctifs.

Configuration de base durcie

Avant de configurer les virtual hosts, on durcit la configuration globale.

Éditez /etc/nginx/nginx.conf :

nginx
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log warn;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    # —- Performance —-
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 50m;

    # —- Sécurité : masquer la version —-
    server_tokens off;

    # —- Types MIME —-
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # —- Logging —-
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $upstream_response_time';
    access_log /var/log/nginx/access.log main;

    # —- Gzip —-
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 4;
    gzip_min_length 1000;
    gzip_types text/plain text/css text/xml application/json
               application/javascript application/xml+rss
               application/atom+xml image/svg+xml;

    # —- Rate limiting (zones globales) —-
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    # —- Headers de sécurité globaux —-
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # —- Includes —-
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Reverse proxy : configuration complète

Créez le fichier pour votre application :

bash
sudo nano /etc/nginx/sites-available/app.mondomaine.fr

Contenu complet :

nginx
## Upstream : définit le(s) backend(s)
upstream app_backend {
    server 127.0.0.1:3000;

    # Pour du load balancing, ajoutez d'autres serveurs :
    # server 127.0.0.1:3001;
    # server 127.0.0.1:3002;

    # Garder les connexions ouvertes vers le backend
    keepalive 32;
}

## Redirection HTTP → HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name app.mondomaine.fr;
    return 301 https://$host$request_uri;
}

## Configuration HTTPS principale
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name app.mondomaine.fr;

    # —- SSL (sera rempli par Certbot ou manuellement) —-
    ssl_certificate /etc/letsencrypt/live/app.mondomaine.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.mondomaine.fr/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # —- HSTS —-
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # —- Headers de sécurité —-
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "0" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # —- Rate limiting —-
    limit_req zone=general burst=20 nodelay;
    limit_conn addr 50;

    # —- Logs dédiés —-
    access_log /var/log/nginx/app.mondomaine.fr.access.log main;
    error_log /var/log/nginx/app.mondomaine.fr.error.log warn;

    # —- Proxy vers le backend —-
    location / {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;

        # Headers standards
        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;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Keepalive vers l'upstream
        proxy_set_header Connection "";

        # Timeouts
        proxy_connect_timeout 10s;
        proxy_send_timeout 30s;
        proxy_read_timeout 60s;

        # Buffering
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 16k;
    }

    # —- Assets statiques (si servis par Nginx) —-
    location /static/ {
        alias /var/www/app/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # —- Bloquer les fichiers sensibles —-
    location ~ /\.(git|env|htaccess|htpasswd) {
        deny all;
        return 404;
    }

    # —- Page d'erreur custom —-
    error_page 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
        internal;
    }
}

Note sur WebSocket et keepalive : les deux directives Connection dans l'exemple ci-dessus sont mutuellement exclusives. Si votre application utilise des WebSockets, gardez le bloc WebSocket (Upgrade + Connection "upgrade"). Sinon, utilisez Connection "" pour le keepalive HTTP. Pour supporter les deux cas, utilisez une map :

nginx
## Dans le bloc http {} de nginx.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

## Puis dans le location :
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

Activation et test

bash
## Activer le site
sudo ln -s /etc/nginx/sites-available/app.mondomaine.fr /etc/nginx/sites-enabled/

## Supprimer la config par défaut si elle existe encore
sudo rm -f /etc/nginx/sites-enabled/default

## Tester la syntaxe
sudo nginx -t

## Recharger sans interruption
sudo systemctl reload nginx

Obtenir le certificat SSL avec Certbot

Si vous n'avez pas encore le certificat :

bash
## Installer Certbot
sudo apt install certbot python3-certbot-nginx -y

## Obtenir le certificat
sudo certbot —nginx -d app.mondomaine.fr

## Vérifier le timer de renouvellement
sudo systemctl list-timers | grep certbot

## Test de renouvellement
sudo certbot renew —dry-run

Si vous préférez configurer le SSL manuellement (sans laisser Certbot modifier votre config) :

bash
## Obtenir le certificat sans modifier Nginx
sudo certbot certonly —webroot -w /var/www/html -d app.mondomaine.fr

Load balancing multi-backends

Pour répartir la charge entre plusieurs instances :

nginx
upstream app_backend {
    # Round-robin par défaut
    server 127.0.0.1:3000 weight=3;
    server 127.0.0.1:3001 weight=2;
    server 127.0.0.1:3002 backup;

    # Alternatives au round-robin :
    # least_conn;       # envoie vers le backend le moins chargé
    # ip_hash;          # session sticky basée sur l'IP client

    keepalive 64;
}

Pour du health checking passif (inclus dans la version open source) :

nginx
upstream app_backend {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    keepalive 64;
}

Cache reverse proxy

Accélérer les réponses en cachant les résultats côté Nginx :

nginx
## Dans http {} de nginx.conf
proxy_cache_path /var/cache/nginx/app levels=1:2
    keys_zone=app_cache:10m max_size=1g inactive=60m
    use_temp_path=off;

## Dans le server {} ou location {}
location / {
    proxy_pass http://app_backend;
    proxy_cache app_cache;
    proxy_cache_valid 200 10m;
    proxy_cache_valid 404 1m;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
    proxy_cache_lock on;
    add_header X-Cache-Status $upstream_cache_status;
}

Créez le dossier de cache :

bash
sudo mkdir -p /var/cache/nginx/app
sudo chown www-data:www-data /var/cache/nginx/app

Bloquer les bots et user-agents indésirables

nginx
## Dans http {} ou dans un fichier inclus
map $http_user_agent $bad_bot {
    default 0;
    ~*semrush 1;
    ~*ahrefs 1;
    ~*mj12bot 1;
    ~*dotbot 1;
    ~*petalbot 1;
    ~*bytespider 1;
}

## Dans le server {}
if ($bad_bot) {
    return 403;
}

Script de déploiement automatisé

Pour automatiser la création d'un nouveau reverse proxy :

Sur le même sujet

À lire aussi

#tutoriel#nginx#reverse-proxy#sécurité-serveur#load-balancing