Cheatsheet de Nginx: comandos, fragmentos de configuración y solución de errores
Referencia rápida para las operaciones diarias de Nginx en Debian 12 y Ubuntu 24.04. Organizada por tarea para encontrar lo que necesitas rápido. Para una guía completa, consulta Administración de Nginx en un VPS.
¿Cómo gestiono el servicio Nginx?
Usa systemctl para controlar Nginx a través de systemd, o envía señales directamente con nginx -s. Systemctl es el estándar en sistemas Debian y Ubuntu modernos. Los comandos nativos nginx -s se comunican directamente con el proceso maestro a través de su archivo PID. Ambos funcionan. Systemctl es mejor para automatización y persistencia en el arranque.
Correspondencia de señales y comandos
| Acción | Comando systemctl | Equivalente nginx -s | Señal Unix | Efecto en los workers |
|---|---|---|---|---|
| Iniciar | sudo systemctl start nginx |
(no aplica) | - | El maestro inicia y genera workers |
| Detener (graceful) | sudo systemctl stop nginx |
sudo nginx -s quit |
SIGQUIT | Los workers terminan las peticiones en curso y luego se detienen |
| Detener (inmediato) | sudo systemctl kill nginx |
sudo nginx -s stop |
SIGTERM | Los workers cortan las conexiones y se detienen |
| Recargar config | sudo systemctl reload nginx |
sudo nginx -s reload |
SIGHUP | Se generan nuevos workers con la nueva config. Los antiguos terminan sus peticiones y luego se detienen. Sin conexiones perdidas. |
| Reabrir logs | (no integrado) | sudo nginx -s reopen |
SIGUSR1 | Los workers reabren los descriptores de archivo de logs. Usar después de la rotación de logs. |
| Activar en arranque + iniciar | sudo systemctl enable --now nginx |
(no aplica) | - | Crea el enlace simbólico para el arranque, inicia inmediatamente |
| Desactivar + detener | sudo systemctl disable --now nginx |
(no aplica) | - | Elimina el enlace simbólico del arranque, detiene inmediatamente |
enable --now hace que Nginx sobreviva a los reinicios y lo inicia inmediatamente. Prefiere siempre este comando a un simple start.
Reload vs restart
reload envía SIGHUP. El proceso maestro lee la nueva config, genera nuevos workers y deja que los antiguos terminen sus conexiones activas. Cero tiempo de inactividad.
restart envía SIGTERM (detener), luego inicia de nuevo. Todas las conexiones activas se cortan. Usa restart solo para cambiar puertos de escucha, cargar nuevos módulos o actualizar el binario de Nginx.
Prueba siempre antes de recargar:
sudo nginx -t && sudo systemctl reload nginx
Si nginx -t falla, la recarga no se ejecuta. Tu config en producción queda intacta.
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Después de la recarga:
sudo systemctl status nginx
● 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-03-20 10:15:32 UTC; 2s ago
El enabled en la línea Loaded significa que se iniciará en el arranque. Instalar Nginx en Debian 12 y Ubuntu 24.04 desde el repositorio oficial
¿Cómo pruebo e inspecciono la configuración de Nginx?
Ejecuta nginx -t para validar la sintaxis sin tocar el servidor en ejecución. Ejecuta nginx -T para validar y volcar la config completa analizada en stdout. Ejecuta nginx -V para ver los módulos y flags de compilación.
| Comando | Propósito |
|---|---|
sudo nginx -t |
Probar la sintaxis de la config, verificar que los archivos referenciados existen |
sudo nginx -t -q |
Misma prueba, suprime la salida no-error (útil en scripts) |
sudo nginx -T |
Prueba + volcado de la config completa analizada en stdout |
sudo nginx -V |
Muestra versión, compilador, argumentos de configure, módulos integrados |
sudo nginx -v |
Muestra solo el número de versión |
Volcar y buscar en la config activa
sudo nginx -T 2>/dev/null | grep -A5 "server_name example.com"
Este comando muestra la config completa (todos los archivos incluidos fusionados) y filtra un bloque server específico. Más rápido que abrir archivos manualmente cuando tienes decenas de includes.
Comprobar qué módulos están compilados
sudo nginx -V 2>&1 | tr ' ' '\n' | grep module
--with-http_ssl_module
--with-http_v2_module
--with-http_realip_module
--with-http_gzip_static_module
--with-http_stub_status_module
No puedes usar una directiva si su módulo no está compilado. Es lo primero que debes comprobar cuando una directiva causa errores de "unknown directive".
¿Dónde están los archivos de configuración y logs de Nginx?
En Debian 12 y Ubuntu 24.04, el gestor de paquetes instala todo bajo /etc/nginx/. Los logs van a /var/log/nginx/. Esta es la estructura completa.
| Ruta | Propósito |
|---|---|
/etc/nginx/nginx.conf |
Config principal. Define el número de workers, events, bloque http, includes |
/etc/nginx/sites-available/ |
Archivos de bloques server (disponibles pero no necesariamente activos) |
/etc/nginx/sites-enabled/ |
Enlaces simbólicos a sites-available. Nginx carga estos. |
/etc/nginx/conf.d/ |
Fragmentos de config adicionales. Cargados por el include predeterminado en nginx.conf |
/etc/nginx/snippets/ |
Snippets de config reutilizables (parámetros SSL, cabeceras de seguridad) |
/etc/nginx/mime.types |
Mapeo de tipos MIME |
/var/log/nginx/access.log |
Log de peticiones |
/var/log/nginx/error.log |
Log de errores |
/run/nginx.pid |
Archivo PID del proceso maestro |
Para activar un sitio:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Para desactivar un sitio:
sudo rm /etc/nginx/sites-enabled/example.com
sudo nginx -t && sudo systemctl reload nginx
Para una explicación detallada de la estructura de directorios, consulta Estructura de los archivos de configuración de Nginx.
¿Cuáles son los snippets de configuración Nginx más comunes?
Cada snippet a continuación es un ejemplo mínimo funcional. Copia, adapta los valores, prueba con nginx -t, recarga. Para guías completas de cada tema, sigue los enlaces internos.
¿Cómo configuro un bloque server básico?
Un bloque server (host virtual) asocia un dominio a un directorio raíz. Coloca esto en /etc/nginx/sites-available/example.com.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html;
server_tokens off;
location / {
try_files $uri $uri/ =404;
}
}
server_tokens off oculta la versión de Nginx en las cabeceras de respuesta. Revelar la versión ayuda a los atacantes a explotar vulnerabilidades conocidas.
Crea un enlace simbólico en sites-enabled y recarga. Server Blocks de Nginx: Aloja Varios Dominios en un VPS
¿Cómo redirijo HTTP a HTTPS?
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
return 301 es más rápido que rewrite para redirecciones de URL completas. Nginx procesa return antes de tocar el sistema de archivos.
¿Cómo configuro Nginx como reverse proxy?
Reenvía peticiones a un backend en el puerto 3000. Coloca esto en el bloque server HTTPS.
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;
}
La barra final importa. proxy_pass http://127.0.0.1:3000; (sin barra final) pasa la URI original completa. proxy_pass http://127.0.0.1:3000/; (con barra final) elimina el prefijo del location. Esta es la causa de muchas configuraciones proxy rotas.
Cómo configurar Nginx como reverse proxy
¿Cómo activo la compresión gzip?
Añade al bloque http {} en /etc/nginx/nginx.conf o en un archivo snippet:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types
text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml;
gzip_min_length 1024 omite archivos menores de 1 KB. Comprimir archivos pequeños añade carga de CPU sin reducción de tamaño significativa. gzip_comp_level 5 ofrece un buen equilibrio entre ratio de compresión y coste de CPU. Por encima de 6 los beneficios son marginales.
Optimización del rendimiento de Nginx en un VPS
¿Cómo añado limitación de velocidad?
Define una zona en el bloque http {} y aplícala en un bloque location o server.
# In http {} block
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
# In server or location block
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://127.0.0.1:8080;
}
$binary_remote_addr usa 4 bytes por dirección IPv4. Una zona de 10 MB alberga unas 160.000 direcciones. burst=20 permite picos cortos. nodelay sirve las peticiones en ráfaga inmediatamente en lugar de ponerlas en cola.
Limitación de tasa en Nginx y protección contra DDoS
¿Cómo hago proxy de conexiones WebSocket?
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
proxy_http_version 1.1 es obligatorio. HTTP/1.0 no soporta la cabecera Upgrade. proxy_read_timeout 86400s mantiene las conexiones WebSocket inactivas abiertas durante 24 horas en lugar de los 60 segundos predeterminados.
¿Cómo configuro páginas de error personalizadas?
server {
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
root /var/www/errors;
internal;
}
location = /50x.html {
root /var/www/errors;
internal;
}
}
La directiva internal impide el acceso directo a las URL de las páginas de error. Sin ella, los usuarios podrían navegar directamente a /404.html.
¿Cómo añado cabeceras de seguridad?
Crea /etc/nginx/snippets/security-headers.conf:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Inclúyelo en cualquier bloque server:
include snippets/security-headers.conf;
El parámetro always añade las cabeceras incluso en respuestas de error (4xx, 5xx). Sin él, Nginx solo las añade en 2xx/3xx. Hardening de seguridad de Nginx en Ubuntu y Debian
Bloque server TLS mínimo
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
server_tokens off;
# ... location blocks
}
No actives TLSv1 ni TLSv1.1. Ambos tienen vulnerabilidades conocidas y son rechazados por los navegadores modernos. Configurar SSL/TLS de Let's Encrypt para Nginx en Debian 12 y Ubuntu 24.04
¿Cómo leo y depuro los logs de Nginx?
Nginx escribe dos logs por defecto: access.log para cada petición y error.log para problemas. Ambos están en /var/log/nginx/.
Seguir los logs en tiempo real
sudo tail -f /var/log/nginx/error.log
O a través de journald:
journalctl -u nginx -f
Niveles de severidad del log de errores
La directiva error_log acepta un nivel. De más a menos detallado:
debug > info > notice > warn > error > crit > alert > emerg
El nivel predeterminado es error. Para activar el log de depuración temporalmente:
error_log /var/log/nginx/error.log debug;
Recarga Nginx. El log de depuración es extremadamente detallado. Desactívalo después de diagnosticar el problema o llenará tu disco.
Formato JSON para el log de acceso
Los logs estructurados son más fáciles de analizar con herramientas como jq, Loki u OpenObserve.
log_format json_combined escape=json
'{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"http_user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.log json_combined;
Kit de herramientas de depuración
| Comando | Qué hace |
|---|---|
curl -I https://example.com |
Muestra solo las cabeceras de respuesta. Comprueba código de estado, versión del servidor, cabeceras de caché. |
curl -v https://example.com 2>&1 | head -30 |
Salida detallada: handshake TLS, cabeceras de petición/respuesta. |
sudo nginx -T 2>/dev/null | grep server_name |
Lista todos los server_name configurados en todos los archivos de config. |
sudo ss -tlnp | grep nginx |
Muestra en qué puertos/direcciones está escuchando Nginx. |
sudo ls -la /var/log/nginx/ |
Comprueba tamaño y permisos de los archivos de log. |
Activar stub_status para monitorización
location /nginx_status {
stub_status;
allow 127.0.0.1;
allow ::1;
deny all;
}
curl http://127.0.0.1/nginx_status
Active connections: 3
server accepts handled requests
1542 1542 4890
Reading: 0 Writing: 1 Waiting: 2
Restringe stub_status a localhost o a la IP de tu herramienta de monitorización. Expone información sobre la carga del servidor.
¿Qué significan los códigos de error de Nginx y cómo los soluciono?
Cuando Nginx devuelve un error HTTP, el error.log indica qué ocurrió. Estos son los códigos más comunes, su significado y cómo solucionarlos.
| Código | Nombre | Mensaje típico en error.log | Causa común | Solución |
|---|---|---|---|---|
| 403 | Forbidden | directory index of "/var/www/html/" is forbidden |
Archivo index faltante, permisos incorrectos, autoindex off (predeterminado) |
Añade un index.html, corrige permisos (chmod 644 para archivos, 755 para directorios), o activa autoindex on |
| 404 | Not Found | open() "/var/www/html/page" failed (2: No such file or directory) |
Ruta root incorrecta, try_files incorrecto, el archivo no existe |
Comprueba la directiva root, verifica la ruta del archivo en disco |
| 413 | Request Entity Too Large | client intended to send too large body |
La subida excede client_max_body_size (predeterminado: 1 MB) |
Establece client_max_body_size 50m; en el bloque server o location |
| 502 | Bad Gateway | connect() failed (111: Connection refused) while connecting to upstream |
Backend no está ejecutándose, puerto/socket incorrecto en proxy_pass |
Inicia el backend, comprueba que el puerto coincide con proxy_pass |
| 503 | Service Unavailable | no live upstreams while connecting to upstream |
Todos los backends en un bloque upstream están caídos |
Inicia al menos un backend, comprueba la config de health check |
| 504 | Gateway Timeout | upstream timed out (110: Connection timed out) while reading response header |
El backend tarda demasiado en responder | Aumenta proxy_read_timeout, optimiza el backend, revisa los logs del backend |
Diagnosticar un 502
El 502 es el error proxy más frecuente. Sigue estos pasos:
# 1. Is the backend running?
sudo ss -tlnp | grep 3000
# 2. Can Nginx reach it?
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/
# 3. What does the error log say?
sudo tail -20 /var/log/nginx/error.log
Si ss no muestra nada en el puerto 3000, el backend está caído. Si curl devuelve una respuesta pero Nginx devuelve 502, comprueba los permisos de los sockets (frecuente con sockets Unix de PHP-FPM o Gunicorn).
¿Cuáles son los errores de Nginx más comunes?
Estos causan la mayoría de los momentos de "cambié la config y ahora está roto".
Puntos y coma faltantes
Cada directiva debe terminar con un punto y coma. Nginx da un error claro:
nginx: [emerg] unexpected "}" in /etc/nginx/sites-enabled/example.com:12
El error señala la línea después del punto y coma faltante, no la línea del problema. Mira una línea arriba.
Confusión entre root y alias
# root: appends the location to the path
location /images/ {
root /var/www;
# serves /var/www/images/photo.jpg
}
# alias: replaces the location with the path
location /images/ {
alias /var/www/media/;
# serves /var/www/media/photo.jpg
}
Con alias, la barra final es obligatoria tanto en el location como en la ruta del alias. Omitirla causa 404 sin razón aparente en el log de errores.
Confusión en el orden de evaluación de location
Nginx evalúa las locations en este orden, independientemente de dónde aparezcan en el archivo de config:
= /exact- Coincidencia exacta. Se comprueba primero. Si coincide, se detiene inmediatamente.^~ /prefix- Prefijo preferente. La coincidencia más larga gana. Si coincide, se omiten todas las regex.~ regex- Regex sensible a mayúsculas. Evaluada de arriba a abajo. La primera coincidencia gana.~* regex- Regex insensible a mayúsculas. Mismo orden de arriba a abajo./prefix- Prefijo estándar. La coincidencia más larga gana. Solo se usa si ninguna regex coincidió.
En los prefijos importa la longitud de la coincidencia, no el orden en el archivo. En las regex importa el orden en el archivo, no la longitud. Mezclarlos sin entender esto crea enrutamiento impredecible.
Barra final en proxy_pass
# No trailing slash: passes /app/foo to backend as /app/foo
location /app/ {
proxy_pass http://127.0.0.1:3000;
}
# Trailing slash: strips /app/ and passes /foo to backend
location /app/ {
proxy_pass http://127.0.0.1:3000/;
}
Elige una opción y sé consistente. La mayoría de los backends esperan la ruta completa (sin barra final en proxy_pass).
Olvidar nginx -t antes de recargar
Si recargas con una config rota, Nginx sigue funcionando con la config anterior y registra un error. No se cae. Pero ahora tienes una config en disco que no coincide con la config en ejecución. Esto genera confusión más adelante.
Crea el hábito: sudo nginx -t && sudo systemctl reload nginx. El && asegura que la recarga solo se ejecuta si la prueba pasa.
Editar sites-available sin crear el enlace simbólico
Los archivos en /etc/nginx/sites-available/ no se cargan automáticamente. Debes crear un enlace simbólico a /etc/nginx/sites-enabled/. Una copia directa también funciona, pero los enlaces simbólicos mantienen una única fuente de verdad.
¿Algo salió mal?
Secuencia de diagnóstico rápido cuando Nginx se comporta de forma extraña:
# Check if Nginx is running
sudo systemctl status nginx
# Test the config
sudo nginx -t
# Check which config is actually loaded
sudo nginx -T 2>/dev/null | head -50
# Check the last 30 error log entries
sudo tail -30 /var/log/nginx/error.log
# Check what ports Nginx is listening on
sudo ss -tlnp | grep nginx
# Check file permissions on the web root
sudo ls -la /var/www/example.com/html/
Si el servicio ha fallado, journalctl -u nginx --no-pager -n 50 da la historia completa. Busca las entradas [emerg].
¿Listo para probarlo?
Despliega tu propio servidor en segundos. Linux, Windows o FreeBSD. →