ロリポップ固定IPアクセス byGMOペパボ
nginxのIP制限設定|allow/denyの書き方と効かないときの原因

nginxのIP制限設定|allow/denyの書き方と効かないときの原因

基礎知識

nginxのIP制限は allowdeny の2つのディレクティブで設定します。 許可リスト方式にするなら、許可したいIPアドレスを allow で並べ、最後に deny all; を置くのが基本形です。

location /admin/ {
    allow 203.0.113.10;
    allow 198.51.100.0/24;
    deny  all;
}

書き方自体は数行で終わります。実際に手間取るのは、設定したのに効かないというケースのほうです。原因のほとんどは次の3つです。

  1. ロードバランサーやCDNの背後にある —— nginxから見える接続元がすべてLBのIPアドレスになっている
  2. より内側の location に上書きされている —— nginxはマッチした1つの location のディレクティブしか見ない
  3. 設定を再読み込みしていない —— nginx -s reload を忘れている

この記事では、目的別の設定例と、この3つの原因への対処を解説します。

allow / deny の基本

評価のルール

ngx_http_access_moduleallow / deny は、書かれた順に上から評価し、最初に一致したものが適用されます。一致するものがなければ許可されます。

そのため、許可リスト方式では必ず末尾に deny all; を置きます。これを忘れると「列挙したIPを許可し、それ以外も許可」というザルな設定になります。

# 正しい:許可リスト方式
allow 203.0.113.10;
deny  all;

# 間違い:deny all がないので全員通る
allow 203.0.113.10;

書ける場所

allow / denyhttp / server / location / limit_except のコンテキストに書けます。目的に応じて使い分けます。

目的 書く場所
サイト全体を制限 server ブロック
管理画面など特定パスだけ制限 該当する location ブロック
全サイト共通で制限 http ブロック

目的別の設定例

サイト全体を社内IPだけに限定する

server {
    listen 80;
    server_name staging.example.com;

    allow 203.0.113.0/24;
    deny  all;

    location / {
        proxy_pass http://backend;
    }
}

ステージング環境を社外から見えないようにする、といった用途で使います。

管理画面だけ制限し、公開ページは誰でも見られるようにする

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
    }

    location /wp-admin/ {
        allow 203.0.113.10;
        deny  all;
        proxy_pass http://backend;
    }
}

WordPressの管理画面を守る典型的な構成です。この場合、location /wp-admin/ の中に proxy_pass などの必要なディレクティブも書き直す必要がある点に注意してください(後述)。

更新系のメソッドだけ制限する

参照は誰でも、更新は社内からだけ、という制御は limit_except で書けます。

location /api/ {
    limit_except GET HEAD {
        allow 203.0.113.0/24;
        deny  all;
    }
    proxy_pass http://backend;
}

特定のIPだけをブロックする

拒否リスト方式なら deny を並べるだけです。ただし攻撃元は次々変わるため、恒久的な対策としては許可リスト方式のほうが確実です。

deny 192.0.2.10;
deny 192.0.2.0/24;

「IP制限が効かない」の原因と対処

原因1:ロードバランサーやCDNの背後にある

もっとも多い原因です。 ALB、CloudFront、Cloudflareなどの背後でnginxを動かしていると、nginxから見た接続元IPアドレスはすべてそのサービスのIPアドレスになります。利用者のIPアドレスで判定しているつもりが、実際にはLBのIPアドレスを見ているため、全員が通るか全員が弾かれます。

対処は ngx_http_realip_module を使い、X-Forwarded-For ヘッダーの値を接続元として扱わせることです。

# 信頼する前段のアドレス帯を指定する
set_real_ip_from 10.0.0.0/16;
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

location /admin/ {
    allow 203.0.113.10;
    deny  all;
}

set_real_ip_from は必ず指定する

X-Forwarded-For はクライアントが自由に付けられるヘッダーです。set_real_ip_from で信頼する前段のアドレスを限定しないと、ヘッダーを偽装してIP制限を突破されます。
前段のLBやCDNのアドレス帯だけを信頼する設定にしてください。

