お名前ドットコムVPSへ移行への道6-WordPress

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

この記事は約24分で読めます。
広告

お名前.com VPS にこれまでに
owasp/modsecurity-crs:nginxとDjangoのDockerイメージをインストールして、
Djangoを表示できるようにしてある。
今回はWordPressのDockerイメージをインストールする。

メモリのことを何も気にせずやっていたので
メモリ不足になりVPSの再起動を繰り返してやっている状態です。
なのでDjangoのコンテナは削除、owasp/modsecurity-crs:nginx-alpineとWordPress、データベースのコンテナのみにしてます。
次回メモリの対策をしていきます。

あくまでも私は、こうやってみたということで動作やセキュリティの保証はできません。
まとまってないので完全に個人メモになってます。
環境
パソコン Windows11
VPS OS Ubuntu 20.04.3 LTS、 Dockerを使用
こちらの続きです。

広告

WordPressインストール

参考:docker-composeを使ってWordPress環境を構築する #Docker – Qiita

dockerディレクトリの下に
mkdir wordpress
cd wordpress
docker-compose.ymlと.envを作成。
version: '3.9'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWD}

   wordpress:
     depends_on:
       - db
     image: wordpress:latest

     restart: always
     environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWD}
      WORDPRESS_DB_NAME: ${DB_NAME}
volumes:
    db_data:
networks:
  default:
      name: shared
      external: true

.env

DB_NAME=wp_dbname
DB_USER=wp_user
DB_PASSWD=wp_passwd
DB_ROOT=wp_root

右側は、それぞれ任意の文字列を設定。

docker-compose up -d
インストール前後のメモリ使用量確認。
free
              total        used        free      shared  buff/cache   available
Mem:         987916      516364      125224        5212      346328      310372
Swap:             0           0           0

↓docker-compose up -d後
Mem:         987916      562060      353336        8016       72520      310244
その後なぜか、メモリ使用量が増え重くなった。
Mem:         987912      740764       70660        5424      176488       90448
目次へ

アクセス制限

Nginxのproxy_passを設定する前にWordPressの.htaccessで以下のIP制限をしておいた。
WordPressはapatchではなくNginxで動かしている場合もある。
この記事内ではApache使用ですが
最終的にはNginxを使ってるimage(fpm-alipine)に変更してます。
その場合.htaccessは関係ないので以下参照してください。

sudo docker container exec -it コンテナ名 bash
でコンテナの中に入る。
ls -a
で.のディレクトリやファイルも表示して.htaccessがあるか確認。
.htaccessの中身を確認
cat .htaccess
# BEGIN WordPress

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

Vsコードの今、作業しているWordPressのディレクトリに.htaccessを作り中身をコピー。
もとのファイルは念のため、名前を変えて保存しておく。

.htaccessを修正。参考:WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめ 

# BEGIN WordPress

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
<Files ~ "^(xmlrpc\.php|wp-config\.php)$">
Order deny,allow
Deny from all

</Files>
<Files wp-cron\.php>
Order deny,allow
Deny from all
allow from ***.***.***.***
</Files>
<Files wp-login\.php>
Order deny,allow
Deny from all
allow from ***.***.***.***
</Files>
<Files wlwmanifest\.xml>
Order deny,allow
Deny from all

</Files>
<Files ~ "^(license\.txt|readme\.html|wp-config-sample\.php)$">
Order deny,allow
Deny from all

</Files>
# END WordPress

今回追加した<Files >の中でのファイル名の書き方で動作が違った。
恐らく使っているエディタやWindows、Macなど環境によって違うのかも。
私の場合Windows11、SSH接続のVsコード
NG <Files wp-login\.php>
OK <Files wp-login.php>
ドット’.’の前の’\’はエスケープシーケンスのようで、これをなくしたらうまくいきました。
実際にドメイン/wp-login.phpにアクセスしてForbiddenになるかで確認できます。
記事の中ではエスケースシーケンス付きで記述していますが実際には削除して使ってます。

pwd
/var/www/html
で今いるところを確認。
exit
sudo docker cp .htaccess <コンテナID>:/var/www/html
でコピー。

