nginx njs:モジュールのインストールと js_set の設定、reload の適用で JavaScript 変数を作る

nginx njsは、nginxの設定の中でJavaScriptの関数を使ってリクエストを処理したり変数の値を作ったりする、nginx公式のモジュールです。Nginx + Apache構成のサーバーで、nginxの設定だけでは変えられないリクエストURLの大文字・小文字をそろえるため、njsモジュールをインストール済みのnginxと同じバージョンで入れ、js_setで作った変数をキャッシュファイルのパスに入れて、再起動なしのreloadで適用しました。
例に挙げた関数は、ハングルURLのパーセントエンコーディングを小文字に変える1行だけのもので、リクエストオブジェクトからヘッダーや引数の値を読んで変数を作るやり方も同じです。
1️⃣ nginx njsとは:JavaScriptでnginxの機能を拡張するモジュール
njsはNode.jsのように単独で動くJavaScriptの実行環境ではなく、起動スクリプトや独自のイベントループもありません。nginxが設定で指定された関数を呼び出したときだけコードが実行され、その後処理はnginxに戻ります。
nginxがJavaScriptの関数を呼び出す場所は、HTTPのリクエストと応答の処理段階、TCP・UDPセッションの処理段階、変数の値の計算、定期タイマーに決まっています。関数はnginxが渡すリクエストオブジェクトからURL・ヘッダー・引数を読み、結果を応答や変数の値として返します。
HTTP側のディレクティブは、[js_import]でスクリプトファイルを読み込み、[js_set]で変数の値を、[js_content]で応答本文を作り、[js_header_filter]と[js_body_filter]で応答ヘッダーと本文を加工します。今回の適用で使ったディレクティブは[js_import]と[js_set]の2つです。
njsモジュールの基本エンジンは、ECMAScript 5.1(strict mode)に一部のECMAScript 6以降の機能を加えた範囲で実装されています。正規表現の置換や関数程度の文字列処理は、この範囲内で動作します。
2️⃣ njsが必要な場合:nginxの設定だけでは変えられない変数の値
WordPressプラグインのWP Rocketは、ハングルURLの記事のキャッシュフォルダー名をパーセントエンコーディングの小文字で作り、ブラウザーは同じURLを大文字でエンコードしてリクエストします。このサーバーではWordPressサイトが運用されています。
nginxがリクエストURLのままキャッシュファイルのパスを作ると大文字・小文字が食い違ってファイルが見つからず、リクエストはApacheとPHPに渡ります。
nginxの設定だけではこの値を小文字に変えられません。[map]は決めておいた値の中から一つを選ぶだけで文字列を変換できず、インストール前の[nginx -V]の出力とモジュールフォルダーにはperlやluaのモジュールもありませんでした。
変えるURLが数個だけなら[map]の対応表でも処理できますが、新しい記事ができるたびに表を作り直してreloadしなければなりません。URLごとに異なる値を同じ規則で変える必要がある場合は、[js_set]の関数1つで新しい記事やタグ、カテゴリーのURLまで処理できます。

