ちょっと前に CentOS で nginx (1.8) の設定をした時に、「ん?」となったところを、簡単にまとめておきます。
分かってしまえば当たり前のことばかりなのですが、もしどなたかのお役に立ちましたら。
読み込み中です。少々お待ち下さい
前提
まずは、前提として CentOS の話であり、ディレクトリ構成は yum で単純にインストールしたままとします。
すなわち、設定ファイル等は「/etc/nginx/」配下、http のドキュメントルートは「/usr/share/nginx/html/」です。
設定ファイルもデフォルトのまま、http Context は「/etc/nginx/nginx.conf」、server および location Context は「/etc/nginx/conf.d/default.conf」に、ここでは記述することとします。
お手持ちの環境と異なる場合は、適宜読み替えてください。
root を指定しよう
すんごい基本的なところから。
nginx の設定例として、次のような書き方を、良く見かけます。
location /test/ {
index index.$geo.html index.html;
}
もしくは、以下のようだったり。
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
...
server {
...
location /download/ {
limit_conn addr 1;
}
素直に、上の通りに書いてしまうと、「/usr/share/nginx/html/」配下に test や download ディレクトリ(及びコンテンツファイル)が確かに存在するにも関わらず、Web ブラウザからアクセスすると 404 が返されてしまい、「あれ?」となってしまうことがあります。
これは何故かといいますと、location コンテキストで root が指定されていない為、ドキュメントルートのディレクトリから相対パスでファイルを読み込もうとして見つからないので発生しているようです。
で、エラーログを見ると、内部的なドキュメントルートが「/etc/nginx/html/」になっちゃってるっぽいんですよね。
これは、あくまで CentOS の yum でインストールした場合の話であり、特に何も弄らずにソースから make install すると「/usr/local/nginx」配下に html も conf も全部まとめられるので、この問題は発生しないのだろうと思います。
まぁ、でも、なんか良く分からんけど 404 になってしまう場合は、以下のように location コンテキストでドキュメントルートの実際のパスを root として指定してあげるといいんじゃないでしょうか。
location /test/ {
root /usr/share/nginx/html;
index index.$geo.html index.html;
}
もちろん、server コンテキスト等で一括して指定しても構いません。
include に関する注意点
これも、あちこちで見かける書き方なのですが、例えば DoS 対策として同時接続数やリクエスト数による制限を行なう場合に、以下のように記述されたしと説明されていることが多いです。
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
...
server {
...
location /download/ {
limit_conn addr 1;
}
location /search/ {
limit_req zone=one burst=5;
}
上記の内容はどうでもよくて、あくまで説明に際しての書き方のサンプルです。
なので、接続制限の内容については本家の ngx_http_limit_conn_module や ngx_http_limit_req_module をご覧いただきたいのですが(簡単に説明すると、上の設定は同一 IP アドレスから同時に 1 接続しか許可せず、burst は置いといて 1 秒間に 1 リクエストしか許可しません。本家の例そのままですが、これだと厳しすぎるので、実際は実態に即した設定をしましょう)、このような例を参考にした場合、「nginx -t」でテストした時や「nginx -s reload」で設定を再読み込みした時に、気をつけないと「unknown limit_req_zone "one" in /etc/nginx/conf.d/default.conf」みたいに怒られてしまうことがあります。
これは何故かといいますと、limit_conn_zone や limit_req_zone は http コンテキストのディレクティブなので「/etc/nginx/nginx.conf」に、limit_conn や limit_req は http, server, location コンテキストに記述できますが、上の例では location コンテキストなので、ここでは「/etc/nginx/conf.d/default.conf」に記述することになります。
そして、デフォルトのままだと「/etc/nginx/nginx.conf」の一番下の方に「include /etc/nginx/conf.d/*.conf」という行があり、これによって、「/etc/nginx/conf.d/」配下の設定ファイルがインクルードされる訳なのですが、遅延ではなく即時 include なので、limit_conn_zone や limit_req_zone を include 文の後に書いてしまうと、default.conf が読み込まれた時には、まだ設定されていないことになってしまい、エラーとなるのです。
つまり、インクルード先で利用する設定を nginx.conf に記述する場合は、
http {
...
include /etc/nginx/conf.d/*.conf;
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
ではなく、以下のように「include /etc/nginx/conf.d/*.conf」行の前に書きましょう。
http {
...
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
include /etc/nginx/conf.d/*.conf;
自分で新たに設定を追加する場合は、設定ファイルの一番下に書くクセのある方も多いと思いますので、ちょっと意識しておくと良いかも知れません。
参照元(Referer)によるアクセス制限
ここからは、もう少し具体的なサンプルをご紹介します。
まずは、良くある「参照元(Referer)が自ドメイン以外の場合はアクセスを拒否する」≒「画像への直リンを禁止する」設定方法について。
location ~* /images/.*(\.jpg|\.png|\.gif|\.jpeg)$ {
root /usr/share/nginx/html;
valid_referers server_names *.yourdomain.com yourdomain.com;
if ($invalid_referer) { return 403; }
}
大抵の場合は、こんな感じでイケると思います(もちろん、yourdomain は自分のドメインに置き換えます)。
~* というプレフィックスは case-insensitive という意味なので、拡張子の大文字小文字は区別されません。
Google 先生に限って追加で許可したい場合は、valid_referers のお尻に「~\.google\.」を足したりすると良いでしょう。
さらに詳しくは、本家の ngx_http_referer_module をご覧ください。
なるべくキャッシュさせない
Web ブラウザ等のクライアントに効率良くキャッシュさせる方法はあちこちで見かけるのですが、逆にキャッシュさせたくない場合については、「HTTP のレスポンスヘッダに Cache-Control とかを追加したかったら、HttpHeadersMoreModule を使えばいいんじゃね」みたいに書かれていることが多く、ところが HttpHeadersMoreModule を利用するにはソースからビルドしないといけないので管理面が煩雑になってしまう為、できれば標準の機能だけで賄いたいところです。
で、実際にどうするかというと、ngx_http_core_module と ngx_http_headers_module でなんとかしてみます。
具体的には、こんな感じ(no-cache 配下のコンテンツをキャッシュさせない例)。
location /no-cache/ {
root /usr/share/nginx/html;
expires -1;
etag off;
if_modified_since off;
}
expires にマイナスを指定すると、"Cache-Control: no-cache" が自動的に追加されます。
さらに etag と if-modified-since を無視することにより、クライアントからの要求がどうだろうと、基本的に 200 でデータを送り返すようになります。
常にキャッシュではなく最新の実データを、クライアントに読み込ませたい場合に、このような設定が使えるかも知れません。
ただし、当然ですが、その分だけサーバーと帯域に負荷がかかりますので、ご注意を。
おわりに
ホントは、それぞれ別記事にして見通しを良くするべきかも知れませんが、分けて書くほどの内容でもないのでまとめてしまいました。
いちいち記事を長くしてしまうのは、悪い癖ですね。すみません。