こんにちは、優香です。
今回は、ConoHa VPS(KUSANAGI)で動かしているWordPressを、無料で毎日自動バックアップする仕組みを作ったので、その手順を超詳しくまとめておきます。
これまで私はphpMyAdminからデータベースをエクスポートしてバックアップしていたんですが、DBが700MBくらいあるサイトだと途中でエラーになって泣いたことが何度もありました。今回の方法なら、DBのサイズに関係なくサーバーの中で直接バックアップが取れるので、あの苦労はもう不要です。
コマンドをコピペしていくだけで完成するように書いたので、同じようにConoHa VPSやKUSANAGIでWordPressを運用している方は参考にしてみてください。
今回の環境
| 項目 | 内容 |
|---|---|
| サーバー | ConoHa VPS(メモリ1GBプラン) |
| OS | AlmaLinux 9 |
| 環境 | KUSANAGI 9 |
| データベース | MariaDB |
| WordPress | 4サイト(KUSANAGIのプロファイルごとに1サイト) |
| 作業するPC | Windows(PowerShellからSSH接続、ファイル確認はWinSCP) |
そもそもバックアップの方法は何があるの?
ConoHa VPSでWordPressをバックアップする方法は、大きく分けて3つあります。
| 方法 | 料金 | メリット | デメリット |
|---|---|---|---|
| ConoHa公式の自動バックアップ | 有料オプション | 申し込むだけで毎日自動。サーバー丸ごと復元できる | お金がかかる。サイト単位の細かい復元には向かない |
| WordPressプラグイン(UpdraftPlusなど) | 無料〜 | 管理画面から設定できて簡単 | サイトごとに設定が必要。アクセスが少ないと実行が遅れることも |
| シェルスクリプト+cron | 無料 | 全サイトまとめて管理できる。DBが大きくてもエラーにならない | 最初の設定にコマンド操作が必要 |
最初はConoHa公式の自動バックアップを考えたんですが、有料オプションだったので今回は見送りました(笑)。
ということで今回は、無料でできる「シェルスクリプト+cron」の方法でいきます。
シェルスクリプト+cronってどういう仕組み?
難しそうに聞こえますが、やっていることはシンプルで、「毎晩、VPSが自分でバックアップを取ってくれる仕組み」を作るだけです。
| 用語 | 意味 |
|---|---|
| シェルスクリプト | サーバーにやってほしい作業を1つのファイルにまとめた「作業手順書」 |
| cron(クーロン) | 「毎日○時にこれを実行して」とサーバーに予約できるタイマー機能 |
今回作る仕組みの流れはこんな感じです。
- 毎日深夜3時になるとcronがスクリプトを起動
- 各サイトのデータベースを書き出して圧縮
- 各サイトのファイル一式を圧縮
- 7日より古いバックアップを自動で削除
- 結果をログファイルに記録
寝ている間に勝手にバックアップが取られて、1週間分たまったら古い順に入れ替わっていきます。
WordPressのバックアップは「DB」と「ファイル」の2つが必要
ここ、意外と知らない方も多いと思うので先に説明しておきます。
WordPressのサイトは、実は2つのパーツでできています。
| パーツ | 中身 | 保存場所 |
|---|---|---|
| データベース(DB) | 記事の本文、固定ページ、設定、コメントなど | MariaDBが管理(DocumentRootの中には無い) |
| ファイル | テーマ、プラグイン、アップロードした画像など | DocumentRootの中 |
この2つは別々の場所で管理されているので、両方バックアップしないと完全には復元できません。
- ファイルだけ戻す → 見た目は戻るけど、記事が空っぽ
- DBだけ戻す → 記事はあるけど、画像やテーマが無い
なので今回のスクリプトでは、DBとファイルを別々のファイルとして、同じ日付でセットで保存するようにしています。
ConoHaの管理画面にある「イメージ」「スナップショット」とは?
ConoHaのコントロールパネルを見ていると「イメージ」や「スナップショット」というメニューがあって、何これ?と思ったので調べました。
| 機能 | 内容 | 料金 |
|---|---|---|
| 保存イメージ | VPS全体(OS・設定・全サイト)を丸ごと手動で保存。そこからサーバーを戻したり、同じ中身のVPSを作ったりできる | 各リージョン50GBまで無料 |
| スナップショット | こちらも丸ごとコピーだが、作成から24時間で自動削除される一時的なもの | — |
| 自動バックアップ | 有料オプション。1日1回自動取得、最大30世代まで管理 | 有料 |
保存イメージは無料で使えますが、サーバーを停止しないと保存できないのと、使われないまま90日たつと削除対象になるので、毎日のバックアップには向きません。「WordPressの大型アップデートの前」など、大きな作業の前の保険として使うのがおすすめです。
毎日のバックアップは今回のスクリプト、大きな作業の前は保存イメージ、という2段構えにしておけば無料でもかなり安心です。
手順1:現状を確認する
まずはSSHでVPSにログインして、バックアップ対象や空き容量を確認します。ここで実行するコマンドはすべて「見るだけ」なので、何かが変わったり消えたりすることはありません。
プロファイル(サイト)の一覧を確認
ls /home/kusanagi/KUSANAGIでは、サイトごとに「プロファイル」というフォルダが作られます。ここに表示された名前が、バックアップ対象になるサイトです。
ディスクの空き容量を確認
df -h /「残り(Avail)」の列が空き容量です。バックアップはVPSの中に保存するので、何日分置けるかの目安になります。私の環境では99GB中85GB空いていたので余裕でした。
各サイトのファイル容量を確認
du -sh /home/kusanagi/*/DocumentRootサイトごとのファイルの大きさがわかります。私の環境では4サイトで合計約2.9GBでした。
DBを書き出すコマンドがあるか確認
which mysqldump mariadb-dump/usr/bin/mariadb-dump と表示されればOKです。今回はこのコマンドを使ってDBを書き出します。
手順2:バックアップスクリプトを作成する
いよいよスクリプトを作ります。以下をまるごとコピーして、ターミナルに貼り付けてEnterしてください(最後の chmod の行まで全部です)。
PROFILES の行は、手順1で確認したご自身のプロファイル名に書き換えてください。複数ある場合は半角スペースで区切ります。
mkdir -p /root/scripts
cat > /root/scripts/wp-backup.sh << 'EOF'
#!/bin/bash
# ============================================
# WordPress 自動バックアップ(KUSANAGI用)
# DB と ファイル(DocumentRoot + wp-config.php) を保存
# ============================================
set -uo pipefail
PROFILES="site1 site2 site3 site4" # 対象プロファイル(自分の環境に合わせて変更)
BASE=/home/kusanagi
DEST=/root/backups # 保存先
KEEP_DAYS=7 # 保存日数
DATE=$(date +%Y-%m-%d)
LOG=$DEST/backup.log
mkdir -p "$DEST"
chmod 700 "$DEST"
log(){ echo "[$(date '+%F %T')] $*" >> "$LOG"; }
# wp-config.php から定数の値を取り出す
get_conf(){
grep -E "define\(\s*['\"]$1['\"]" "$2" | head -n1 \
| sed -E "s/.*define\(\s*['\"]$1['\"]\s*,\s*['\"]([^'\"]*)['\"].*/\1/"
}
log "===== バックアップ開始 ====="
for P in $PROFILES; do
DIR=$BASE/$P
OUT=$DEST/$P
mkdir -p "$OUT"
# wp-config.php の場所(KUSANAGIは DocumentRoot の1つ上)
if [ -f "$DIR/wp-config.php" ]; then
WPCONF=$DIR/wp-config.php
CONF_REL="$P/wp-config.php"
elif [ -f "$DIR/DocumentRoot/wp-config.php" ]; then
WPCONF=$DIR/DocumentRoot/wp-config.php
CONF_REL=""
else
log "[$P] wp-config.php が見つからないのでスキップ"
continue
fi
DB_NAME=$(get_conf DB_NAME "$WPCONF")
DB_USER=$(get_conf DB_USER "$WPCONF")
DB_PASS=$(get_conf DB_PASSWORD "$WPCONF")
DB_HOST=$(get_conf DB_HOST "$WPCONF")
[ -z "$DB_HOST" ] && DB_HOST=localhost
# --- DB バックアップ(パスワードは一時ファイル経由で安全に渡す)---
CNF=$(mktemp)
chmod 600 "$CNF"
printf "[client]\nuser=%s\npassword=%s\nhost=%s\n" "$DB_USER" "$DB_PASS" "$DB_HOST" > "$CNF"
if mariadb-dump --defaults-extra-file="$CNF" --single-transaction --quick \
--default-character-set=utf8mb4 "$DB_NAME" | gzip > "$OUT/${P}_${DATE}_db.sql.gz"; then
log "[$P] DB OK ($DB_NAME)"
else
log "[$P] DB 失敗 ($DB_NAME)"
fi
rm -f "$CNF"
# --- ファイル バックアップ(キャッシュは除外)---
if tar czf "$OUT/${P}_${DATE}_files.tar.gz" \
--exclude="$P/DocumentRoot/wp-content/cache" \
-C "$BASE" "$P/DocumentRoot" $CONF_REL; then
log "[$P] ファイル OK"
else
log "[$P] ファイル 失敗"
fi
# --- 古いバックアップを削除 ---
find "$OUT" -name "${P}_*" -type f -mtime +$((KEEP_DAYS - 1)) -delete
done
log "===== バックアップ終了 ====="
EOF
chmod 700 /root/scripts/wp-backup.shスクリプトの中身をざっくり解説
| 部分 | やっていること |
|---|---|
PROFILES | バックアップするサイト(プロファイル名)の一覧 |
DEST | バックアップの保存先。今回は /root/backups |
KEEP_DAYS | 何日分残すか。7なら1週間分 |
get_conf | wp-config.php からDB名・ユーザー名・パスワードを自動で読み取る |
mariadb-dump | DBを書き出して、gzipで圧縮して保存 |
tar czf | DocumentRootとwp-config.phpをまとめて圧縮して保存(キャッシュは除外) |
find ... -delete | 保存日数を過ぎた古いバックアップを削除 |
log | 結果を backup.log に記録 |
ここがポイント
- DBのパスワードをスクリプトに直接書かなくていい。wp-config.phpから自動で読み取るので、サイトを追加するときもPROFILESに名前を足すだけです。
- パスワードは一時ファイル経由で渡して、使い終わったらすぐ削除しています。コマンドの引数に直接書くと、サーバー内の他のプロセスから見えてしまうことがあるためです。
- KUSANAGIでは wp-config.phpがDocumentRootの1つ上の階層にあるので、DocumentRootだけ圧縮すると取りこぼします。スクリプトではwp-config.phpも一緒に保存するようにしています。
--single-transactionを付けているので、サイトを動かしたままでも整合性のとれたDBバックアップが取れます。
手順3:手動でテスト実行する
いきなり自動化する前に、まずは手動で動かしてみます。
/root/scripts/wp-backup.shサイトの大きさによりますが、数分かかります。私の環境(4サイト合計約2.9GB)では約3分で終わりました。コーヒーでも飲んで待ちましょう。
手順4:結果を確認する
ログを確認
cat /root/backups/backup.logこんな感じで、全サイト「DB OK」「ファイル OK」になっていれば成功です。
[2026-09-21 13:42:54] ===== バックアップ開始 =====
[2026-09-21 13:42:54] [site1] DB OK (site1_db)
[2026-09-21 13:43:10] [site1] ファイル OK
[2026-09-21 13:43:13] [site2] DB OK (site2_db)
[2026-09-21 13:43:50] [site2] ファイル OK
[2026-09-21 13:43:51] [site3] DB OK (site3_db)
[2026-09-21 13:45:00] [site3] ファイル OK
[2026-09-21 13:45:02] [site4] DB OK (site4_db)
[2026-09-21 13:45:45] [site4] ファイル OK
[2026-09-21 13:45:45] ===== バックアップ終了 =====バックアップファイルを確認
ls -lh /root/backups/*/サイトごとのフォルダに、こんな感じで2つずつファイルができています。
| ファイル名 | 中身 |
|---|---|
サイト名_日付_db.sql.gz | データベース(記事・設定など) |
サイト名_日付_files.tar.gz | ファイル一式(テーマ・プラグイン・画像・wp-config.php) |
私の環境では、1日分で合計約1.7GBでした。圧縮が効くので、元のサイズよりだいぶ小さくなります。7日分でも約12GBなので、空き85GBなら全然余裕です。
DBの中身がちゃんと入っているか確認
記事の少ないサイトだとDBのバックアップが数十KBと小さくなるので、「本当に入ってる?」と不安になるかもしれません。そんなときはこれで確認できます。
zcat /root/backups/site1/site1_2026-09-21_db.sql.gz | grep -c "CREATE TABLE"WordPressの標準テーブルは12個なので、12以上の数字が出ればOKです。プラグインがテーブルを追加していると、もっと多くなります。私の小さいサイトでも16個入っていました。
よく使う確認コマンドの意味
| コマンド | 意味 |
|---|---|
ls | ファイルの一覧を表示 |
-l | サイズや日時など詳しい情報も表示 |
-h | サイズを「324M」のように読みやすい単位で表示 |
/root/backups/*/ | backupsの中の全フォルダをまとめて表示 |
tail -n 10 | ファイルの最後の10行だけ表示(1回分のログがちょうど10行) |
手順5:cronに登録して毎日自動化する
テストがうまくいったら、毎日自動で実行されるようにcronに登録します。今回は毎日深夜3時に実行します。
(crontab -l 2>/dev/null | grep -v wp-backup.sh; echo "0 3 * * * /root/scripts/wp-backup.sh") | crontab -このコマンドは、今あるcronの設定を残したまま、バックアップの行だけを追加します。何度実行しても同じ行が重複しないようにしてあるので安心です。
「0 3 * * *」の意味
| 位置 | 値 | 意味 |
|---|---|---|
| 1番目 | 0 | 分(0分) |
| 2番目 | 3 | 時(3時) |
| 3番目 | * | 日(毎日) |
| 4番目 | * | 月(毎月) |
| 5番目 | * | 曜日(毎曜日) |
つまり「毎日3時0分に実行」という意味です。時間を変えたい場合は2番目の数字を変えればOKです。
登録できたか確認
crontab -l
systemctl is-active crond0 3 * * * /root/scripts/wp-backup.sh が表示されて、active と出れば登録完了です。すでに他のcron(WordPressのwp-cronなど)を設定している場合も、そちらはそのまま残っています。
翌朝の確認
次の日の朝に、ログを確認してみましょう。
tail -n 10 /root/backups/backup.log深夜3時の日付でOKが並んでいれば、自動バックアップの完成です。
WinSCPでバックアップを確認する
今回のバックアップは「VPSの中のフォルダにファイルを置いているだけ」なので、ConoHaの管理画面にもWordPressの管理画面にも表示されません。
一番かんたんに確認できるのはWinSCPです。rootでログインして /root/backups/ を開くと、サイトごとのフォルダとバックアップファイルが並んでいます。そのままドラッグすれば、PCにダウンロードすることもできます。
毎日のチェックは、WinSCPで覗いて「日付入りのファイルが増えているか」を見るくらいで十分です。
もしものときの復元方法
バックアップは戻せてこそ意味があるので、復元方法もまとめておきます。
※復元は今のデータを上書きします。実行する前に、念のため今の状態もバックアップしておきましょう。
DBの復元
zcat /root/backups/site1/site1_2026-09-21_db.sql.gz | mariadb -u DBユーザー名 -p DB名パスワードを聞かれるので、wp-config.phpに書いてあるDBのパスワードを入力します。phpMyAdminのインポートと違って、ファイルサイズの制限もタイムアウトもありません。
ファイルの復元
tar xzf /root/backups/site1/site1_2026-09-21_files.tar.gz -C /home/kusanagi
chown -R httpd:www /home/kusanagi/site1/DocumentRoot展開したあとは、KUSANAGIのWordPressが正しく動くように所有者を httpd:www に戻しておきます。
DBとファイルは、必ず同じ日付のペアで戻してください。日付がずれると、記事と画像が噛み合わなくなることがあります。
phpMyAdminでエラーになっていた理由
最後に、なぜphpMyAdminだとエラーになって、この方法だと大丈夫なのかを整理しておきます。
| 比較 | phpMyAdmin | mariadb-dump(今回の方法) |
|---|---|---|
| 動く場所 | ブラウザ経由(PHPで動作) | サーバーの中で直接 |
| サイズ制限 | PHPのアップロード上限・メモリ上限に引っかかる | 実質なし |
| 時間制限 | PHPの実行時間上限でタイムアウトしがち | なし |
| 大きなDB(700MBなど) | エラーになりやすい | 普通に取れる |
| 自動化 | できない(毎回手作業) | cronで毎日自動 |
phpMyAdminはPHPで動いているので、PHPのいろいろな上限に引っかかってしまうんですね。サーバーの中で直接コマンドを実行すれば、そういう制限とは無縁です。
注意点
- バックアップがVPSの中にしか無いので、VPS自体が壊れたり消えたりすると、バックアップも一緒に消えてしまいます。これは次回の課題です。
- バックアップにはwp-config.php(DBのパスワード入り)も含まれるので、保存先は
/rootの下にして、root以外は見られないようにしています。 - サイトを追加したら、スクリプトの
PROFILESに名前を追加するのを忘れずに。 - ディスクの空き容量は、ときどき
df -h /で確認しておきましょう。
まとめ
今回作った仕組みをまとめると、こうなります。
| 項目 | 内容 |
|---|---|
| スクリプト | /root/scripts/wp-backup.sh |
| 保存先 | /root/backups/プロファイル名/ |
| 保存するもの | DB + ファイル一式(DocumentRoot・wp-config.php) |
| 実行タイミング | 毎日深夜3時(cron) |
| 保存期間 | 7日分(古いものは自動削除) |
| ログ | /root/backups/backup.log |
| 費用 | 0円 |
コマンド操作と聞くと身構えてしまいますが、実際にやったことは「スクリプトを貼り付けて、テストして、cronに登録する」だけです。これで寝ている間に毎日バックアップが取られるようになりました。
phpMyAdminのエクスポートでエラーになって泣いていた頃を思うと、本当に楽になりました。同じ悩みを持っている方は、ぜひ試してみてください。
次回予告:Googleドライブに自動保存します
今回の仕組みで毎日のバックアップは取れるようになりましたが、注意点にも書いた通り、バックアップがVPSの中にしか無いのが弱点です。
そこで次回は、rcloneというツールを使って、バックアップをGoogleドライブに自動で保存する仕組みを追加します。これができれば、万が一VPSごと壊れても、Googleドライブからサイトを復元できるようになります。
Googleドライブの無料枠(15GB)に収まるように、何日分を置くかの調整方法も含めてまとめる予定です。お楽しみに!





コメント