WordPressの普通のインストールをDockerに移行する

2023年1月13日

Lolipop上の標準プランで構築したWordpressサイトを、新たに借りたVPSサーバのDocker環境に移行したい。

Docker環境に新たにWordpressをインストールするなら簡単で、Docker-ComposeでWordPressをインストールに示したが、既に動いている物をDockerに移行するにはどうしたら良いのだろうか。

バックアップの取得

バックアップの実行

当然のことながら、現状のMySQLデータベースとウェブコンテンツのバックアップをLolipopから取得しておくのだが、lolipopのやり方は非常に面倒になっている。ここでは、BackWPupというプラグインを使う。これをまずインストールする。

このプラグインは、基本的には、定期的に自動でバックアップをとってくれるものらしい。バックアップ「ジョブ」を定義して、そのジョブを定期的に動作させることにより、バックアップをとっていってくれる。しかし、今回はそんな仕組みは必要無い。ジョブを定義したら、「今すぐ実行」すれば良い。

まずジョブを作成する。

おそらくは以下の設定で大丈夫かと思う。

※実際には、「インストール済のプラグイン一覧」は無意味だ(後述)。

フォルダへバックアップする。場所は後述。

ジョブ一覧に定義したジョブが現れるので、「今すぐ実行」する。

ジョブが終了すると、「バックアップ」リストにバックアップが現れる。ここに作成されたバックアップファイルのパスが示されている。

ここにダウンロードボタンがあるのだが、何かしらphpの設定がまずいのかもしれない。この1.11GBのファイルの48MB程度しかダウンロードできず、途中で中止されてしまう。

わざわざphpを設定するのも面倒なので、FTPでファイルダウンロードすることにした。

BackWPupによるバックアップファイルの中身

FTPで表示したファイル一覧(左)と、上で取得したバックアップZIPを展開した結果(右)を比較してみる。

明らかにsqlはデータベースのバックアップである。

plugins*.txtは単にインストールされているプラグインのリスト。なぜこんなものが必要なのか不明。
backup_readme.txtには以下が記述されているが、何のことなのか不明。

このアーカイブ内の manifest.json ファイルに気づいているかもしれません。
manifest.json はこのアーカイブからバックアップを復元するとき必要になる場合があります。
manifest.json は手つかずの所定の位置に残してください。それ以外の場合は無視されても安全です。

それとmanifest.jsonがある。

BackWPupプラグインでバックアップを作成して管理画面からダウンロードする方法によれば、この二つのファイルは不要だそうだ。plugins*.txtも大した情報は無いので、これも不要と思われる。つまり、新たに加わった.sqlファイルのみが必要になる。

wp-config.phpの内容

リストアの際に最も重要なのが、トップにあるwp-config.phpである。この内容は以下のようになっている。

/** WordPress のためのデータベース名 */
define('DB_NAME', 'LAA123********');

/** MySQL データベースのユーザー名 */
define('DB_USER', 'LAA12****');

/** MySQL データベースのパスワード */
define('DB_PASSWORD', '5LC****');

/** MySQL のホスト名 */
define('DB_HOST', 'mysql***.phy.lolipop.lan');

そして、以下の記述がある。

/**
 * WordPress データベーステーブルの接頭辞
 *
 * それぞれにユニーク (一意) な接頭辞を与えることで一つのデータベースに複数の WordPress を
 * インストールすることができます。半角英数字と下線のみを使用してください。
 */
$table_prefix  = 'wp20********_';

他は簡単に変更できる。テーブル接頭辞はもっと簡単にしたいものだが、変更方法はこれだそうだ。

【WordPress】テーブル接頭辞の変更方

※最終的には、各テーブルの名称変更はしなかった。レコードデータとしてテーブル名が格納されてしまっているからである。今回最大のトラブルの元になった。

移行

ここでは、いったんオリジナルのexample.comではなく、migrate.example.comとして移行する。なぜなら、移行がうまくいかない間は、example.comが見れなくなってしまうからだ。とりあえず、migrate.example.comとして動きを確認し、その後にexample.comにする。そのためには、wp-config.phpを少々いじらなくてはいけない。

データベースのリストア

データベースは、mariadbコンテナに集約させているため、そこにリストアする。このとき、DB名称変更、各テーブル名称変更を行う。

※最終的には不要

