FreeBSDのNginxをportsでビルド → 本番環境はダウンタイムなしで切り替える
Nginxのパフォーマンス改善にはportsからビルドするのがベストだと思ってやってみたときの覚書。
Gemini 2.5 Proと対話。
環境: FreeBSD 14.3-RELEASE-p2, nginx 1.28.0
1. Portsリポジトリを取得
FreeBSD14からportsnapコマンドではなくgitコマンドを使う。
参考: Chapter 4. Installing Applications: Packages and Ports | FreeBSD Documentation Portal
まずは公式サイトにあるようにgit cloneする。
--depth 1 を付けることで、最新のコミット1つ分のみを取得。
# git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports
移動して確認。
# cd /usr/ports/
# ls
2. Nginxをビルド
pkgでインストールしたNginxのバージョンとビルドオプションを確認。
# nginx -V 2>&1 | sed 's/ --/\n--/g'
nginx version: nginx/1.28.0built with OpenSSL 3.0.16 11 Feb 2025TLS SNI support enabledconfigure arguments:--prefix=/usr/local/etc/nginx--with-cc-opt='-I /usr/local/include'--conf-path=/usr/local/etc/nginx/nginx.conf--sbin-path=/usr/local/sbin/nginx--pid-path=/var/run/nginx.pid--error-log-path=/var/log/nginx/error.log--user=www--group=www--with-compat--with-pcre--modules-path=/usr/local/libexec/nginx--with-file-aio--http-client-body-temp-path=/var/tmp/nginx/client_body_temp--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp--http-proxy-temp-path=/var/tmp/nginx/proxy_temp--http-scgi-temp-path=/var/tmp/nginx/scgi_temp--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp--http-log-path=/var/log/nginx/access.log--with-http_v2_module--with-http_v3_module--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--without-mail_imap_module--without-mail_pop3_module--without-mail_smtp_module--with-mail_ssl_module--with-stream--with-stream_realip_module--with-stream_ssl_module--with-stream_ssl_preread_module--with-threads--with-mail=dynamic--with-stream=dynamic--with-ld-opt='-L /usr/local/lib'
ディレクトリに移動してビルドオプション設定。
# cd www/nginx/
# make config
Gemini先生による各オプションの説明。
基本オプション
- DEBUGLOG: 開発者向けのデバッグログを有効にします。
- DSO: Nginx本体を再ビルドせずに、モジュールを動的に追加・削除できるようにします(.soファイルを別途コピーし、load_moduleする必要あり)。オフにした場合、モジュールはすべて本体に一体化されるためload_moduleする必要なし。
- FILE_AIO: ファイルの非同期I/Oを有効にし、ディスクI/Oのパフォーマンスを改善します。
- IPV6: IPv6をサポートします。
- NJS: 設定ファイル内でJavaScript(NJS)を実行できるようにします。
- NJS_XML: NJSでXMLを扱う機能を追加します。
- OTEL: OpenTelemetryによる分散トレーシングをサポートします。
- THREADS: スレッドプールを有効にし、ブロッキングI/O(ディスク読み込み等)の性能を向上させます。
- WWW: index.htmlや50x.htmlなどのサンプルファイルをインストールします。
HTTPモジュール関連
- GOOGLE_PERFTOOLS: Googleのパフォーマンス解析ツールを有効にします。
- HTTP: HTTPサーバー機能を有効にします。(通常は必須)
- HTTP_ADDITION: レスポンスの前後に別のコンテンツを追記する機能です。
- HTTP_AUTH_REQ: 外部サーバーに問い合わせて認証を行う機能です。
- HTTP_CACHE: プロキシキャッシュ機能を有効にします。
- HTTP_DAV: WebDAV(ファイルのアップロードや管理)機能を有効にします。
- HTTP_DEGRADATION: メモリ不足時にレスポンス品質を落としてサービスを継続させる機能です。
- HTTP_FLV: FLV形式の動画ストリーミング配信をサポートします。
- HTTP_GUNZIP_FILTER: gzip圧縮されたレスポンスを動的に解凍する機能です。
- HTTP_GZIP_STATIC: 事前に圧縮された.gzファイルを配信し、CPU負荷を軽減します。
- HTTP_IMAGE_FILTER: 画像のリサイズや回転などの処理を行う機能です。
- HTTP_MP4: MP4形式の動画ストリーミング配信をサポートします。
- HTTP_PERL: 設定ファイル内でPerlスクリプトを実行できるようにします。
- HTTP_RANDOM_INDEX: ディレクトリからランダムに選んだファイルをインデックスページとして表示します。
- HTTP_REALIP: ロードバランサ経由のアクセス時に、クライアントの本当のIPアドレスを取得します。
- HTTP_SECURE_LINK: 期限付き・IP制限付きのセキュアなダウンロードリンクを生成します。
- HTTP_SLICE: 大きなファイルを分割して効率的にキャッシュ・配信します。
- HTTP_SSL: HTTPS (SSL/TLS) 通信を有効にします。(通常は必須)
- HTTP_STATUS: /nginx_statusで簡単な接続情報を表示するstub_statusモジュールです。
- HTTP_SUB: レスポンス内の文字列を置換します。
- HTTP_XSLT: XMLレスポンスをXSLTで変換します。
- HTTPV2: HTTP/2プロトコルをサポートします。
- HTTPV3: HTTP/3 (QUIC) プロトコルをサポートします。
- HTTPV3_BORING: HTTP/3にGoogleのBoringSSLを使用します。
- HTTPV3_LSSL: HTTP/3にLibreSSLを使用します。
- HTTPV3_QTLS: HTTP/3にopenssl-quictlsを使用します。(今回の推奨)
MAILモジュール関連
- MAIL: IMAP/POP3/SMTPのメールプロキシ機能を有効にします。
- MAIL_IMAP / MAIL_POP3 / MAIL_SMTP: 各メールプロトコルのプロキシ機能です。
- MAIL_SSL: メールプロキシでSSL/TLSを有効にします。
STREAMモジュール関連
- STREAM: TCP/UDPの汎用プロキシ(L4ロードバランサ)機能を有効にします。
- STREAM_REALIP: PROXYプロトコルからクライアントのIPアドレスを取得します。
- STREAM_SSL: STREAMプロキシでSSL/TLSを有効にします。
- STREAM_SSL_PREREAD: SSL/TLSハンドシェイク情報(SNIなど)を先に読み取って処理を分岐させます。
サードパーティモジュール (代表的なもの)
- BROTLI: GoogleのBrotli圧縮アルゴリズムを有効にします。(Gzipより高圧縮)
- HTTP_GEOIP2: IPアドレスから国や都市などの位置情報を判定します。
- HTTP_UPSTREAM_CHECK: バックエンドサーバーのヘルスチェック(死活監視)を行います。
- HEADERS_MORE: HTTPヘッダーの追加・変更・削除をより柔軟に行います。
- LUA: 設定ファイル内で高機能なLuaスクリプトを実行できるようにします。
- MODSECURITY3: WAF (Web Application Firewall) であるModSecurityを有効にします。
- PASSENGER: Ruby/Python/Node.jsアプリケーションサーバーのPhusion Passengerを統合します。
- VTS: バーチャルホストごとの詳細なアクセス統計情報(Virtual host Traffic Status)を表示します。
- RTMP: ライブ動画ストリーミング(RTMPプロトコル)を配信するサーバー機能を追加します。
- HTTP_FANCYINDEX: 標準より見栄えの良いファイル一覧ページを生成します。
GSSAPI実装
- GSSAPI_HEIMDAL / GSSAPI_MIT: Kerberos認証などで使われるGSSAPIの実装ライブラリを選択します。
オンにしたビルドオプション一覧
- FILE_AIO
- IPV6
- THREADS
- HTTP
- HTTP_CACHE
- HTTP_GUNZIP_FILTER
- HTTP_GZIP_STATIC
- HTTP_REALIP
- HTTP_SLICE
- HTTP_SSL
- HTTP_STATUS
- HTTP_SUB
- HTTPV2
- HTTPV3
- HTTPV3_QTLS
---
- BROTLI
- CACHE_PURGE
- HTTP_GEOIP2
- VTS
既存のNginxを停止し、設定をバックアップ。
# service nginx stop
# cp -Rp /usr/local/etc/nginx /usr/local/etc/nginx.bak
Nginxのビルドとインストールを実行。
make reinstallを使うと、既存版のアンインストールと新規インストールを自動で行ってくれる。
# make reinstall clean
openssl-quictls-3.0.15_1のビルドオプションが表示された。
デフォルトのままでOK。
TLS 1.3が項目にないのは常に有効な機能だから。
gmake-4.4.1のビルドオプションが表示された。
NLSを選択したままでOK。
数分でビルド完了した。
バージョンとビルドオプションを確認。
# nginx -V 2>&1 | sed 's/ --/\n--/g'
nginx version: nginx/1.28.0built with OpenSSL 3.0.15+quic 3 Sep 2024TLS SNI support enabledconfigure arguments:--prefix=/usr/local/etc/nginx--with-cc-opt='-I /usr/local/include'--conf-path=/usr/local/etc/nginx/nginx.conf--sbin-path=/usr/local/sbin/nginx--pid-path=/var/run/nginx.pid--error-log-path=/var/log/nginx/error.log--user=www--group=www--with-compat--with-pcre--modules-path=/usr/local/libexec/nginx--with-file-aio--http-client-body-temp-path=/var/tmp/nginx/client_body_temp--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp--http-proxy-temp-path=/var/tmp/nginx/proxy_temp--http-scgi-temp-path=/var/tmp/nginx/scgi_temp--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp--http-log-path=/var/log/nginx/access.log--with-http_v2_module--with-http_v3_module--with-http_gunzip_module--with-http_gzip_static_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-dynamic-module=/usr/ports/www/nginx/work/ngx_brotli-a71f931--add-dynamic-module=/usr/ports/www/nginx/work/ngx_cache_purge-a84b0f3--add-dynamic-module=/usr/ports/www/nginx/work/ngx_http_geoip2_module-3.4--add-dynamic-module=/usr/ports/www/nginx/work/nginx-module-vts-bf64dbf--with-ld-opt='-L /usr/local/lib'
設定ファイルを確認。
# cd /usr/local/etc/nginx/
# less nginx.conf
とりあえず今の設定で起動できるか確認。
# nginx -t
# service nginx start
# service nginx status
サイトを表示して確認。
pkg upgrade で上書きされないようにNginxパッケージをロック。
# pkg lock nginx
早くHTTP/3を確認したくなるけども、まずはこのportsからのビルドバージョンで本番環境のpkgバージョンと入れ替えを行う。
3. 本番環境はダウンタイムなしで切り替える
本番環境ではNginxをビルドのみ実行。
# git clone --depth 1 https://git.FreeBSD.org/ports.git /usr/ports
# cd /usr/ports/www/nginx
# make config
# make
下記エラー
===> openssl-quictls-3.0.15_1 has known vulnerabilities:openssl-quictls-3.0.15_1 is vulnerable:OpenSSL -- OOB memory access vulnerabilityCVE: CVE-2024-9143WWW: https://vuxml.FreeBSD.org/freebsd/c6f4177c-8e29-11ef-98e7-84a93843eb75.html1 problem(s) in 1 package(s) found.=> Please update your ports tree and try again.=> Note: Vulnerable ports are marked as such even if there is no update available.=> If you wish to ignore this vulnerability rebuild with 'make DISABLE_VULNERABILITIES=yes'*** Error code 1Stop.make[3]: stopped in /usr/ports/security/openssl-quictls*** Error code 1Stop.make[2]: stopped in /usr/ports/security/openssl-quictls*** Error code 1Stop.make[1]: stopped in /usr/ports/www/nginx*** Error code 1Stop.
CVE-2024-9143という脆弱性が見つかってまだパッチが適用されていないらしい。
とりあえずダウンタイムなしで切り替えることを試したいからHTTPV3_QTLSは外す。
# make config
# make clean
# make
現在のバイナリの場所と新しいバイナリの場所を確認。
# whereis nginx
nginx: /usr/local/sbin/nginx /usr/local/share/man/man8/nginx.8.gz /usr/ports/www/nginx
# ls /usr/ports/www/nginx/work/stage/usr/local/sbin
バージョンとビルドオプションを確認。# /usr/ports/www/nginx/work/stage/usr/local/sbin/nginx -V 2>&1 | sed 's/ --/\n--/g'
新しいバイナリでテスト実行。
# /usr/ports/www/nginx/work/stage/usr/local/sbin/nginx -t -c /usr/local/etc/nginx/nginx.conf
マスタープロセスとワーカープロセスの親子関係をツリー形式で視覚的に確認pstreeをインストールする。
# pkg install pstree
nginxのプロセスを表示。
# pstree -s nginx
ダウンタイムなしのオンラインアップグレード開始
別コンソールでnginxプロセスを監視(1秒ごとに再実行と再描画)。# while true; do clear; pstree -s nginx; sleep 1; done
現在のマスタープロセスのPIDを確認。
# cat /var/run/nginx.pid
pstreeの表示と一致していることを確認。
現在のバイナリをバックアップして新しいバイナリを配置。
# mv /usr/local/sbin/nginx /usr/local/sbin/nginx.old
# cp /usr/ports/www/nginx/work/stage/usr/local/sbin/nginx /usr/local/sbin/nginx
# chmod +x /usr/local/sbin/nginx
USR2シグナルを送信して、新バイナリで新しいマスタープロセスを起動。
(USR2 = ユーザー定義のシグナル2 => nginxのソースコードにオンラインアップグレードはUSR2で行うと定義されている)
参考: Controlling nginx
# kill -USR2 $(cat /var/run/nginx.pid)
pstreeでマスタープロセスが増えているのを確認。
nginx.pid.oldbinがあるか確認して、古いプロセスを段階的に終了させる。
(WINCH = Window Change)
# ls /var/run/
# kill -WINCH $(cat /var/run/nginx.pid.oldbin)
古いワーカープロセスはすべて終了したのをpstreeで確認。
最後に古いマスタープロセス自体を終了させる。
# kill -QUIT $(cat /var/run/nginx.pid.oldbin)
/var/run/には新しいPIDのnginx.pidしか残っていないはず。
# ls /var/run/
# cat /var/run/nginx.pid
ブラウザで正常に表示されるか確認する。
もし元のバイナリに戻す場合の手順
新しいマスタープロセスをすぐに停止。
# kill -QUIT $(cat /var/run/nginx.pid)
この時点では、PIDファイルが /var/run/nginx.pid.oldbin のままなので、古いマスタープロセスに設定を再読み込みさせ、PIDファイルを元に戻すよう指示。
参考: Controlling nginx
# kill -HUP $(cat /var/run/nginx.pid.oldbin)
バイナリを元に戻す。
# mv /usr/local/sbin/nginx.old /usr/local/sbin/nginx
これで元に戻っているはず。
分からなくなったらnginxを再起動する。
(この場合はダウンタイムが発生する)
# service nginx restart
▼ 関連記事
- FreeBSDのportsとは?pkgとは?rpm/yum/dnf(Red Hat系Linux)との違い。
- MariaDB Serverのチューニング設定(2025年8月版)
- FreeBSD14 + Nginx + fail2banで不正なアクセスを自動ブロック
- FreeBSD 14 + Nginx + PHP + MariaDB + Postfixの環境を構築(2024年版)
- Nginx+PHP-FPMのTuning設定