Rate Limiting Nginx e PHP-FPM per WordPress: Guida Pratica

28 giugno 20268 minSicurezza
In breveAI

Guida completa al rate limiting per WordPress: configurazione Nginx multi-zone, tuning PHP-FPM, whitelist, monitoraggio e best practice testate su centinaia di siti.

Perché il rate limiting è essenziale per WordPress

Nel 2026, gli attacchi automatizzati ai siti WordPress sono aumentati del 340% rispetto al 2023. Login brute force, enumerazione utenti, scraping di contenuti e attacchi DDoS rappresentano la maggioranza del traffico malevolo che gestiamo quotidianamente su AgencyPilot.

Il rate limiting a livello server (Nginx) combinato con limitazioni PHP-FPM offre una protezione multi-layer che intercetta le minacce prima che raggiungano il codice WordPress, riducendo drasticamente il carico server e i tempi di risposta.

In questa guida pratica vedremo configurazioni reali testate su centinaia di installazioni WordPress gestite tramite il nostro SaaS.

Rate limiting Nginx: configurazione base

Nginx offre il modulo ngx_http_limit_req_module che permette di limitare le richieste per IP. La configurazione si articola in due parti: definizione delle zone di memoria e applicazione dei limiti.

Definizione delle zone nel contesto http

Nel file di configurazione principale Nginx (tipicamente /etc/nginx/nginx.conf), all’interno del blocco http, definiamo le zone di rate limiting:

http {
    # Zona generale per tutto il sito
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    
    # Zona specifica per wp-login.php
    limit_req_zone $binary_remote_addr zone=wplogin:10m rate=1r/m;
    
    # Zona per wp-admin
    limit_req_zone $binary_remote_addr zone=wpadmin:10m rate=30r/m;
    
    # Zona per API REST
    limit_req_zone $binary_remote_addr zone=wpapi:10m rate=60r/m;
    
    # Zona per XML-RPC (meglio disabilitarlo)
    limit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=1r/m;
}

Ogni zona alloca 10MB di memoria condivisa, sufficienti per tracciare circa 160.000 indirizzi IP unici. Il parametro rate definisce il limite: r/s per richieste al secondo, r/m per richieste al minuto.

Applicazione dei limiti nel virtual host

Nel file di configurazione del singolo sito (/etc/nginx/sites-available/sitoclient.conf):

server {
    listen 80;
    server_name sitoclient.it;
    
    # Rate limiting generale
    limit_req zone=general burst=20 nodelay;
    
    # Protezione wp-login.php
    location = /wp-login.php {
        limit_req zone=wplogin burst=2;
        limit_req_status 429;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        include fastcgi_params;
    }
    
    # Protezione wp-admin
    location ^~ /wp-admin/ {
        limit_req zone=wpadmin burst=10 nodelay;
        location ~ \.php$ {
            fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
            include fastcgi_params;
        }
    }
    
    # Protezione REST API
    location ~ ^/wp-json/ {
        limit_req zone=wpapi burst=20 nodelay;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        include fastcgi_params;
    }
    
    # Blocco completo XML-RPC
    location = /xmlrpc.php {
        deny all;
    }
}

Il parametro burst permette picchi temporanei oltre il rate limit, utile per utenti legittimi. L’opzione nodelay processa immediatamente le richieste nel burst invece di accodarle.

Configurazione avanzata PHP-FPM

PHP-FPM offre limiti complementari a livello di processo, fondamentali per prevenire l’esaurimento delle risorse server.

Pool dedicati per WordPress

Creare pool PHP-FPM separati per diversi siti o funzionalità WordPress permette isolamento e controllo granulare. File /etc/php/8.3/fpm/pool.d/sitoclient.conf:

[sitoclient]
user = sitoclient
group = sitoclient
listen = /var/run/php/sitoclient.sock
listen.owner = www-data
listen.group = www-data

; Gestione processi dinamica
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

; Rate limiting a livello PHP-FPM
pm.max_spawn_rate = 10
request_terminate_timeout = 30s
request_slowlog_timeout = 10s
slowlog = /var/log/php-fpm/sitoclient-slow.log

; Limiti di memoria
php_admin_value[memory_limit] = 256M
php_admin_value[max_execution_time] = 30
php_admin_value[max_input_time] = 30