# docker cp backup.sql mariadb:/
# docker exec -it mariadb bash
# mysql -u *** -p****
> create database example default character set utf;
> quit
# mysql -u *** -p*** example < backup.sql
# mysql -u *** -p****
> use example
> show tables;
+--------------------------------------------+
| Tables_in_example                          |
+--------------------------------------------+
| wp20201215125458_commentmeta               |
| wp20201215125458_comments                  |
| wp20201215125458_links                     |
| wp20201215125458_options                   |
| wp20201215125458_postmeta                  |
| wp20201215125458_posts                     |
| wp20201215125458_term_relationships        |
| wp20201215125458_term_taxonomy             |
| wp20201215125458_termmeta                  |
| wp20201215125458_terms                     |
| wp20201215125458_uam_accessgroup_to_object |
| wp20201215125458_uam_accessgroups          |
| wp20201215125458_usermeta                  |
| wp20201215125458_users                     |
+--------------------------------------------+

あらかじめテキストエディタで次を作成
※最終的には不要

alter table wp20201215125458_commentmeta               rename to wp_commentmeta;
alter table wp20201215125458_comments                  rename to wp_comments; 
alter table wp20201215125458_links                     rename to wp_links; 
alter table wp20201215125458_options                   rename to wp_options;
alter table wp20201215125458_postmeta                  rename to wp_postmeta; 
alter table wp20201215125458_posts                     rename to wp_posts;
alter table wp20201215125458_term_relationships        rename to wp_term_relationships;
alter table wp20201215125458_term_taxonomy             rename to wp_term_taxonomy;
alter table wp20201215125458_termmeta                  rename to wp_termmeta;
alter table wp20201215125458_terms                     rename to wp_terms;
alter table wp20201215125458_uam_accessgroup_to_object rename to wp_uam_accessgroup_to_object;
alter table wp20201215125458_uam_accessgroups          rename to wp_uam_accessgroups;
alter table wp20201215125458_usermeta                  rename to wp_usermeta;
alter table wp20201215125458_users                     rename to wp_users;

これを一度に流し込めば良い。
※最終的には不要

> show tables;
+------------------------------+
| Tables_in_example            |
+------------------------------+
| wp_commentmeta               |
| wp_comments                  |
| wp_links                     |
| wp_options                   |
| wp_postmeta                  |
| wp_posts                     |
| wp_term_relationships        |
| wp_term_taxonomy             |
| wp_termmeta                  |
| wp_terms                     |
| wp_uam_accessgroup_to_object |
| wp_uam_accessgroups          |
| wp_usermeta                  |
| wp_users                     |
+------------------------------+

この状態のデータベースをバックアップし、mariadbのシェルを抜ける。

> quit
# mysqldump -u *** -p*** example > new-backup.sql
# exit

コンテンツのリストアと変更

このwordpress用のフォルダを決める。仮に/opt/docker/exampleとする。この下にhtmlというフォルダを作成し、そこに展開したバックアップを入れる。もちろん、*.sqlはもはや不要。ファイルのパーミッションを適切なものにする。

wp-config.phpを変更する。このDockerコンテナからは、mariadbのコンテナはmariadbというホストとして参照できるようにする。

/** WordPress のためのデータベース名 */
define('DB_NAME', 'example');

/** MySQL データベースのユーザー名 */
define('DB_USER', '***');

/** MySQL データベースのパスワード */
define('DB_PASSWORD', '***');

/** MySQL のホスト名 */
define('DB_HOST', 'mariadb');

※以下は最終的には不要。接頭辞は変更しない

/**
 * WordPress データベーステーブルの接頭辞
 *
 * それぞれにユニーク (一意) な接頭辞を与えることで一つのデータベースに複数の WordPress を
 * インストールすることができます。半角英数字と下線のみを使用してください。
 */
$table_prefix  = 'wp_';

さて、ここで、本来運用されているexample.comではない、migrate.example.comにするために、wp-config.phpでそれを強制する。
一番上で良いので、以下を入れる。これは後から消すことになる。

define( 'WP_HOME', 'https://migrate.example.com' );
define( 'WP_SITEURL', 'https://migrate.example.com' );

docker-compose.yml

このコンテナのルート位置に以下を作成する。
traefikについては、他の記事を参照されたい。

version: '3'

services:
  wordpress:
    image: wordpress:6.0.2
    container_name: example
    volumes:
      - ./html:/var/www/html
    restart: always
    environment:
      - WORDPRESS_DB_HOST=mariadb:3306
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=root
      - WORDPRESS_DB_NAME=example
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.example.rule=Host(`migrate.example.com`)"
      - "traefik.http.routers.example.entrypoints=websecure"
      - "traefik.http.routers.example.tls.certresolver=myresolver"
      - "traefik.http.routers.example-http.entrypoints=web"
      - "traefik.http.routers.example-http.rule=Host(`migrate.example.com`)"
      - "traefik.http.routers.example-http.middlewares=example-https"
      - "traefik.http.middlewares.example-https.redirectscheme.scheme=https"
