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

AspectoApacheNginx
Modelo de conexionesProcesos e hilos (MPM event, worker o prefork)Orientado a eventos, pocos procesos
Memoria con muchas conexionesCrece con el número de hilos o procesosCasi constante
Contenido estáticoBuenoExcelente
PHPmod_php (con prefork) o PHP-FPMSolo PHP-FPM
Configuración por directorioSí, con .htaccessNo existe
MódulosSe cargan y descargan con a2enmodCompilados o dinámicos, sin equivalente a .htaccess
Proxy inverso y balanceoCon mod_proxy y mod_proxy_balancerNativo y muy usado
Versión en Ubuntu 24.042.4.581.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 con mod_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: como worker, 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.

  1. Cambia el puerto de Apache en /etc/apache2/ports.conf a Listen 127.0.0.1:8080 y el virtual host a <VirtualHost 127.0.0.1:8080>.
  2. Activa mod_remoteip para 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
  1. En Nginx, reenvía las peticiones a Apache con los mismos proxy_set_header del ejemplo anterior y proxy_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 .htaccess o 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 wrk sobre tu propia aplicación antes de decidir una migración.