wp-adminのアクセス制限については
Vsコードで.htaccess0を作って中身は
Order deny,allow
Deny from all
allow from ***.***.***.***
コンテナの中にコピー
sudo docker cp .htaccess0 <コンテナID>:/var/www/html/wp-admin/.htaccess

REST API アクセス制限については
コンテナの中に入って
WordPressインストールディレクトリに「wp-json」というディレクトリを作成
exit
でコンテナから出る。
Vsコードで.htaccess1を作って中身は
Order deny,allow
Deny from all
allow from ***.***.***.***
後で分かったがallow fromで自分のIPを許可しないと新規投稿で
「jsonレスポンスがありません。」というエラーの原因になっているかもしれません。
この件はあいまい。wafをオフしただけでも新規投稿できたかもしれないので記憶があやふやです。

コンテナの中にコピー
sudo docker cp .htaccess1 <コンテナID>:/var/www/html/wp-json/.htaccess
目次へ
wp-cronにアクセス制限してやったとき
WordPressで投稿した直後に以下のエラーが出る。
もしIP制限にするには自分のIPアドレスではなく
sudo docker inspect ネットワーク名で調べたGatewayのIPで
Allow from にしないとダメなのかと思ったが、なぜclientがGatewayのIPになっているのか分からないのでGatewayのIPをallow fromにするのはやめた。
[error] 128#128: *364 access forbidden by rule, client: GatewayのIP, server: kikuichigevps.com, request: "POST /wp-cron.php?doing_wp_cron=**** HTTP/1.1", host: "kikuichigevps.com"
(要調査)→https://kikuichige.com/24955/#toc2

接続

Nginx設定

前回作ったmodsecurity/jikken1.confの以下をWordPressのコンテナに変えます。

80と443の設定を以下に変更
    location / {
        #allow ***.***.***.***;  # ***.***.***.***からのアクセスのみ許可
        #deny all;  
        proxy_pass   http://wordpress-wordpress-1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $remote_addr;# クライアントのIPを渡す
    }
最初アクセスしたときwp-admin/install.php が HTTPS で、
dashicons.min.css等が HTTPになっていて
cssが当たっていない状態でした。以下追加したらうまく表示しました。
proxy_set_header X-Forwarded-Proto https;
多分httpとhttpsで混ざった状態でアクセスするとダメで、
こうすればhttpがhttpsになるんだと思います。

またproxy_set_header X-Forwarded-For $remote_addr;は
http://wordpress-wordpress-1にクライアントのIPを渡すためです。
これがないとwaf-nginxのIPがWordPressに渡ってアクセス制限できませんでした。
(この文章、後日見直したらなぜこうやったか疑問が出てきた。waf-nginxでIP制限してるのでWordPressのnginxは関係ないはず。結局、PV数の件で必要になったけど(後述))
X-Forwarded-Forについてはこちらに書かれてます。
 https://beyondjapan.com/blog/2024/02/nginx-access-log/   
また注意点として参考:nginxでX-Forwarded-Forの値に`$proxy_add_x_forwarded_for`を安易に使わない方が良い | せろとにんぱわー. (serotoninpower.club) 

コメントアウトしている2行を使うとIPアドレス制限できます。
準備中は自分のIPアドレスだけ許可するようにしてます。 

CocoonのPV数が1以上にならなくなった

こちらCocoonでPV数が「1」から増えない場合の対処【解決】 | wnkhs.netを参考にして原因は多分同じだろうと思った。つまり同一IPの連続アクセスはカウントしないことが原因。
WordPressのコンテナのremote_addrにNginxのコンテナのIPが渡っていて
クライアントのIPアドレスが渡っていないと思われる。
なのでいつも同じIP(172.*.*.*)でPV数が1以上にならない。
ヘッダの受け渡しがよく分かってないので取り合えずproxy_set_header Remote-Addr $remote_addr;を追加したがダメだった。
こちらクライアントのIPアドレスを正しく取得する #nginx – Qiitaを見る限りNginxの層ではRemote-Addrは変更できなさそうです。
上記でproxy_set_header X-Forwarded-For $remote_addr;してクライアントのIPは渡っているので参考サイトと同じようにCocoonのファイルをいじってRemote-AddrではなくX-Forwarded-ForでIP判定するように変更した。

