Tutoriales 9 min de lectura

Configurar Nginx como reverse proxy con SSL gratuito

Guía paso a paso para configurar Nginx como proxy inverso con certificados SSL de Let's Encrypt para exponer aplicaciones web de forma segura en producción.

Diagrama de arquitectura mostrando Nginx como reverse proxy con SSL frente a múltiples aplicaciones backend
Diagrama de arquitectura mostrando Nginx como reverse proxy con SSL frente a múltiples aplicaciones backend

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:

  1. Email para notificaciones de renovación
  2. Aceptar los términos de servicio
  3. 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_zone de 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.

Solicitar evaluación

Preguntas frecuentes

Temas relacionados

#nginx#ssl#reverse-proxy#lets-encrypt#linux#tutorial

¿Te fue útil? Compártelo

Artículos relacionados

Ver todos

Consultoría gratuita

¿Necesitas ayuda con la arquitectura web de tu aplicación?

Diseñamos e implementamos la infraestructura web de tu aplicación — Nginx, SSL, balanceo de carga y alta disponibilidad.

Solicitar evaluación