HTTP/2 and HTTP/3 on the same `server`

My issue: I’d like HTTP/1.1, HTTP/2 and HTTP/3 on the same port.

How I encountered the problem: I have HTTP/1.1 & HTTP/2 running smoothly, but I’m missing something in my server block to get HTTP/3 recognised by multiple online HTTP/3 checkers.

Solutions I’ve tried:

    add_header Alt-Svc 'h3=":$server_port"; ma=86400' always;
    […]
    http2 on;
    http3 on;
    http3_hq on;
    […]
    listen [::]:443 ssl;
    listen [::]:443 quic reuseport;
    listen 443 ssl;
    listen 443 quic;
    quic_retry on;

My config:

server {#hostname, https
    access_log /var/log/nginx/nginx/live/heartbeat/hobby.tlsvps.com.heartbeat.access.log ips-50;
    set $consecpol_heartbeat '';
    set $consecpol_heartbeat '${consecpol_heartbeat}base-uri \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}child-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}connect-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}default-src \'none\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}font-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}form-action \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}frame-ancestors \'none\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}frame-src \'none\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}img-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}manifest-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}media-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}object-src \'none\';';
    #set $consecpol_heartbeat '${consecpol_heartbeat}sandbox;';
    set $consecpol_heartbeat '${consecpol_heartbeat}script-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}script-src-attr \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}script-src-elem \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}style-src \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}style-src-attr \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}style-src-elem \'self\';';
    set $consecpol_heartbeat '${consecpol_heartbeat}worker-src \'self\';';
    add_header Alt-Svc 'h3=":$server_port"; ma=86400' always;
    add_header Content-Security-Policy $consecpol_heartbeat always;
    add_header Referrer-Policy "strict-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    error_log /var/log/nginx/nginx/live/heartbeat/hobby.tlsvps.com.heartbeat.error.log warn;
    http2 on;
    http3 on;
    http3_hq on;
    index index.html;
    listen [::]:443 ssl;
    listen [::]:443 quic reuseport;
    listen 443 ssl;
    listen 443 quic;
    quic_retry on;
    root /var/www/heartbeat/live/;
    server_name hobby.tlsvps.com;
    ssl_certificate /etc/certbot/letsencrypt.org/live/hobby.tlsvps.com/fullchain.pem;
    ssl_certificate_key /etc/certbot/letsencrypt.org/live/hobby.tlsvps.com/privkey.pem;
    ssl_trusted_certificate /etc/certbot/letsencrypt.org/live/hobby.tlsvps.com/fullchain.pem;
    location ^~ /.well-known/ {
        location ~ ^.+\.php(?:/.*)?$ {
            return 502;
        }
        allow all;
        default_type "text/plain";
        root /var/www/heartbeat/_well-known/;
        try_files $uri/ $uri =404;
    }
    location /favicon.ico {
        access_log off;
        log_not_found off;
    }
    location /robots.txt {
        access_log off;
        log_not_found off;
    }
    location ~ /\. {
        deny all;
    }
    location / {
        index index.html;
        limit_except GET HEAD POST {
            deny all;
        }
        try_files $uri $uri/ =404;
    }
    location ~ ^.+\.php(?:/.*)?$ {
        return 502;
    }
}

The server is https://hobby.tlsvps.com. I’m clearly missing something obvious, but I’ve got snowblindness looking for it.

I’d really appreciate additional eyes & brains on this, if you’re inclined. Thank you.

Edits: clarity.

1 Like

You can follow the instructions at How to install NGINX with full QUIC HTTP/3 support which include details on required steps to configure firewall for HTTP/3 support.

2 Likes

Thank you @dvershinin - I really appreciate your advice.

1 Like

I burned 3 further hours on this and was close to walking away, until I re-read @dvershinin’s comment:

on required steps to configure firewall for HTTP/3 support.

I hadn’t opened port 443 for UDP traffic. Now I have, and it works. Thank you @dvershinin!