2026年8月29日
2026年8月29日
WordPressにBasic認証を設定する方法|サイト全体・wp-login.phpのみ・WP-Cron/REST APIの副作用対策
WordPressにBasic認証をかけるには、Apacheなら .htaccess、Nginxならサーバー設定に数行を足し、パスワードファイルを用意するだけです。ただし、サイト全体にかけるとWP-Cronのループバック通信やREST API、アプリケーションパスワードが動かなくなる副作用があり、ここで多くの人がつまずきます。この記事では、ステージング環境をまるごと保護する設定と、本番の wp-login.php だけを保護する設定の両方を、副作用の避け方とあわせて説明します。
Basic認証の性質を先に押さえる
Basic認証は、Webサーバーがリクエストごとに Authorization ヘッダーのIDとパスワードを照合する仕組みです。WordPressより手前で動くため、WordPress本体やプラグインに脆弱性があっても、認証を通らない相手にはPHPが実行されません。公開前のステージング環境を検索エンジンや第三者から隠す用途や、ログイン画面への総当たり攻撃を手前で止める用途に向いています。
一方で、IDとパスワードは暗号化ではなくBase64で符号化されているだけです。HTTPのままだと通信経路上で読み取れるため、HTTPSのサイトでのみ使うのが前提です。また、ブラウザはいったん認証に成功すると、同じサイトへのリクエストに認証情報を自動で付け続けます。この「自動で付く」挙動が、後述するアプリケーションパスワードとの衝突の原因になります。
パスワードファイルを作る
htpasswd コマンドでパスワードファイルを作ります。Ubuntu/Debianでは apache2-utils、RHEL系では httpd-tools パッケージに含まれます。
# 新規作成(-c)。bcrypt(-B)でハッシュ化する
sudo htpasswd -c -B /etc/apache2/.htpasswd-staging staging-user
# 2人目以降は -c を付けない(付けると既存ユーザーが消える)
sudo htpasswd -B /etc/apache2/.htpasswd-staging another-user
# Nginxで使う場合は、互換性の高いapr1形式(-m)でも作れる
sudo htpasswd -c -m /etc/nginx/.htpasswd-staging staging-user
つまずきやすいのは次の2点です。
-cは「ファイルを新規作成する」オプションで、既存ファイルがあると上書きされます。ユーザーを追加するときは外してください。- パスワードファイルはドキュメントルートの外に置きます。公開ディレクトリに置くと、設定ミスでファイル自体がダウンロードされるおそれがあります。
Nginxはパスワードの照合にOSの crypt() を使うため、bcrypt形式が通るかは環境に依存します。うまく認証できない場合はapr1形式で作り直してください。レンタルサーバーでSSHが使えない場合は、コントロールパネルの「アクセス制限」機能で同等の設定ができることが多いので、そちらを使うと安全です。
Apache:サイト全体を保護する(ステージング向け)
WordPressのドキュメントルートにある .htaccess の先頭、# BEGIN WordPress より上に追記します。編集前に .htaccess のコピーを取っておいてください。
AuthType Basic
AuthName "Staging"
AuthUserFile /etc/apache2/.htpasswd-staging
<RequireAny>
# 事務所などの固定IPは認証なしで通す
Require ip 203.0.113.10
Require valid-user
</RequireAny>
# サーバー自身からのWP-Cron呼び出しは認証から外す
<Files "wp-cron.php">
Require all granted
</Files>
AuthUserFile は / から始まるフルパスで書きます。レンタルサーバーではホームディレクトリのフルパスをコントロールパネルやSSHの pwd で確認してください。<RequireAny> で囲むと「指定IPから来た」か「正しいID・パスワードを入力した」のどちらかで通過できます。
設定後はシークレットウィンドウで開き、認証ダイアログが出るか、正しい情報で表示されるかを確認します。500エラーになった場合は、AuthUserFile のパスの誤りか、サーバー側で .htaccess による認証設定が許可されていない(AllowOverride の設定)可能性が高いです。
Nginx:サイト全体を保護する
Nginxは .htaccess を読まないので、サーバー設定(server ブロック)に書きます。
server {
listen 443 ssl;
server_name staging.example.com;
root /var/www/staging;
auth_basic "Staging";
auth_basic_user_file /etc/nginx/.htpasswd-staging;
# WP-Cronのループバックは認証なしで通す
location = /wp-cron.php {
auth_basic off;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
auth_basic を server レベルに書くと、個別に auth_basic off; を書いた location 以外すべてに適用されます。location = /wp-cron.php は完全一致なので、PHPの処理設定をこのブロックにも書く必要があります。PHP-FPMのソケットのパスはPHPのバージョンや環境で異なります(例はUbuntuでPHP 8.3を使う場合、2026年10月現在)。
変更後は sudo nginx -t で構文を確認してから sudo systemctl reload nginx で反映します。
副作用1:WP-Cronが動かなくなる
WordPressは、ページが表示されたタイミングで、サーバー自身から wp-cron.php にHTTPリクエストを送って予約処理を実行します(ループバックリクエスト)。サイト全体にBasic認証がかかっていると、このリクエストは認証情報を持たないため401で拒否され、次のような症状が出ます。
- 予約投稿が時刻を過ぎても公開されない(「予約投稿の失敗」と表示される)
- プラグインやテーマの更新チェック、定期バックアップ、メール配信などの定期処理が止まる
対策は3通りあります。
- 上の設定例のように
wp-cron.phpだけを認証から外す。wp-cron.phpは期限の来た処理を実行するだけなので、公開されても影響は限定的です。気になる場合はRequire ipでサーバー自身のIPアドレスだけを許可します(ループバックはサイトのURLに対して送られるため、127.0.0.1ではなく公開IPから届く構成もあります)。 wp-config.phpにdefine( 'DISABLE_WP_CRON', true );を書いてWP-Cronのループバックを止め、OSのcronからwp cron event run --due-nowを定期実行する。ループバックに頼らないので、Basic認証の影響を受けません。cron_requestフィルターでループバックに認証ヘッダーを付ける。動きますが、Basic認証のパスワードをコードや設定に書くことになるので、上の2つが使えない場合の手段と考えてください。
ステージングで予約投稿のテストをする予定があるなら、2の方式にしておくと本番に近い挙動で確認できます。
副作用2:サイトヘルスやファイル編集のエラー
「ツール」→「サイトヘルス」のループバックリクエストやREST APIの検査もサーバー自身からのリクエストなので、Basic認証下では失敗と表示されます。ステージングでは想定どおりの結果です。
管理画面のテーマ・プラグインファイルエディターも、PHPファイルの保存後にループバックで致命的エラーの有無を確かめるため、これが失敗すると変更が保存されません。ファイルはSFTPやGitで更新する運用にしておけば影響はありません。
副作用3:REST APIとアプリケーションパスワードの衝突
ここが最も分かりにくい部分です。WordPress 5.6以降は、REST APIへのリクエストに Authorization: Basic ヘッダーが付いていると、それをアプリケーションパスワードとして照合しようとします。Basic認証を通過したブラウザは、同じヘッダーをREST APIへのリクエストにも自動で付けるため、次のことが起こります。
- WordPressにログインしている状態では、ログインCookieの判定が先に成立するため、ブロックエディターなど管理画面の操作は通常どおり動きます。
- WordPressにログインしていない訪問者として表示したとき、フロント側のJavaScriptがREST APIを呼ぶと、Basic認証のIDとパスワードがアプリケーションパスワードとして照合されて失敗し、401エラーになります。フォームや検索、無限スクロールなどがステージングでだけ壊れる、という形で現れます。
ステージングでアプリケーションパスワードを使わないなら、テーマの functions.php か小さなプラグインで機能自体を止めるのが簡単です。
// アプリケーションパスワード機能を無効にする(Basic認証のヘッダーを照合しなくなる)
add_filter( 'wp_is_application_passwords_available', '__return_false' );
逆に、外部ツールからステージングのREST APIをアプリケーションパスワードで操作したい場合は、Basic認証と同時には使えません。HTTPリクエストに付けられる Authorization ヘッダーは1つだけで、サーバーのBasic認証とアプリケーションパスワードの両方を1つのヘッダーで満たすことはできないためです。その場合は、外部ツールの接続元IPを Require ip(Nginxなら allow と satisfy any)で認証なしにし、アプリケーションパスワードだけで認証させる構成にします。
決済サービスなどからREST APIに届くWebhookも、Basic認証の手前で止まります。ステージングで試す場合は送信元IPを許可してください。
本番でwp-login.phpだけを保護する
本番サイトでは、全体ではなくログイン画面だけにBasic認証をかけ、総当たり攻撃をPHPの手前で止める使い方が一般的です。
<Files "wp-login.php">
AuthType Basic
AuthName "Login"
AuthUserFile /home/example/.htpasswd-login
Require valid-user
</Files>
Nginxなら location = /wp-login.php の中に auth_basic と auth_basic_user_file を書き、PHPの処理設定も同じブロックに入れます。
この場合の注意点は次のとおりです。
- ログアウト、パスワードリセット、新規登録もすべて wp-login.php を通るため、会員登録を受け付けるサイトでは利用者全員にBasic認証の情報を知らせることになり、現実的ではありません。会員制サイトでは別の対策(ログイン試行回数の制限や二段階認証)を検討します。
wp-adminディレクトリ全体に認証をかける場合は、フロント側のAjax処理が使うwp-admin/admin-ajax.phpを除外してください。除外しないと、訪問者向けのフォームやカート機能が動かなくなることがあります。
公開時に外し忘れない
ステージングの設定ごと本番に持ち込むと、サイトが誰にも見えなくなります。移行手順に「Basic認証の解除」と「DISABLE_WP_CRON を使った場合のcron設定の移行」を入れておくと安心です。
まとめ
- Basic認証はWordPressの手前で動くので、ステージングの保護やログイン画面の総当たり対策に向いている。HTTPSでのみ使う
- サイト全体にかけると、WP-Cronのループバックが401で失敗する。
wp-cron.phpを除外するか、DISABLE_WP_CRONとOSのcronに切り替える - Basic認証のヘッダーはアプリケーションパスワードとして照合されるため、未ログイン時のREST APIが401になる。使わないなら
wp_is_application_passwords_availableで機能を止める - 外部からアプリケーションパスワードでREST APIを使うなら、Basic認証ではなくIP許可で通す
- wp-login.phpだけを保護する場合は、パスワードリセットや会員登録への影響を確認する