2026年8月4日

2026年8月4日

NginxのIP制限・アクセス制御の設定(allow/denyの書き方とWordPress管理画面の保護)

NginxでIPアドレスによるアクセス制限を行うには、allow と deny を server や location の中に並べます。書いた順に上から照合され、最初に一致した行で許可か拒否かが決まります。この記事では、基本の書き方と評価の順序、WordPressのログイン画面と管理画面を守るときに admin-ajax.php を壊さない書き方、CDNやロードバランサーの裏で本来の接続元IPを使う方法、多数のIPをまとめて管理する方法、締め出されたときの戻し方を説明します。

基本の書き方と評価の順序

allow・deny は標準で組み込まれている ngx_http_access_module の機能で、http・server・location の各階層に書けます。

location /private/ {
    allow 203.0.113.10;      # 1件のIPv4アドレス
    allow 198.51.100.0/24;   # 範囲(CIDR)
    allow 2001:db8::/32;     # IPv6 の範囲
    deny  all;               # それ以外はすべて拒否
}

照合は上から順に行われ、最初に一致した行で終わります。そのため、許可したいアドレスを先に書き、最後に deny all; を置くのが基本の形です。順番を逆にして deny all; を先頭に書くと、後ろの allow に届かず、すべて拒否されます。拒否されたリクエストには403が返ります。

設定は、内側の階層に allow・deny が1行も無い場合だけ、外側の階層から引き継がれます。server に書いた制限を前提にしていても、ある location に allow を1行足すと、その location では外側の指定がすべて無効になる点に注意します。

IPv6でも接続を受け付けているサーバーでは、IPv4のアドレスだけを許可していると、IPv6で接続してきた自分自身が拒否されることがあります。自分の接続元がどちらのアドレスかを確認してから書きます。

WordPressのログイン画面と管理画面を守る

WordPressでは、wp-login.php と /wp-admin/ を自分のIPアドレスだけに限ると、ログインへの総当たりをNginxの段階で止められます。ただし、2つの点に気をつけます。

1つ目は、/wp-admin/admin-ajax.php と /wp-admin/admin-post.php を、ログインしていない訪問者のためにも開けておくことです。フォームの送信や「もっと見る」の読み込みなど、公開ページの機能がこれらを使っていることが多く、まとめて拒否すると表側の機能が動かなくなります。

2つ目は、location の選ばれ方です。よくあるWordPressの設定には location ~ \.php$ があり、正規表現の location は通常の前方一致より優先されます。location /wp-admin/ と書いただけでは、PHPファイルへのリクエストは正規表現の側に吸われ、制限がかかりません。完全一致の = か、正規表現の確認を止める ^~ を使い、その中でPHPを処理します。

# 管理用に許可するアドレス(このファイルを各 location で読み込む)
# /etc/nginx/snippets/admin-allow.conf
#   allow 203.0.113.10;
#   deny  all;

