NGINX の if
は本当に “evil” なのか?
IfIsEvil ドキュメントを読み解き、運用で失敗しないためのチェックリスト
1. はじめに
NGINX の設定サンプルを調べると、「if
は evil だから使うな」という警告をよく目にします。実際に公式 Wiki の IfIsEvil ページでも強い表現が使われていますが、それは location コンテキスト内の if に限った話です。
2. IfIsEvil とは?
「ディレクティブ if には location コンテキストで問題がある」
“100% 安全” とされているのは return
と rewrite ... last
のみです。
3. なぜ location 内の if が危険なのか
3-1. 暗黙の “nested location” が発生する
rewrite モジュールと宣言型の設定のギャップにより、NGINX は内部で一時的な location を生成・破棄します。これにより副作用が起きる可能性があります。
3-2. 具体的な事故例
# add_header が片方しか付かない
location /only-one-if {
set $true 1;
if ($true) { add_header X-First 1; }
if ($true) { add_header X-Second 2; }
return 204;
}
# proxy_pass の URI が書き換わらない
location /proxy-pass-uri {
proxy_pass http://127.0.0.1:8080/;
if ($arg_debug) { }
}
# if を入れた瞬間 try_files が無効化
location /if-try-files {
try_files /file @fallback;
if ($true) { }
}
4. “安全な if” の範囲
- server コンテキストで使う
return
とrewrite ... last
のみ location 内でも可
location /old/ {
if ($request_uri ~* /$) { return 301 /new/; }
}
5. 代替パターン
用途 | 代替手段 | 例 |
---|---|---|
ファイル存在チェック | try_files | try_files $uri $uri/ /index.php?$args; |
変数マッチでルーティング | map | map $http_user_agent $is_bot { default 0; ~*bot 1; } |
リダイレクト / ステータス | return | return 403; |
複雑な分岐 | Lua / Perl / njs | content_by_lua_block { ... } |
6. if 使用時のチェックリスト
- server コンテキストに置けないか?
- return または rewrite ... last だけで済まないか?
- 再帰的 rewrite を起こさないか?
- nginx -t だけでなく実リクエストで確認したか?
7. 最近の議論と誤解
「if は evil」という表現が誤解を招くとの指摘があり、現在は「location コンテキストでの if に注意」へと解釈が整理されています。
8. まとめ
- “evil” は location コンテキストの if の話
- return と rewrite ... last 以外は location で使わない
- try_files / map / return / Lua などで代替を
- 使うなら server 内 or 十分にテストを
参考リンク
この記事が役立ったらぜひシェアしてください!