bbizinets.life
XserverからHetzner VPSへWordPressを移行した手順【6サイト移行の実践ログ】
実践ログ

XserverからHetzner VPSへWordPressを移行した手順【6サイト移行の実践ログ】

# XserverからHetzner VPSへWordPressを移行した手順【6サイト移行の実践ログ】

XserverからHetzner VPSへ移行した理由

Xserverの更新時期が近づいてきたとき、ふと立ち止まって考えた。

月額約1,100円のXserverと、すでに稼働しているHetzner CX22(月額約600円)。WordPressのためだけに2つのサーバーを契約し続けることに、合理的な理由が見当たらなかった。Xserver上のディスク使用量は3GB程度。500GBの枠のほとんどを使っていない状態で、毎月1,100円を払い続けるのはもったいないという判断だった。

もう一つ、背中を押した理由がある。n8nの構築やSanityを使ったNext.jsサイトの移行など、これまでAIと一緒に進めてきた経験が自信になっていた。「技術がわからなくても、AIの力を使えば自分で動かせる」という感覚が積み上がっていた。サーバー移行も、その延長線上にあると判断した。

レンタルサーバーを分けて持つコスト

Hetzner CX22にはすでにn8nが稼働していた。記事自動生成ワークフローもWordPressへの自動投稿も、このVPSを中心に動いている。ここにWordPressを集約すれば、サーバー管理の窓口が一本化できる。コスト削減と運用効率化、どちらも同時に達成できる移行だった。

Hetzner CX22にまとめる判断

Hetzner CX22のスペックは2コア・4GBメモリ・40GB SSD。月額約600円で使えるVPSとしては十分な構成です。Xserverの3GBのデータをまるごと移してもストレージには余裕があります。

PHP-FPMをondemandモードに設定することで、アクセスのないサイトはプロセスが起動しません。複数のWordPressを入れても、常駐プロセスによる無駄なメモリ消費を抑えられます。

非エンジニアでも移行できるのか

結論から言うと、できました。ただし「一人でできた」ではなく「AIと一緒にできた」が正確な表現です。

mysqldumpもscpもPython3も、コマンドの意味を完全に理解していたわけではありません。AIが提示したコマンドをターミナルにコピペしながら進めました。それでも移行は完了しました。今回の経験でわかったのは、「技術を理解すること」と「技術を使って目的を達成すること」は別物だということです。

移行前に確認した環境と準備

移行元:XserverのWordPress環境

今回移行したサイトは以下の6サイト。

サイト | 用途
--- | ---
bizinets.co.jp | 会社サイト
bizinets.biz | 思想・判断設計メディア
jogtime.jp | フレイル予防・ランニングメディア
shibukidai.com | 自動化検証用デモサイト
karadanonioi.info | 稼働停止中サイト
4buki.net | 稼働停止中サイト

XserverへのSSHはポート10022、公開鍵認証で接続する。ユーザー名はXserverのサーバーパネルの「SSH設定」画面で確認できる。

移行先:Hetzner CX22のUbuntu環境

項目 | 内容
--- | ---
OS | Ubuntu 24.04
PHP | 8.3.6(FPM / ondemand)
データベース | MariaDB 10.11
Webサーバー | Nginx
SSL | Certbot + Cloudflare DNS認証
DNS管理 | Cloudflare(全ドメイン移行済み)

使用したツールと作業

  • SSH:Xserver・VPS両方への接続
  • mysqldump:XserverのDBをダンプ
  • scp:XserverからVPSへのファイル直接転送
  • Certbot + Cloudflare APIトークン:SSL証明書の取得
  • Python3:特殊文字を含むパスワードの文字列置換

移行前にバックアップを取る

データが消えないかどうかが、移行前に一番不安だったポイントだ。対策として、mysqldumpとtarによるファイルアーカイブをXserver上に作成してからVPSへ転送する手順を取った。元のXserverはすぐには削除せず、移行・動作確認がすべて完了するまで維持した。

XserverからHetznerへWordPressを移行した手順

Step1:Xserver側でWordPressのDB情報を確認する

まずXserverにSSH接続し、移行対象サイトのwp-config.phpからDB情報を取得する。

grep -E "DB_NAME|DB_USER|DB_PASSWORD" /home/[ユーザー名]/[ドメイン]/public_html/wp-config.php

Step2:mysqldumpでデータベースをエクスポートする

取得したDB情報を使ってダンプファイルを作成する。

mysqldump -u [DBユーザー名] -p'[DBパスワード]' [DB名] > /home/[ユーザー名]/site_dump.sql

複数サイトを一括でダンプする場合も、同じコマンドをサイト分繰り返す。

Step3:WordPressファイルをアーカイブする

tar -czf /home/[ユーザー名]/site_files.tar.gz -C /home/[ユーザー名]/[ドメイン]/public_html .

