Apache y Nginx sirven juntos la mayor parte de la web y ambos son software libre, maduro y bien mantenido. La diferencia no está en cuál es "mejor", sino en cómo gestionan las conexiones, cómo se configuran y qué tipo de carga resuelven con menos esfuerzo. Esta guía compara los dos servidores en Ubuntu 24.04 con configuraciones equivalentes, para que puedas decidir con criterio cuál usar o cuándo combinarlos.
Resumen rápido
| Aspecto | Apache | Nginx |
|---|---|---|
| Modelo de conexiones | Procesos e hilos (MPM event, worker o prefork) | Orientado a eventos, pocos procesos |
| Memoria con muchas conexiones | Crece con el número de hilos o procesos | Casi constante |
| Contenido estático | Bueno | Excelente |
| PHP | mod_php (con prefork) o PHP-FPM | Solo PHP-FPM |
| Configuración por directorio | Sí, con .htaccess | No existe |
| Módulos | Se cargan y descargan con a2enmod | Compilados o dinámicos, sin equivalente a .htaccess |
| Proxy inverso y balanceo | Con mod_proxy y mod_proxy_balancer | Nativo y muy usado |
| Versión en Ubuntu 24.04 | 2.4.58 | 1.24.0 |
Arquitectura: procesos frente a eventos
Apache y los MPM
Apache delega la gestión de conexiones en un MPM (Multi-Processing Module), y solo puede haber uno activo:
prefork: un proceso por conexión, sin hilos. Es el único compatible conmod_php, que no es seguro con hilos, y el que más memoria consume.worker: varios procesos con varios hilos cada uno. Un hilo atiende una conexión de principio a fin.event: comoworker, pero las conexiones keep-alive inactivas pasan a un hilo de escucha y liberan su hilo de trabajo. Es el MPM por defecto en Ubuntu 24.04.
Puedes comprobar cuál tienes activo:
sudo a2query -M
event
Si instalas libapache2-mod-php, Ubuntu desactiva event y activa prefork automáticamente. Por eso, con Apache moderno, lo recomendable es usar PHP-FPM y mantener event.
Nginx y el bucle de eventos
Nginx arranca un proceso maestro y unos pocos procesos de trabajo (normalmente uno por núcleo, con worker_processes auto;). Cada proceso atiende miles de conexiones a la vez con un bucle de eventos no bloqueante (epoll en Linux), sin dedicar un hilo a cada cliente:
ps -o pid,user,cmd -C nginx
PID USER CMD
1021 root nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
1022 www-data nginx: worker process
1023 www-data nginx: worker process
Qué implica en la práctica
Con pocas conexiones simultáneas la diferencia es pequeña. Con miles de clientes lentos o conexiones keep-alive abiertas, Apache necesita un hilo (o un proceso con prefork) por conexión activa, mientras que Nginx mantiene un consumo de memoria casi estable. Esa es la razón por la que Nginx suele colocarse en primera línea en sitios con mucho tráfico, CDN y proxies.
Contenido dinámico: PHP
Ninguno de los dos ejecuta PHP de forma eficiente por sí solo en una instalación moderna: ambos pasan las peticiones a PHP-FPM, que gestiona su propio pool de procesos. En Ubuntu 24.04 el paquete es php8.3-fpm y escucha en /run/php/php8.3-fpm.sock.
En Apache, activa los módulos de proxy FastCGI y la configuración que trae el paquete:
sudo apt install php8.3-fpm
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl reload apache2
En Nginx, se añade una location al server block usando el fragmento que incluye Ubuntu:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
Con PHP-FPM detrás, el rendimiento de PHP depende sobre todo de PHP-FPM y de OPcache, no del servidor web. La diferencia real aparece en cómo cada servidor gestiona las conexiones y los archivos estáticos que acompañan a la aplicación.
Configuración: .htaccess frente a configuración centralizada
Apache permite que cada directorio tenga un archivo .htaccess con directivas propias si el virtual host lo permite con AllowOverride. Es muy cómodo en hosting compartido, donde el cliente no tiene acceso a la configuración del servidor, y muchas aplicaciones (WordPress, Laravel, Drupal) lo incluyen de serie.
El coste es que, con AllowOverride All, Apache busca un .htaccess en cada directorio de la ruta en cada petición. Si controlas el servidor, lo más eficiente es poner esas reglas en el virtual host y usar AllowOverride None.
Nginx no tiene nada equivalente: toda la configuración está en archivos que solo root puede editar y los cambios requieren sudo nginx -t && sudo systemctl reload nginx. Es más rápido y más predecible, pero obliga a traducir los .htaccess de las aplicaciones.
Reescritura de URLs: ejemplos equivalentes
Redirigir HTTP a HTTPS
Apache (virtual host del puerto 80):
<VirtualHost *:80>
ServerName your_domain
Redirect permanent / https://your_domain/
</VirtualHost>
Nginx:
server {
listen 80;
server_name your_domain;
return 301 https://your_domain$request_uri;
}
Enlaces permanentes tipo WordPress
Apache, en el .htaccess o en el bloque <Directory> (requiere mod_rewrite):
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
Nginx logra lo mismo con una sola línea:
location / {
try_files $uri $uri/ /index.php?$args;
}
Redirigir una ruta antigua
Apache:
Redirect permanent /blog-antiguo /blog
Nginx:
location = /blog-antiguo {
return 301 /blog;
}
En general, las reglas de Nginx son más cortas, pero no existe un conversor automático fiable de .htaccess a Nginx: hay que entender qué hace cada regla y reescribirla.
Proxy inverso y balanceo de carga
Los dos pueden actuar como proxy inverso, pero en Nginx es el uso más habitual y la configuración es mínima:
upstream app_backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
server {
listen 80;
server_name your_domain;
location / {
proxy_pass http://app_backend;
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;
}
}
El equivalente en Apache necesita activar proxy, proxy_http, proxy_balancer y lbmethod_byrequests:
sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests
<VirtualHost *:80>
ServerName your_domain
<Proxy "balancer://app_backend">
BalancerMember "http://10.0.0.11:8080"
BalancerMember "http://10.0.0.12:8080"
</Proxy>
ProxyPreserveHost On
ProxyPass "/" "balancer://app_backend/"
ProxyPassReverse "/" "balancer://app_backend/"
</VirtualHost>
Ambos funcionan. Nginx, sin embargo, gestiona mejor miles de conexiones de clientes lentos mientras mantiene pocas conexiones con el backend, que es justo lo que se le pide a un proxy.
Módulos
Apache carga módulos dinámicamente y Ubuntu los gestiona con a2enmod y a2dismod. Hay módulos para casi todo: mod_security (WAF), autenticación LDAP, mod_evasive, etc.
sudo apache2ctl -M
Nginx también admite módulos dinámicos, pero hay menos y en Ubuntu se instalan como paquetes (libnginx-mod-*), que se cargan desde /etc/nginx/modules-enabled/:
apt list --installed 2>/dev/null | grep libnginx-mod
Si dependes de un módulo concreto de Apache sin equivalente en Nginx, esa suele ser la decisión.
Enfoque híbrido: Nginx delante de Apache
Una arquitectura común consiste en poner Nginx en los puertos 80 y 443 para terminar TLS y servir estáticos, y dejar Apache en un puerto interno para las aplicaciones que dependen de .htaccess.
- Cambia el puerto de Apache en
/etc/apache2/ports.confaListen 127.0.0.1:8080y el virtual host a<VirtualHost 127.0.0.1:8080>. - Activa
mod_remoteippara que Apache registre la IP real del cliente y no la de Nginx:
sudo a2enmod remoteip
Crea /etc/apache2/conf-available/remoteip.conf:
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
sudo a2enconf remoteip
sudo systemctl restart apache2
- En Nginx, reenvía las peticiones a Apache con los mismos
proxy_set_headerdel ejemplo anterior yproxy_pass http://127.0.0.1:8080;.
Comprueba que Apache solo escucha en local y Nginx en los puertos públicos:
sudo ss -tlnp | grep -E ':80 |:443 |:8080 '
Esta arquitectura añade una capa más que mantener, así que úsala solo cuando de verdad necesites .htaccess y el rendimiento de Nginx a la vez.
Cómo medir el rendimiento en tu caso
Las cifras de benchmarks publicados rara vez se parecen a tu carga real. Mide tú mismo con la misma página en ambos servidores. wrk está en los repositorios de Ubuntu:
sudo apt install wrk
wrk -t4 -c200 -d30s http://your_server_ip/
Running 30s test @ http://your_server_ip/
4 threads and 200 connections
...
Requests/sec: ...
Transfer/sec: ...
Ejecuta la prueba desde otra máquina en la misma red (no desde el propio servidor, que competiría por la CPU), repite varias veces y observa además el consumo de memoria con free -m durante la prueba. Compara siempre configuraciones equivalentes: mismo contenido, compresión activada en ambos y PHP-FPM en los dos si mides PHP.
Cuál elegir
Elige Apache si:
- Tu aplicación depende de
.htaccesso la vas a desplegar en un entorno donde los usuarios no editan la configuración del servidor. - Necesitas un módulo que solo existe en Apache.
- Tu equipo ya conoce Apache y el tráfico no justifica un cambio.
Elige Nginx si:
- Vas a servir mucho contenido estático o muchas conexiones simultáneas.
- Necesitas un proxy inverso o balanceador delante de aplicaciones Node.js, Python, Go o contenedores.
- Partes de cero y controlas toda la configuración del servidor.
Combínalos solo cuando necesites a la vez la compatibilidad de Apache y la eficiencia de Nginx en primera línea.
Conclusión
Apache ofrece flexibilidad y compatibilidad gracias a sus MPM, sus módulos y .htaccess; Nginx ofrece un uso de recursos muy contenido y es la opción natural como proxy inverso. Para un proyecto nuevo sin dependencias de .htaccess, Nginx con PHP-FPM es un buen punto de partida; para aplicaciones existentes que ya funcionan bien en Apache, migrar solo tiene sentido si has medido un problema real. Como siguientes pasos puedes:
- Instalar Apache o Nginx en Ubuntu 24.04 con las guías de instalación correspondientes.
- Configurar varios sitios con virtual hosts en Apache o server blocks en Nginx.
- Probar ambos con
wrksobre tu propia aplicación antes de decidir una migración.
