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
| Aspecto | Apache 2.4 | Nginx |
|---|---|---|
| Modelo de conexiones | Procesos o hilos según el MPM (prefork, worker, event) | Pocos procesos worker con bucle de eventos asíncrono |
| Versión en Ubuntu 24.04 | 2.4.58 (paquete apache2) | 1.24.0 (paquete nginx) |
| Configuración por directorio | Sí, con .htaccess | No, todo en la configuración central |
| PHP | mod_php (solo con prefork) o PHP-FPM vía proxy_fcgi | Siempre PHP-FPM vía fastcgi_pass |
| Módulos | Carga dinámica con a2enmod / a2dismod | Dinámicos limitados; la mayoría se compilan dentro |
| Memoria con muchas conexiones lentas | Crece con cada hilo o proceso ocupado | Casi constante |
| Punto fuerte | Flexibilidad, hosting compartido, .htaccess | Está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_proxyfunciona 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 ProdyServerSignature Offen/etc/apache2/conf-available/security.conf. En Nginx,server_tokens off;dentro del bloquehttp. - 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, dejaAllowOverride None.- Límites: en Nginx,
limit_reqylimit_connlimitan peticiones por IP sin módulos extra. En Apache necesitas módulos adicionales comomod_evasiveo 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
.htaccesspero 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.
