技術系(Tips)
PR

nginx のバージョンアップで使える小ネタ集 ─ 署名鍵の特定・コンテナ内バージョン確認・脆弱性追跡

saratogax
記事内に商品プロモーションを含む場合があります

nginx を Docker でビルドして運用していると、毎年やってくる マイナーアップデート(例:1.28.x → 1.30.x)に加えて、リビジョンアップデート(例:1.30.0 → 1.30.2)にも目を配る必要があります。

とくに .0 リリース直後に脆弱性が公表されてパッチが切られるケースは珍しくなく、リビジョンの差分でも 「自分たちのユースケースに刺さる脆弱性か」を毎回判断する目線が要ります。

本記事では、nginx のバージョンアップ作業のなかで 過去の自分が地味に詰まった 3 つのポイント を、ショートカットになるコマンドや判断材料とあわせて整理します。

  • tarball を実際に署名している GPG 鍵を 1 コマンドで特定する
  • 起動中の Docker コンテナで動いている nginx のバージョンを確認する
  • nginx の security advisories ページを使って「いつバージョンを上げるか」を判断する

前提:nginx の mainline と stable

nginx のリリースは 2 系統に分かれています。

  • mainline:奇数マイナー(1.27, 1.29 など)。新機能が随時入る系統
  • stable:偶数マイナー(1.26, 1.28, 1.30 など)。バグ修正中心で、新機能は基本入らない系統

この「奇数=開発系・偶数=安定系」というルールは、Wikipedia の Software versioning では odd-even system と呼ばれており、古い Linux カーネル(1.0〜2.6)や Node.js(0.x 系時代)でも採用されていた方式です。

なお現在の Node.js(4.x 以降)は奇偶ルールではなく LTS スケジュールを採用しており、偶数メジャー(18, 20, 22, 24…)が LTS、奇数メジャー(19, 21, 23…)は LTS に昇格しないという別の仕組みになっています。

奇数偶数で安定版を区別するルール自体は同じですが、内部メカニズムは異なるので、nginx の mainline / stable と Node.js の LTS / Current を 「同じ仕組みだ」と一括りにしない ように注意してください。

本記事では、本番運用しているプロダクトを想定して stable 系(偶数マイナー)を追いかける前提で話を進めます。

tarball を署名している GPG 鍵を 1 コマンドで特定する

nginx を Docker でソースから自前ビルドしている場合、Dockerfile の中で nginx-X.Y.Z.tar.gz.asc の署名検証をしているケースがほとんどです。

このとき必要になるのが 「その tarball を実際に署名している GPG 鍵の fingerprint」 で、これを Dockerfile の GPG_KEYS 変数などに埋め込んで gpg --recv-keys します。

遠回りなやり方(あえて失敗させる)

以前の自分は、鍵が未登録の状態で一度 gpg --verify を実行し、エラー出力に出てくる鍵 ID を控えるという遠回りなやり方をしていました。

  • nginx_signing.key を取得して gpg --dearmor--import-show で候補の鍵 3 つを列挙
  • 未登録のまま gpg --verify nginx.tar.gz.asc nginx.tar.gz を叩いて「No public key」のエラーから鍵 ID を取り出す
  • その鍵 ID を --recv-keys で取り込み、再度 --verify

これでも答えにはたどり着けますが、対話的にコマンドを 3〜4 回叩く必要があり、毎年やるには面倒です。

1 コマンドで鍵を割り出すやり方

gpg --list-packets を使うと、鍵をひとつもインポートしていない状態でも、署名パケットに記録されている fingerprint をそのまま読み出せます。

ローカルに nginx の検証環境がなければ、Docker で使い捨ての Ubuntu を立てて中で実行するのが手軽です。

以下は nginx 1.30.2 を例にした実行コマンドです(バージョン部分だけ書き換えれば他のバージョンにも使えます)。

docker run --rm ubuntu:22.04 bash -c '
  apt-get update -qq &&
  apt-get install -y -qq curl gnupg2 ca-certificates >/dev/null &&
  curl -fsSL http://nginx.org/download/nginx-1.30.2.tar.gz.asc -o /tmp/nginx.tar.gz.asc &&
  gpg --list-packets /tmp/nginx.tar.gz.asc | grep -E "keyid|issuer"
'

出力はこんな感じです。

:signature packet: algo 1, keyid C8464D549AF75C0A
	hashed subpkt 33 len 21 (issuer fpr v4 D6786CE303D9A9022998DC6CC8464D549AF75C0A)
	subpkt 16 len 8 (issuer key ID C8464D549AF75C0A)

issuer fpr v4 の値 がそのリリースを署名している鍵の full fingerprint(40 桁)です。

