1. はじめに
WordPress を新しく立ち上げるとき、「まずサイトを公開して、セキュリティは後から」という順番になりがちです。
しかし、現在では公開初日から攻撃の対象になります。Patchstack の「State of WordPress Security In 2026 」によると、新しい脆弱性が公開されてから悪用されるまでの中央値はわずか5時間です。プラグインのアップデートで対応しようとしても、間に合わないケースが多々あります。
本記事では、AWS Lightsail 上に WordPress を立ち上げる際に Cloudflare WAF の設定を構築手順の一部として組み込む方法を解説します。最初から WAF を前提とした構成です。
ソーイでは受託案件や自社・他社のHPでWordPress を構築するケースがあります。その際に「後からセキュリティを足す」またはプラグインの互換性の問題でバージョン更新が遅れるといったことがありました。今改めてWordpressをゼロから立ち上げる場合に、セキュリティを考慮した構築手順を整理しました。
2. 構成の全体像
本記事で構築する構成は以下の通りです。
ユーザー
↓
Cloudflare(DNS プロキシ + WAF + DDoS 軽減)
↓
AWS Lightsail(静的 IP + WordPress)
Cloudflare を DNS プロキシとして挟むことで、Lightsail インスタンスの実 IP アドレスが外部に露出しなくなります。攻撃者がサーバーの所在を特定しにくくなる点も、WAF 以外の副次的なメリットです。
Lightsail 固有の特性として、デフォルトでは WAF 相当の機能が付いていません。一般的なレンタルサーバーではサーバー会社側が WAF を提供しますが、Lightsail などの VPS は、アプリケーション層の防御はすべて自分で用意する必要があります。Lightsail 付属のファイアウォールはポートレベルの制御(SSH の開閉など)に留まり、HTTP/HTTPS の攻撃には対応できません。
下記の環境と条件で設定を行います。
- DNS管理: Cloudflare
- ドメイン: wp.sugumura.dev (テスト用のドメイン)
- サーバ: AWS Lightsail
3. ステップ1 — Lightsail の初期設定
3-1. インスタンスの作成
Lightsail コンソールから「インスタンスの作成」を選び、プラットフォームは Linux/Unix、ブループリントは「WordPress」を選択します。2026年2月以降、ガイド付きセットアップウィザードが追加されており、数クリックでインスタンスが起動します。
プランは月額 $5(1vCPU / 1GB メモリ / 40GB SSD)から選択できます。個人ブログや小規模サイトであればこのプランで十分です。
3-2. 静的 IP の割り当て(必須)
Cloudflare と連携する前に、必ず静的 IP を割り当てます。Lightsail のデフォルト IP はインスタンスを停止→起動するたびに変わります。静的 IP なしで Cloudflare の DNS を設定すると、インスタンスの再起動後に DNS が古い IP を指したままになり、サイトにアクセスできなくなります。
Lightsail コンソール → 対象インスタンス → 「ネットワーキング」タブ → 「静的 IP を作成してアタッチ」
静的 IP はインスタンスにアタッチ中であれば無料です。割り当てだけして使わない状態だと課金されます。
3-3. Lightsail ファイアウォールの設定
SSH(22番)のソースを自分の IP アドレスに絞ります。デフォルトでは全 IP からのアクセスを許可しているため、ブルートフォース攻撃の対象になります。
Lightsail コンソール → ネットワーキング → ファイアウォール → SSH のルールを編集 → 「自分の IP を使用」を選択
HTTP(80番)と HTTPS(443番)は全 IP に開けたままにします。
3-4. HTTP/HTTPS のソースを Cloudflare IP レンジに制限する
Cloudflare の設定が完了した後(ステップ2の後)、HTTP(80番)と HTTPS(443番)のソースを Cloudflare の IP レンジに制限します。これにより、Cloudflare を経由しない直接アクセスをファイアウォールレベルでブロックできます。
Cloudflare は自社の IP レンジを公開しています。
Lightsail コンソール → ネットワーキング → ファイアウォール で、HTTP と HTTPS のルールを編集し、ソースを Cloudflare の IP レンジ(IPv4)に変更します。
IPv4 ルール例:
HTTPS / TCP / 443 / 173.245.48.0/20
HTTPS / TCP / 443 / 103.21.244.0/22
HTTPS / TCP / 443 / 103.22.200.0/22
HTTPS / TCP / 443 / 103.31.4.0/22
... (公開されている全レンジを追加)
この制限を入れないと、攻撃者が過去の DNS 履歴(SecurityTrails 等)から実 IP を特定し、Cloudflare を迂回して直接アクセスできてしまいます。Cloudflare WAF を導入しても、実 IP に直接アクセスされればルールは一切適用されません。
Cloudflare の IP レンジは変更される場合があります。公式ページを定期的に確認し、ファイアウォールルールを更新してください。Cloudflare は IP レンジの変更を事前に通知しています。
4. ステップ2 — Cloudflare の設定
4-1. DNS レコードの設定
Cloudflare ダッシュボードで対象ドメインの A レコードを追加し、Lightsail の静的 IP を指定します。この時点ではプロキシステータスをグレー雲(DNS のみ・プロキシ無効)に設定します。次のステップで SSL 証明書を取得するため、Lightsail の実 IP が DNS から直接返される必要があるからです。
4-2. SSL/TLS の設定
本記事の手順は以下の環境で実際に確認しています。
- ブループリント: WordPress(Bitnami スタックではない)
- OS: Debian GNU/Linux 12 (bookworm)
- Web サーバー: Apache
- PHP: 8.2.33
- WordPress: 7.1
- certbot: 2.1.0
SSL 証明書の取得と Cloudflare プロキシの有効化は順番が重要です。
certbot の HTTP-01 チャレンジは、Let's Encrypt がドメインに対して HTTP リクエストを送り、サーバー上に配置したファイルで所有権を確認する仕組みです。
Cloudflare のプロキシ(オレンジ雲)が有効な状態だと、Let's Encrypt からの確認リクエストが Cloudflare 経由になり、Cloudflare 側でキャッシュされたり書き換えられたりして検証が通らないケースがあります。
certbotに所有権を確認してもらうため、順番は以下の通り行います。
1. Cloudflare の A レコードをグレー雲(DNS のみ・プロキシ無効)に設定
2. DNS 反映を確認(dig コマンドで Lightsail の実 IP が返ること)
3. certbot で Let's Encrypt 証明書を取得
4. 取得完了後にオレンジ雲(プロキシ有効)に切り替える
5. Cloudflare SSL モードを「フル(厳格)」に設定する
Cloudflare ダッシュボード → 「SSL/TLS」→「概要」で暗号化モードを「フル(厳格)」に設定します。「フレキシブル」モードでは Cloudflare ↔ Lightsail 間が HTTP になるため必ず「フル(厳格)」を選びます。
Lightsail で「WordPress」ブループリントを選んだ場合、SSL 設定は certbot で行います。SSH でインスタンスに接続して以下の手順を実行します。
まず Apache が動いているか確認します。
systemctl is-active apache2
active が返れば Apache です。certbot をインストールします。
sudo apt update && sudo apt install -y certbot python3-certbot-apache
Apache の vhost 設定に ServerName がないと certbot の自動インストールが失敗します。先に追加しておきます。
sudo nano /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80> の直下に1行追加します。
<VirtualHost *:80>
ServerName example.com
# 以下既存の設定が続く
保存後、証明書を取得します(example.com は実際のドメインに変えます)。
sudo certbot --apache -d example.com
途中でメールアドレスの入力と利用規約への同意を求められます。最後に自動更新が正常に設定されているか確認します。
sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded が出れば完了です。
4-3. カスタムルール — /wp-login.php を Managed Challenge で保護する
ここからが本記事の核心です。Cloudflare のカスタムルール(WAF)を設定します。
Cloudflare ダッシュボード → 「セキュリティ」→「WAF」→「カスタムルール」→「ルールを作成」
ルール名: WordPress ログイン保護
一致条件:
URI パス が次の値で始まる: /wp-login.php
AND
IP アドレス が次の値ではない: (自分の固定 IP)
アクション: Managed Challenge
Block ではなく Managed Challenge から始める理由は、自分自身や正規ユーザーを誤ってブロックするリスクを避けるためです。Managed Challenge は Cloudflare が自動で JS チャレンジや CAPTCHA を出し、Bot を弾きながら正規ユーザーは通します。固定 IP がない場合は IP アドレスの条件を省いて Managed Challenge のみにします。
4-4. カスタムルール — /wp-admin を保護する
ルール名: WordPress 管理画面保護
一致条件:
URI パス が次の値で始まる: /wp-admin
AND
IP アドレス が次の値ではない: (自分の固定 IP)
アクション: Managed Challenge(または Block)
/wp-admin/admin-ajax.php はプラグインが外部から呼び出すケースがあります。フォームやカートなどの機能が動かなくなる場合は、このパスだけスキップするルールを追加します。
4-5. カスタムルール — xmlrpc.php を即ブロックする
ルール名: XML-RPC ブロック
一致条件:
URI パス が次の値で終わる: /xmlrpc.php
アクション: Block
XML-RPC は WordPress の古い API エンドポイントで、現在は REST API に置き換えられています。Jetpack 等の一部プラグインが使用しますが、使っていなければ即ブロックが正解です。ブルートフォース攻撃や DDoS 増幅の踏み台として悪用されるケースが多いです。
4-6. 動作確認
指定したIPアドレス以外で、指定パスに接続するとManaged Challenge画面が表示されます。
またxmlrpc.phpに接続するとブロック画面が表示されます。
4-7. 無料プランで使える範囲の整理
Cloudflare の無料プランは商用利用可能です。以前存在した「CDN 経由で HTML 以外のコンテンツを主に配信してはいけない」という条項は 2023年5月の規約改定で廃止されています。
| 機能 | 無料プラン | Pro(月額$20) |
|---|---|---|
| DDoS 軽減 | ✅ | ✅ |
| Universal SSL | ✅ | ✅ |
| カスタムルール(WAF) | ✅ 5件まで | ✅ 100件まで |
| OWASP Managed Ruleset | ❌ | ✅ |
| Bot Fight Mode(基本) | ✅ | ✅ |
| 詳細な WAF 分析 | ❌ | ✅ |
上記3本のカスタムルールはすべて無料プランで設定できます。
5. ステップ3 — WordPress 本体の初期設定
Cloudflare WAF を設定した後、WordPress 側でも最低限の設定を行います。
5-1. ファイルエディターの無効化
管理者アカウントが乗っ取られた際に、ダッシュボードからサーバー上のファイルを直接書き換えられる「テーマエディター」「プラグインエディター」を無効化します。wp-config.php に以下を追加します。
define( 'DISALLOW_FILE_EDIT', true );
5-2. バージョン情報の非表示化
攻撃者はバージョン情報をもとに既知の脆弱性を絞り込みます。functions.php に以下を追加します。
remove_action( 'wp_head', 'wp_generator' );
5-3. 自動更新の有効化
WordPress コアの自動更新が無効になっている場合は有効に戻します。2026年8月時点の最新安定版は 7.1 です(WordCamp US 2026 にあわせて8月19日にリリース)。7.0.4 で修正された RCE 脆弱性 CVE-2026-65640(認証済みユーザーによる画像アップロードを経由するもので、サーバー側で Imagick または Ghostscript が有効な環境が条件)も 7.1 に含まれています。
wp-config.php に以下を追加することで、マイナーバージョンの自動更新を強制できます。
define( 'WP_AUTO_UPDATE_CORE', 'minor' );
5-4. 使わないプラグインは削除する
無効化しただけではファイルがサーバー上に残ります。使わないプラグインは「削除」まで行います。
Patchstack の調査では、WordPress エコシステムで発見された脆弱性の 91%がプラグインおよびテーマ由来(出典:Patchstack「State of WordPress Security In 2026」)です。インストールしているプラグインの数がそのままリスクの数に比例します。
6. セキュリティプラグインではなく Cloudflare WAF を使う理由
「Wordfence のようなセキュリティプラグインを入れればいいのでは?」という疑問は自然です。ここで両者の構造的な違いを整理します。
6-1. プラグイン型WAFの限界 — PHP が起動してから判定する
Wordfence のようなセキュリティプラグインは WordPress の内側で動きます。攻撃リクエストが来たとき、次の順序で処理が走ります。
攻撃リクエスト
→ Lightsail インスタンスに到達(サーバーのリソースを消費)
→ PHP が起動
→ WordPress がロード
→ Wordfence がリクエストを検査
→ ブロック or 通過
正規ユーザーへの応答に使えるはずだった CPU サイクルを、最初から弾くべき攻撃トラフィックの検査に使っています。通常時はほとんど問題になりませんが、ブルートフォース攻撃や Bot の大量アクセスが来ると、PHP ワーカーが攻撃の検査で埋まり、正規ユーザーへの応答が遅延します。実際に攻撃下でプラグイン型 WAF のレスポンスタイムが 8 秒を超え、稼働率が 90% を下回るケースも報告されています(BigScoots WAF テスト、Shield Security による解説)。
Lightsail の最小プランではこの影響が顕著に出ます。
6-2. Cloudflare WAF はサーバーに到達する前に止める
Cloudflare WAF はエッジ(Cloudflare のネットワーク上)で動作します。
攻撃リクエスト
→ Cloudflare のエッジで検査・ブロック
→ Lightsail には届かない(サーバーのリソースを消費しない)
ブロックされた攻撃はサーバーに一切到達しません。Lightsail インスタンスのリソースは正規ユーザーへの応答だけに使えます。Cloudflare 自身の機械学習による処理改善により、検査レイテンシは 1,519μs から 275μs まで短縮されており、エッジ WAF が追加するネットワーク遅延は実測で数ミリ秒程度です。
6-3. セキュリティプラグインをゼロにする必要はない
Cloudflare WAF が優れているのはネットワーク層の防御です。一方、プラグイン型ツールが得意なのは WordPress の内側を見ること、つまりファイルの改ざん検知やマルウェアスキャンです。
| 役割 | Cloudflare WAF | セキュリティプラグイン |
|---|---|---|
| 攻撃トラフィックのブロック | ◎ サーバー到達前に止める | △ PHP 起動後に判定 |
| DDoS・Bot 対策 | ◎ | △ |
| ファイル改ざん検知 | ✕ | ◎ |
| マルウェアスキャン | ✕ | ◎ |
| ログイン試行の制限 | ◎ カスタムルールで対応 | ◎ |
本記事では Cloudflare WAF を主軸に置き、セキュリティプラグインは「侵入後を見る補完的な役割」として位置づけます。両方入れること自体は問題ありませんが、WAF 機能が重複するプラグイン(Wordfence の WAF 機能等)は Cloudflare と共存させるとルールが競合したり誤検知が増えたりするため、プラグイン側の WAF 機能は無効にして軽量に運用するのが現実的です。
7. ステップ4 — バックアップの設定(Lightsail スナップショット)
攻撃を受けてから気づいても遅いです。Lightsail の自動スナップショットを有効にします。
Lightsail コンソール → 対象インスタンス → 「スナップショット」タブ → 「自動スナップショットを有効にする」
1日1回のスナップショットが最大7日分保存されます。インスタンスのプランに応じて月数ドル程度のコストです。データベースを Lightsail マネージドデータベースで運用している場合は、データベース側のスナップショットも別途設定が必要です。
8. 構築後の確認チェックリスト
すべての設定が完了したら以下を確認します。
| 確認項目 | 確認方法 |
|---|---|
| Lightsail 静的 IP がアタッチされている | Lightsail コンソール → ネットワーキング |
| Cloudflare DNS のプロキシが有効(オレンジ雲) | Cloudflare DNS 設定画面 |
| HTTPS でアクセスできる | ブラウザのアドレスバーで施錠マークを確認 |
| SSL モードが「フル(厳格)」 | Cloudflare SSL/TLS 設定 |
| カスタムルール3本が有効 | Cloudflare WAF → カスタムルール |
| SSH が自分の IP のみ許可 | Lightsail ファイアウォール設定 |
| HTTP/HTTPS が Cloudflare IP のみ許可 | Lightsail ファイアウォール設定 |
| WordPress が最新バージョン | ダッシュボード → 更新 |
| 自動スナップショットが有効 | Lightsail スナップショット設定 |
9. まとめ
本記事で解説した構築手順をコスト面でまとめます。
| 項目 | コスト |
|---|---|
| Lightsail インスタンス(最小プラン) | 月 $5〜 |
| Lightsail 静的 IP(アタッチ中) | 無料 |
| Lightsail 自動スナップショット | 月数ドル |
| Cloudflare 無料プラン(WAF・DDoS・CDN) | 無料 |
| Cloudflare Pro(OWASP Managed Ruleset) | 月 $20(任意) |
Cloudflare WAF(無料プランのカスタムルール3本)と Lightsail の組み合わせは、月 $5 台のコストで WAF ありの WordPress 環境を立ち上げられる現実的な構成です。
最初から WAF を前提として構築することで、「後からセキュリティを足す」手間と、その間に晒されるリスクの両方を避けられます。
お知らせ
技術ブログを週1〜2本更新中、ソーイをフォローして最新記事をチェック!
https://qiita.com/organizations/sewii





