Fedora では、nginx 1.26.0 で(experimental)HTTP/3 モジュールが有効になりましたので、早速使ってみることにします。

nginx の設定

HTTP/2 に関する設定が古くなっていたので、最初に修正します。

server {
  listen       443 ssl http2;
  listen       443 ssl;
  listen       [::]:443 ssl http2;
  listen       [::]:443 ssl;
  http2        on;
  server_name  example.com;
  root         /path/to/htdocs;

  # Load configuration files for the default server block.
  include /etc/nginx/default.d/*.conf;

  ...
}

listenhttp2 と指定する書き方は非推奨になりました。代わりに、http2 on; の行を追加します。

HTTP/3 を有効にします。

server {
  listen       443 ssl;
  listen       443 quic reuseport;
  listen       [::]:443 ssl;
  listen       [::]:443 quic reuseport;
  http2        on;
  server_name  example.com;
  root         /path/to/htdocs;

  # Load configuration files for the default server block.
  include /etc/nginx/default.d/*.conf;
  add_header Alt-Svc 'h3=":443"; ma=86400';

  ...
}

上記 3行を追加します。クライアントは、一旦 HTTP/2 で接続し、その際にサーバが「HTTP/3 にも対応してますよ」というヘッダを返すことで、以後の接続を HTTP/3 に切り替えます。このことから、HTTP/2 と HTTP/3 の listen が必要です。バーチャルホストで複数のサーバを同居させる場合、はどれでもよいので、一つだけのバーチャルホストで上記のように reuseport を指定します。一つも指定しない、複数指定はいずれもエラーになります。

add_header を指定して、HTTP/3 対応している旨のヘッダを追加します。

firewalld の設定

firewalld では HTTP/3 は http3 として定義済みです。

# firewall-cmd --permanent --service=http3 --get-ports
443/udp
# 

サービスを提供する各ゾーンで、http3 の接続を許可します。

# firewall-cmd --permanent --zone=public --add-service=http3
success
# firewall-cmd --permanent --zone=trusted --add-service=http3
success
# firewall-cmd --reload

自前の証明書を使う

HTTP/3 ではオレオレ証明書を使うことはできないようです。

自前の認証局を作り、その認証局のルート証明書を取り込んで有効にし、その認証局で発行したサーバ証明書を使って、HTTP/3 サーバを建ててみます。

server {
  listen       10443 quic;
  listen       [::]:10443 quic;
  listen       10443 ssl;
  listen       [::]:10443 ssl;
  http2        on;
  server_name  test.seinolab.jp;
  root         /path/to/htdocs;

  ssl_certificate "/path/to/seinolab.jp.cert.pem";
  ssl_certificate_key "/path/to/seinolab.jp.key.pem";
  ssl_session_cache shared:SSL:1m;
  ssl_session_timeout 10m;
  ssl_session_tickets off;
  ssl_dhparam "/path/to/dh2048.pem";

  ssl_protocols TLSv1.3 TLSv1.2;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA;
  ssl_prefer_server_ciphers on;

  ssl_client_certificate "/path/to/root.cert.pem";
  ssl_crl "/path/to/crl.pem";

  add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload';

  add_header Alt-Svc 'h3=":443"; ma=86400';
  access_log /var/log/nginx/test.access.log;
}

このサーバ(seinolab.jp)でテストしたので、ポート 443 は使えません。適当なポートに変更しています。このサーバは既に Let's Encrypt 発行の SSL 証明書を使用しています。同じポートで複数の SSL 証明書を切り替えて使うことはできません。

seinolab.jp.cert.pem は自前の認証局で発行した *.seinolab.jp のワイルドカード証明書です。全く問題なく通信できます。開発環境でも大丈夫です。

自前の認証局を作る方法は、strongSwan 用の証明書を作成するを参照してください。

通信テスト

現状は、Google Chrome か Safari で接続し、nginx のログを確認するしか方法はなさそうです。

curl既に対応済みですが、残念ながら、ビルドし直す必要がありそうです。

$ curl --http3-only https://seinolab.jp:433/
curl: option --http3-only: the installed libcurl version doesn't support this
curl: try 'curl --help' or 'curl --manual' for more information
$