2026年5月21日
2026年5月21日
WordPressをrsyncでバックアップする方法|差分コピー・世代管理・DB書き出し・cron自動化
rsync は、コピー元とコピー先を比べて、変わったファイルだけを転送するコマンドです。2回目以降のバックアップは差分だけで済むため、画像が多い WordPress サイトでも短い時間で終わります。
この記事では、Linux サーバー(VPS・専用サーバー)上の WordPress を rsync でバックアップし、cron で毎日自動で取る手順を説明します。シェルにログインできないレンタルサーバーでは、各社のバックアップ機能やプラグインを使ってください。
rsyncでバックアップできるもの・できないもの
WordPress のデータは、ファイルとデータベースの2か所にあります。
| 置き場所 | 中身 | rsync でコピーできるか |
|---|---|---|
ファイル(/var/www/html など) |
WordPress 本体、wp-config.php、テーマ、プラグイン、wp-content/uploads の画像 |
できる |
| データベース(MySQL・MariaDB) | 投稿・固定ページ・設定・ユーザー・コメント | できない(動いているデータベースのファイルをそのままコピーしても、壊れた状態になることがある) |
データベースは mysqldump(または WP-CLI の wp db export)で SQL ファイルに書き出し、そのファイルを rsync で一緒に保存します。
手順1:rsyncを入れる
# Ubuntu・Debian
sudo apt update
sudo apt install rsync
# AlmaLinux・Rocky Linux
sudo dnf install rsync
# 入ったことを確かめる
rsync --version
別のサーバーへ転送する場合は、転送先のサーバーにも rsync が必要です。
手順2:オプションと書き方の基本を押さえる
この記事で使うオプションは次のとおりです。
| オプション | 意味 |
|---|---|
-a |
アーカイブモード。フォルダーの中まで再帰的にコピーし、パーミッション・所有者・更新日時・シンボリックリンクを保つ |
-H |
ハードリンクを保つ |
-v |
コピーしたファイル名を表示する |
-n |
実際にはコピーせず、何が起きるかだけを表示する(ドライラン) |
-z |
転送中に圧縮する。別のサーバーへ送るときだけ使う(同じサーバー内のコピーでは効果がない) |
--delete |
コピー元にないファイルを、コピー先から削除する |
--exclude |
指定したファイル・フォルダーをコピーしない |
--link-dest |
前回のバックアップと同じファイルは、コピーせずハードリンクにする |
注意が必要な点が2つあります。
コピー元の末尾のスラッシュ:/var/www/html/ のように末尾に / を付けると、フォルダーの「中身」がコピー先に入ります。/var/www/html と付けないと、コピー先の中に html フォルダーが作られます。
--delete の向き:--delete は、コピー先をコピー元と同じ状態にします。コピー元とコピー先を逆に書くと、サイトのファイルが削除されます。--delete を使うコマンドは、初めに -n を付けて結果を確かめてから実行してください。
sudo rsync -aHv --delete -n /var/www/html/ /backup/wordpress/test/
手順3:データベースの接続情報を用意する
mysqldump にパスワードをコマンドで渡すと、プロセスの一覧や履歴から見えてしまいます。root だけが読めるファイルに接続情報を書いておきます。ユーザー名とパスワードは、wp-config.php の DB_USER と DB_PASSWORD と同じものを使えます。
sudo nano /root/.my.cnf
[client]
user=wordpress_db_user
password=wp-config.phpのDB_PASSWORDと同じ値
sudo chmod 600 /root/.my.cnf
# 書き出せることを確かめる(wordpress は DB_NAME に置き換える)
sudo mysqldump --single-transaction --no-tablespaces wordpress | head -5
--single-transaction:InnoDB のテーブルを、サイトを止めずに一貫した状態で書き出します--no-tablespaces:MySQL 8.0.21 以降で、PROCESS 権限のないユーザーで実行したときに出るエラーを避けます
手順4:バックアップのスクリプトを作る
ファイルとデータベースを日付ごとのフォルダーに保存し、14日より古いものを消すスクリプトです。--link-dest を使うので、前回から変わっていないファイルはハードリンクになり、ディスクの使用量は「1回分+毎日の変更分」程度で済みます。
sudo nano /usr/local/sbin/wp-backup.sh
#!/bin/bash
# WordPress のファイルとデータベースを日付ごとのフォルダーにバックアップする
set -euo pipefail
SRC=/var/www/html/ # WordPress のフォルダー(末尾の / を付ける)
DEST=/backup/wordpress # バックアップの保存先
DB_NAME=wordpress # wp-config.php の DB_NAME
KEEP_DAYS=14 # 何日分残すか
TODAY=$(date +%F)
SNAP="$DEST/$TODAY"
mkdir -p "$SNAP"
# 1. データベースを書き出す(接続情報は /root/.my.cnf から読む)
mysqldump --single-transaction --no-tablespaces --default-character-set=utf8mb4 "$DB_NAME" \
| gzip > "$SNAP/db.sql.gz"
# 2. ファイルをコピーする(前回と同じファイルはハードリンクにする)
LINK_DEST=()
if [ -d "$DEST/latest" ]; then
LINK_DEST=(--link-dest="$DEST/latest/files")
fi
set +e
rsync -aH --delete \
--exclude='wp-content/cache/' \
--exclude='wp-content/upgrade/' \
"${LINK_DEST[@]}" \
"$SRC" "$SNAP/files/"
rc=$?
set -e
# 24 = コピー中にファイルが消えた(キャッシュなど)。それ以外の失敗は止める
if [ "$rc" -ne 0 ] && [ "$rc" -ne 24 ]; then
echo "rsync failed: $rc" >&2
exit "$rc"
fi
# 3. latest を今回のバックアップに向け直す
ln -sfn "$SNAP" "$DEST/latest"
# 4. 古いバックアップを消す(日付の名前のフォルダーだけを対象にする)
find "$DEST" -mindepth 1 -maxdepth 1 -type d \
-name '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]' -mtime +"$KEEP_DAYS" \
-exec rm -rf {} +
echo "backup done: $SNAP"
sudo chmod 700 /usr/local/sbin/wp-backup.sh
sudo mkdir -p /backup/wordpress
sudo /usr/local/sbin/wp-backup.sh
スクリプトの要点は次のとおりです。
wp-content/cache/(キャッシュプラグインの作るファイル)とwp-content/upgrade/(更新時の作業用フォルダー)は、復元に不要なので除きます。使っているプラグインによっては、ほかにも除いてよいフォルダーがあります- rsync の終了コード 24 は、コピー中にファイルが消えたことを表します。キャッシュファイルなどで起きるため、失敗としては扱いません
/backup/wordpress/latestは、最新のバックアップを指すシンボリックリンクです。次回の--link-destの比較先になります
2回目を実行すると、変わっていないファイルはハードリンクになります。ls -li で、同じファイルの i ノード番号が前回と同じであることを確かめられます。
この記事のスクリプトは、Ubuntu 24.04(rsync 3.2.7)で、日付フォルダーの作成、ハードリンクでの世代管理、古いフォルダーの削除が動くことを確認しています(データベースの書き出しは、実際の MySQL・MariaDB で確かめてください)。
手順5:cronで毎日実行する
/etc/cron.d/ にファイルを作ります。
sudo nano /etc/cron.d/wp-backup
# 毎日 3時15分に実行する(前回の実行が終わっていなければ、今回は飛ばす)
15 3 * * * root flock -n /run/wp-backup.lock /usr/local/sbin/wp-backup.sh >> /var/log/wp-backup.log 2>&1
/etc/cron.d/のファイルは、時刻の後ろに実行するユーザー(ここではroot)を書きます。crontab -eで書くときは、ユーザーの欄は書きませんflock -nは、前回のバックアップがまだ動いているときに、2つ目を始めないためのものです- 翌朝、
/var/log/wp-backup.logにbackup done:が出ていることを確かめます
cron の書き方は crontabの書き方と設定方法 を参照してください。
手順6:別のサーバーにも保存する
同じサーバーの中にあるバックアップは、ディスクの故障やサーバーの乗っ取りで一緒に失われます。別のサーバーにも保存しておきます。
バックアップ専用のサーバーから、WordPress のサーバーのバックアップを取りに行く形(プル型)にすると、WordPress のサーバーが乗っ取られても、バックアップ側を消される心配が小さくなります。バックアップ用サーバーで、SSH の鍵を使って次のように実行します。
rsync -aHz --delete \
-e "ssh -i /home/backup/.ssh/id_ed25519" \
root@wp.example.com:/backup/wordpress/latest/ \
/srv/backup/example.com/
-zは、サーバー間の転送なので付けていますlatest/の末尾の/で、シンボリックリンクの先の中身がコピーされます- 実際の運用では、root でのログインは許可せず、バックアップ用のユーザーに読み取りの権限だけを与えるようにします。SSH の鍵の作り方は OpenSSHの鍵ペア生成と公開鍵認証の設定手順 を参照してください
保存先を何か所に分けるかの考え方は バックアップ戦略の設計(3-2-1バックアップルール) で説明しています。
手順7:復元する
復元は、ファイルを戻してからデータベースを読み込みます。上書きする前に、今の状態も別の場所にコピーしておくと安全です。
# 1. 何が変わるかを確かめる(-n でドライラン)
sudo rsync -aHv --delete -n \
--exclude='wp-content/cache/' \
/backup/wordpress/2026-10-01/files/ /var/www/html/
# 2. 問題がなければ -n を外して実行する
sudo rsync -aH --delete \
--exclude='wp-content/cache/' \
/backup/wordpress/2026-10-01/files/ /var/www/html/
# 3. データベースを読み込む
gunzip -c /backup/wordpress/2026-10-01/db.sql.gz | sudo mysql wordpress
2026-10-01 は、戻したい日付のフォルダーに置き換えます。キャッシュプラグインを使っている場合は、復元後にキャッシュを削除します。
運用での注意
- 復元の練習をする:バックアップが取れていても、戻せなければ意味がありません。検証用のサーバーで、ときどき実際に復元してサイトが表示されるかを確かめます
- 保存先の権限:バックアップには
wp-config.php(データベースのパスワード)とデータベースの中身が入っています。保存先のフォルダーは root だけが読めるようにします(sudo chmod 700 /backup) - ディスクの空き:
df -h /backupで空きを確かめ、足りなくなる前にKEEP_DAYSを見直します - 失敗に気付く仕組み:ログを見に行かないと失敗に気付けません。失敗時に通知する仕組みを足すと安心です
まとめ
- rsync はファイルだけをコピーする。データベースは
mysqldumpで書き出して一緒に保存する - コピー元の末尾の
/と--deleteの向きに注意し、初めは-nで結果を確かめる --link-destで日付ごとの世代を少ない容量で残し、cron とflockで毎日実行する- 別のサーバーにも保存し、復元の練習もしておく
関連記事: