Apache HTTP Server y Nginx son los dos servidores web de código abierto más usados en Linux. Los dos sirven archivos estáticos, terminan TLS, hacen de proxy inverso y ejecutan PHP, pero lo hacen con arquitecturas distintas que cambian el consumo de memoria, la forma de configurarlos y lo que ocurre bajo carga. En esta guía verás esas diferencias con configuraciones reales en Ubuntu 24.04 y un criterio claro para elegir uno, el otro o los dos juntos.

Resumen rápido

AspectoApache 2.4Nginx
Modelo de conexionesProcesos o hilos según el MPM (prefork, worker, event)Pocos procesos worker con bucle de eventos asíncrono
Versión en Ubuntu 24.042.4.58 (paquete apache2)1.24.0 (paquete nginx)
Configuración por directorioSí, con .htaccessNo, todo en la configuración central
PHPmod_php (solo con prefork) o PHP-FPM vía proxy_fcgiSiempre PHP-FPM vía fastcgi_pass
MódulosCarga dinámica con a2enmod / a2dismodDinámicos limitados; la mayoría se compilan dentro
Memoria con muchas conexiones lentasCrece con cada hilo o proceso ocupadoCasi constante
Punto fuerteFlexibilidad, hosting compartido, .htaccessEstáticos, proxy inverso, balanceo, alta concurrencia

Arquitectura: por qué se comportan distinto

Apache y sus MPM

Apache delega la gestión de conexiones en un módulo de multiprocesamiento (MPM). Solo puede haber uno activo:

  • prefork: un proceso por conexión, sin hilos. Es el único compatible con mod_php, pero es el que más memoria consume.
  • worker: varios procesos, cada uno con varios hilos. Un hilo queda ocupado durante toda la conexión, incluido el keep-alive.
  • event: como worker, pero las conexiones keep-alive inactivas las atiende un hilo dedicado, así que los hilos de trabajo quedan libres. Es el MPM por defecto en Ubuntu 24.04.

Comprueba qué MPM está activo en tu servidor:

a2query -M
event

Si instalas libapache2-mod-php, el paquete desactiva event y activa prefork automáticamente. Es la causa más habitual de que un Apache "consuma mucha RAM".

Nginx y el bucle de eventos

Nginx arranca un proceso maestro (lee la configuración y abre los puertos) y varios procesos worker, normalmente uno por núcleo (worker_processes auto;). Cada worker atiende miles de conexiones a la vez con epoll, sin crear un hilo por cliente. Por eso una conexión lenta o en keep-alive apenas cuesta memoria.

ps -o pid,rss,cmd -C nginx
    PID   RSS CMD
   1234  2380 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
   1235  5412 nginx: worker process
   1236  5408 nginx: worker process

La columna RSS está en KB. El equivalente en Apache es ps -o pid,rss,cmd -C apache2; compara ambos bajo la misma carga para ver la diferencia real en tu servidor.

Rendimiento: qué esperar de verdad

Las cifras de benchmarks publicados dependen tanto del hardware, la configuración y la aplicación que no sirven para decidir. Lo que sí es estable:

  • Archivos estáticos y muchas conexiones concurrentes: Nginx gana, sobre todo en memoria. Con event, Apache se acerca bastante, pero sigue necesitando un hilo por petición activa.
  • PHP dinámico: el cuello de botella es PHP y la base de datos, no el servidor web. Apache con event + PHP-FPM y Nginx + PHP-FPM rinden de forma muy parecida.
  • TLS: ambos usan OpenSSL; el coste criptográfico es el mismo. Las diferencias vienen de la configuración (sesiones, HTTP/2, ciphers).
  • Proxy inverso: Nginx está diseñado para ello y consume menos por conexión. Apache con mod_proxy funciona bien, pero con más recursos.

Para medir tu caso concreto instala apache2-utils, que incluye la herramienta ab:

sudo apt install apache2-utils
ab -n 5000 -c 100 http://127.0.0.1/

Mira las líneas Requests per second y Time per request. Ejecuta la prueba desde otra máquina si quieres incluir la red, y siempre contra la misma página en ambos servidores.

Configuración equivalente en los dos servidores

Virtual host básico

En Apache, crea /etc/apache2/sites-available/your_domain.conf:

<VirtualHost *:80>
    ServerName your_domain
    ServerAlias www.your_domain
    DocumentRoot /var/www/your_domain/public

    <Directory /var/www/your_domain/public>
        AllowOverride None
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/your_domain_error.log
    CustomLog ${APACHE_LOG_DIR}/your_domain_access.log combined
</VirtualHost>

Actívalo y valida la sintaxis antes de recargar:

sudo a2ensite your_domain.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

En Nginx, el equivalente va en /etc/nginx/sites-available/your_domain:

