Activer HTTP/3 dans nginx : étape par étape

HTTP/3 passe par QUIC et UDP au lieu de TCP. Dans nginx, il suffit de quelques lignes ; la plupart des problèmes viennent du pare-feu ou d’un en-tête Alt-Svc manquant.

Prérequis

Avec l’OpenSSL standard, nginx utilise une couche de compatibilité pour QUIC. Elle fonctionne mais ne gère pas le 0-RTT (early data). Pour la plupart des sites, cela n’a pas d’importance.

La configuration

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;

    # indiquer aux navigateurs que HTTP/3 est disponible
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
}

Important : reuseport ne peut apparaître qu’une seule fois par adresse et port. Avec plusieurs blocs server, seul le premier reçoit listen 443 quic reuseport;, les autres seulement listen 443 quic;. Sinon nginx refuse de démarrer avec « duplicate listen options ».

Ensuite nginx -t et systemctl reload nginx. Le générateur de configuration TLS crée une configuration complète et sûre avec HSTS (option « HTTP/3 »).

Ouvrir l’UDP 443

La raison la plus fréquente pour laquelle HTTP/3 « ne marche pas » : le pare-feu ne laisse passer que le TCP. Les navigateurs reviennent alors silencieusement à HTTP/2, sans message d’erreur.

# ufw
sudo ufw allow 443/udp
# firewalld
sudo firewall-cmd --permanent --add-port=443/udp && sudo firewall-cmd --reload
# nftables (exemple)
nft add rule inet filter input udp dport 443 accept

Pense aussi aux pare-feu en dehors du serveur : groupes de sécurité dans le cloud, pare-feu de l’hébergeur ou répartiteur de charge en amont. Beaucoup de répartiteurs ne laissent pas passer QUIC.

Comment le navigateur passe à HTTP/3

À la première visite, le navigateur se connecte en TCP (HTTP/2). L’en-tête Alt-Svc lui apprend que HTTP/3 est disponible sur le port 443, et il l’utilise dès la requête suivante. ma=86400 signifie que l’information vaut un jour.

Un enregistrement HTTPS dans le DNS va plus vite : le navigateur connaît HTTP/3 avant même la première connexion.

example.com.  3600  IN  HTTPS  1 . alpn="h3,h2"

Un piège classique : add_header n’est plus hérité dès qu’un bloc location a ses propres lignes add_header. Alt-Svc manque alors précisément là. Solution : mettre les en-têtes dans un fichier et l’inclure avec include dans chaque bloc concerné.

Tester

# en-tête présent ?
curl -sI https://example.com | grep -i alt-svc
# vraie connexion HTTP/3 (curl avec support HTTP/3 requis)
curl -sI --http3-only https://example.com
# nginx écoute-t-il en UDP ?
sudo ss -ulpn | grep ':443'

Dans les outils de développement du navigateur, la vue réseau a une colonne « Protocole » : h3 signifie HTTP/3. À la toute première requête, elle indique encore h2 ; cela change après un rechargement.

Le test HTTP/2 & HTTP/3 vérifie ALPN, Alt-Svc et l’enregistrement HTTPS et envoie un paquet QUIC au serveur.

FAQ

HTTP/3 apporte-t-il vraiment quelque chose ?

Surtout sur les réseaux mobiles et Wi-Fi avec perte de paquets : un paquet perdu ne bloque plus toutes les requêtes et l’établissement de la connexion est plus rapide. Sur un réseau filaire rapide, la différence est souvent à peine mesurable.

Dois-je continuer à proposer HTTP/2 ?

Oui. Tout navigateur commence en TCP, et certains réseaux bloquent l’UDP. HTTP/3 complète HTTP/2, il ne le remplace pas.

Pourquoi le navigateur n’affiche-t-il que h2 malgré Alt-Svc ?

En général l’UDP 443 n’arrive pas (pare-feu, répartiteur de charge, réseau d’entreprise) ou le navigateur n’a pas encore l’information. Recharger, sinon tester de l’extérieur avec curl --http3-only.

HTTP/3 fonctionne-t-il avec Apache ?

Non, Apache ne gère pas HTTP/3 à ce jour. On place généralement devant un proxy comme nginx, Caddy ou un CDN.