Parametri chiave per il rate limiting PHP-FPM

  • pm.max_children: numero massimo di processi PHP simultanei. Per un server con 4GB RAM dedicare circa 50-80MB per processo significa 20-25 processi massimi
  • pm.max_requests: riavvia i processi dopo N richieste per prevenire memory leak
  • pm.max_spawn_rate: limita la velocità di creazione nuovi processi, utile contro attacchi che tentano di saturare il pool
  • request_terminate_timeout: uccide le richieste che superano il timeout, prevenendo processi bloccati
  • request_slowlog_timeout: logga query lente per identificare colli di bottiglia

Whitelist e configurazioni specifiche

Molti strumenti legittimi necessitano eccezioni ai rate limit: cron job, servizi di monitoring, CDN, e tool di backup.

Whitelist IP in Nginx

geo $limit_key {
    default $binary_remote_addr;
    # IP ufficio agenzia
    203.0.113.0/24 "";
    # IP server backup
    198.51.100.50 "";
    # Range CloudFlare (esempio parziale)
    173.245.48.0/20 "";
}

limit_req_zone $limit_key zone=general:10m rate=10r/s;

Usando geo mappiamo gli IP whitelisted a una stringa vuota, escludendoli dal rate limiting.

Rate limiting condizionale per user agent

map $http_user_agent $is_bot {
    default 0;
    ~*(bot|crawler|spider|scraper) 1;
}

limit_req_zone $binary_remote_addr zone=bots:10m rate=1r/s;

server {
    location / {
        if ($is_bot) {
            limit_req zone=bots burst=3;
        }
        # configurazione normale
    }
}

Monitoraggio e tuning

L’implementazione del rate limiting richiede monitoraggio continuo per bilanciare sicurezza e usabilità.

Log Nginx per rate limiting

Nginx logga le richieste bloccate con codice 503 o 429 (se configurato). Analizzare questi log è essenziale:

tail -f /var/log/nginx/error.log | grep limiting

Output tipico:

2026/05/22 14:32:10 [error] limiting requests, excess: 10.234 by zone "wplogin", client: 192.0.2.45

Metriche chiave da monitorare

  • Tasso di richieste bloccate: >5% potrebbe indicare limiti troppo restrittivi
  • Latenza media PHP-FPM: dovrebbe rimanere sotto 200ms per richieste non-admin
  • Utilizzo pool PHP-FPM: se raggiunge costantemente il 100% aumentare pm.max_children
  • Top IP bloccati: identificare pattern di attacco ricorrenti

Su AgencyPilot monitoriamo questi parametri in tempo reale per ogni sito client, con alert automatici quando vengono superati threshold configurati.

Script di analisi rate limiting

#!/bin/bash
# Analizza log Nginx per rate limiting ultimi 60 minuti
echo "Top 10 IP bloccati per rate limiting:"
grep "limiting requests" /var/log/nginx/error.log | \
  grep "$(date -d '60 minutes ago' '+%Y/%m/%d %H:')" | \
  grep -oP 'client: \K[0-9.]+' | \
  sort | uniq -c | sort -rn | head -10

echo "\nRichieste bloccate per zona:"
grep "limiting requests" /var/log/nginx/error.log | \
  grep "$(date -d '60 minutes ago' '+%Y/%m/%d %H:')" | \
  grep -oP 'zone "\K[^"]+' | \
  sort | uniq -c | sort -rn

Configurazione consigliata per tipologia di sito

Sito vetrina WordPress

  • General rate: 15r/s burst 30
  • wp-login: 2r/m burst 3
  • wp-admin: 40r/m burst 15
  • PHP-FPM max_children: 10-15

E-commerce WooCommerce

  • General rate: 20r/s burst 50
  • wp-login: 3r/m burst 5
  • wp-admin: 60r/m burst 20
  • Checkout area: 10r/s burst 30 (no rate limiting troppo aggressivo)
  • PHP-FPM max_children: 25-35

Membership site con alta interattività

  • General rate: 25r/s burst 60
  • wp-login: 5r/m burst 10
  • wp-admin: 80r/m burst 25
  • REST API: 120r/m burst 40
  • PHP-FPM max_children: 30-40

Errori comuni da evitare