Step4:scpでHetznerへ直接転送する

XserverとHetzner間でscpを使って直接転送する。ローカルPCを経由しないため転送が速い。

scp -P 22 /home/[ユーザー名]/site_dump.sql /home/[ユーザー名]/site_files.tar.gz root@[HetznerのIP]:/tmp/

初回接続時はホストの信頼確認が出るのでyesと入力して進める。

Step5:Hetzner側にDBをインポートする

VPSでDBとユーザーを事前に作成しておき、以下でインポートする。

mysql -u [VPS側DBユーザー] -p'[VPS側DBパスワード]' [VPS側DB名] < /tmp/site_dump.sql

Step6:WordPressファイルを展開してパーミッションを設定する

tar -xzf /tmp/site_files.tar.gz -C /var/www/[サイトディレクトリ]/
chown -R www-data:www-data /var/www/[サイトディレクトリ]/

Step7:wp-config.phpのDB情報をVPS用に書き換える

Xserver用のDB名・ユーザー名・パスワードをVPS用に置き換える。

sed -i "s/define('DB_NAME', '[旧DB名]')/define('DB_NAME', '[新DB名]')/" /var/www/[サイト]/wp-config.php
sed -i "s/define('DB_USER', '[旧ユーザー]')/define('DB_USER', '[新ユーザー]')/" /var/www/[サイト]/wp-config.php
sed -i "s/define('DB_PASSWORD', '[旧パスワード]')/define('DB_PASSWORD', '[新パスワード]')/" /var/www/[サイト]/wp-config.php

パスワードに!が含まれる場合、bashで!が特殊文字として展開されてsedが失敗する。その場合はPython3で置換する(詳細は後述)。

Step8:CloudflareのDNSを切り替えてSSL証明書を取得する

CloudflareのAレコードをHetznerのIPアドレスに変更し、CertbotでSSL証明書を取得する。

certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  --dns-cloudflare-propagation-seconds 60 \
  -d [ドメイン] -d www.[ドメイン] \
  --non-interactive --agree-tos -m [メールアドレス]

--dns-cloudflare-propagation-seconds 60でDNS反映の待ち時間を60秒に設定する。デフォルトの待ち時間では反映が間に合わず失敗することがあった。

実際に詰まったエラーと解決策

手順通りに進めても、実際にはいくつかのエラーで止まった。競合記事にはない、実体験ベースの詰まりポイントを記録しておく。

wordfence-waf.phpが古いXserverパスを参照していた

Wordfenceプラグインは.user.iniに以下のような設定を書き込む。

auto_prepend_file = '/home/affiliaterpt/[ドメイン]/public_html/wordfence-waf.php'

このパスがXserver時代のままVPSに持ち込まれたため、PHP Fatal error: Failed opening required '/home/affiliaterpt/...'が発生した。

解決策: .user.ini内のパスをVPS側のパスに書き換える。

sed -i "s|/home/[旧ユーザー]/[ドメイン]/public_html/wordfence-waf.php|/var/www/[サイトディレクトリ]/wordfence-waf.php|" /var/www/[サイト]/.user.ini

MySQLソケットパスがXserver用のままだった

Xserverの.user.iniにはMySQLのソケットパスが設定されていた。

mysql.default_socket = /var/lib/mysql/mysql.sock
mysqli.default_socket = /var/lib/mysql/mysql.sock
pdo_mysql.default_socket = /var/lib/mysql/mysql.sock

VPS(MariaDB)のソケットパスは/var/run/mysqld/mysqld.sockなので、このままではDB接続に失敗する。

解決策: Python3でソケットパスとセッション保存パスを一括置換する。

python3 -c "
with open('/var/www/[サイト]/.user.ini', 'r') as f:
    content = f.read()
content = content.replace('/var/lib/mysql/mysql.sock', '/var/run/mysqld/mysqld.sock')
content = content.replace('/home/[旧ユーザー]/[ドメイン]/xserver_php/session', '/tmp')
with open('/var/www/[サイト]/.user.ini', 'w') as f:
    f.write(content)
"

「!」を含むパスワードがsedで置換できなかった

強いパスワードには!が含まれることがある。bashでは!がヒストリ展開の特殊文字として扱われるため、sedコマンドで置換しようとするとevent not foundエラーが出て失敗する。

解決策: Python3で置換する。

python3 -c "
with open('/var/www/[サイト]/wp-config.php', 'r') as f:
    content = f.read()
