HTTP/3 in nginx aktivieren: Schritt für Schritt

HTTP/3 läuft über QUIC und UDP statt TCP. Für nginx sind es nur wenige Zeilen, die meisten Probleme entstehen an der Firewall oder an einem fehlenden Alt-Svc-Header.

Voraussetzungen

Mit dem normalen OpenSSL nutzt nginx eine Kompatibilitätsschicht für QUIC. Sie funktioniert, kann aber kein 0-RTT (Early Data). Für die meisten Websites spielt das keine Rolle.

Die Konfiguration

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;

    # Browsern mitteilen, dass es HTTP/3 gibt
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
}

Wichtig: reuseport darf pro Adresse und Port nur einmal vorkommen. Hast du mehrere server-Blöcke, bekommt nur der erste listen 443 quic reuseport;, alle anderen nur listen 443 quic;. Sonst startet nginx nicht und meldet „duplicate listen options“.

Danach nginx -t und systemctl reload nginx. Eine vollständige, sichere Konfiguration samt HSTS erzeugt dir der TLS-Konfigurationsgenerator (Option „HTTP/3“).

UDP 443 freigeben

Der häufigste Grund, warum HTTP/3 „nicht geht“: Die Firewall lässt nur TCP durch. Browser fallen dann still auf HTTP/2 zurück, es gibt keine Fehlermeldung.

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

Denk auch an Firewalls außerhalb des Servers: Security Groups in der Cloud, die Hoster-Firewall oder ein vorgeschalteter Load Balancer. Viele Load Balancer reichen QUIC nicht durch.

Wie der Browser zu HTTP/3 wechselt

Ein Browser verbindet sich beim ersten Besuch per TCP (HTTP/2). Im Header Alt-Svc erfährt er, dass HTTP/3 auf Port 443 verfügbar ist, und nutzt es ab der nächsten Anfrage. ma=86400 heißt: Diese Info gilt einen Tag.

Schneller geht es mit einem HTTPS-Eintrag im DNS. Damit kennt der Browser HTTP/3 schon vor der ersten Verbindung:

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

Eine typische Falle: add_header wird nicht vererbt, sobald ein location-Block eigene add_header-Zeilen hat. Dann fehlt Alt-Svc genau dort. Lösung: Header in eine Datei auslagern und per include in jedem betroffenen Block einbinden.

Testen

# Header vorhanden?
curl -sI https://example.com | grep -i alt-svc
# Echte HTTP/3-Verbindung (curl mit HTTP/3-Unterstützung nötig)
curl -sI --http3-only https://example.com
# Lauscht nginx auf UDP?
sudo ss -ulpn | grep ':443'

Im Browser zeigen die Entwicklertools in der Netzwerkansicht die Spalte „Protokoll“: h3 heißt HTTP/3. Beim allerersten Aufruf steht dort noch h2, erst nach einem Neuladen wechselt es.

Der HTTP/2- & HTTP/3-Check prüft ALPN, Alt-Svc und den HTTPS-Eintrag und schickt ein QUIC-Paket an den Server.

FAQ

Bringt HTTP/3 wirklich etwas?

Vor allem in Mobilfunk- und WLAN-Netzen mit Paketverlust: Ein verlorenes Paket blockiert nicht mehr alle Anfragen, und der Verbindungsaufbau ist schneller. Im schnellen Kabelnetz ist der Unterschied oft kaum messbar.

Muss ich HTTP/2 weiter anbieten?

Ja. Jeder Browser startet per TCP, und manche Netze blockieren UDP. HTTP/3 ergänzt HTTP/2, es ersetzt es nicht.

Warum zeigt der Browser trotz Alt-Svc nur h2?

Meist kommt UDP 443 nicht an (Firewall, Load Balancer, Firmennetz) oder der Browser hat die Info noch nicht. Neu laden, sonst mit curl --http3-only von außen testen.

Geht HTTP/3 auch mit Apache?

Nein, Apache unterstützt HTTP/3 bisher nicht. Üblich ist ein vorgeschalteter Proxy wie nginx, Caddy oder ein CDN.