perlモジュールの[perl_set]も同じ場所で使え、リポジトリにはnginxと対になるパッケージもありますが、nginxの公式ドキュメントはperlモジュールを実験的なモジュールとして案内しています。
3️⃣ nginx njsのインストール:インストール済みのnginxと同じバージョンで
パッケージ名だけでインストールするとnjsだけが追加されそうですが、リポジトリの最新njsが最新のnginxを要求するため、nginxまで一緒にアップグレードされます。インストール前の確認では、バージョンを書かないインストールコマンドがnginx 1.28.0を1.30.6に上げる計画を表示しました。
そこで、まず今インストールされているnginxのバージョンを確認します。
rpm -q nginxnginx-1.28.0-1.el9.ngx.x86_64リポジトリにはnginxのバージョンごとに対になるnjsパッケージが別にあり、バージョン番号の+の前がnginxのバージョン、後ろがnjsのバージョンです。
dnf list --showduplicates nginx-module-njs | grep '1.28.0+'nginx-module-njs.x86_64 1:1.28.0+0.9.4-1.el9.ngx @nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.8.10-1.el9.ngx nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.9.0-1.el9.ngx nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.9.1-1.el9.ngx nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.9.2-1.el9.ngx nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.9.3-1.el9.ngx nginx-stable
nginx-module-njs.x86_64 1:1.28.0+0.9.4-1.el9.ngx nginx-stablenginx 1.28.0と対になるバージョンは0.8.10から0.9.4までの6つで、一番上の@nginx-stableの行がインストール済みのバージョンです。インストールはその中で最新の0.9.4を、バージョン番号まで書いて進めます。
dnf install nginx-module-njs-1:1.28.0+0.9.4-1.el9.ngxインストールしたパッケージが要求するnginxのバージョンは、rpmで確認できます。
rpm -q --requires nginx-module-njs | grep nginxnginx-r1.28.0rpm -ql nginx-module-njs | grep -v build-id/usr/bin/njs
/usr/lib64/nginx/modules/ngx_http_js_module-debug.so
/usr/lib64/nginx/modules/ngx_http_js_module.so
/usr/lib64/nginx/modules/ngx_stream_js_module-debug.so
/usr/lib64/nginx/modules/ngx_stream_js_module.so
/usr/share/doc/nginx-module-njs
/usr/share/doc/nginx-module-njs/CHANGES
/usr/share/doc/nginx-module-njs/COPYRIGHTインストールされたファイルは、HTTPモジュールとTCP・UDPを処理するstreamモジュール、それぞれのデバッグ版、コマンドラインツールnjsです。今回の設定で読み込むファイルは、HTTPモジュールの[ngx_http_js_module.so]1つです。
4️⃣ js_setの設定:モジュールの読み込みからキャッシュファイルのパスまで
パッケージをインストールしてもnginxはモジュールを自動では読み込まず、nginx.confの一番上に[load_module]の行が必要です。公式ドキュメントによると[load_module]はmainコンテキストのディレクティブなので、events・httpブロックの外に置きます。
# /etc/nginx/nginx.conf の一番上(events・httpブロックの外)
load_module modules/ngx_http_js_module.so;変換関数は設定ファイルとは別の.jsファイルに置き、最後の行のexport defaultで書き出した関数をnginxの設定から読み込みます。
// /etc/nginx/njs/rocket.js — パーセントエンコーディング %XX だけ小文字に
function lc(r) {
return r.variables.request_uri.replace(/%[0-9A-F]{2}/g, function (m) { return m.toLowerCase(); });
}
export default { lc };関数はリクエストオブジェクトrから[request_uri]変数を読み、パーセント記号の後ろの2文字が大文字のところだけを小文字に変えて返します。英字はそのままにするので大文字が混じった英語のURLは変わらず、WP Rocketがキャッシュフォルダー名を作る規則と同じです。
# httpブロック内(conf.d の .conf ファイル)
js_import rkt from /etc/nginx/njs/rocket.js;
js_set $rocket_uri rkt.lc;[js_import]のrktはモジュール内の関数を呼ぶ名前で、[js_set]がその関数の結果を[$rocket_uri]変数にします。公式ドキュメントによると、この関数はリクエストで変数が初めて参照されたときに実行され、同期処理だけをサポートします。
# serverブロック — キャッシュファイルのパスの $request_uri を $rocket_uri に
set $rocket_file '/wp-content/cache/wp-rocket/example.com${rocket_uri}index$rocket_mobile-https.html';変わったのはキャッシュファイルのパスを作るこの1行だけで、ログインCookieやクエリ、POSTリクエストをキャッシュから外す判定はそのままにします。
5️⃣ 適用と確認:reload後のエラーログと応答ヘッダー
まず設定チェックを実行し、通ればreloadします。
nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successfulsystemctl reload nginx新しく入れた[load_module]の行は、再起動なしのreloadで反映されました。エラーログにはnjsの仮想マシンを初期化した行が残り、JavaScriptのエラーはありませんでした。
grep 'js vm init' /var/log/nginx/error.log | head -12026/10/17 18:21:35 [notice] 27992#27992: js vm init njs: 0000559FDF6D0E00行末のnjsは使用中のエンジン名です。同じ行は[nginx -t]で設定をチェックするときにも記録されるので、reloadの時刻と合わせて確認します。
curl -sI 'https://example.com/-/' | grep -i 'x-rocket\|content-type'content-type: text/html
x-rocket-nginx-serving-file: HIT大文字でエンコードされたハングルURLにも、nginxがキャッシュファイルで応答したことを示すヘッダーが付きました。クエリやログインCookieが付いたリクエストとPOSTリクエストは、適用後もそのヘッダーなしでPHPに渡りました。
6️⃣ njsの取り消しとnginxのアップデート
元に戻すときは、キャッシュファイルのパスの[$rocket_uri]を[$request_uri]に戻し、[js_import]・[js_set]の設定ファイルと[load_module]の行を外してから、設定チェックを経てreloadします。
# serverブロック — 元の変数に
set $rocket_file '/wp-content/cache/wp-rocket/example.com${request_uri}index$rocket_mobile-https.html';パッケージは残しておいても[load_module]の行がなければnginxは読み込まないので、完全に消すときだけパッケージを削除します。
dnf remove nginx-module-njsnginxをアップデートするときは、njsパッケージも新しいnginxのバージョンと対になるバージョンへ一緒に上げる必要があります。アップデートの前に[dnf list --showduplicates]で、新しいnginxのバージョンに対応するnjsがリポジトリにあるかを確認します。
🔢 FAQ & おすすめコンテンツ









ℹ️ 提携について
当サイトのコンテンツにはアフィリエイトリンクが含まれています。訪問者がこのリンクを通じて商品やサービスを購入すると、当サイトは販売元から手数料を受け取ります。この過程において、購入者が支払う金額(イベント割引適用で金額が下がります↓)は上昇しません。掲載されている価格・割引・在庫情報は作成時点のものであり、実際とは異なる場合がありますので、ご購入前に販売元にて最終確認をお願いいたします。商品の選定および評価は独自の基準に基づいて行われており、手数料の支払いの有無は紹介順や評価内容に影響を与えません。






