Nginx SSL/TLS en la práctica: del certificado HTTPS al endurecimiento A+

Sonó la alarma de monitorización. Miré el móvil: el certificado del sitio había caducado — un certificado gratuito de 90 días olvidado por completo. La advertencia roja de «No seguro» en el navegador colgaba en la portada del blog como una bandera burlona.
Tras ese incidente, dediqué una semana a repasar la configuración SSL/TLS de Nginx de arriba abajo. De F en SSL Labs a A+, de renovación manual a totalmente automática, y de cuello de botella de rendimiento a handshake por debajo de 100 ms.
HTTPS no es solo el candado en la barra de direcciones. Google deja claro que HTTPS es un factor de posicionamiento; una configuración correcta puede aumentar el tráfico orgánico entre un 15 y un 20 %. Más importante aún: impide la escucha en mitad de camino. Sin HTTPS, es como gritar la contraseña del banco en público.
Este artículo te guía para configurar HTTPS en Nginx desde cero: solicitud de certificado Let’s Encrypt, endurecimiento TLS 1.3, plantilla para A+ en SSL Labs y renovación automática imprescindible en producción. Toda la configuración se puede copiar y usar directamente.
Capítulo 1: Conceptos básicos de HTTPS y elección del tipo de certificado
1.1 Por qué todo sitio necesita HTTPS
HTTP transmite en texto plano: cada página que visitas y cada formulario que envías viajan desnudos por la red. El WiFi del café, la salida de red de la oficina, el equipo del operador en tu barrio — cualquier nodo intermedio puede ver qué enviaste.
HTTPS añade una capa TLS entre HTTP y TCP. Los datos se cifran al salir y se descifran al llegar; quien intercepte en el camino solo ve ruido.
TLS no solo cifra. También autentica — confirma que accedes al example.com real y no a un sitio de phishing tras un secuestro DNS. Por eso el navegador muestra advertencias rojas con certificados caducados o dominios que no coinciden: te avisa de que «este sitio puede no ser quien dice ser».
1.2 Los tres tipos de certificado SSL: DV, OV y EV
Los certificados se clasifican según el nivel de verificación:
| Tipo | Verificación | Precio | Caso de uso |
|---|---|---|---|
| DV (Domain Validation) | Propiedad del dominio | Gratis - bajo | Blog personal, entorno de pruebas, proyectos pequeños |
| OV (Organization Validation) | Dominio + identidad de la organización | Medio | Web corporativa, producto SaaS |
| EV (Extended Validation) | Verificación de identidad estricta | Alto | Finanzas, pagos, organismos públicos |
Para la mayoría de proyectos personales y equipos pequeños, un certificado DV basta. El DV gratuito de Let’s Encrypt dura 90 días y los navegadores lo confían igual que uno de pago. La única «desventaja» es renovar cada 90 días — con renovación automática, deja de serlo.
OV y EV destacan sobre todo en lo que muestran en la barra de direcciones. EV mostraba el nombre de la empresa (por ejemplo, «Industrial and Commercial Bank of China»), pero los navegadores ya no lo enfatizan tanto; Chrome ni siquiera muestra el nombre por defecto. Sumado a precios de cientos o miles, la relación calidad-precio es baja.
1.3 Let’s Encrypt: la mejor opción gratuita
Let’s Encrypt es una CA sin ánimo de lucro operada por ISRG (Internet Security Research Group). Ventajas principales:
- Totalmente gratuito: certificados DV gratis para siempre
- Automatización: emisión y renovación vía protocolo ACME
- Amplia confianza: todos los navegadores y sistemas operativos principales lo aceptan
- Validez de 90 días: certificados de corta duración más seguros e impulsan la automatización
También tiene límites: solo DV, no OV/EV; los wildcard exigen verificación DNS (un poco más laboriosa). Para el 99 % de proyectos personales y sitios medianos, no son problema.
A continuación usamos Certbot — cliente oficial de Let’s Encrypt — para solicitar el certificado.
Capítulo 2: Solicitud de certificado Let’s Encrypt en la práctica
2.1 Instalar Certbot
La instalación depende del sistema operativo. En Ubuntu es sencilla:
# Ubuntu 20.04+ / Debian 10+
sudo apt update
sudo apt install certbot python3-certbot-nginx
En CentOS/RHEL hay que habilitar antes el repositorio EPEL:
# CentOS 8 / RHEL 8
sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx
Tras instalar, comprueba la versión con certbot --version. Si todo cuadra, el siguiente paso es solicitar el certificado.
2.2 Solicitar el certificado
Certbot admite varios métodos de verificación; los más usados son standalone y webroot. Si Nginx ya está en marcha, conviene webroot:
# Modo webroot: cuando el sitio ya está activo
sudo certbot certonly --webroot -w /var/www/example.com -d example.com -d www.example.com
-w indica la raíz del sitio; -d el dominio. Puedes incluir varios dominios en una sola solicitud.
Si Nginx aún no arranca o pruebas en un servidor temporal, usa standalone:
# Modo standalone: requiere ocupar temporalmente el puerto 80
sudo certbot certonly --standalone -d example.com -d www.example.com
Certbot levanta un servidor HTTP temporal, verifica y lo cierra. Necesitas el puerto 80 libre; si Nginx ya corre, deténlo antes.
También existe el plugin de Nginx, que modifica la configuración automáticamente:
# Modo automático: Certbot ajusta la configuración de Nginx
sudo certbot --nginx -d example.com -d www.example.com
Solicita el certificado, configura HTTPS y la redirección. Útil para empezar rápido; en producción suele preferirse configuración manual para controlar mejor los parámetros SSL.
2.3 Estructura de archivos del certificado
Tras una solicitud correcta, los archivos quedan en /etc/letsencrypt/live/example.com/:
/etc/letsencrypt/live/example.com/
├── cert.pem # Certificado del dominio
├── chain.pem # Cadena de certificados intermedios
├── fullchain.pem # Cadena completa (cert + chain)
└── privkey.pem # Clave privada
Nginx necesita dos archivos: fullchain.pem (ssl_certificate) y privkey.pem (ssl_certificate_key). privkey.pem es sensible; permisos 600 y nunca filtrarlo.
Capítulo 3: Configuración básica SSL en Nginx
3.1 La configuración HTTPS mínima
Con el certificado en mano, toca configurar HTTPS en Nginx. Lo más simple:
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Otras directivas...
root /var/www/example.com;
index index.html;
}
HTTPS funciona, pero apenas alcanzaría una D. No se fijan versiones TLS; por defecto pueden quedar TLS 1.0 y 1.1, ya considerados inseguros.
3.2 Redirigir HTTP a HTTPS
Configurar HTTPS no basta: algunos usuarios entran por HTTP. Hay que redirigir todo a HTTPS:
server {
listen 80;
server_name example.com www.example.com;
# Redirección permanente a HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Otras directivas...
}
return 301 es redirección permanente; el navegador la cachea. La próxima vez que escriban http://, irán directo a https:// sin una petición extra.
3.3 Un error de configuración frecuente
Muchos escriben listen 443 ssl http2;. Desde Nginx 1.25.1, HTTP/2 va en la directiva http2:
# Sintaxis nueva en Nginx 1.25.1+
server {
listen 443 ssl;
http2 on; # Directiva http2 independiente
server_name example.com;
# ...
}
En versiones recientes conviene la sintaxis nueva para evitar avisos. Comprueba con nginx -v.
Capítulo 4: Endurecimiento con TLS 1.3
4.1 Elección de versión TLS
Hay cuatro versiones: 1.0, 1.1, 1.2 y 1.3. La 1.0 y la 1.1 están obsoletas; los navegadores principales dejaron de soportarlas en 2020.
| Versión | Seguridad | Rendimiento | Compatibilidad | Recomendación |
|---|---|---|---|---|
| TLS 1.0 | Insegura | Lenta | Amplia | Deshabilitar |
| TLS 1.1 | Insegura | Lenta | Amplia | Deshabilitar |
| TLS 1.2 | Segura | Media | Casi universal | Mantener |
| TLS 1.3 | Máxima | Más rápida | Navegadores modernos | Obligatorio |
La ventaja clave de TLS 1.3 es el rendimiento: handshake de 2-RTT a 1-RTT, la mitad de latencia teórica. En pruebas reales suele quedar por debajo de 100 ms.
En Nginx se fija con ssl_protocols:
ssl_protocols TLSv1.2 TLSv1.3;
No conviene solo TLS 1.3. En 2026 casi todos los navegadores lo soportan, pero algunos clientes HTTP antiguos (herramientas API, dispositivos embebidos) pueden no hacerlo. Mantener TLS 1.2 como respaldo es más prudente.
4.2 Configuración de Cipher Suite
El Cipher Suite define algoritmos de cifrado, intercambio de claves y MAC. Una mala elección deja HTTPS casi inútil.
Lista recomendada para TLS 1.3 en 2026:
ssl_protocols TLSv1.2 TLSv1.3;
# Ciphers TLS 1.3 (Nginx usa la lista por defecto de OpenSSL)
# Esta línea puede omitirse
ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
# Ciphers TLS 1.2 (compatibilidad hacia atrás)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
# Priorizar ciphers del servidor
ssl_prefer_server_ciphers on;
Puntos clave:
- ECDHE: intercambio elíptico, más seguro y rápido que RSA
- AES-GCM: cifrado autenticado, más seguro que CBC
- CHACHA20-POLY1305: mejor en móviles sin aceleración AES por hardware
Si dudas, genera configuración con Mozilla SSL Configuration Generator: https://ssl-config.mozilla.org/
4.3 HSTS: forzar acceso HTTPS
HSTS (HTTP Strict Transport Security) indica al navegador: «este sitio solo acepta HTTPS». Aunque el usuario escriba http://, el navegador redirige localmente a https:// sin una petición de red.
# Cabecera HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Parámetros:
max-age=31536000: validez de 1 año (segundos)includeSubDomains: incluye todos los subdominiospreload: entrada en HSTS Preload List (requiere envío en hstspreload.org)
Atención: HSTS se cachea mucho tiempo. Si aún pruebas HTTP, no uses preload de entrada o acorta max-age.
Capítulo 5: Optimización del rendimiento SSL
5.1 SSL Session Cache
Cada handshake TLS implica intercambio de claves y verificación del certificado. Session Cache permite reutilizar sesiones durante un tiempo y evitar el handshake completo.
# Configuración Session Cache
ssl_session_cache shared:SSL:10m; # 10 MB, ~40 000 sesiones
ssl_session_timeout 1d; # Validez de sesión 1 día
ssl_session_tickets off; # Desactivar Session Ticket (más seguro)
shared:SSL:10m es una zona compartida entre workers. ~4000 sesiones por MB; 10 MB bastan para sitios medianos.
ssl_session_tickets off por seguridad: Session Ticket cifra tickets con una clave del servidor; si se filtra, podrían descifrarse sesiones antiguas. Desactivarlo aumenta carga pero mejora la seguridad en entornos exigentes.
5.2 OCSP Stapling
Al validar un certificado, el navegador comprueba si fue revocado. Lo clásico es una consulta OCSP al CA, con petición extra y exposición de qué sitios visitas.
OCSP Stapling hace que el servidor consulte OCSP, cachee el resultado y lo envíe al cliente. Más privacidad y menos latencia.
# Configuración OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
resolver indica servidores DNS para resolver el host OCSP. 8.8.8.8 y 8.8.4.4 de Google son habituales.
Tras configurar, prueba con OpenSSL:
openssl s_client -connect example.com:443 -status < /dev/null 2>&1 | grep -A 17 "OCSP response"
Si aparece «OCSP Response Status: successful», OCSP Stapling funciona.
5.3 Ajuste de ssl_buffer_size
ssl_buffer_size controla el tamaño del registro TLS. Por defecto 16 KB; para respuestas pequeñas (API, blog) es excesivo y empeora el TTFB.
ssl_buffer_size 4k; # Adecuado para respuestas pequeñas
Para descargas de archivos grandes, mantén 16 KB o sube a 32 KB.
Capítulo 6: Renovación automática del certificado
6.1 Comando de renovación de Certbot
Los certificados Let’s Encrypt duran 90 días; hay que renovarlos. Certbot ofrece renew:
# Probar renovación (sin renovar de verdad)
sudo certbot renew --dry-run
# Renovación real
sudo certbot renew
renew revisa la caducidad y solo renueva si quedan menos de 30 días. Puedes ejecutarlo a diario sin gastar cuota de rate limit innecesariamente.
6.2 Tarea programada con crontab
Lo más fiable es crontab:
# Editar crontab de root
sudo crontab -e
Añade estas líneas:
# Comprobación a las 3:00 y a las 15:00 cada día
0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
0 15 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
--quiet reduce salida. --post-hook "systemctl reload nginx" recarga Nginx tras renovar para aplicar el certificado nuevo.
¿Por qué dos veces al día? A veces falla la renovación (DNS temporal, etc.); más comprobaciones aumentan las probabilidades de éxito.
6.3 Prueba de renovación y resolución de problemas
Los fallos quedan en /var/log/letsencrypt/letsencrypt.log. Problemas habituales:
- Puerto ocupado: standalone necesita el 80 libre
- DNS incorrecto: comprueba que el dominio apunta al servidor
- Rate limit: máximo 5 solicitudes del mismo certificado por semana; usa
--dry-runen pruebas - Permisos: Certbot debe leer/escribir en
/etc/letsencrypt/
Flujo de prueba completo:
# 1. dry-run
sudo certbot renew --dry-run
# 2. Si ok, renovación real
sudo certbot renew
# 3. Comprobar validez
sudo certbot certificates
# 4. Recargar Nginx
sudo systemctl reload nginx
Plantilla de configuración completa
Plantilla lista para producción con puntuación A+ en SSL Labs:
# Redirección HTTP
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
# Servicio HTTPS
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
# Certificados
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Versiones TLS
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher Suite
ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers on;
# Cabeceras de seguridad
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
# Session Cache
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Rendimiento
ssl_buffer_size 4k;
# Sitio
root /var/www/example.com;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
Tras configurar, prueba en SSL Labs: https://www.ssllabs.com/ssltest/
Resumen
Configurar HTTPS es fácil al principio — unas líneas y funciona. Llegar a A+ en SSL Labs equilibrando rendimiento y compatibilidad exige entender TLS, Cipher Suite, Session Cache y OCSP Stapling.
Puntos clave:
- Certificado: Let’s Encrypt gratuito; Certbot automatiza
- Versiones TLS: TLS 1.2 + 1.3; deshabilitar 1.0 y 1.1
- Cipher Suite: priorizar ECDHE y AES-GCM; incluir CHACHA20
- HSTS: forzar HTTPS y reducir redirecciones
- Rendimiento: Session Cache y OCSP Stapling imprescindibles
- Renovación: crontab doble y recarga automática de Nginx
Copia la plantilla, ajusta dominio y rutas de certificado y listo. Después prueba en SSL Labs y cuéntame el resultado en comentarios — apuesto a A+.
Configurar Nginx SSL/TLS para obtener A+ en seguridad
Flujo completo desde la solicitud del certificado hasta el endurecimiento de seguridad
⏱️ Estimated time: 30 min
- 1
Step 1: Instalar Certbot y solicitar el certificado
Usa Certbot para solicitar un certificado SSL gratuito de Let's Encrypt:
• Ubuntu/Debian: sudo apt install certbot python3-certbot-nginx
• CentOS/RHEL: sudo dnf install certbot python3-certbot-nginx
• Solicitar certificado: sudo certbot certonly --webroot -w /var/www/example.com -d example.com
• Directorio de certificados: /etc/letsencrypt/live/example.com/
• Necesitas dos archivos: fullchain.pem y privkey.pem - 2
Step 2: Configurar HTTPS básico en Nginx
Añade el certificado SSL y la redirección HTTP en la configuración de Nginx:
• listen 443 ssl; para escuchar HTTPS
• http2 on; para habilitar HTTP/2 (Nginx 1.25.1+)
• ssl_certificate apunta a fullchain.pem
• ssl_certificate_key apunta a privkey.pem
• return 301 https://$server_name$request_uri; redirige HTTP a HTTPS - 3
Step 3: Configurar TLS 1.3 y Cipher Suite
Habilita versiones TLS seguras y suites de cifrado:
• ssl_protocols TLSv1.2 TLSv1.3; deshabilita versiones antiguas
• ssl_ciphers configura ECDHE + AES-GCM + CHACHA20
• ssl_prefer_server_ciphers on; prioriza la selección del servidor
• add_header Strict-Transport-Security habilita HSTS - 4
Step 4: Optimizar el rendimiento SSL
Configura Session Cache y OCSP Stapling para mejorar el rendimiento:
• ssl_session_cache shared:SSL:10m; caché de sesiones compartida
• ssl_session_timeout 1d; validez de sesión de 1 día
• ssl_stapling on; habilita OCSP Stapling
• ssl_buffer_size 4k; optimizado para respuestas pequeñas - 5
Step 5: Configurar la renovación automática del certificado
Usa crontab para configurar la renovación automática con Certbot:
• sudo crontab -e para editar la tarea programada
• 0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
• Comprobación dos veces al día (madrugada y tarde)
• --post-hook recarga Nginx tras renovar el certificado - 6
Step 6: Probar la seguridad de la configuración SSL
Verifica que la configuración alcance A+:
• Visita https://www.ssllabs.com/ssltest/ para probar la configuración SSL
• Usa openssl s_client -connect example.com:443 -status para probar OCSP
• Comprueba certbot certificates para confirmar la validez del certificado
• Asegúrate de que HSTS, OCSP Stapling y Session Cache estén activos
FAQ
¿Cuánto dura un certificado de Let's Encrypt? ¿Hay que renovarlo manualmente?
¿Cómo probar la seguridad de la configuración SSL en Nginx?
• A+ es la puntuación máxima e indica configuración segura y buen rendimiento
• También puedes probar OCSP Stapling en local con openssl s_client
• Comando de prueba: openssl s_client -connect example.com:443 -status
¿HTTPS afecta al rendimiento del sitio? ¿Cómo optimizarlo?
• TLS 1.3 reduce el handshake de 2-RTT a 1-RTT, la mitad de latencia
• Session Cache permite reutilizar sesiones y evitar el handshake completo
• OCSP Stapling reduce las peticiones de verificación del certificado
• Tras optimizar, el handshake puede mantenerse por debajo de 100 ms
¿Qué hacer si falla la renovación del certificado? ¿Cómo diagnosticarlo?
• Puerto ocupado: el modo standalone requiere el puerto 80 libre
• Fallo de resolución DNS: comprueba que el dominio apunta a la IP del servidor
• Límite de tasa: Let's Encrypt permite como máximo 5 solicitudes del mismo certificado por semana
• Revisa el log: /var/log/letsencrypt/letsencrypt.log
¿Qué diferencia hay entre TLS 1.2 y TLS 1.3? ¿Por qué habilitar ambos?
• Rendimiento: handshake de 2-RTT a 1-RTT, la mitad de latencia
• Seguridad: elimina algoritmos de cifrado inseguros
• Compatibilidad: habilitar ambos permite soportar clientes antiguos; TLS 1.2 actúa como opción de compatibilidad
¿Qué hay que tener en cuenta al configurar HSTS?
• max-age se recomienda en 31536000 (1 año)
• includeSubDomains afecta a todos los subdominios
• preload requiere envío en hstspreload.org para surtir efecto
• En la primera configuración conviene un max-age corto para probar antes de alargarlo
¿Cómo elegir el tipo de certificado SSL? ¿Qué diferencia hay entre DV, OV y EV?
• DV: gratuito, valida la propiedad del dominio, ideal para blogs personales y proyectos pequeños
• OV: valida la identidad de la organización, muestra datos de la empresa, adecuado para sitios corporativos
• EV: validación estricta, Chrome ya no muestra el nombre de la empresa, poca relación calidad-precio
• En el 99% de los casos se recomienda el certificado DV gratuito de Let's Encrypt
11 min de lectura · Publicado el: 20 abr 2026 · Actualizado el: 21 ago 2026
Guía práctica de Nginx
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Ajuste de rendimiento en Nginx: gzip, caché y pool de conexiones
Guía detallada de la configuración clave para optimizar el rendimiento de Nginx: compresión gzip que reduce el volumen de transferencia un 60-80 %, estrategia proxy_cache con hasta 95 % de aciertos y pool de conexiones worker_connections que multiplica la concurrencia por 3-4
Parte 2 de 6
Siguiente
Balanceo de carga con Nginx en la práctica: configuración upstream y comprobaciones de salud
Guía detallada de la configuración de balanceo de carga upstream en Nginx: asignación por pesos, cinco estrategias, comprobaciones de salud pasivas y activas, y buenas prácticas de seguridad en producción
Parte 4 de 6



Comentarios
Inicia sesión con GitHub para dejar un comentario