Requisitos
- nginx 1.25.0 o posterior con
http_v3_module. Los paquetes de nginx.org lo incluyen.nginx -V 2>&1 | grep -o http_v3_modulemuestra si tu versión lo tiene. - TLS 1.3 debe estar activo; QUIC se basa en él.
- El puerto UDP 443 debe ser accesible desde fuera, además del TCP 443.
Con el OpenSSL normal, nginx usa una capa de compatibilidad para QUIC. Funciona, pero no admite 0-RTT (early data). Para la mayoría de las webs da igual.
La configuración
server {
listen 443 ssl;
listen [::]:443 ssl;
listen 443 quic reuseport;
listen [::]:443 quic reuseport;
http2 on;
http3 on;
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;
# avisar a los navegadores de que hay HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400' always;
}
Importante: reuseport solo puede aparecer una vez por dirección y puerto. Con varios bloques server, solo el primero lleva listen 443 quic reuseport; y los demás solo listen 443 quic;. Si no, nginx no arranca y avisa de «duplicate listen options».
Después nginx -t y systemctl reload nginx. El generador de configuración TLS crea una configuración completa y segura con HSTS (opción «HTTP/3»).
Abrir UDP 443
El motivo más habitual por el que HTTP/3 «no funciona»: el cortafuegos solo deja pasar TCP. Los navegadores vuelven entonces en silencio a HTTP/2, sin mensaje de error.
# ufw sudo ufw allow 443/udp # firewalld sudo firewall-cmd --permanent --add-port=443/udp && sudo firewall-cmd --reload # nftables (ejemplo) nft add rule inet filter input udp dport 443 accept
Piensa también en cortafuegos fuera del servidor: grupos de seguridad en la nube, el cortafuegos del proveedor o un balanceador de carga delante. Muchos balanceadores no dejan pasar QUIC.
Cómo cambia el navegador a HTTP/3
En la primera visita el navegador se conecta por TCP (HTTP/2). La cabecera Alt-Svc le indica que hay HTTP/3 en el puerto 443, y lo usa desde la siguiente petición. ma=86400 significa que la información vale un día.
Un registro HTTPS en el DNS es más rápido: el navegador conoce HTTP/3 antes de la primera conexión.
example.com. 3600 IN HTTPS 1 . alpn="h3,h2"
Una trampa típica: add_header deja de heredarse en cuanto un bloque location tiene sus propias líneas add_header, y Alt-Svc falta justo ahí. Solución: poner las cabeceras en un archivo e incluirlo con include en cada bloque afectado.
Probar
# ¿está la cabecera? curl -sI https://example.com | grep -i alt-svc # conexión HTTP/3 real (requiere curl con soporte HTTP/3) curl -sI --http3-only https://example.com # ¿escucha nginx en UDP? sudo ss -ulpn | grep ':443'
En las herramientas de desarrollo del navegador, la vista de red tiene la columna «Protocolo»: h3 significa HTTP/3. En la primera petición aún pone h2; cambia tras recargar.
El comprobador HTTP/2 y HTTP/3 revisa ALPN, Alt-Svc y el registro HTTPS y envía un paquete QUIC al servidor.
FAQ
¿Aporta algo HTTP/3 de verdad?
Sobre todo en redes móviles y wifi con pérdida de paquetes: un paquete perdido ya no bloquea todas las peticiones y la conexión se establece antes. En una red cableada rápida la diferencia suele ser mínima.
¿Debo seguir ofreciendo HTTP/2?
Sí. Todo navegador empieza por TCP y algunas redes bloquean UDP. HTTP/3 complementa a HTTP/2, no lo sustituye.
¿Por qué el navegador solo muestra h2 pese a Alt-Svc?
Normalmente UDP 443 no llega (cortafuegos, balanceador, red corporativa) o el navegador aún no tiene la información. Recarga; si no, prueba desde fuera con curl --http3-only.
¿Funciona HTTP/3 con Apache?
No, Apache no admite HTTP/3 por ahora. Lo habitual es poner delante un proxy como nginx, Caddy o una CDN.