WordPressのコンテナの中に入ってviで修正(SSH接続でマウントされたファイルを変更しても保存できなかった)
ファイルは
./html/wp-content/themes/cocoon-master/lib/page-access/access-func.phpにある。
またCocoonの更新をしたときはデフォルトに戻ってしまうので、再度変更する必要がある。

パーミッション変更(変更後は644に戻す)
sudo chmod 664 /home/wazyken/docker/zakword/html/wp-content/themes/cocoon-master/l
ib/page-access/access-func.php
でパーミッション644→664に変更
$last_ip = $_SERVER['REMOTE_ADDR'];→$last_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
にして保存。
WordPressのコンテナをdocker restartで再起動。うまくカウントするようになった。
また、WordPressのテーマエディタで修正したが私のシステムの場合、保存でエラーになる。
別のファイルはテーマエディタで以下対策すればうまくいったのだが今回はダメだった。

お名前ドットコムVPSへ移行への道12-エラーログを見て対策 | イチゲ ブログ (kikuichige.com)

ちなみに自分(管理者)はどうやってカウントに含ませないようにしているか考えた。
Cocoon設定→アクセス解析・認証に「サイト管理者も含めてアクセス解析する」のチェックをはずすと自分(サイトの管理者)はカウントされない。
これは自分のIPを設定するところはないのでIPで管理しているわけではない。
ログインしてるかしてないかでカウントの可否を判断しているようです。ログアウトしてページにアクセスするとカウントされることから、そう考えました。

confを反映させる
sudo docker restart コンテナ名
目次へ

セキュリティ対策

すでに上で実施している部分もあります。

シンクラウド for FreeのWordPressセキュリティ設定の項目を参考に対策

プラグインを入れすぎると何かあったとき調べるのが大変になるのではないかと思っているので、
セキュリティ対策にプラグインは使わないことにしました。
シンクラウド for FreeのWordPressセキュリティ設定の項目を参考に対策していきます。

国外IPアクセス制限 ←結果的に国内外区別せず制限することになった。
 ダッシュボード アクセス制限
  →wp-login.php、wp-adminを.htaccessでIP制限した。
   参考:https://kingsite.jp/blog/0174#11
   参考:WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめ  
 XML-RPC API アクセス制限
  →XML-RPC API を.htaccessでアクセス制限した。
   参考:WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめ  
  →(代替方法)function.phpを直接編集。詳細XML-RPCを無効にしてみる
 REST API アクセス制限
  →REST API「wp-json」を.htaccessでアクセス制限した。
   参考:WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめ  
  →(限定的代替方法)ユーザー名を表示させないようにする対策のみ。
   詳細:ユーザー名を見えなくした
 wlwmanifest.xml アクセス制限
  →wlwmanifest.xml を.htaccessでアクセス制限した。
   参考:WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめ  
その他、WordPressのアクセス制限を掛けておくべきファイル・ディレクトリのまとめに書かれていることをやりました。  
ログイン試行回数制限
 ログイン試行回数制限
  →調べるとプラグインを使う方法しか見つからなかったのでやらない。
   IP制限のみで様子を見て必要ならプラグイン導入を考える。

コメント・トラックバック制限
 単一ユーザーからの大量投稿
 国外IPアドレスからの投稿
  →コメントできないようにした。

【WorldPress入門】スパムコメント対策
WorldPressダッシュボードを見るとコメントに1となっていた。見てみると外人からコメントがきた。明らかに宣伝のコメントだ。さらにメールで「 モデレートしてください: "Hello world!"」ときた。ということ

その他

個人メモ
WordPressのテーマファイルエディタを使うとき「ファイルの更新」をクリックすると
「致命的なエラーをチェックするためにサイトと通信できないため、PHP の変更は取り消されました。SFTP を使うなど、他の手段で PHP ファイルの変更をアップロードする必要があります。」
対策:WAFのnginxのconfでGatewayのIPを一時的にallowにする。
以下↓に詳しく書きました。

シンクラウド for FreeのWordPressのログを見たり運営していて気付いた対策。

ユーザー名を見えなくした

こちらを参照してください。

