Nginxでセキュリティヘッダー(HSTSやX-Content-Type-Options)や、特定の「Allow」ヘッダーなどを付与する際、add_header ディレクティブは非常に便利です。
しかし、設定したはずのヘッダーがブラウザ側で確認できない、あるいは特定のページだけ消えてしまうといった現象に遭遇することがあります。これにはNginx特有の「継承ルール」と「ステータスコード」が深く関わっています。
今回は、add_header が効かない時の2大原因とその対策についてまとめます。
1. serverとlocationに記載した場合の「継承の罠」
Nginxの設定で、server ブロックと location ブロックの両方に add_header を記載した場合、「現在の階層(location)で定義されたものだけ」が有効になります。
つまり、上位の server ブロックで定義した設定は、下位の location ブロックに add_header が一つでも書かれた時点で、すべて上書き(無視)されてしまいます。
設定例:継承されないケース
例えば以下の設定では、index.html にアクセスした際、Strict-Transport-Security などのヘッダーは付与されません。
server {
listen 443 ssl http2 default_server;
server_name xxx.xx;
charset UTF-8;
# server階層の設定
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Allow "GET, POST, HEAD" always;
add_header X-Content-Type-Options nosniff;
location = /index.html {
# ここでadd_headerを定義したため、上位の3つは無視される
add_header Allow "GET, POST" always;
root /xxxx/html;
}
}公式ドキュメントの定義
Nginxの公式ページにも、以下のように明記されています。
There could be several
add_headerdirectives. These directives are inherited from the previous level if and only if there are noadd_headerdirectives defined on the current level.
(現在の階層にadd_headerディレクティブが定義されていない場合に限り、前の階層から継承されます。)
解決策
location 内で個別の add_header を設定しつつ、共通のヘッダーも付与したい場合は以下の対応が必要です。
- 設定をコピーする: 各
locationブロックに、serverブロックで共通化したい設定を再度記述します。 - サードパーティーモジュールの使用: もし環境が許すなら、headers-more-nginx-moduleを使用することで、階層に関係なくヘッダーを制御できるようになります。
2. 「always」なしは特定のHTTPステータスコードのみ有効
もう一つの落とし穴が、レスポンスのステータスコードです。
公式ページによると、デフォルト(always パラメータなし)の状態では、add_header は以下のステータスコードに対してのみ動作します。(カッコ内はNginxの対応バージョン)
- 200
- 201 (1.3.10以降)
- 204
- 206
- 301
- 302
- 303
- 304
- 307 (1.1.16, 1.0.13以降) or 308 (1.13.0以降)
REST APIやエラーページでの注意点
REST APIなどで上記以外のステータスコードを使用している場合や、4xx系・5xx系のエラーレスポンスで返却された場合は、add_headerが付与されなくなります。
解決策:全てのステータスコードで付与する設定例
エラー発生時にも共通のヘッダーを付与したい場合は、必ず末尾に always パラメータを追加します。
server {
listen 443 ssl http2 default_server;
server_name xxx.xx;
charset UTF-8;
# 「always」を付与することで、全ステータスコードでヘッダーが返る
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Allow "GET, POST, HEAD" always;
add_header X-Content-Type-Options nosniff always;
}上記の例では、全てのステータスコードに対して指定したヘッダーを追加するように設定しています。
まとめ
add_header についての仕様を正しく理解していないと、設定したはずのセキュリティヘッダーが特定のページやエラー画面で漏れてしまうなど、思わぬところでハマりかねません。
- locationブロックに個別のadd_headerを書いていないか?
- エラー時にも付与したい設定に「always」を忘れていないか?
設定を変更した際は、この2点を意識して確認しておくことをおすすめします。