2026年6月29日
2026年6月29日
NginxでBasic認証とIPアドレス制限を組み合わせる方法(satisfy all/any)
Nginxでは、Basic認証(auth_basic)とIPアドレスによる制限(allow/deny)を同じ location に書けます。2つをどう組み合わせるかは satisfy ディレクティブで決まり、書き方によって「許可したIPアドレスから、かつパスワードを知っている人だけ」にも「社内からはパスワード不要、外からはパスワードが必要」にもなります。
この記事の設定と結果は、2026年10月時点のNginx 1.30.6(Docker公式イメージ nginx:stable)で確かめています。Basic認証だけ、IPアドレス制限だけの設定は、それぞれNginxでBasic認証を設定する方法とNginxでIPアドレスによるアクセス制限をする方法を参照してください。
satisfy all と satisfy any の違い
| 設定 | 動き | 向いている場面 |
|---|---|---|
satisfy all;(既定値) |
IPアドレスが許可されていて、かつ認証に成功したときだけ通す | 管理画面を、決まった場所からだけ、さらにパスワード付きで使わせたい |
satisfy any; |
IPアドレスが許可されているか、認証に成功したかのどちらかで通す | 社内や自宅からはそのまま、外出先からはパスワードで使わせたい |
satisfy を書かなければ all です。検証で、許可したIPアドレス(127.0.0.1)と許可していないIPアドレスから、パスワードなし・正しいパスワード・誤ったパスワードでアクセスした結果は次のとおりです。
| 接続元 | パスワード | satisfy all | satisfy any |
|---|---|---|---|
| 許可したIP | なし | 401 | 200 |
| 許可したIP | 正しい | 200 | 200 |
| 許可したIP | 誤り | 401 | 200 |
| 許可していないIP | なし | 403 | 401 |
| 許可していないIP | 正しい | 403 | 200 |
| 許可していないIP | 誤り | 403 | 401 |
satisfy all では、許可していないIPアドレスからは正しいパスワードでも403になります。satisfy any では、許可したIPアドレスからはパスワードを聞かれません。
手順1: パスワードファイルを作る
パスワードファイルは htpasswd コマンドで作ります。Debian/Ubuntuでは apache2-utils パッケージ、RHEL系(AlmaLinux、Rocky Linuxなど)では httpd-tools パッケージに入っています。
# Debian/Ubuntu
sudo apt install apache2-utils
# RHEL系
sudo dnf install httpd-tools
最初のユーザーを作るときだけ -c を付けます。-c はファイルを新しく作り直すので、2人目以降に付けると既存のユーザーが消えます。
# 1人目(ファイルを新規作成)
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 2人目以降(-c を付けない)
sudo htpasswd /etc/nginx/.htpasswd editor
# ユーザーを削除する
sudo htpasswd -D /etc/nginx/.htpasswd editor
パスワードは対話形式で入力します。htpasswd の既定の形式($apr1$ で始まるMD5方式)は、Nginxが対応している形式です。
パスワードファイルはWebから見える場所(ドキュメントルートの下)に置かず、Nginxのワーカープロセスだけが読めるようにします。
# Debian/Ubuntuのnginxパッケージはwww-dataユーザーで動く
sudo chown root:www-data /etc/nginx/.htpasswd
sudo chmod 640 /etc/nginx/.htpasswd
nginx.orgのパッケージやRHEL系では、ワーカープロセスのユーザーが nginx です。nginx.conf の user ディレクティブで確かめて、グループを合わせてください。
手順2: 両方を満たしたときだけ通す(satisfy all)
/admin/ を、指定したIPアドレスからだけ、かつパスワード付きで使えるようにする例です。server ブロックの中に書きます。
location /admin/ {
allow 203.0.113.10;
allow 198.51.100.0/24;
allow 2001:db8::/32;
deny all;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}
allowとdenyは上から順に照合され、最初に当てはまったものが使われます。許可するアドレスを先に並べ、最後にdeny all;を書きます。- IPv6で接続してくる利用者がいる場合は、IPv6のアドレスも
allowに書きます。書き忘れると、IPv4では入れるのにIPv6では403になります。 satisfyを書いていないのでallとして動きます。
手順3: どちらかを満たせば通す(satisfy any)
社内のIPアドレスからはパスワードなしで、それ以外からはパスワードで入れるようにする例です。
location /staff/ {
satisfy any;
allow 203.0.113.10;
allow 198.51.100.0/24;
deny all;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}
deny all; を書いておかないと、すべてのIPアドレスが許可された扱いになり、誰でもパスワードなしで入れてしまいます。satisfy any を使うときは、allow の並びの最後に deny all; を置きます。
手順4: 設定を確かめて反映する
sudo nginx -t
sudo systemctl reload nginx
反映したら、許可したIPアドレスと許可していないIPアドレスの両方から、curlでステータスコードを確かめます。
# パスワードなし
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/admin/
# パスワードあり
curl -s -o /dev/null -w '%{http_code}\n' -u admin https://example.com/admin/
-u admin とだけ書くと、curlがパスワードを尋ねます。結果を前述の表と照らし合わせます。拒否されたアクセスは /var/log/nginx/error.log に、access forbidden by rule(IPアドレスで拒否)や user "…" was not found/password mismatch(認証の失敗)として記録されます。
WordPressのwp-login.phpにかける例
WordPressのログイン画面 wp-login.php を、社内のIPアドレスからはそのまま、外からはBasic認証付きで使えるようにする例です。
location = /wp-login.php {
satisfy any;
allow 203.0.113.10;
deny all;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location = /wp-login.php は、PHPを処理する location ~ \.php$ より優先されるので、この中にもPHP-FPMへ渡す設定を書く必要があります。書かないと、PHPが実行されずにファイルがダウンロードされます。fastcgi_pass のソケットのパスは、PHPのバージョンや環境に合わせて、既存の location ~ \.php$ と同じものにします。
/wp-admin/ 全体にかける場合は、サイトの表側からも使われる /wp-admin/admin-ajax.php を対象から外さないと、一部の機能が動かなくなることがあります。WordPressの管理画面を守る方法はWordPressにBasic認証をかける方法も参照してください。
プロキシやCDNの後ろにある場合
ロードバランサーやCDN(Cloudflareなど)を経由していると、Nginxから見える接続元はプロキシのIPアドレスになり、allow に利用者のIPアドレスを書いても一致しません。この場合は、realipモジュールで本来の接続元に置き換えます。
# http ブロックか server ブロックに書く
set_real_ip_from 192.0.2.0/24; # 信頼するプロキシのアドレス
real_ip_header X-Forwarded-For;
real_ip_recursive on;
set_real_ip_from には、自分が使っているプロキシのアドレスだけを書きます。誰からの X-Forwarded-For でも信用すると、ヘッダーを偽装した接続を許可してしまいます。CloudflareのIPアドレス範囲は、Cloudflareが公開している一覧を使います。realipモジュールは、nginx.orgのパッケージやDebian/Ubuntuのパッケージには含まれています(nginx -V の出力に --with-http_realip_module があるかで確かめられます)。
注意点
- Basic認証のパスワードは暗号化されずに送られます。HTTPSのサイトでだけ使ってください。HTTPSの設定はNginxでSSL(HTTPS)を設定する方法を参照してください。
- IPアドレスを許可した拠点のネットワークを、ほかの人と共有していないか確かめます。共有のWi-Fiなどを許可すると、同じ回線の誰でも入れます(
satisfy anyの場合はパスワードも不要です)。 - 自宅など、IPアドレスが変わる回線を
allowに書いていると、変わったときに入れなくなります。satisfy anyにしてパスワードでも入れるようにしておくと、締め出されずに済みます。
まとめ
Basic認証とIPアドレス制限を同じ location に書くと、既定の satisfy all では両方を満たしたときだけ、satisfy any ではどちらかを満たしたときに通します。satisfy any では最後の deny all; を忘れないようにします。パスワードファイルは htpasswd で作り、ドキュメントルートの外に置いて権限を絞ります。プロキシの後ろでは set_real_ip_from で本来の接続元を使い、反映後は許可したIPアドレスと許可していないIPアドレスの両方からステータスコードを確かめます。