Dockerfile の GPG_KEYS=... に書く値はこの 40 桁をそのままコピーすれば OK です。

鍵はリリースごとに変わりうる

nginx 公式の PGP keys ページにあるとおり、nginx には複数の signing key が並列に存在しており、誰がリリースを切ったかによってどの鍵で署名されているかが変わります。

そのため、「去年と同じ鍵だろう」と決めつけずに、毎回このコマンドで確認するのがおすすめです。

運がよければ去年と同じ鍵で Dockerfile を書き換えなくて済みますし、変わっていた場合も 1 コマンドで気付けます。

起動中の Docker コンテナで nginx のバージョンを確認する

ビルド後に「本当に狙ったバージョンの nginx が入ったか」を確かめる場面で使える方法を 2 つ紹介します。

公式 nginx イメージ(起動ログから読む)

Docker Hub の nginx 公式イメージは、起動時に worker process を立ち上げる notice ログでバージョンを出してくれます。

$ docker logs <container>
...
2026/05/26 09:27:46 [notice] 1#1: nginx/1.30.2
2026/05/26 09:27:46 [notice] 1#1: built by gcc 15.2.0 (Alpine 15.2.0)
2026/05/26 09:27:46 [notice] 1#1: OS: Linux 6.10.14-linuxkit

このログが出れば、nginx が正常に立ち上がっていることと、バージョンの両方を一度に確認できます。

自前ビルドイメージ(環境変数なしで確認したい場合)

ソースから nginx をビルドした自前イメージは、本番運用のために大量の環境変数が必要で、検証だけのために docker run するのが手間というケースが多いです。

そういうときは --entrypointnginx -v だけを叩くと、コンテナをすぐ停止できて確認が一瞬で終わります。

$ docker run --rm --entrypoint nginx <image-name> -v
nginx version: nginx/1.30.2

ポイントは --entrypoint nginx を指定して、引数として -v を渡すところです。

イメージ側の CMD["nginx", "-g", "daemon off;"] のように常駐起動になっていても、こちらの一発確認には影響しません。

いつバージョンを上げるか:security advisories の使い方

新しい stable が 4 月に出たからといって、必ずしも 4 月のうちに本番投入する必要はありません。

逆に「年内のいつでもいい」と先送りすると、その間に脆弱性が見つかった場合、対応が遅れてしまうこともあります。

判断材料として最も使いやすいのは、nginx 公式の security advisories ページです。

「fixed in」の列に注目する

各 advisory には Not vulnerableVulnerable のバージョン範囲が併記されています。

たとえば「1.X.0 系のうちこの脆弱性は 1.X.2 で fix」となっていれば、少なくとも 1.X.2 以降を入れるべきと読み取れます。

実際、stable 系の最初の .0 リリース直後に CVE が出てパッチが切られるケースは珍しくありません。

マイナーとリビジョンで判断軸を分ける

追従の判断軸は マイナーアップとリビジョンアップで分けて考えると整理しやすくなります。

  • マイナーアップ(例:1.28.x → 1.30.x):新しい stable の .0 が出てもすぐには本番に入れず、.1.2 で advisory が一段落したのを確認してから動く
  • リビジョンアップ(例:1.30.0 → 1.30.2):advisory のページを開いて脆弱性の内容と影響範囲を読み、自分たちのユースケース(使っているモジュール、HTTP/2・HTTP/3 の有効化、外部公開の有無など)に刺さるかで都度判断する

現場によっては「重大な脆弱性であれば社内のセキュリティチームから連絡が来る」「他プロジェクトが対応し始めてざわついたらやる」のような外部からのシグナル待ちの運用も多いと思います。

その運用自体は否定する必要はないですが、シグナルが届くのを待つだけだと「自分たちにとっては重大だがチーム全体では拾われない」脆弱性を見落とすことがあるため、advisory のページに自分で目を通す習慣だけは持っておくと安心です。

まとめ

nginx のバージョンアップ作業で、過去の自分を救えたであろう小ネタを 3 つに絞って整理しました。

  • tarball の署名鍵は gpg --list-packets *.asc | grep -E "keyid|issuer" で 1 コマンド特定
  • コンテナ内 nginx のバージョン確認は、公式イメージなら起動ログ、自前ビルドなら docker run --rm --entrypoint nginx <image> -v
  • マイナーアップは .0 直後ではなく .1 / .2 待ちで本番投入、リビジョンアップは advisory の内容を見て自分たちのユースケースに刺さるかで都度判断する

頻度が低い作業こそ、こうしたショートカットを把握しておくと地味に効きます。

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました