編集者 – 「NGINX JavaScriptモジュールの概要」というタイトルのブログ記事から、このページにリダイレクトされます。この記事は、2021年4月時点でサポートされているNGINX JavaScript Moduleのディレクティブと機能を反映して更新されています。

NGINX JavaScriptモジュール(njs)は、NGINX Open Source 1.11.10およびNGINX Plus R12で安定版モジュールとして一般提供が開始されました。[このモジュールは当初nginScriptと呼ばれていたため、一部の古い投稿ではその名称が使用されています。]NGINX JavaScriptは2015年9月のリリース以来、継続的に開発が進められ、安定版モジュールに含まれる機能と言語サポートが追加されてきました。
NGINX JavaScriptは、サーバーサイドのユースケースとリクエスト単位の処理に特化して設計された、NGINXおよびNGINX Plus向けの独自のJavaScript実装です。NGINXの設定構文をJavaScriptコードで拡張し、高度な設定ソリューションを実現します。
NGINX JavaScriptモジュールはHTTPとTCP/UDPの両方のプロトコルで利用できるため、幅広いユースケースに対応します。NGINX JavaScriptのユースケース例は次のとおりです。
- 通常のNGINX変数では取得できない値を使用したカスタムログ形式の生成(例:診断ログ)
- プロキシ先サーバーからのレスポンスの変更(レスポンスフィルタリング)
- カスタム認証スキームの実装(例:OAuth 2.0トークンイントロスペクション)
- アプリケーションレベルのスティッキーセッション用にTCP/UDPプロトコルを解析(例:MQTT負荷分散)
NGINX JavaScriptについて詳しく説明する前に、まずよくある2つの誤解を解消しておきましょう。
NGINX JavaScriptはLuaではない
NGINXコミュニティは長年にわたり、プログラムによる拡張機能を複数開発してきました。執筆時点では、その中でLuaが最も広く利用されており、NGINX用モジュールおよびNGINX Plus向けのサポート対象のビルド済みサードパーティ製ダイナミックモジュールとして提供されています。Luaモジュールとアドオンライブラリは、NGINXコアとの緊密な統合に加え、Redis用ドライバーを含む豊富な機能を提供します。
Luaは強力なスクリプト言語です。しかし、採用は比較的限定的であり、フロントエンド開発者やDevOpsエンジニアが一般的に備えているスキルセットには含まれていません。
NGINX JavaScriptはLuaに取って代わることを目指すものではなく、同等の機能レベルに達するまでにはしばらく時間がかかります。NGINX JavaScriptの目標は、広く普及しているプログラミング言語を使用することで、プログラムによる構成ソリューションを可能な限り幅広いコミュニティに提供することです。
NGINX JavaScriptはNode.jsではない
NGINX JavaScriptは、NGINXまたはNGINX Plusをアプリケーションサーバーに変えることを目的としたものではありません。簡単に言えば、JavaScriptコードはクライアントとコンテンツの間で実行されるため、NGINX JavaScriptのユースケースはミドルウェアに似ています。技術的には、Node.jsと、NGINX JavaScriptをNGINXまたはNGINX Plusと組み合わせた構成には、イベント駆動型アーキテクチャとJavaScriptプログラミング言語という2つの共通点がありますが、類似点はそれだけです。
Node.jsはGoogle V8 JavaScriptエンジンを使用します。一方、NGINX JavaScriptは、NGINXおよびNGINX Plus専用に設計されたECMAScript標準の独自実装です。Node.jsは永続的なJavaScript仮想マシン(VM)をメモリ内に保持し、メモリ管理のために定期的なガベージコレクションを実行します。一方、NGINX JavaScriptはリクエストごとに新しいJavaScript VMと必要なメモリを初期化し、リクエストが完了するとそのメモリを解放します。
サーバーサイド言語としてのJavaScript
前述のとおり、NGINX JavaScriptはJavaScript言語の独自実装です。既存の他のJavaScriptランタイムエンジンはすべて、Webブラウザ内で実行されるように設計されています。クライアント側とサーバー側では、システムリソースの可用性から同時実行可能なランタイム数に至るまで、コード実行の性質がさまざまな点で異なります。
サーバーサイドでのコード実行要件を満たし、NGINXのリクエスト処理アーキテクチャに無理なく適合させるため、独自のJavaScriptランタイムを実装することにしました。NGINX JavaScriptの設計原則は次のとおりです。
- ランタイム環境のライフサイクルはリクエストと連動NGINX JavaScriptモジュールは、迅速に初期化および破棄できるよう設計された、シングルスレッドのバイトコード実行方式を採用しています。ランタイム環境はリクエストごとに初期化されます。初期化が必要な複雑な状態やヘルパーがないため、起動は非常に高速です。実行中のメモリはプールに蓄積され、完了時にプールを解放することで一括して解放されます。このメモリ管理方式により、個々のオブジェクトを追跡して解放したり、ガベージコレクターを使用したりする必要がありません。
- ノンブロッキングでのコード実行NGINXとNGINX Plusのイベント駆動モデルは、個々のNGINX JavaScriptランタイム環境の実行をスケジューリングします。NGINX JavaScriptルールがブロッキング操作(ネットワークデータの読み取りや外部サブリクエストの発行など)を実行すると、NGINXとNGINX Plusは、関連するNGINX JavaScript VMの実行を透過的に一時停止し、イベントの完了時に再スケジューリングします。これにより、ルールをシンプルかつ直線的に記述でき、NGINXとNGINX Plusが内部でブロッキングすることなく実行をスケジューリングします。
- 必要な言語機能のみを実装JavaScriptの仕様は、ECMAScript標準で定義されています。NGINX JavaScriptは、ECMAScript 5.1に準拠し、数学関数には一部のECMAScript 6を採用しています。独自のJavaScriptランタイムを実装することで、サーバーサイドのユースケースに必要な言語機能を優先し、不要な機能を除外できます。現在サポートされている言語要素の一覧を公開しています。
- リクエスト処理フェーズとの緊密な統合NGINXとNGINX Plusは、リクエストを個別のフェーズに分けて処理します。通常、設定ディレクティブは特定のフェーズで動作し、ネイティブNGINXモジュールでは、特定のフェーズでリクエストを検査または変更できる機能がよく活用されます。NGINX JavaScriptでは、一部の処理フェーズを設定ディレクティブを通じて公開し、JavaScriptコードを実行するタイミングを制御できるようにしています。この設定構文との統合により、ネイティブNGINXモジュールの強力さと柔軟性を、JavaScriptコードの簡潔さとともに活用できます。以下の表は、執筆時点でNGINX JavaScriptからアクセスできる処理フェーズと、そのアクセスを可能にする設定ディレクティブを示しています。
| 処理フェーズ | HTTPモジュール | Streamモジュール |
|---|---|---|
Access – 認証とアクセス制御 | auth_requestおよびjs_content | js_access |
Pre-read – ペイロードの読み取り/書き込み | 該当なし | js_preread |
Filter – プロキシ処理中のレスポンスの読み取り/書き込み | js_body_filterjs_header_filter | js_filter |
Content – クライアントへのレスポンス送信 | js_content | 該当なし |
Log / Variables – オンデマンドで評価 | js_set | js_set |
NGINX JavaScript入門 – 実践的な例
NGINX JavaScriptは、NGINX Open Sourceバイナリにコンパイルして組み込むことも、NGINXまたはNGINX Plusに動的にロードすることもできるモジュールとして実装されています。NGINX JavaScriptを有効にする手順(NGINXおよびNGINX Plus向け)は、この記事の末尾に記載されています。
この例では、NGINXまたはNGINX Plusをシンプルなリバースプロキシとして使用し、NGINX JavaScriptを使用して、次のような特殊な形式のアクセスログエントリを作成します。
- クライアントから送信されたリクエストヘッダーを含む
- バックエンドから返されたレスポンスヘッダーを含む
- キーと値のペアを使用することで、ELK Stack(現在の名称はElastic Stack)、Graylog、Splunkなどのログ処理ツールへの効率的な取り込みと検索が可能です
この例のNGINX設定は非常にシンプルです。
コード例を読み込み中…
ご覧のとおり、NGINX JavaScriptコードは設定構文内に直接記述しません。代わりに、js_importディレクティブを使用して、すべてのJavaScriptコードを含むファイルを指定します。js_setディレクティブでは、新しいNGINX変数$access_log_headersと、その値を設定するJavaScript関数を定義します。log_formatディレクティブでは、kvpairsという新しい形式を定義します。この形式では、各ログ行に$access_log_headersの値が書き込まれます。
The serverブロックでは、すべてのリクエストをhttps://www.example.comに転送するシンプルなHTTPリバースプロキシを定義します。access_logディレクティブでは、すべてのリクエストをkvpairs形式でログに記録するよう指定します。
次に、ログエントリを作成するJavaScriptコードを見てみましょう。
コード例を読み込み中…
The return value from the kvAccess関数の戻り値であるログエントリは、js_set設定ディレクティブ(rawheader_logging.conf内)に渡されます。NGINX変数は必要に応じて評価されるため、js_setで定義されたJavaScript関数は、その変数の値が必要になった時点で実行されます。この例では、$access_log_headersがlog_formatディレクティブで使用されているため、kvAccess()はログ記録時に実行されます。mapまたはrewriteディレクティブ(この例には記載されていません)で使用される変数は、対応するJavaScriptをより早い処理フェーズで実行させます。
リクエストをリバースプロキシ経由で送信し、生成されたログファイルのエントリを確認すると、このNGINX JavaScript拡張ロギングソリューションの動作を確認できます。このエントリには、接頭辞「in.」が付いたリクエストヘッダーと、接頭辞「out.」が付いたレスポンスヘッダーが含まれます。
$ curl http://127.0.0.1/$ tail --lines=1 /var/log/nginx/access_headers.log2021-04-23T10:08:15+00:00 client=172.17.0.1 method=GET uri=/index.html status=200 in.Host=localhost:55081 in.User-Agent=curl/7.64.1 in.Accept=*/* out.Content-Type=text/html out.Content-Length=612 out.ETag=x22606339ef-264x22 out.Accept-Ranges=bytesNGINX JavaScriptの有用性の多くは、NGINXの内部機能にアクセスできることによるものです。この例では、リクエスト(r)オブジェクトのプロパティをいくつか使用しています。Stream NGINX JavaScriptモジュール(TCPおよびUDPアプリケーション向け)では、独自のプロパティセットを持つセッションオブジェクト(s)を使用します。HTTPおよびTCP/UDP向けのNGINX JavaScriptソリューションのその他の例については、NGINX JavaScriptモジュールのユースケースを参照してください。
NGINX JavaScriptのユースケースを思いついたら、ぜひ下のコメント欄でお聞かせください。
NGINX JavaScriptモジュールのユースケース
NGINX JavaScriptモジュールのその他のHTTPおよびTCP/UDPユースケースについては、以下のブログ記事をご覧ください。
- ローカルコンテキストでのJavaScriptコードと変数の宣言(「njs 0.7.7でNGINX設定をさらにモジュール化し、再利用性を向上」より)
- NGINXをDoTまたはDoHゲートウェイとして使用する
- NGINX Plus R26の発表 – 非同期関数の使用、WebCrypto APIを使用した暗号学的に安全な乱数の生成とテキスト文字列のハッシュ化
- NGINXによるlog4j脆弱性の緩和
- NGINX JavaScriptモジュールによる高度なロギング(「TCPロードバランシングとGalera ClusterによるMySQLのスケーリング」内)
- NGINX Plus R24の発表 – ボディとヘッダーの両方に対するレスポンスフィルタリング、組み込みHTTPクライアントを使用したTCP/UDP接続の認証
- リクエストボディの検証(「NGINX PlusをAPIゲートウェイとして導入する:パート2:バックエンドサービスの保護」内)
- NGINX JavaScriptモジュールを使用した診断ログ<.htmla>
- NGINX Plus R22の発表 – エラーが発生するたびに、クライアントから送信されたヘッダー一式を正確にログに記録
- NGINX Plus R21の発表 – コールバックを使用せずに単一のコードシーケンス内でサブリクエストを連鎖させる機能、およびリクエストヘッダーのコピーをセキュリティ情報イベント管理(SIEM)システムに送信する機能
- POSTは1回だけ:F5とNGINX JavaScript Moduleで宣言型DNSを実現
- NGINX JavaScript Moduleによる
auth_requestの拡張(「NGINXおよびNGINX PlusによるOAuth 2.0アクセストークンの検証」内) - NGINXを使用したIoTデバイスの無線アップデート
- NGINX Plus R18の発表 – クライアントの実際のIPアドレスではなく、ハッシュ化(マスキング)したIPアドレスをログに記録
- NGINX JavaScript Moduleによる仮想パッチ適用
- NGINX PlusとNGINX JavaScript ModuleによるAPIリクエストのバッチ処理
- NGINX Plus R15の発表 – 2つの異なるバックエンドにHTTPリクエストを同時に送信し、最初のレスポンスを転送して2番目のレスポンスを無視する機能、およびアプリケーションCookieにデータ整合性を追加する機能
- JavaScriptハッシュによる変更検出のスケールアウト(「アクティブヘルスチェックによるホームページ改ざんの検出」より)
- nginScriptによるTCP.htmlUDPロードバランシングの拡張(「NGINXによるTCP/UDPロードバランシング:概要、ヒント、テクニック」内)
- クライアント証明書を使用したMQTTクライアントの認証(「IoT向けNGINX Plus:MQTTトラフィックの暗号化と認証」)
- NGINX JavaScriptモジュールを使用したセッション永続化のためのMQTT負荷分散(「IoT向けNGINX Plus:MQTTの負荷分散」)
- NGINX JavaScript Moduleによるユーザープライバシー保護のためのデータマスキング
- NGINX Plus R11の発表 – MySQLプロトコルストリーム内のメッセージから主要なパターンを検索し、SQL操作を特定
- NGINX JavaScriptモジュールを使用してクライアントを新しいサーバーへ段階的に移行する
[ngx_snippet name=’njs-enable-instructions’]
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります