
先日、とある会社さんのサーバーにAWSのWAFをセットしたいとのことで、色々な対応をしました。
Nginxを使っているそのサーバーで色々な処理をすることになったので、
今更ながら、Nginxの設定備忘録として、ブログに残しておきたいと思います。
そもそも、Nginxって何?という人は、この記事は読み飛ばしてくださいませ。
何故ApacheよりもNginxの方がいいのか?
まず前提として、ApacheがダメでNginxが優れている、という単純な話ではありません。用途と設計思想が違う、というのが正確な理解です。
Apacheは「プロセスベース(あるいはスレッドベース)」でリクエストを処理するため、柔軟性が高く、.htaccessのようなディレクトリ単位の設定も可能です。
その代わり、同時接続数が増えるとメモリ消費が増えやすくなります。
一方でNginxは「イベント駆動型」のアーキテクチャを採用しています。
少ないプロセスで大量の接続を効率よく捌くことができるため、以下のようなケースで真価を発揮します。
・高トラフィックなWebサイト
・APIサーバー
・リバースプロキシ用途
・静的コンテンツ配信
実際の現場では「フロントにNginx、バックエンドにApacheやアプリケーションサーバ」という構成もよく見かけます。
今回のようにWAFと組み合わせる場合も、Nginxは非常に扱いやすいポジションにいます。
まあ、とにかく軽くて早いんですよね。
Basic認証
NginxでのBasic認証は非常にシンプルです。Apacheと違い.htaccessが使えないため、設定ファイルに直接書く形になるのが少し面倒に感じるかもしれませんが、慣れればこっちの方が安定感があります。
サンプル
まずはパスワードファイルを作成します。
htpasswd -c /etc/nginx/.htpasswd testuser
そして、Nginxの設定に以下を追加します。
location /admin/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
これだけで /admin/ 以下にアクセスした際に認証が求められるようになります。
ポイントは「location単位で制御できる」ことです。
つまり、
特定のパスだけを簡単に保護できます。開発環境や一時的な制限にも便利ですね。
自分はよく忘れてしまうんですが、Web制作の時のサンプルデモ画面などをクライアントに伝えるときに、Basic認証をつけるようにしましようね。
locationでURIやGETクエリの振り分け
Nginxの肝とも言えるのが location ディレクティブです。
これによってリクエストの振り分けを行います。
例えば、URIベースの振り分けは以下のように書きます。
location /api/ {
proxy_pass http://backend_api;
}
location /static/ {
root /var/www/html;
}
ここまでは基本ですが、少し踏み込むと正規表現も使えます。
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
include fastcgi_params;
}
さらに厄介なのが「GETクエリで分岐したい」というケースです。
Nginxは基本的に
URIベースなので、クエリは直接扱いづらいです。
例えば ?preview=1 のときだけ挙動を変えたい場合、以下のように書くことができます。
if ($arg_preview = "1") {
return 403;
}
ただし、この if はクセが強く、使い方を間違えると意図しない挙動になります。
そのため、実務では次に説明する map を使うことが多いです。
ちなみに、前述したBasic認証は、if文の中には書くことができないので、そういう場合はmapを使わざるを得ません。
mapを使って変数対応
map はNginxで条件分岐を安全に扱うための強力な機能です。
設定ファイルの上位(httpコンテキスト)に書くことで、変数を生成できます。
例えば、特定のクエリが付いている場合だけフラグを立てる場合は以下のように書きます。
map $arg_preview $is_preview {
default 0;
1 1;
}
これによって $is_preview という変数が使えるようになります。
実際の制御は以下のように書けます。
location / {
if ($is_preview) {
return 403;
}
proxy_pass http://backend;
}
また、複雑な条件もまとめることができます。
map "$request_uri|$arg_token" $block_flag {
default 0;
"~^/admin/|$" 1;
}
このように「URI + クエリ」を組み合わせた判定も可能です。
実務的には、WAFの前段や軽いフィルタリング、A/Bテストの分岐などにも応用できます。
if を乱用するより、map で整理した方が読みやすく、事故も減ります。
ちなみに、mapの記述は、
/etc/nginx/nginx.conf このファイルに記述するんですが、この説明があまりされなくて、勘違いしてlocationと同じファイルに書いてしまいました。
あとがき
久しぶりにNginxの設定をがっつり触ってみて、「やっぱりよくできてるな」と改めて感じました。
最初はとっつきにくい部分もありますが、仕組みがわかってくると、かなり直感的に扱えるようになります。
特に今回のようにAWS WAFと組み合わせたり、細かい条件分岐を求められるケースでは、Nginxの柔軟性がそのまま開発スピードに直結します。
設定ファイル一つでここまで制御できるのは、やはり強みです。
こういった設定は一度作って終わりではなく、あとから見返すことが多いので、今回のように備忘録として残しておくのは大事だなと改めて思いました。
未来の自分が「これどうやってたっけ?」となったときに、きっと助けてくれるはずです。
0 件のコメント:
コメントを投稿