シンクラウド for FreeのアクセスログをPythonで解析する方法
シンクラウド for Freeでアクセスログが見れるようになったのでPython(JupiterNotebook)を使って解析してみました。アクセスログについてはこちらで説明されています。実施してみて危なそうなログが見つかったので対策(XM

ニックネームを変える

フィードに含まれるユーザー名を隠す。
→ニックネームを変える。詳細:feed

PHPのバージョンをかくす

参考:[技術ブログVol.4] Webサーバセキュリティの基本の「き」 – DENET 技術ブログ

アクセスログに以下があったので調べた
"GET /?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 HTTP/1.1"
アクセスしてブラウザの開発者ツールのネットワークタブで
ヘッダを見るとX-Powered-By:PHP/*.*.*
とPHPのバージョンが表示される。

対策
vim php.iniに以下追加
expose_php = Off

保存したら
sudo docker cp ./php.ini コンテナ名:/usr/local/etc/php/php.ini
コンテナ名はsudo docker ps -aで調べられます。
sudo docker restart コンテナ名で再起動
目次へ

アップロードMAXサイズを変更

ダッシュボードのメディア→新しいメディアファイルを追加
で最大アップロードサイズ: 2 MB。と表示されます。
テーマをアップロードするときなど必要なときだけ大きくしようと思います。
やり方は、こちら↓。最後WordPressのコンテナをrestartすると設定が反映されます。

テーマをアップロードするときmodsecurityをOFFにしないと引っかかります。
私は自分のIPだけ許可するルールを追加して使ってます。

サイト内検索スパムの対策

“POST /index.php HTTP/1.1” 200

見知らぬIPから”POST /index.php HTTP/1.1″ 200をいうアクセスログがあった。
ステータスコード200は「成功」を意味し、サーバーがリクエストを正常に処理し、
要求されたリソースを提供したことを示します。
しかし、これはファイルが書き換えられたことを意味するものではありません。(ChatGpt談)
コンテナの中に入って

cat index.php
で中身を確認しChatGptに改ざんされてないか聞いたら改ざんされてないという答えだった。
ファイルのタイムスタンプの確認: ファイルの最終変更日時が不審なものでないか確認しといた。
アクセスログに残っていた日付よりだいぶ前なので大丈夫だと思われる。
2024/5/27実施。(個人的に確認するため記録しておきます。)
ls -l
total 252
-rw-rw-r--    1 1001     1001            58 Apr 15 01:34 ads.txt
-rw-r--r--    1 www-data www-data       405 Feb  6  2020 index.php
-rw-r--r--    1 www-data www-data     19915 Apr  2 23:43 license.txt
-rw-r--r--    1 www-data www-data      7401 May  7 18:30 readme.html
-rw-r--r--    1 www-data www-data      7387 Apr  2 23:43 wp-activate.php
drwxr-xr-x    9 www-data www-data      4096 Jan 30 19:27 wp-admin
-rw-r--r--    1 www-data www-data       351 Feb  6  2020 wp-blog-header.php
-rw-r--r--    1 www-data www-data      2323 Jun 14  2023 wp-comments-post.php
-rw-r--r--    1 www-data www-data      5512 Mar 16 02:50 wp-config-docker.php
-rw-r--r--    1 www-data www-data      3012 Apr  2 23:43 wp-config-sample.php
-rw-r--r--    1 www-data www-data      5784 May 26 06:39 wp-config.php
drwxr-xr-x   15 www-data www-data      4096 May 26 07:58 wp-content
-rw-r--r--    1 www-data www-data      5638 May 30  2023 wp-cron.php
drwxr-xr-x   30 www-data www-data     16384 Apr  2 23:43 wp-includes
-rw-r--r--    1 www-data www-data      2502 Nov 26  2022 wp-links-opml.php
-rw-r--r--    1 www-data www-data      3927 Jul 16  2023 wp-load.php
-rw-r--r--    1 www-data www-data     50917 Apr  2 23:43 wp-login.php
-rw-r--r--    1 www-data www-data      8525 Sep 16  2023 wp-mail.php
-rw-r--r--    1 www-data www-data     28427 Apr  2 23:43 wp-settings.php
-rw-r--r--    1 www-data www-data     34385 Jun 19  2023 wp-signup.php
-rw-r--r--    1 www-data www-data      4885 Jun 22  2023 wp-trackback.php
-rw-r--r--    1 www-data www-data      3246 Apr  2 23:43 xmlrpc.php
目次へ

移行

2024/4/15~レンタルサーバーからVPSに変更し、当ブログを運営してます。
実行する順番はよく考えてからやってください。バックアップが取れなくなったりします。
以下は例です。手順はだいぶ抜粋されてます。(いろいろハマったので記録してない。)

お名前.comレンタルサーバーからVPSへ移行する場合
データベース、アップロード、その他をダウンロード
プラグインとテーマはバックアップを使わず直接インストールしてます。
またファイルサイズを確認してアップロードできるサイズを広げるために
あとで以下の調整が必要です。
php.iniwordpressのnginx、wafのnginxのconf
全体の流れは、こちら↓を参照してください。
ドメインを移行した後はバックアップが取れなくなるので注意してください。
また別のドメインで作ったWordPressに復元するとドメインを変えるのが大変なので
ドメイン移行、SSL対応後、初期状態のWordPressに復元したほうがいいです。

シンクラウド for FreeとUpdraftPlusでサーバー移行の練習をした!
データベースだけをバックアップして移行先ではテーマやプラグインは手動でインストールした後にデータベースだけ復元すればスムーズに移行できるのではないかと考えたので実験した。具体的にはシンクラウド for Freeのサーバー内の2つのWordP
ドメイン移行は
ネームサーバーを変更する。参考:https://www.onamae-server.com/guide/rs/p/24
VPS(KVM)のところの設定するをクリック→有料サービスは設定しない→設定する
ドメインのDNS設定→ドメインを選ぶ→DNSレコード設定を利用する
Aレコードを空欄とwwwの2つ作成する。参照:https://www.onamae.com/column/domain/33/
MXやTXT(default._domainkey~)などのメール関係は、
このまま使えるか分からないので使ってません。
改めてメールアドレスを新規で作ってます。↓
SSL対応では
/etc/letsencrypt/archive/kikuichige.com/privkey.pem;のパーミッションが
600でうまくいかないので644に変更。(変更していいものなのかは不明)

wafのnginx(本シリーズの最終形態)のconfで80と443のドメインを変更→sudo docker restart waf-nginxで変更反映

移行先でバックアップファイルをアップロードに3つドラッグアンドドロップ
復元→全部チェック→次へ→復元
1回失敗したけどWordPressとデータベースのコンテナとボリュームを削除してcomposeupしたら再開できた。

移行して表示はできました。しかし、次項に続く。

公開に失敗しました。 返答が正しい JSON レスポンスではありません。

新規投稿すると「公開に失敗しました。 返答が正しい JSON レスポンスではありません。」
ログを見るとModSecurityに引っかかっている。
→offにして新規投稿したらできましたが下に対策があります。

2024/03/19 07:52:10 [error] 127#127: *102 [client ***.***.***.***] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:BLOCKING_INBOUND_ANOMALY_SCORE' (Value: `10' ) [file "/etc/modsecurity.d/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "176"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] [data ""] [severity "0"] [ver "OWASP_CRS/4.0.0"] [maturity "0"] [accuracy "0"] [tag "modsecurity"] [tag "anomaly-evaluation"] [hostname "***.***.***.***"] [uri "/wp-json/wp/v2/posts/24801/autosaves"] [unique_id "171080233091.334238"] [ref ""], client: ***, server: django7.kikuichigevps.com, request: "POST /wp-json/wp/v2/posts/24801/autosaves?_locale=user HTTP/2.0", host: "django7.kikuichigevps.com", referrer: "https://django7.kikuichigevps.com/wp-admin/post-new.php"

対策として2つ
WordPressのwp-jsonの.htaccessで自分のIPを許可した。(関係ないかも)
Modesecurityで自分のIPを許可した。↓(ymlのenviromentでon/off切り替えるのが大変なので)

所感

wafも効いてるし結構対策できたと思う。
しかしメモリ不足の問題を解決しないといけないので次回やります。(次回で解決した。)
取り合えずVsコードでサクサクやってfreeでメモリ見て0.7G超えるとメモリ不足になって
VPSの再起動が必要になった。
不便だがシリアルコンソールをなるべく使うようにしてる。
目次へ

イチゲをOFUSEで応援する(御質問でもOKです)Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)

コメント

タイトルとURLをコピーしました