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アドレスの両方からステータスコードを確かめます。

お気軽にご相談ください

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