なお、前段がCDNの場合は、nginxのIP制限よりCDN側でIP制限をかけるほうが素直です。CloudFrontを使っているならCloudFrontのIP制限設定ガイドを参照してください。

原因2:location の継承で上書きされている

nginxはリクエストにマッチした1つの location のディレクティブだけを使います。server ブロックに allow / deny を書いていても、マッチした location の中に別の allow / deny があれば、そちらだけが有効になります。

「サイト全体に制限をかけたのに一部のパスだけ通ってしまう」場合は、そのパスにマッチする location の中身を確認してください。

原因3:設定を再読み込みしていない

編集しただけでは反映されません。構文チェックしてから再読み込みします。

nginx -t
nginx -s reload

nginx -t は必ず先に実行してください。構文エラーのまま reload すると、サービスが落ちる可能性があります。

Basic認証との併用

「社内からはそのまま、社外からはID・パスワードを要求する」という運用は、satisfy any で書けます。

location /admin/ {
    satisfy any;

    allow 203.0.113.0/24;
    deny  all;

    auth_basic           "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

satisfy any は「IP制限か認証のどちらかを満たせば通す」という意味です。両方満たすことを求める場合は satisfy all にします。

nginxのIP制限には固定IPアドレスが必要

ここまでの設定はすべて、許可リストに書いたIPアドレスが変わらないことが前提です。

オフィス回線が動的IPだと、ルーターの再起動や回線の切断でIPアドレスが変わり、そのたびに設定ファイルを書き換えて reload する運用になります(IPアドレスが変わる原因とタイミング)。テレワークの開発者がいれば、自宅回線のIPアドレスを1件ずつ allow に足していくことになり、そう長くは続きません。

ロリポップ!固定IPアクセスのようなVPN型の固定IPサービスを使えば、回線を変えずにメンバー全員のアクセス元IPアドレスを1つに揃えられますallow に書くのは1行だけで済み、サーバーに入って設定を直す機会そのものが減ります。

⇒【ロリポップ!固定IPアクセス】 月額490円(税込539円)〜、すぐに使えて最大2ヶ月間無料!

nginxのIP制限に関するよくある質問

allow と deny はどちらを先に書くべきですか?

上から順に評価され最初に一致したものが適用されるため、許可したいIPを allow で先に並べ、最後に deny all; を書きます。順序を逆にすると、deny all; が先に一致してすべて拒否されます。

IP制限がかかったとき、利用者には何が表示されますか?

HTTP 403 が返ります。専用のページを出したい場合は error_page 403 /custom_403.html; を設定してください。

.htaccess のようにディレクトリ単位で設定できますか?

nginxには .htaccess に相当する仕組みがありません。設定はすべて nginx.conf(および include されるファイル)に書き、location ブロックでパス単位に制御します。

IPv6も制限できますか?

できます。allow 2001:db8::/32; のようにIPv6のCIDR表記をそのまま書けます。IPv4のみを許可していると、IPv6で接続してきた利用者がブロックされるため、両対応の環境では両方を登録してください。

Dockerコンテナで動かしている場合に注意することはありますか?

コンテナの前段にリバースプロキシやポートフォワードが入ると、nginxから見える接続元がゲートウェイのアドレスになることがあります。原因1と同じ状況なので、set_real_ip_fromreal_ip_header の設定を検討してください。

まとめ

nginxのIP制限は allowdeny で書け、許可リスト方式では末尾の deny all; が必須です。書く場所(http / server / location)で効く範囲が変わります。

「設定したのに効かない」ときは、前段のLB・CDNでIPアドレスが置き換わっていないかマッチした location に別の指定がないかreload したかの3点を順に確認してください。

そして、許可リストに書くIPアドレスが固定であることが大前提です。IP制限そのものの考え方はIP制限(IPアドレス制限)とは?仕組みと設定方法を解説にまとめています。

⇒【ロリポップ!固定IPアクセス】 月額490円(税込539円)〜、すぐに使えて最大2ヶ月間無料!

おすすめの記事

どこからでも簡単に
固定IPアドレスでアクセス

導入相談