networks:
  default:
    external:
      name: traefik-network

これで「docker-compose up -d」を行えばよい。実際にサイトを表示させてみると、エラーが発生するものの、正しく表示されているようである。エラーの内容は例えば以下だ。これはブラウザのデバッグ機能に表示された文字列。

Access to font at 'https://example.com/wp-content/themes/luxeritas/fonts/icomoon/fonts/icomoon.woff' from origin 'https://migrate.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

ドメインが違っているために、フォントが取得できないらしい。また、当然だが、投稿やページに画像を貼り付けた場合、そのままでは、ドメイン名まで記述されているので、貼り付けられた画像は、元のドメインからひっぱってきている。

ともあれ、問題無いと思われるので、本格移行を行う。

本格移行

DNSを変更して、本番に移行する。

wp-config.phpの以下の二行を削除

define( 'WP_HOME', 'http://migrate.example.com' );
define( 'WP_SITEURL', 'http://migrate.example.com' );

docker-compose.ymlの以下の二つの行を修正

      - "traefik.http.routers.example.rule=Host(`example.com`)"
      - "traefik.http.routers.example-http.rule=Host(`example.com`)"

トラブル

ERR_TOO_MANY_REDIRECTS

一般ユーザの閲覧はごく普通にできるのだが、なぜか、管理者になれない。

https://example.com/wp-loginは404 NOT FOUNDとなるし、https://example.com/wp-login.phpは以下のエラーになる。

https://www.redirect-checker.org/で調べてみる。

https://example.com/wp-login.php
302 Found
https:///example.com/wp-login.php
302 Found
https:///example.com/wp-login.php
302 Found
https:///example.com/wp-login.php
302 Found
https:///example.com/wp-login.php
302 Found

という状態だ。

原因としては、おそらく、以前の環境では、wordpress自体にhttpからhttpsへのリダイレクトをさせていたが、現在の環境では、wordpress側はhttpアクセスに専念し、traefik側がリダイレクトとSSL化をしているからと思われる。

つまり、現在の環境では、wordpress側には常にhttpでリクエストが来るのだが、wordpress側ではそれを許さず、httpsにリダイレクトしろと指示し、しかしそれでもhttpでリクエストが来てしいまい、これを延々と繰り返すというわけだ。

一般ユーザの閲覧で問題が無いのは、これが管理者画面にのみ適用されるからである。管理者画面へのhttpアクセスは許さないというわけだ。

ERR_TOO_MANY_REDIRECTSへの対処方法 – WordPressサイトのSSL化によりログイン管理画面にアクセスできない問題の解決にこの問題の解決策があるのだが、単純には適用できなかった。

有効な解決策は、管理画面での SSL 通信にあった。

wp-config.phpに以下を記述することにより、wp-login.phpは正常に動作する。

define('FORCE_SSL_ADMIN', true);
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ) {
       $_SERVER['HTTPS']='on';
}

※根本的に、「なぜ管理者画面ではSSLアクセスしか許さないのか」を追求しなければならないのだが、とりあえず解決したのでよしとする。

このページにアクセスする権限がありません。

しかし、ログインした後、wp-adminに行ってみると、以下のエラーが発生する。

これは以下が原因のようだ。

[WordPress] 「このページにアクセスする権限がありません」で管理画面に入れない場合の対処 [テーブル接頭辞]

手順1はOKとして、手順2は非常に面倒。つまり、テーブル名が、他のテーブルのレコードとして格納されてしまっているため、これをすべてチェックしなければまともには動かないことがわかった。

この時点でテーブル接頭辞変更はあきらめ、lolipop側が作成した接頭辞のままにする。

以上で、完全な移行ができ、正常に動作している。

まとめ

教訓としては以下だ。

  • テーブル接頭辞変更はしない。レコードデータとしてテーブル名が格納されている場合がある。
  • 環境によって、Wordpress自体に管理画面SSLアクセスを強制している場合と、httpオンリーの場合がある。
  • Dockerでのインストールでも、単純にデータベースを用意し、コンテンツ場所を教えてやれば、すんなり動く。

未分類

Posted by ysugimura