location = /wp-login.php {
    include /etc/nginx/snippets/admin-allow.conf;
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

location = /wp-admin/admin-ajax.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

location = /wp-admin/admin-post.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

location ^~ /wp-admin/ {
    include /etc/nginx/snippets/admin-allow.conf;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}

snippets/fastcgi-php.conf とソケットのパスは、Debian/Ubuntu系の例です。RHEL系や独自にビルドした環境では、すでに使っているPHP用の location と同じ内容をそれぞれの中に書きます。内側の location ~ \.php$ には allow・deny を書いていないため、外側の ^~ /wp-admin/ の制限が引き継がれます。

設定の後は、許可したアドレスとそれ以外の両方から確認します。携帯回線などの別の回線から curl -I https://www.example.com/wp-login.php を実行して403になること、許可したアドレスからはログインでき、公開ページのフォームなどが動くことを確かめます。

XML-RPCを使っていない場合は、location = /xmlrpc.php { deny all; } で拒否する方法もあります。スマートフォンのアプリや一部の連携サービス、プラグインの機能がXML-RPCを使っていることがあるため、使っていないことを確認してから閉じます。

CDNやロードバランサーの裏では本来のIPを使う

CloudflareなどのCDNやロードバランサーの裏にNginxがある場合、Nginxから見た接続元はCDNのアドレスになります。そのまま allow を書くと、CDN経由のすべての人を許可する、あるいはすべて拒否することになります。

ngx_http_realip_module を使うと、信用するプロキシから届いたヘッダーの値を接続元として扱えます。allow・deny やアクセスログも、この値を使うようになります。

# http または server の階層に書く
set_real_ip_from 10.0.0.0/8;          # 手前のロードバランサーのアドレス
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

set_real_ip_from には、信用するプロキシのアドレスだけを書きます。ここを広く取りすぎると、誰でもヘッダーを偽って許可されたIPになりすませます。Cloudflareを使う場合は、Cloudflareが公開しているIPアドレスの範囲を指定し、ヘッダーには CF-Connecting-IP を使う方法が案内されています。範囲は変わることがあるため、提供元の最新の一覧を確認し、定期的に更新します(2026年10月現在)。また、オリジンサーバーへCDNを経由せず直接アクセスできる状態だと、この制限を回り込まれるため、ファイアウォールでCDN以外からの接続を閉じることも検討します。

多数のIPアドレスを管理する

許可・拒否するアドレスが多い場合は、allow・deny を並べるより、geo モジュールで一覧を変数に変える方法が見通しやすくなります。geo は http の階層に書きます。

geo $blocked_ip {
    default        0;
    192.0.2.0/24   1;
    198.51.100.7   1;
}

server {
    # ...
    if ($blocked_ip) {
        return 403;
    }
}

geo は接続元のIPアドレス(realipモジュールを設定していれば置き換え後の値)で照合します。一覧を別ファイルにして include すれば、アドレスを足すときに本体の設定を触らずに済みます。if の中で return だけを使う書き方は、Nginxで安全に使える形として知られています。国単位で制限したい場合はGeoIPのデータベースを使う方法がありますが、データの入手と更新が別に必要になります。

パスワード認証と組み合わせる

外出先など、IPアドレスが固定できない人にも管理画面を使わせたい場合は、Basic認証と組み合わせ、satisfy any; を指定します。許可したIPからはパスワードなしで、それ以外からはパスワードを入力すれば入れるようになります。

location ^~ /wp-admin/ {
    satisfy any;
    allow 203.0.113.10;
    deny  all;
    auth_basic           "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;
    # PHP の処理は前の例と同じ
}

satisfy all;(既定)にすると、IPとパスワードの両方を満たした場合だけ入れます。Basic認証はHTTPSで使い、.htpasswd は公開ディレクトリの外に置きます。

締め出されたときの戻し方

自宅や会社の回線のIPアドレスは、契約によっては変わります。変わった途端に管理画面へ入れなくなるため、次の準備をしておきます。

  • 設定を変える前に、元のファイルをコピーして残しておきます。
  • SSHやサーバー会社のコンソールなど、Webとは別の経路でサーバーに入れることを確認しておきます。
  • 締め出されたら、別の経路から許可リストに新しいアドレスを足すか、該当の include 行をコメントにして、sudo nginx -t の後に sudo systemctl reload nginx で反映します。

IP制限は、ログインの総当たりを入口で減らす効果がありますが、それだけで安全になるわけではありません。WordPress本体とプラグインの更新、強いパスワードや2段階認証、ログイン試行の制限と組み合わせて使います。

まとめ

  • allow・deny は上から照合し、最初に一致した行で決まります。許可を先に書き、最後に deny all; を置きます。
  • 内側の階層に1行でも書くと、外側の allow・deny は引き継がれません。
  • WordPressでは = と ^~ を使って wp-login.php と /wp-admin/ を守り、admin-ajax.php と admin-post.php は開けておきます。
  • CDNやロードバランサーの裏では、realipモジュールで信用するプロキシだけを指定します。
  • 締め出されたときに戻せるよう、別の経路とバックアップを用意してから設定します。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