Nginx es un servidor web de arquitectura orientada a eventos que sirve contenido estático con muy poco consumo de memoria y se usa mucho como proxy inverso y balanceador delante de aplicaciones. En este tutorial instalarás Nginx en Ubuntu 24.04, abrirás el firewall, publicarás un sitio en su propio server block, ajustarás la configuración global, activarás compresión y cabeceras de seguridad y lo protegerás con un certificado de Let's Encrypt.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. - UFW activo con SSH permitido (
sudo ufw allow OpenSSH). - Para el paso de HTTPS: un dominio (en esta guía,
your_domain) con un registro DNSAque apunte a la IP pública del servidor, y opcionalmente otro parawww.your_domain. - Ningún otro servidor web (por ejemplo Apache) escuchando en los puertos 80 y 443.
Paso 1: Instalar Nginx
La versión de Nginx de los repositorios de Ubuntu 24.04 (1.24) es estable y recibe parches de seguridad durante todo el ciclo de vida de la distribución. Es la opción recomendada para la mayoría de servidores:
sudo apt update
sudo apt install nginx
El servicio arranca y queda habilitado en el inicio. Compruébalo:
sudo systemctl status nginx --no-pager
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-09-24 10:20:41 UTC; 8s ago
nginx -v
nginx version: nginx/1.24.0 (Ubuntu)
Alternativa: repositorio oficial de nginx.org
Si necesitas una versión más reciente (por ejemplo para usar la directiva http2 on; o HTTP/3), puedes usar el repositorio de nginx.org en lugar del paquete de Ubuntu. Hazlo antes de instalar nginx o desinstala primero el paquete de Ubuntu.
sudo apt install curl gnupg2 ca-certificates lsb-release
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/nginx.gpg
echo "deb [signed-by=/etc/apt/keyrings/nginx.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx
sudo systemctl enable --now nginx
Importanteel paquete de nginx.org no usa
sites-availablenisites-enabled. Sus sitios se definen en/etc/nginx/conf.d/*.conf, trabaja con el usuarionginxen lugar dewww-datay no registra perfiles en UFW. El resto de esta guía usa el paquete de Ubuntu.
Paso 2: Abrir el firewall
Nginx registra tres perfiles de UFW: Nginx HTTP (puerto 80), Nginx HTTPS (443) y Nginx Full (ambos). Permite los dos puertos:
sudo ufw allow 'Nginx Full'
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
Comprueba que el servidor responde:
curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/html
Desde el navegador, http://your_server_ip muestra la página "Welcome to nginx!".
Paso 3: Conocer la estructura de configuración
| Ruta | Contenido |
|---|---|
/etc/nginx/nginx.conf | Configuración global: procesos, bloque http, includes |
/etc/nginx/sites-available/ | Un archivo por sitio (server block) |
/etc/nginx/sites-enabled/ | Enlaces simbólicos a los sitios activos |
/etc/nginx/conf.d/ | Fragmentos que se cargan dentro del bloque http |
/etc/nginx/snippets/ | Fragmentos reutilizables, como fastcgi-php.conf |
/var/www/html/ | Raíz web del sitio por defecto |
/var/log/nginx/ | access.log y error.log |
La configuración de Nginx se organiza en contextos anidados: main (el nivel superior de nginx.conf), events, http, server (un sitio) y location (una ruta dentro del sitio). Una directiva definida en http se hereda en todos los server salvo que la redefinas.
Paso 4: Ajustar la configuración global
Abre el archivo principal:
sudo nano /etc/nginx/nginx.conf
Los valores de Ubuntu ya son razonables: worker_processes auto; crea un proceso por núcleo de CPU y worker_connections 768; limita las conexiones por proceso. Dentro del bloque http { ... }, cambia o añade estas directivas:
server_tokens off;
client_max_body_size 20m;
server_names_hash_bucket_size 64;
server_tokens off;oculta la versión en la cabeceraServery en las páginas de error.client_max_body_sizesube el límite de subida por defecto (1 MB), que provoca errores 413 en formularios con archivos.server_names_hash_bucket_size 64;evita el errorcould not build server_names_hashcon nombres de dominio largos. En Ubuntu ya aparece comentada: basta con quitar el#.
En el mismo bloque http, Ubuntu trae gzip on; pero con el resto de opciones comentadas, así que solo comprime HTML. Descomenta o añade estas líneas para comprimir también CSS, JavaScript, JSON y SVG:
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;
Guarda, comprueba la sintaxis y recarga:
sudo nginx -t
sudo systemctl reload nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Consejousa siempre
reloaden lugar derestarttras cambiar la configuración. Nginx arranca procesos nuevos con la configuración nueva y deja terminar las conexiones abiertas, sin cortar el servicio. Si la sintaxis es incorrecta, sigue funcionando con la anterior.
Paso 5: Crear un server block para tu dominio
Crea el directorio del sitio con una página de prueba:
sudo mkdir -p /var/www/your_domain/html
sudo chown -R $USER:$USER /var/www/your_domain
nano /var/www/your_domain/html/index.html
<!DOCTYPE html>
<html lang="es">
<head><meta charset="utf-8"><title>your_domain</title></head>
<body><h1>El server block de your_domain funciona</h1></body>
</html>
Crea el archivo del sitio:
sudo nano /etc/nginx/sites-available/your_domain
server {
listen 80;
listen [::]:80;
server_name your_domain www.your_domain;
root /var/www/your_domain/html;
index index.html;
access_log /var/log/nginx/your_domain.access.log;
error_log /var/log/nginx/your_domain.error.log;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
try_files $uri $uri/ =404;
}
location ~ /\.(?!well-known) {
deny all;
}
location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|woff2)$ {
expires 30d;
access_log off;
}
}
Qué hace cada parte:
try_filesbusca el archivo o directorio pedido y devuelve 404 si no existe.- La
locationcon/\.bloquea archivos ocultos como.gito.env, pero deja pasar/.well-known/, que Let's Encrypt necesita. - La última
locationindica al navegador que guarde en caché los recursos estáticos durante 30 días.
Nota
add_headersolo se hereda si el bloque hijo no define ningúnadd_headerpropio. Si añades uno dentro de unalocation, repite en ella las cabeceras de seguridad.
Activa el sitio con un enlace simbólico, desactiva el sitio por defecto y recarga:
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Comprueba la respuesta aunque el DNS no haya propagado todavía:
curl -i --resolve your_domain:80:127.0.0.1 http://your_domain
HTTP/1.1 200 OK
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
<h1>El server block de your_domain funciona</h1>
La cabecera Server ya no muestra la versión gracias a server_tokens off;.
Paso 6: Limitar la tasa de peticiones (opcional)
Si el sitio tiene un formulario de login o una API, limitar las peticiones por IP frena los ataques de fuerza bruta. Define una zona compartida en el contexto http creando un archivo en conf.d:
sudo nano /etc/nginx/conf.d/ratelimit.conf
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
Aplica el límite solo a la ruta sensible dentro del server block de your_domain:
location = /login {
limit_req zone=login burst=5 nodelay;
limit_req_status 429;
try_files $uri $uri/ =404;
}
Sustituye try_files por lo que sirva realmente esa ruta en tu sitio (por ejemplo un proxy_pass o fastcgi_pass). Tras sudo nginx -t y sudo systemctl reload nginx, las peticiones que superen 5 por minuto (más una ráfaga de 5) recibirán un 429 Too Many Requests.
Paso 7: Añadir HTTPS con Let's Encrypt
Instala Certbot y su plugin para Nginx:
sudo apt install certbot python3-certbot-nginx
Solicita el certificado. Certbot localiza el server block por server_name, añade la configuración TLS y crea la redirección de HTTP a HTTPS:
sudo certbot --nginx -d your_domain -d www.your_domain
Comprueba la redirección y el acceso por HTTPS:
curl -I http://your_domain
curl -I https://your_domain
HTTP/1.1 301 Moved Permanently
Location: https://your_domain/
HTTP/1.1 200 OK
Server: nginx
El temporizador certbot.timer renueva el certificado antes de que caduque. Simula una renovación para confirmar que funcionará:
sudo certbot renew --dry-run
Paso 8: Revisar los logs
Sigue las peticiones del sitio en tiempo real:
sudo tail -f /var/log/nginx/your_domain.access.log
Consulta los errores recientes:
sudo tail -n 50 /var/log/nginx/your_domain.error.log
Para ver la configuración completa que Nginx está usando, con todos los include resueltos, ejecuta sudo nginx -T. Es la forma más rápida de encontrar una directiva duplicada.
Solución de problemas
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use): otro servicio, normalmente Apache, ocupa el puerto. Compruébalo con sudo ss -tlnp | grep ':80 ' y detén ese servicio (sudo systemctl disable --now apache2) si no lo necesitas.
conflicting server name "your_domain" on 0.0.0.0:80, ignored: el mismo server_name aparece en dos server blocks activos. Búscalo con grep -r "server_name" /etc/nginx/sites-enabled/ y deja solo uno.
403 Forbidden: no hay archivo índice en el directorio o el usuario www-data no puede leer los archivos. namei -l /var/www/your_domain/html/index.html muestra los permisos de cada directorio de la ruta.
413 Request Entity Too Large: la subida supera client_max_body_size. Súbelo en el bloque http o solo en el server block afectado.
502 Bad Gateway: Nginx no puede conectar con el backend (PHP-FPM o una aplicación en proxy_pass). Comprueba que el servicio está activo y que la ruta del socket o el puerto coinciden; el log de errores indica cuál intentó usar.
Conclusión
Has instalado Nginx en Ubuntu 24.04, abierto el firewall, ajustado la configuración global, publicado un sitio con compresión, caché de estáticos y cabeceras de seguridad, y activado HTTPS con renovación automática. Como siguientes pasos puedes:
- Alojar varios dominios en el mismo servidor siguiendo la guía de server blocks en Nginx.
- Instalar PHP-FPM (
php8.3-fpm) para servir aplicaciones PHP. - Usar Nginx como proxy inverso delante de una aplicación Node.js, Python o un contenedor Docker.
