CentOS Stream 10(開発環境) + Nginx + HTTP/3 QUIC

CentOS Stream 10の開発環境でNginx + HTTP/3 QUICを試したときの覚書。
Gemini 2.5 Proと対話

環境: CentOS Stream 10


1. ビルドしたNginxをアンインストール

前にビルドしたときはwith-cc-optやwith-ld-optはどうでもいいと思っていたけど、結構大事ということを知ったので、dnf経由でインストールしたNginxのビルドオプションを確認するため、まずは手動ビルドしたNginxをアンインストールする。

仮想マシン環境なのでスナップショットをとっておく。

サービスの停止
# systemctl stop nginx

設定ファイルをバックアップ。
# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.old20251017

ビルドしたソースファイルに移動してMakefile確認。
# cd /usr/local/src/nginx-1.28.0/
# less Makefile

make uninstallがないので、手動で削除する。
# rm /usr/sbin/nginx

ビルドするとnginx.serviceは作成されないのでリネームする。
# mv /etc/systemd/system/nginx.service /etc/systemd/system/nginx.service.bak

サービスの再読み込み。
# systemctl daemon-reload

再インストールするので、設定ファイルはそのまま。


2. dnf経由でインストールしてビルドオプション確認

標準リポジトリにあるNginxは1.26.3だったので、nginx公式リポジトリから1.28.0をインストールした。
参考: nginx: Linux packages
# vi /etc/yum.repos.d/nginx.repo

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

dnf経由でインストール。
# dnf install nginx

ビルドオプションを確認。改行して見やすくする。
# nginx -V 2>&1 | sed 's/ --/\n--/g'

nginx version: nginx/1.28.0
built with OpenSSL 3.2.2 4 Jun 2024 (running with OpenSSL 3.5.1 1 Jul 2025)
TLS SNI support enabled
configure arguments:
--prefix=/etc/nginx
--sbin-path=/usr/sbin/nginx
--modules-path=/usr/lib64/nginx/modules
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--pid-path=/var/run/nginx.pid
--lock-path=/var/run/nginx.lock
--http-client-body-temp-path=/var/cache/nginx/client_temp
--http-proxy-temp-path=/var/cache/nginx/proxy_temp
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
--http-scgi-temp-path=/var/cache/nginx/scgi_temp
--user=nginx
--group=nginx
--with-compat
--with-file-aio
--with-threads
--with-http_addition_module
--with-http_auth_request_module
--with-http_dav_module
--with-http_flv_module
--with-http_gunzip_module
--with-http_gzip_static_module
--with-http_mp4_module
--with-http_random_index_module
--with-http_realip_module
--with-http_secure_link_module
--with-http_slice_module
--with-http_ssl_module
--with-http_stub_status_module
--with-http_sub_module
--with-http_v2_module
--with-http_v3_module
--with-mail
--with-mail_ssl_module
--with-stream
--with-stream_realip_module
--with-stream_ssl_module
--with-stream_ssl_preread_module
--with-cc-opt='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fPIC'
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

with-cc-optとwith-ld-optをメモっておく。

nginx.serviceをバックアップするのを忘れたら、コピーしておく。
# cp /usr/lib/systemd/system/nginx.service /etc/systemd/system/nginx.service.bak

ひとまずアンインストール。
# dnf remove nginx

インストール済みの一覧。
# dnf list installed | grep nginx

nginx-filesystemはphp-fpmと依存関係にあるので残っていても問題なし。
nginx-filesystemの依存関係を表示するコマンド。
# dnf repoquery --whatrequires nginx-filesystem


3.Nginxを再ビルド

既にソースコードはダウンロード済み。
参考: CentOS Stream 10でNginxをソースからビルド
# cd /usr/local/src/nginx-1.28.0/
# make clean

必要なライブラリをインストール。
# dnf install redhat-rpm-config

サードパーティ製モジュールのソースコードを最新にする。
# git -C ngx_cache_purge/ pull
# git -C nginx-module-vts/ pull
# git -C ngx_http_geoip2_module/ pull

configure実行。

