Tus aplicaciones no deberían estar expuestas directamente a internet. Un servidor Node.js escuchando en el puerto 3000, un ERP en el 8069, una API en el 8080 — cada uno con su puerto abierto al mundo, sin SSL, sin protección. Nginx como reverse proxy resuelve todo eso: un solo punto de entrada con HTTPS, certificados gratuitos que se renuevan solos y la capacidad de manejar múltiples aplicaciones bajo diferentes dominios o rutas.
En esta guía vas a configurar Nginx como reverse proxy con SSL de Let's Encrypt para exponer una o varias aplicaciones web de forma segura.
Requisitos previos
Un servidor Ubuntu 24.04 con IP pública, un dominio que apunte a esa IP (registro DNS tipo A) y tus aplicaciones corriendo en puertos internos. Tu firewall UFW debe permitir los puertos 80 y 443.
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
Paso 1: Instalar Nginx
sudo apt update
sudo apt install nginx -y
sudo systemctl enable --now nginx
Verifica accediendo a http://tu-ip-publica — deberías ver la página por defecto de Nginx.
Paso 2: Configurar el reverse proxy
Supongamos que tienes una aplicación corriendo en localhost:3000 y quieres exponerla en app.tuempresa.com con HTTPS.
Crea el archivo de configuración del sitio:
sudo tee /etc/nginx/sites-available/app.tuempresa.com > /dev/null <<'EOF'
server {
listen 80;
server_name app.tuempresa.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
# Headers esenciales para que la app sepa quién es el cliente real
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;
# WebSocket support (necesario para apps en tiempo real)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts para aplicaciones que procesan peticiones largas
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
EOF
Habilita el sitio y verifica la configuración:
sudo ln -s /etc/nginx/sites-available/app.tuempresa.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
¿Por qué proxy_set_header?
Sin estos headers, tu aplicación ve todas las peticiones como si vinieran de 127.0.0.1 (Nginx). Con X-Real-IP y X-Forwarded-For, la aplicación conoce la IP real del cliente — esencial para logs, rate limiting y geolocalización.
En este punto, http://app.tuempresa.com ya muestra tu aplicación. Pero sin SSL — vamos a arreglar eso.
Paso 3: Instalar Certbot y obtener certificado SSL
Certbot es la herramienta oficial de Let's Encrypt para obtener y renovar certificados SSL automáticamente:
sudo apt install certbot python3-certbot-nginx -y
Obtén el certificado — Certbot configura Nginx automáticamente:
sudo certbot --nginx -d app.tuempresa.com
Certbot te pide:
- Email para notificaciones de renovación
- Aceptar los términos de servicio
- Si quieres redirigir HTTP a HTTPS automáticamente — di que sí
En 30 segundos tienes HTTPS funcionando. Verifica en https://app.tuempresa.com.
¿Qué hizo Certbot?
Certbot modificó tu archivo de configuración de Nginx agregando las directivas de SSL y una redirección automática de HTTP a HTTPS. Si abres el archivo verás algo como:
server {
server_name app.tuempresa.com;
location / {
proxy_pass http://localhost:3000;
# ... (tus headers originales)
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/app.tuempresa.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.tuempresa.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = app.tuempresa.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name app.tuempresa.com;
return 404;
}
Renovación automática
Certbot instala un timer de systemd que verifica los certificados dos veces al día y los renueva automáticamente antes de que expiren (cada 90 días):
# Verificar que el timer está activo
sudo systemctl status certbot.timer
# Probar renovación en seco
sudo certbot renew --dry-run
Si la prueba pasa, no tienes que hacer nada más — el certificado se renueva solo para siempre.
Paso 4: Múltiples aplicaciones en el mismo servidor
La verdadera potencia del reverse proxy aparece cuando tienes varias aplicaciones en el mismo servidor, cada una con su dominio y SSL:
# ERP en erp.tuempresa.com → localhost:8069
sudo tee /etc/nginx/sites-available/erp.tuempresa.com > /dev/null <<'EOF'
server {
listen 80;
server_name erp.tuempresa.com;
client_max_body_size 100M; # ERP sube archivos grandes
location / {
proxy_pass http://localhost:8069;
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;
}
# Longpolling (necesario para Odoo/ERP)
location /longpolling {
proxy_pass http://localhost:8072;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
EOF
# Grafana en monitor.tuempresa.com → localhost:3000
sudo tee /etc/nginx/sites-available/monitor.tuempresa.com > /dev/null <<'EOF'
server {
listen 80;
server_name monitor.tuempresa.com;
location / {
proxy_pass http://localhost: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;
}
location /api/live/ws {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
Habilita los sitios y obtén certificados para todos de una vez:
sudo ln -s /etc/nginx/sites-available/erp.tuempresa.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/monitor.tuempresa.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
# Certificados para todos los dominios
sudo certbot --nginx -d erp.tuempresa.com -d monitor.tuempresa.com
Paso 5: Optimización para producción
La configuración por defecto de Nginx es conservadora. Para producción, agrega estas optimizaciones al bloque http de /etc/nginx/nginx.conf:
http {
# --- Rendimiento ---
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# --- Compresión Gzip ---
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/json
application/javascript
application/xml
image/svg+xml;
# --- Seguridad ---
server_tokens off; # No revelar versión de Nginx
# --- Buffers ---
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# --- Límites ---
client_max_body_size 50M; # Tamaño máximo de upload
}
Paso 6: Headers de seguridad
Agrega headers de seguridad que protegen a los usuarios de ataques comunes. Puedes agregarlos en la configuración global o por sitio:
# Dentro del bloque server { } o en un archivo incluido
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# HSTS — fuerza HTTPS por 1 año (activar solo si estás seguro de usar HTTPS siempre)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Verifica tu configuración de SSL en SSL Labs — con Let's Encrypt y estos headers deberías obtener calificación A o A+.
Paso 7: Balanceo de carga
Si tu aplicación tiene múltiples réplicas (por ejemplo, con Docker Compose), Nginx puede distribuir el tráfico entre ellas:
upstream app_backend {
# Round-robin por defecto
server localhost:3001;
server localhost:3002;
server localhost:3003;
# Alternativas:
# least_conn; # Envía al servidor con menos conexiones activas
# ip_hash; # Mismo cliente siempre al mismo servidor (sticky sessions)
}
server {
listen 443 ssl;
server_name app.tuempresa.com;
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;
}
# SSL config...
}
Si una réplica falla, Nginx la detecta automáticamente y deja de enviarle tráfico hasta que se recupere.
Caché de contenido estático
Para aplicaciones que sirven archivos estáticos (imágenes, CSS, JS), configura Nginx para cachearlos y servirlos directamente sin pasar por la aplicación:
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
proxy_pass http://localhost:3000;
proxy_cache_valid 200 7d;
expires 7d;
add_header Cache-Control "public, immutable";
access_log off;
}
Debugging y logs
Cuando algo no funciona, los logs son tu mejor herramienta:
# Logs de acceso
sudo tail -f /var/log/nginx/access.log
# Logs de error
sudo tail -f /var/log/nginx/error.log
# Logs por sitio (si los configuras)
access_log /var/log/nginx/app.tuempresa.com.access.log;
error_log /var/log/nginx/app.tuempresa.com.error.log;
# Verificar configuración antes de recargar
sudo nginx -t
Siguientes pasos
Con Nginx configurado como reverse proxy con SSL, puedes mejorar la arquitectura:
- Rate limiting — protege tus APIs de abuso con
limit_req_zonede Nginx - WAF (Web Application Firewall) — ModSecurity con Nginx para proteger contra inyección SQL, XSS y OWASP Top 10
- Monitoreo — exporta métricas de Nginx a Prometheus con
nginx-prometheus-exporter - Docker — Nginx como contenedor con Traefik o nginx-proxy para descubrimiento automático de servicios
- Ciberseguridad profesional — auditoría de tu configuración web y hardening completo
Infraestructura web
¿Necesitas ayuda con la arquitectura web de tu aplicación?
Diseñamos e implementamos Nginx, SSL, balanceo de carga y alta disponibilidad para tus aplicaciones empresariales.



