Hardening Apache Reverse Proxy in produzione

Published: (February 17, 2026 at 06:52 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

Guida completa a timeout, worker e gestione dei carichi applicativi

In un’infrastruttura dove Apache HTTP Server funge sia da frontend (TLS, routing, bilanciamento) che da tramite verso container Docker, la stabilità non dipende dalla potenza dell’hardware, ma dalla coerenza della catena dei timeout, dai limiti del sistema operativo e dal dimensionamento dell’intero stack applicativo.

Questa guida è focalizzata sul caso reale in cui:

  • Apache frontend agisce da reverse proxy e load balancer
  • Il backend applicativo gira in container
  • In alcuni casi Apache è anche il web server dentro il container
  • L’applicazione è PHP (ma i principi restano validi anche per Python o altri stack)

1. Il Sistema Operativo: Preparare il terreno (Systemd)

Prima di configurare Apache, dobbiamo assicurarci che il sistema operativo gli permetta di lavorare.

Sui sistemi moderni come Debian o Ubuntu, il limite di processi e thread per servizio è gestito da systemd tramite i Cgroups.

Il problema

Sotto carico Apache può raggiungere il limite di task e generare errori nei log simili a:

Fork Rejected

La soluzione

Aumentare TasksMax per il servizio Apache.

systemctl edit apache2.service

Inserire:

[Service]
TasksMax=3000

Applicare:

systemctl daemon-reload
systemctl restart apache2

Per un server con 4 GB RAM e ~400 worker, 3000 è un valore equilibrato.


2. Monitoraggio in tempo reale: i comandi “Manometro”

Per capire se il limite è corretto, interroga direttamente i Cgroups:

cat /sys/fs/cgroup/system.slice/apache2.service/pids.current
cat /sys/fs/cgroup/system.slice/apache2.service/pids.max

Se pids.current si avvicina a pids.max, il server inizierà a rifiutare connessioni.
Questo è il primo indicatore reale di saturazione.


3. Il Motore: MPM Event dimensionato per 4 GB RAM

Il modulo MPM Event gestisce le connessioni in modo asincrono, evitando che i thread restino bloccati su KeepAlive.

Configurazione

/etc/apache2/mods-available/mpm_event.conf


    ServerLimit              16
    StartServers             3
    ThreadsPerChild          25
    MaxRequestWorkers       400
    MinSpareThreads          25
    MaxSpareThreads          75
    MaxConnectionsPerChild 10000

Perché questi numeri?

  • 16 processi × 25 thread = 400 richieste simultanee
  • circa 800 MB occupati da Apache
  • RAM restante per PHP, sistema e cache

Se PHP cresce, Apache deve ridursi.


4. La catena dei timeout: sincronia Proxy ↔ Backend

Se proxy e backend non sono coordinati, i worker restano occupati inutilmente.

Regola fondamentale: l’applicazione deve morire prima del proxy.

ParametroProxyBackendNote
KeepAliveTimeout3 s5 sIl backend aspetta di più
Timeout60 s65 sRicezione dati
ProxyTimeout300 sAttesa risposta backend
PHP max_execution_time290 sL’app muore prima del proxy

5. Configurazione globale dei timeout (operativa)

Creare:

/etc/apache2/conf-available/global-timeouts.conf
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 3

Timeout 60
ProxyTimeout 300

Attivare:

a2enconf global-timeouts
systemctl reload apache2

Questo file evita configurazioni duplicate nei VirtualHost.


6. Bilanciamento e failover rapido

Il failover lento è uno dei problemi più comuni nei proxy Apache.
Usiamo connectiontimeout per forzare il rilevamento immediato dei nodi down.


    BalancerMember "http://node01:8080" route=n1 connectiontimeout=2 retry=30
    BalancerMember "http://node02:8080" route=n2 connectiontimeout=2 retry=30
    ProxySet lbmethod=bybusyness timeout=60

Con questa configurazione:

  • un nodo morto viene escluso in ~2 secondi
  • il traffico migra subito sugli altri

7. Separare traffico veloce e lento

Questa tecnica serve a proteggere le richieste normali da quelle pesanti.
È corretta solo se il backend lento ha risorse dedicate.

# Pool veloce

    BalancerMember "http://app:8080" connectiontimeout=2
    ProxySet timeout=60

# Pool lento

    BalancerMember "http://app_dedicated:8080" connectiontimeout=2
    ProxySet timeout=1200

Se entrambi puntano allo stesso backend, non serve a nulla.


8. PHP‑FPM: il vero limite della capacità

Apache accetta la richiesta, ma PHP la esegue.

Per 4 GB con 2 GB dedicati a PHP:

pm.max_children ≈ RAM_php / memoria_media_script

Configurazione

/etc/php/8.x/fpm/pool.d/www.conf

pm = dynamic
pm.max_children = 40
pm.start_servers = 10
pm.max_requests = 500
request_terminate_timeout = 300s

Se PHP si satura, Apache sembra lento anche se non lo è.


9. Quando il tuning non basta: strategie architetturali

Il tuning dei timeout migliora la stabilità, ma non cambia il modello di carico.
Le operazioni lunghe dovrebbero diventare asincrone.

Soluzioni tipiche

  • Code con Redis

  • Code con RabbitMQ

    • job worker separati
    • risposta immediata “presa in carico” al client

Fine della guida.

10. Checklist finale operativa

  • TasksMax aumentato e verificato
  • MPM Event dimensionato sulla RAM
  • Timeout coerenti tra proxy, backend e PHP
  • Failover rapido con connectiontimeout
  • Backend lento separato solo se realmente isolato
  • PHP‑FPM dimensionato sulla RAM reale
  • Monitoraggio periodico dei PID di Apache

Conclusione

La stabilità di un reverse proxy Apache non dipende da un singolo parametro, ma dall’allineamento di:

  • limiti del sistema operativo
  • modello di concorrenza di Apache
  • timeout della catena proxy‑backend
  • capacità reale dell’applicazione

Quando questi quattro livelli sono coerenti, Apache diventa estremamente stabile anche sotto carico elevato.

0 views
Back to Blog

Related posts

Read more »