content = content.replace(\"define('DB_PASSWORD', '[旧パスワード]')\", \"define('DB_PASSWORD', '[新パスワード!含む]')\")
with open('/var/www/[サイト]/wp-config.php', 'w') as f:
    f.write(content)
"

CertbotのDNS認証で待ち時間が足りなかった

Cloudflare DNS認証でSSL証明書を取得する際、DNSレコードの反映を待つ時間がデフォルトでは不足することがあります。エラーが出た場合は--dns-cloudflare-propagation-seconds 60を明示的に指定してください。

ここまでで「何がエラーの原因か」の構造は見えてきたと思います。
ただし、このままだと同じエラーが自分の別環境で出たときに、どこから調べればいいかは判断できません
なぜなら、「エラーの現象」と「設計の問題」を分けて考える判断軸が、まだ整理されていないからです。

判断軸の整理はこちら

移行後の確認とVPS負荷対策

移行後に確認すべきポイントと、複数サイトを安定稼働させるための設定はどうすればよいでしょうか。順に整理します。

移行後に行った確認作業

移行後は以下の項目を順に確認しました。

トップページと投稿ページの表示: ブラウザでドメインにアクセスし、フロントエンドが正常に表示されるか確認する。

管理画面へのログイン: /wp-adminにアクセスしてログインできるか確認する。アプリケーションパスワードを使った外部ツールからの投稿は、DBごと移行しているため変更不要だった。

画像・CSS・リンク切れ: サイトURL自体はDB内にhttps://[ドメイン]で保存されており、ドメインが変わっていないため基本的にリンク切れは発生しない。

SSLの有効化: ブラウザのアドレスバーに鍵マークが表示されていれば正常。

Wordfenceの確認: .user.iniを修正してPHP-FPMを再起動した後、管理画面からWordfenceの状態を確認してください。

PHP-FPMをondemandにしてVPS負荷を抑えた

Hetzner CX22で複数のWordPressを動かすとき、気になるのがサーバー負荷ではないでしょうか。

今回は6サイトをVPSに集約したが、PHP-FPMをondemandモードに設定しているため、アクセスのないサイトはプロセスが起動しない。稼働していない4buki.netやkaradanonioi.infoは、実質的にメモリをほぼ消費しない状態になっている。

各サイトのPHP-FPMプール設定は以下の通り。

[サイト名]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm-[サイト名].sock
listen.owner = www-data
listen.group = www-data
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s

pm.process_idle_timeout = 10sで、10秒間アクセスがなければプロセスが終了する。n8nのワークフローが稼働している間も、VPSのメモリ使用量は安定して推移している。

XserverからHetznerへ移行して良かった点

実際に移行してみて、感じたメリットは何だったでしょうか。コスト削減だけではなかった点を整理します。

Xserver(月額約1,100円)を解約することで、VPS1台(月額約600円)に集約できる。年間で約6,000円の削減になる。

n8nとWordPressを同じサーバーにまとめられた

記事自動生成のワークフローと、投稿先のWordPressが同じVPS上にある。サーバー管理の窓口が一本化され、運用がシンプルになった。

サーバー構成の自由度が上がった

レンタルサーバーと違い、VPSはNginxやPHP-FPMの設定を自分でコントロールできる。今後さらにサービスを追加する際も、同じVPS上に構築できる。

ただし非エンジニアには注意点もある

今回の移行はすべてAIとの対話を通じて進めた。コマンドの意味を完全に理解していたわけではなく、エラーが出るたびにAIに診断してもらいながら解決した。「VPSは自由度が高い分、トラブル対応も自分でやる必要がある」という点は理解した上で移行を判断してほしい。

まとめ:XserverからVPS移行は可能。ただしエラー対応まで含めて考える

今回の移行で一番伝えたいのは、「手順通りにやっても必ずどこかで詰まる」ということです。

wordfence-waf.phpのパス問題、MySQLソケットパスの違い、!を含むパスワードのsed失敗、Certbotの待ち時間不足。これらはどれも、一般的な移行手順の記事には載っていません。実際に移行してみて初めてわかる詰まりポイントです。

それでも移行は完了しました。エラーが出るたびにログを確認し、原因を特定して対処する。その繰り返しで6サイトの移行が終わりました。AIと一緒に進めたからこそ、非エンジニアでも完走できました。

VPS移行を検討しているなら、「完璧な手順」を探すより「詰まったときにどう対処するか」を先に考えておくことをおすすめします。

ここまでの内容で、移行の流れと詰まりポイントの対処法は整理できたと思います。
ただし、このままだと「自分の状況でどこから手を入れるか」という判断は難しいままです
なぜなら、「何をどの順番で設計・移行するか」の判断基準が、まだ整理されていないからです。

無料PDFを受け取る

関連記事

bizinets.biz

記事を読んで「もっと知りたい」と思ったあなたへ

bizinets.biz では、ビジネスの仕組みづくりを体系的に学べるコンテンツを用意しています。まずは一度、覗いてみてください。

bizinets.biz へ行く →

関連記事