TLS y HTTP/2
TLS cifra el trafico entre cliente y Nginx. HTTP/2 multiplexa peticiones sobre una conexion TLS y mejora latencia percibida. En la mayoria de despliegues, Nginx termina TLS y habla HTTP claro con backends locales.
Flujo TLS
Cliente --TLS--> Nginx:443 --HTTP--> 127.0.0.1:3000
|
+-- certificado + clave privadaEl certificado acredita el dominio; la clave privada debe quedar solo en el servidor (permisos 600, root).
Certificado de prueba (lab)
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/lab.key \
-out /etc/nginx/ssl/lab.crt \
-subj "/CN=app.local"
sudo chmod 600 /etc/nginx/ssl/lab.keySolo para laboratorio: el navegador marcara el cert como no confiable.
Server block HTTPS
server {
listen 80;
listen [::]:80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name app.example.com;
ssl_certificate /etc/nginx/ssl/lab.crt;
ssl_certificate_key /etc/nginx/ssl/lab.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}En Nginx >= 1.25.1, http2 es directiva independiente (http2 on). En versiones anteriores se usaba listen 443 ssl http2;.
sudo nginx -t && sudo systemctl reload nginx
curl -Ik https://127.0.0.1/ -H 'Host: app.example.com' --resolve app.example.com:443:127.0.0.1Let's Encrypt con Certbot
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.comCertbot crea/ajusta server blocks y programa renovacion. Comprueba:
sudo certbot renew --dry-run
systemctl list-timers | grep certbotRutas tipicas:
/etc/letsencrypt/live/app.example.com/fullchain.pem
/etc/letsencrypt/live/app.example.com/privkey.pemssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;Tras renovar, Certbot suele ejecutar nginx -t + reload. Si renuevas a mano:
sudo certbot renew
sudo nginx -t && sudo systemctl reload nginxChallenge HTTP-01
Certbot debe alcanzar http://app.example.com/.well-known/acme-challenge/.... No bloquees ese path:
location ^~ /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
default_type text/plain;
}Si solo tienes el server de redirect 301 a HTTPS, deja el challenge en el server :80 antes del return.
Parametros TLS recomendados
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;- Desactiva TLSv1.0/1.1.
- HSTS solo cuando todo el dominio ya esta en HTTPS (incluye subdominios si usas
includeSubDomains). - OCSP stapling reduce latencia de validacion del cliente.
Redireccion y canonical host
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# locations...
}HTTP/2 y HTTP/3
HTTP/2 (sobre TLS) esta estable en Nginx estable. HTTP/3 (QUIC) requiere build con soporte y puertos UDP 443; valora complejidad operativa antes de activarlo.
Comprobar ALPN/HTTP2:
curl -sI --http2 https://example.com | head -n 1
# HTTP/2 200Diffie-Hellman (legacy)
Algunos guides anaden ssl_dhparam. Con TLS 1.3 y ciphers modernas suele no ser necesario. Si lo usas:
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048ssl_dhparam /etc/nginx/ssl/dhparam.pem;Checklist de puesta en marcha
DNS A/AAAA -> IP del servidor
Puerto 80 y 443 abiertos
nginx -t OK
Certbot o cert propio instalado
Redirect 80 -> 443
curl -Ik https://dominio
Renovacion dry-run OKBuenas practicas
- TLS solo en Nginx; backends en HTTP local.
X-Forwarded-Proto $schemepara que la app genere URLs https.- Permisos 600 en claves; propietario root.
- HSTS cuando el corte HTTP->HTTPS sea definitivo.
- Monitoriza caducidad de certificados (alerta < 15 dias).
Errores habituales
- Certificado para un CN distinto del
server_name(aviso en el navegador). - Firewall sin 443: HTTPS timeout.
- Redirect 80->443 que rompe ACME HTTP-01.
- Mezclar
listen ... http2(sintaxis vieja) conhttp2 onsegun version. - Olvidar
reloadtras renovar a mano: sigue sirviendo el cert viejo en memoria.
Ejercicios
- Genera un cert autofirmado, monta un server
:443 ssly verifica concurl -Ik(aceptando-k). - Anade redirect
return 301 https://$host$request_urien el server:80y comprueba la cadena concurl -I. - Si tienes dominio publico, emite un cert con Certbot y ejecuta
certbot renew --dry-run. - Activa HSTS y comprueba el header con
curl -Is https://tu-dominio | grep -i strict.
Siguiente paso
En el capitulo 5 repartiras trafico entre varios backends con upstream, metodos de balanceo y health checks pasivos.