server {
    listen 80;
    listen [::]:80;
    server_name your_domain www.your_domain;
    root /var/www/your_domain/public;
    index index.html;

    access_log /var/log/nginx/your_domain_access.log;
    error_log /var/log/nginx/your_domain_error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

La salida esperada de nginx -t es:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

PHP con PHP-FPM

Ubuntu 24.04 trae PHP 8.3. En ambos servidores la opción recomendada es PHP-FPM:

sudo apt install php8.3-fpm

En Apache, activa el proxy FastCGI y la configuración que trae el propio paquete de PHP-FPM, que ya envía los .php al socket correcto:

sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl reload apache2

Así puedes mantener el MPM event. En Nginx añade un bloque location dentro del server:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

Añade también index.php a la directiva index y recarga con sudo nginx -t && sudo systemctl reload nginx.

Reglas de reescritura y .htaccess

Esta es la diferencia práctica más importante. Apache lee archivos .htaccess en cada directorio si AllowOverride lo permite, lo que deja a cada aplicación (WordPress, Laravel, Drupal) definir sus propias reglas sin tocar la configuración del servidor. El coste es que Apache busca esos archivos en cada petición.

La regla típica de un front controller en .htaccess:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]

Nginx no tiene .htaccess. La misma lógica se escribe una vez en el server:

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Si migras una aplicación de Apache a Nginx, tienes que traducir a mano cada .htaccess, incluidas las reglas de seguridad que bloquean directorios.

Proxy inverso hacia una aplicación

Para publicar una aplicación que escucha en 127.0.0.1:3000, en Nginx:

location / {
    proxy_pass http://127.0.0.1:3000;
    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;
}

En Apache necesitas sudo a2enmod proxy proxy_http headers y, dentro del VirtualHost:

ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
RequestHeader set X-Forwarded-Proto "http"

Cambia http por https en el VirtualHost *:443.

Configuración híbrida: Nginx delante de Apache

Es habitual cuando una aplicación depende de .htaccess pero quieres que Nginx sirva los estáticos, termine TLS y absorba las conexiones lentas. Apache pasa a escuchar solo en local.

Edita /etc/apache2/ports.conf y cambia la línea Listen 80 por:

Listen 127.0.0.1:8080

Cambia también el <VirtualHost *:80> del sitio a <VirtualHost 127.0.0.1:8080>. Para que Apache registre la IP real del visitante y no la de Nginx, activa mod_remoteip:

sudo a2enmod remoteip

Crea /etc/apache2/conf-available/remoteip.conf:

RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
sudo a2enconf remoteip
sudo apache2ctl configtest
sudo systemctl restart apache2

En Nginx, sirve los estáticos directamente y reenvía el resto:

server {
    listen 80;
    server_name your_domain;
    root /var/www/your_domain/public;

    location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|woff2)$ {
        expires 30d;
        try_files $uri =404;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Comprueba que Apache ya no escucha en el puerto 80 y Nginx sí:

sudo ss -ltnp | grep -E ':80 |:8080 '
LISTEN 0      511        127.0.0.1:8080      0.0.0.0:*    users:(("apache2",pid=2101,fd=4),...)
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=1234,fd=6),...)

Seguridad y mantenimiento

Ambos proyectos publican parches con regularidad y Ubuntu los distribuye por apt, así que la seguridad depende más de la configuración que del servidor elegido. Puntos concretos:

  • Ocultar la versión: en Apache, ServerTokens Prod y ServerSignature Off en /etc/apache2/conf-available/security.conf. En Nginx, server_tokens off; dentro del bloque http.
  • Superficie de ataque: desactiva los módulos de Apache que no uses (a2dismod status autoindex). Nginx ya viene con pocos módulos.
  • .htaccess: cómodo, pero permite que un archivo subido por una aplicación vulnerable cambie el comportamiento del servidor. Si no lo necesitas, deja AllowOverride None.
  • Límites: en Nginx, limit_req y limit_conn limitan peticiones por IP sin módulos extra. En Apache necesitas módulos adicionales como mod_evasive o hacerlo en el firewall.

Cuál elegir

Elige Apache cuando:

  • La aplicación depende de .htaccess (hosting compartido, WordPress con plugins que escriben reglas, paneles de control).
  • Necesitas módulos que solo existen para Apache o tu equipo ya lo domina.
  • El tráfico es moderado y prefieres cambiar reglas sin recargar el servidor.

Elige Nginx cuando:

  • Sirves muchos estáticos o tienes muchas conexiones concurrentes o lentas.
  • Lo usas como proxy inverso o balanceador delante de Node.js, Python, Go o contenedores.
  • Tu VPS tiene poca memoria y quieres un consumo predecible.

Usa los dos cuando:

  • Tienes una aplicación atada a .htaccess pero quieres el rendimiento de Nginx en estáticos y TLS.
  • Estás migrando de Apache a Nginx de forma gradual.

Conclusión

Nginx es la opción por defecto para proxies inversos, estáticos y servidores con poca RAM, mientras que Apache sigue siendo la más cómoda cuando las aplicaciones necesitan .htaccess. Con PHP-FPM y el MPM event la diferencia en PHP es pequeña, así que decide por el modelo de configuración que te conviene más que por benchmarks. Como siguientes pasos, protege el sitio con un certificado de Let's Encrypt usando Certbot, activa HTTP/2 y mide tu propia aplicación con ab antes y después de cada cambio.