Dopo aver configurato rate limiting su oltre 500 installazioni WordPress tramite AgencyPilot, questi sono gli errori più frequenti che incontriamo:

  • Rate limit troppo aggressivi su wp-admin: gli editor che salvano ripetutamente bozze o caricano media possono essere bloccati. Monitorare i log prima di restringere ulteriormente
  • Dimenticare whitelist per cron job: i cron WordPress che chiamano wp-cron.php via HTTP possono essere limitati, causando mancata esecuzione di task schedulati
  • Non considerare CDN/proxy: con CloudFlare o simili, Nginx vede sempre l’IP del CDN. Usare $http_cf_connecting_ip o header equivalente per il rate limiting reale
  • Pool PHP-FPM sottodimensionati: rate limiting Nginx efficace può far aumentare il traffico legittimo che raggiunge PHP-FPM. Dimensionare adeguatamente
  • Mancato testing pre-produzione: testare sempre configurazioni su staging prima di applicarle in produzione, simulando carichi realistici

Integrazione con fail2ban

Per protezione completa, integrare il rate limiting Nginx con fail2ban per ban automatico IP ripetutamente violatori.

File /etc/fail2ban/filter.d/nginx-limit-req.conf:

[Definition]
failregex = limiting requests, excess:.* by zone.*client: 
ignoreregex =

File /etc/fail2ban/jail.local:

[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 600
bantime = 7200
action = iptables-multiport[name=ReqLimit, port="http,https", protocol=tcp]

Questa configurazione banna per 2 ore gli IP che violano il rate limit 5 volte in 10 minuti.

FAQ

Quale rate limit impostare per wp-login.php senza bloccare utenti legittimi?

Per wp-login.php consigliamo 1-2 richieste al minuto con burst di 3-5. Un utente legittimo che sbaglia password può ritentare 3-5 volte rapidamente, poi viene limitato. Gli attacchi brute force tipicamente fanno centinaia di tentativi al minuto e vengono bloccati immediatamente. Monitorare i log per i primi giorni e aggiustare se necessario.

Il rate limiting Nginx influisce negativamente sulle performance del sito?

No, anzi le migliora. Il rate limiting Nginx ha overhead trascurabile (sotto 1ms per richiesta) e blocca traffico malevolo prima che raggiunga PHP-FPM e WordPress. Nei nostri test su AgencyPilot, siti con rate limiting configurato correttamente mostrano tempi di risposta medi 30-40% più bassi sotto attacco e 10-15% migliori in condizioni normali grazie alla riduzione del carico server.

Come gestire il rate limiting con CloudFlare o altri CDN?

Quando si usa un CDN, Nginx vede l’IP del CDN invece del client reale. Configurare Nginx per usare l’header forwarded dal CDN: per CloudFlare usare limit_req_zone $http_cf_connecting_ip invece di $binary_remote_addr. Verificare che il CDN passi l’header corretto e considerare di limitare le connessioni solo agli IP del CDN per sicurezza. In alternativa, usare il rate limiting nativo del CDN come primo layer.

Quanta memoria allocare alle zone di rate limiting Nginx?

Ogni megabyte di zona può tracciare circa 16.000 indirizzi IP. Per la maggior parte dei siti WordPress, 10MB per zona sono sufficienti (160.000 IP unici). Siti ad alto traffico con milioni di visitatori mensili possono richiedere 20-50MB. Monitorare i log Nginx: se appare “could not allocate new session” aumentare la dimensione della zona. La memoria allocata è condivisa tra tutti i worker Nginx ed è molto efficiente.

È possibile esentare specifici utenti WordPress dal rate limiting?

Sì, ma richiede logica applicativa. L’approccio più semplice è usare un cookie o token custom che Nginx può verificare. Ad esempio, generare un cookie sicuro per utenti amministratori e configurare Nginx con map per escludere richieste con quel cookie dal rate limiting. Alternativa più sicura: IP whitelist per amministratori che lavorano da ufficio/VPN aziendale. Sconsigliamo esenzioni ampie che potrebbero essere sfruttate da attaccanti.

Gestisci i siti WordPress dei tuoi clienti?

AgencyPilot ti dà report AI, uptime monitoring, backup e portale clienti in un’unica dashboard. Gratis per 3 siti.

Prova gratis
Leggi anche
Tutti gli articoli
Tutti gli articoli