# ./configure \
--prefix=/etc/nginx \
--conf-path=/etc/nginx/nginx.conf \
--sbin-path=/usr/sbin/nginx \
--pid-path=/run/nginx.pid \
--lock-path=/run/lock/subsys/nginx \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--user=nginx \
--group=www \
--with-compat \
--with-pcre \
--with-file-aio \
--http-client-body-temp-path=/var/lib/nginx/tmp/client_body_temp \
--http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi_temp \
--http-proxy-temp-path=/var/lib/nginx/tmp/proxy_temp \
--http-scgi-temp-path=/var/lib/nginx/tmp/scgi_temp \
--http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi_temp \
--with-http_v2_module \
--with-http_v3_module \
--with-http_gunzip_module \
--with-http_realip_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--without-mail_imap_module \
--without-mail_pop3_module \
--without-mail_smtp_module \
--with-threads \
--add-module=./ngx_http_geoip2_module \
--add-module=./nginx-module-vts \
--add-module=./ngx_cache_purge \
--with-cc-opt='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' 

ビルド実行して確認。
# make
# objs/nginx -V

nginx version: nginx/1.28.0
built by gcc 14.3.1 20250617 (Red Hat 14.3.1-2) (GCC)
built with OpenSSL 3.5.1 1 Jul 2025
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --sbin-path=/usr/sbin/nginx --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --user=nginx --group=www --with-compat --with-pcre --with-file-aio --http-client-body-temp-path=/var/lib/nginx/tmp/client_body_temp --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi_temp --http-proxy-temp-path=/var/lib/nginx/tmp/proxy_temp --http-scgi-temp-path=/var/lib/nginx/tmp/scgi_temp --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi_temp --with-http_v2_module --with-http_v3_module --with-http_gunzip_module --with-http_realip_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --without-mail_imap_module --without-mail_pop3_module --without-mail_smtp_module --with-threads --add-module=./ngx_http_geoip2_module --add-module=./nginx-module-vts --add-module=./ngx_cache_purge --with-cc-opt='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

インストールする(新しいNginxバイナリの配置)。
# make install

サービスファイルを有効化。
# cd /etc/systemd/system/
# mv nginx.service.bak nginx.service
# systemctl daemon-reload
# systemctl enable nginx 

設定ファイルを復元。
# cd /etc/nginx/
# rm nginx.conf
# mv nginx.conf.old20251017 nginx.conf

テストしてNginx起動。
# nginx -t
# systemctl start nginx
# systemctl status nginx


4. HTTP/3をオンにする設定

FreeBSDの時と同じ。
参考: FreeBSD14 + Nginx + HTTP/3 QUIC

テストして再起動。
# nginx -t
# service nginx restart

待ち受けポート確認。UDPでListenしているかどうか。
# ss -ulnp

  • -u: UDPソケットを表示
  • -l: リスニング(待ち受け)状態のソケットのみを表示
  • -n: サービス名ではなく、ポート番号を数値で表示
  • -p: ソケットを使用しているプロセスを表示

このサーバーは開発用なのでファイヤーウォールは起動していない。

Windowsからcurlコマンドを打って確認。
Windows標準のcurlはhttp3に対応していないので注意。
# curl -k --http3 -I -v https://dev.hoge.jp/

  • -I: ヘッダー情報のみ取得
  • -k: SSL/TLS証明書の検証をスキップ
  • --http3: HTTP/3プロトコルを使用して通信することをcurlに強制
  • -v: 詳細表示

成功。

ブラウザで確認。
DevToolsの「Disable cache」がオンで「キャッシュの消去とハード再読み込み(リロードアイコンを長押し)」でもh2のまま。

Gemini先生に相談してChromeのログ出力する。

  1. Chromeのアドレスバーに chrome://net-export/ と入力して開きます。
  2. 「Start Logging to Disk」ボタンをクリックし、ログファイルの保存場所を指定します。
  3. 対象のサイト https://dev.hoge.jp/ にアクセスします。「キャッシュの消去とハード再読み込み(リロードアイコンを長押し)」。
  4. chrome-net-export-log.jsonをGemini先生にアップロードして解析してもらう。

 Gemini先生の回答

ログを解析した結果、ChromeがHTTP/3での接続を試みたものの、TLSハンドシェイクで失敗し、その後HTTP/3の利用を諦めてHTTP/2にフォールバックしていることが判明しました。

自己署名証明書(オレオレ証明書)の信頼性の問題らしい。

公開されているサーバーで試してみる。
追記予定。


▼ 関連記事