家族専用のブログを別環境に移設したところ、メディアがすべて0バイトに見える。
ディレクトリを丸ごとバックアップしておけば、それをリストアするだけで使えるはずなのに…なんでだろ?
症状
OSはUbuntu 22.04、WebサーバーはApache、DBサーバーはMariaDB、WordPressが動作している環境。
メディアファイルはちゃんと復元できているが、中身が見られない。
メディアのURLに直接アクセスすると、NOT FOUNDにならず、0バイトのファイルに見える。
このように、ひどい有様になっている。
デバッグログをオンにして、関係しそうな箇所でログを出力させたけれど、どうやらメディアファイルの位置を正しく指しているようだった。
原因と対策
WordPress側でX-Sendfileを使ってコンテンツを配信しようとしているのに、ApacheでX-Sendfileの設定をしておらず、ファイルが送信されていなかった。
具体的には、以下の設定をセットで入れるか、セットで外しておかなければならない。
wp-config.php
define( 'WPMU_SENDFILE', true );
/etc/apache2/sites-available/hoge.conf
XSendFile on XSendFilePath /path/to/wordpress/wp-content/blogs.dir
※古くから使っているのでこんなディレクトリだけれど、新しいセットアップでは、/path/to/wordpress/wp-uploads になる想定。
こうなってしまった経緯は…
- 過去、動画のシークができないから…と、X-Sendfileの設定を入れた。
これを定期的にバックアップしている。 - 別環境での稼働を急いでいた。
取得済みのバックアップをリストアしたものの、Apacheの設定を最低限で済ませようとして、X-Sendfileの設定をしていなかった。
ということで、ちぐはぐな状態になってしまった。
なお、ApacheでX-Sendfileを使用する場合には、以下のライブラリをインストールしておく必要があるので、メモしておく。
$ sudo apt install libapache2-mod-xsendfile
やったこと
かなり昔に設置したWordPressで、自動でバージョンアップが繰り返され、現在は6.2.2になっている。
マルチサイト設定がしてあって、コンテンツは wp-contents/blogs.dir に保管されている。
これはかなり昔に変更されていて、今は wp-uploads に保管されるようだ。
最初はこれが原因?と思って色々と調査をしていた。
WordPressのリストア
0バイト問題が全然解決できないので、VMware PlayerにUbuntu 22.04 desktopをインストールして、色々と試せる環境を作ることにした。
雑なメモだけれども、Apacheのモジュール以外はだいたいこれで行ける。モジュールはエラーが出たら追加すればOK。
MariaDBをインストールし、ユーザーを作る。
データーベースはwordpress、ユーザーはwordpressの想定で作成。
$ sudo apt install mariadb-server $ sudo mariadb MariaDB [(none)]> create user wordpress; MariaDB [(none)]> set password for wordpress = password('**masked**'); MariaDB [(none)]> create database wordpress default character set utf8mb4 collate utf8mb4_unicode_520_ci; MariaDB [(none)]> grant all privileges on wordpress.* to wordpress@'%'; MariaDB [(none)]> quit
※パスワードはマスクしている。
データーベースwordpressの復元。
$ mysql -u wordpress -p -D wordpress < /opt/wordpress/backup/root/work/backup/wordpress.dmp Enter password: ERROR 1064 (42000) at line 2177: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'Process 76109 detected Child process is finished, exiting...' at line 1
※エラーは、ダンプに出力処理結果が乗っかっていて、それが文法エラーとして検出されているもの。データーベースはすべて復元できているので無視する。
PHPと、mysqlを操作するためのライブラリをインストール。
$ sudo apt install php php-mysql $ php --version PHP 8.1.2-1ubuntu2.11 (cli) (built: Feb 22 2023 22:56:18) (NTS) Copyright (c) The PHP Group Zend Engine v4.1.2, Copyright (c) Zend Technologies with Zend OPcache v8.1.2-1ubuntu2.11, Copyright (c), by Zend Technologies
Apacheにとりあえず動くサイトを設定。
サーバーはhogeserver.hogeddns.jpにマスクしている。
php_valueは.htaccesにあったものだけれど、エラーになったのでこのファイルに持ってきた。
システム管理メモ / Apache2.4: php_value not allowed here
hoge.conf
<VirtualHost *:80> ServerName hogeserver.hogeddns.jp RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} </VirtualHost> <VirtualHost *:443> ServerName hogeserver.hogeddns.jp DocumentRoot /path/to/wordpress ErrorLog ${APACHE_LOG_DIR}/hoge-error.log CustomLog ${APACHE_LOG_DIR}/hoge-access.log combined SSLEngine on SSLCertificateFile /path/to/crt/hogeserver.hogeddns.jp/fullchain.pem SSLCertificateKeyFile /path/to/key/hogeserver.hogeddns.jp/privkey.pem # XSendFile on # XSendFilePath /path/to/wordpress/wp-content/blogs.dir <Directory /path/to/wordpress> Require all granted DirectoryIndex index.php AllowOverride FileInfo FallbackResource /index.php </Directory> </VirtualHost>
本来なら、ココでXSendFileの設定を入れておくべきところであって、これが0バイトの原因。
この機能を使うためにはライブラリをインストールする。
$ sudo apt install libapache2-mod-xsendfile
さて、必要なモジュールを追加して、Apacheを再起動。
$ sudo systemctl restart apache2
ブラウザーからリストアした環境にアクセスするために、以下の設定で自分に向ける。
/etc/hosts
192.168.110.113 hogeserver.hogeddns.jp
※127.0.0.1でもアクセスはできると思うけれど、なんとなく割り付けたローカルのIPアドレスを設定。
これでクローンすることができたが、メディアが見られない。
元々のサーバーでは、/usr/share/wordpressでサービスを構成していたので、一応そこに移して試してみたが、結果は同じでメディアが見られない。
Apacheのログを見る
今回の設定だと、以下にログが出力される。
/var/log/apache2/hoge-access.log
192.168.110.113 - - [08/Jul/2023:18:44:19 +0900] "GET /subsite/files/2020/03/hoge.jpg HTTP/1.1" 200 5025 "https://hogeserver.hogeddns.jp/subsite/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0"
画像へのアクセスに対して、200 OKが戻されている。
でも、0バイトのファイルだから、何も見えない。
WordPressのデバッグログを見る
デバッグに関して、公式で教えてくれている。
WordPress.org 日本語 / WordPress でのデバッグ
こんな感じで書いておいて、必要になったら、コメント行→有効行に切り替えればいいかなと。
wp-config.php
define( 'WP_DEBUG', true ); if ( WP_DEBUG ) { // デバッグログファイルを出力する wp-content/debug.log // PHPのビルトイン関数error_log()関数を使うとログを出力できる define( 'WP_DEBUG_LOG', true ); // デバッグログを画面に出力しない //define( 'WP_DEBUG_DISPLAY', false ); //@ini_set( 'display_errors', 0 ); // CSSやJavaSctiptで開発版を使用(通常は縮小版) //define( 'SCRIPT_DEBUG', true ); // データベースクエリを配列に保存して表示する //define( 'SAVEQUERIES', true ); }
今回の場合は、エラーじゃないので、デバッグログは出力されなかった。
ディレクトリ変換の様子を見る
古いセットアップなので、メディアの格納先は wp-contents/blogs.dir となっている。
探してみると、以下のファイルで、ms_files_rewritingというサイトオプションがあれば、ディレクトリを編集しているようだった。
この変換処理で何か起きているの?と思い、ファイルを探してデバッグログを入れてみた。
wp-includes/ms-default-constants.php
... function ms_upload_constants() { // This filter is attached in ms-default-filters.php but that file is not included during SHORTINIT. ... } error_log("ms_upload_constants " . BLOGUPLOADDIR,0); } ...
画像にアクセスしたところ、以下のようなログが出力される。
wp-contents/debug.log
[08-Jul-2023 10:09:19 UTC] ms_upload_constants /var/www/html/wp-content/blogs.dir/2/files/
ページのソースを確認すると、この時には以下のURLの画像をとってってこようとしている。
https://hogeserver.hogeddns.jp/subsite/files/2023/02/hoge.jpg
これを連結してみたファイルの存在を確認してみると、ちゃんと存在している。
$ ll wp-content/blogs.dir/2/files/2023/02/hoge.jpg -rw-r--r-- 1 www-data www-data 17429 2月 4 15:34 wp-content/blogs.dir/2/files/2023/02/hoge.jpg
これは、ディレクトリ変換がちゃんと動いていることを表している。
X-SendFileを設定してみる
ここまできて、確かにApacheのサイト設定が雑すぎるな…と気付き、1行ずつ確認していった。
この設定ができていないな、ということで「本番サイト」の設定をそのままコピー、ディレクトリが違う状態。
hoge.conf
<VirtualHost *:443>
...
XSendFile on
XSendFilePath /usr/share/wordpress/wp-content/blogs.dir
...
</VirtualHost>
画像にアクセスしてみたところ、WordPressの404じゃなく、Apacheが404を出している。
じゃあ、存在しないファイルにアクセスしたらどうなる?と確認すると、通常通りWordPressが404を返してくれる(殺風景だけれども昔のテーマだし)。
X-SendFileについては、こちらで説明されている。なるほど!
Nginx / XSendfile
Nginx / X-Accel
これを読んで想像するに、X-SendFileというのは…
- WordPressは動的にコンテンツを生成する仕組みだけれど、アップロード済みのメディアファイルは静的。
WordPressとしてはコンテンツ生成で頑張りたいので、静的ファイルの配信はWebサーバーに任せたい。 - そこで、WordPressはヘッダーにメディアファイルのURLを書いておいて、ボディーからリダイレクトさせるように仕掛ける。
アクセスしてきたブラウザは、例えば写真を表示しようとしたら、ん?ヘッダーを見ろって?と、ヘッダーのURLを見て、要求。 - 要求を受けたWebサーバーは、要求をWordPressに渡さずに、自分で静的ファイルを配信する。
WordPressは動的コンテンツの生成を頑張る
という仕掛けのようだ。
設定ミスによってApacheがファイルにたどり着けなくなったので、自分でエラーを出力するな、と。
X-SendFileの設定していなかったことで、
- WordPressとしては、静的ファイルの配信をApacheに任せたつもり。
- Apacheは、X-SendFileを処理するように設定していないから、何もしない(というか、0バイトのファイルを返している?)。
- ブラウザには何も表示されない。
ということになっていたのだった。
間違ったApacheの設定を直して、この問題は収束した。
さいごに
とにかく時間が掛かった。
手を抜く場所を間違った結果、最後までその手抜きにやられている、という感じ。
急がば回れというヤツだ。
1つ1つ丁寧に進めると、最終的には早く結果が得られる。
まぁ、おかげで幾つかの学習ができたのだから、良しとするか。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他