[PR] 本記事にはプロモーションが含まれています。

WordPressのバックアップ|自宅サーバーのデータベース・静的HTML・設定を毎日NASに7日分残す仕組み

WordPress
➔ 自宅サーバー構築メモの目次はこちら

【2026年7月3日時点の情報です】

このブログは、自宅のサーバーで動いています。サーバー構築の手順もこのブログに書いているので、サーバーが壊れると、直すための手順書まで一緒に読めなくなってしまいます。

そこで、毎日夜中に、データベース、記事を静的なHTMLにしたもの、サーバーの設定ファイルをまとめて、家のNAS(Synology DS224+)に送っています。この記事では、その仕組みと、2026年10月に見直して直したところをまとめます。作業はすべてrootで行っています。

バックアップの全体像

バックアップは、サーバー側のスクリプトとWordPressのプラグイン(UpdraftPlus)の2本立てで、どちらも保存先は家のNASです。

時刻何をするか保存先残す数
毎日 4:00データベースをデータベースごとにファイルにする(mariadb-backup.sh)サーバーの /backup/mariadb1
続けて公開中の記事を静的なHTMLにしてZIPにまとめる(wp-html-backup.sh)サーバーの /backup/wordpress1
続けて上の2つと、/home・/root・/var/www・/etc などを1つのファイルにまとめる(backup.sh)サーバーの /backup/backup.tar.bz21
毎日 5:00まとめたファイルを日付付きの名前でNASに送る(backup_to_rclone.sh)NAS(SFTP)7日分
毎日(UpdraftPlusの時刻)WordPressのファイルとデータベースをバックアップNAS(FTP)2回分

サーバーの中には1日分しか置かず、日付ごとの分はNAS側に残す形です。サーバーのディスクが壊れても、NASに7日分あれば、その中から戻せます。

静的HTMLは、WordPressが動かなくなったときでも、ブラウザで開くだけで記事を読めるようにするためのものです。サーバーを直す手順を、壊れたサーバーの中の記事から探せるようにしています。

1. WP-CLIを入れる

静的HTMLを作るときに、公開中の記事のURLの一覧をWordPressから取り出すため、コマンドでWordPressを操作できるWP-CLIを入れます。

Bash
[root@almalinux ~]# curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
[root@almalinux ~]# chmod +x wp-cli.phar
[root@almalinux ~]# mv wp-cli.phar /usr/local/bin/wp
[root@almalinux ~]# wp --info --allow-root  ※バージョンなどが表示されればOK

2. データベースのバックアップ(mariadb-backup.sh)

データベースを、データベースごとにSQLのファイルにします。

大事なのは、スクリプトにMariaDBのrootのパスワードを書かないことです。私は以前、パスワードをスクリプトにそのまま書いていましたが、ファイルを見られるとデータベースを全部操作できてしまいます。そこで、MariaDBのrootを「サーバーのrootからはパスワードなしで入れる(unix_socket)、ほかからはパスワードで入る」設定にしました。

Bash
[root@almalinux ~]# mysql -u root -p -e "ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket OR mysql_native_password USING PASSWORD('新しいパスワード');"
Enter password:  ※今のパスワードを入力

[root@almalinux ~]# mysql -e "SELECT CURRENT_USER();"  ※パスワードなしで入れるか確認

cronはサーバーのrootで動くので、この設定ならスクリプトにパスワードがなくてもバックアップが取れます。phpMyAdminなどからrootで入るときは、新しいパスワードを使います。

スクリプトは次のとおりです。

Bash
[root@almalinux ~]# vi /root/mariadb-backup.sh
#!/bin/bash

PATH=/usr/local/sbin:/usr/bin:/bin

# バックアップ先ディレクトリ
BACKDIR=/backup/mariadb

# バックアップ先ディレクトリを作り直す
rm -rf $BACKDIR
mkdir -p $BACKDIR

# データベース名を取得
DBLIST=`ls -p /var/lib/mysql | grep / | tr -d /`

# データベースごとにバックアップ(パスワードは書かず、unix_socketで接続)
for dbname in $DBLIST
do
    [ $dbname = "performance_schema" ] && continue
    table_count=`mysql -u root -B -e "show tables" $dbname|wc -l`
    [ $table_count -ne 0 ] &&
    mysqldump --events -u root $dbname > $BACKDIR/$dbname.sql
done

[root@almalinux ~]# chmod 700 /root/mariadb-backup.sh
[root@almalinux ~]# /root/mariadb-backup.sh && ls -lh /backup/mariadb/  ※手で動かして確認

wordpress.sql などのファイルが今の時刻で作られていれば成功です。

3. 記事を静的HTMLにする(wp-html-backup.sh)

公開中の記事と固定ページのURLをWP-CLIで取り出し、wgetで1ページずつHTMLとして保存して、ZIPにまとめます。

Bash
[root@almalinux ~]# vi /root/wp-html-backup.sh
#!/bin/bash

# エラーが起きたらすぐに止める
set -e

# 1. 公開中のURLの一覧(list.txt)を作る
cd /var/www/html
/usr/local/bin/wp post list --post_type=post,page --post_status=publish --field=url --allow-root > /backup/wordpress/list.txt

# 2. URLのドメインを、サーバー自身(http://127.0.0.1/)に置き換える
sed -i 's|https://softdev-learn.cc/|http://127.0.0.1/|g' /backup/wordpress/list.txt

# 3. サーバーの中から直接ページを取得する
# (Cloudflareを通らないように127.0.0.1に送り、Hostヘッダーでドメインを伝える)
#(-q で進み具合を出さない。失敗したときだけ、標準エラーに出して止まる → cron がメールで知らせる)
cd /backup/wordpress
HTTPS=on wget -q --page-requisites --adjust-extension --convert-links --no-parent \
  --header="Host: softdev-learn.cc" \
  -i list.txt || { rc=$?; echo "wp-html-backup.sh: wget failed (code ${rc})" >&2; exit ${rc}; }

# 4. 新しい名前でZIPを作り、前回のZIPと入れ替える(前回のZIPとURLの一覧は除く)
zip -q -r wordpress_html_backup.new.zip ./* -x "*.zip" -x "list.txt"
mv -f wordpress_html_backup.new.zip wordpress_html_backup.zip

# 5. 取得したフォルダとURLの一覧を消す
rm -rf ./127.0.0.1 ./list.txt

logger -t wp-html-backup.sh "html backup ended."

[root@almalinux ~]# chmod 700 /root/wp-html-backup.sh
  • set -e:
    途中のコマンドが失敗したら、そこでスクリプトを止める
  • wp post list … --field=url:
    WP-CLI で、公開中の記事と固定ページの URL だけを一覧にして、list.txt に書く
  • sed -i 's|https://softdev-learn.cc/|http://127.0.0.1/|g':
    一覧の URL のドメインを、サーバー自身に置き換える
  • HTTPS=on wget -q --page-requisites --adjust-extension --convert-links --no-parent:
    ページと、表示に要る画像や CSS を取得し、HTML の拡張子を付け、ページの中のリンクを手元で開ける形に直す。-q は、進み具合を画面に出さない
  • --header="Host: softdev-learn.cc":
    127.0.0.1 に送っても、WordPress にどのサイトあてかを伝える
  • -i list.txt || { rc=$?; echo "…" >&2; exit ${rc}; }:
    list.txt の URL を順に取得する。|| の右は、wget が失敗したときだけ動く。戻り値を rc に取っておき、エラーの出口(標準エラー)に1行書いて、同じ戻り値で止まる。C でいえば if (ret != 0) { fprintf(stderr, …); exit(ret); }
  • zip -q -r … -x "*.zip" -x "list.txt":
    取得したものを、新しい名前の ZIP に一から作る。前回の ZIP と URL の一覧は入れない。-q は、入れたファイルの一覧を画面に出さない
  • mv -f wordpress_html_backup.new.zip wordpress_html_backup.zip:
    作り終わった ZIP を、前回の ZIP の名前に入れ替える。作っている途中で失敗したときは、set -e でここまで来ないので、前回の ZIP がそのまま残る
  • rm -rf ./127.0.0.1 ./list.txt:
    取得したフォルダと URL の一覧を消す
  • logger -t wp-html-backup.sh "html backup ended.":
    最後まで動いたことを、システムの記録に名前を付けて1行残す(8で確かめる)
  • chmod 700 /root/wp-html-backup.sh:
    root だけが読み書き・実行できるようにする

URLを127.0.0.1に置き換えているのは、ドメインのまま取得すると、サーバーから一度インターネットに出てCloudflareを通ることになり、時間がかかったり、Cloudflareのルールに止められたりするためです。

set -e があるので、途中のコマンドが失敗すると、このスクリプトはそこで止まります。wget は、記事の中の画像が1つでも見つからない(404)と失敗を返すので、そのときは「wp-html-backup.sh: wget failed (code 8)」の1行が root 宛てのメールで届きます。あとで説明するcronの設定では、ここで止まっても次のバックアップが動くようにしています。

毎朝 cron のメールが届いていたので、静かにした(2026年10月)

このスクリプトを入れてから、毎朝4時ごろに root 宛てのメールが届いていました。中身は、wget の進み具合と、zip の「adding: …」の行です。cron は、スクリプトが画面に出したものを、メールで送ってきます。失敗していなくても毎日届くので、本当に失敗したときのメールに気づけなくなります。そこで、成功したときは何も出さず、失敗したときだけ知らせる形に直しました。

No.直したところ直し方結果
1wget-q を付け、失敗したときだけ、エラーの出口に1行書いて止まる成功なら静か。取得に失敗したらメールが来る
2zip-q を付ける「adding: …」の行が出なくなる
3いちばん最後logger で1行残すメールは来ないが、最後まで動いたことを記録で確かめられる

直す前に控えを取り、直したあとに、書き方の誤りがないかと、変わった行を確かめました。

Bash
[root@almalinux ~]# cp -p /root/wp-html-backup.sh /root/wp-html-backup.sh.20261031
[root@almalinux ~]# vi /root/wp-html-backup.sh
[root@almalinux ~]# bash -n /root/wp-html-backup.sh && echo "syntax OK"
syntax OK
[root@almalinux ~]# diff /root/wp-html-backup.sh.20261031 /root/wp-html-backup.sh
14a15
> #(-q で進み具合を出さない。失敗したときだけ、標準エラーに出して止まる → cron がメールで知らせる)
16c17
< HTTPS=on wget --page-requisites --adjust-extension --convert-links --no-parent \
---
> HTTPS=on wget -q --page-requisites --adjust-extension --convert-links --no-parent \
18c19
<   -i list.txt
---
>   -i list.txt || { rc=$?; echo "wp-html-backup.sh: wget failed (code ${rc})" >&2; exit ${rc}; }
21c22
< zip -r wordpress_html_backup.zip ./* -x "*.zip" -x "list.txt"
---
> zip -q -r wordpress_html_backup.zip ./* -x "*.zip" -x "list.txt"
24a26,27
> 
> logger -t wp-html-backup.sh "html backup ended."
  • cp -p … .20261031:
    直す前のスクリプトを、日付を付けた名前で残す。-p は持ち主・権限・日付もそのまま写す
  • vi /root/wp-html-backup.sh:
    上のスクリプトのとおりに直す
  • bash -n …:
    スクリプトを動かさずに、書き方の誤りだけを調べる(C でいえば、コンパイルだけ通す)
  • diff 控え 新しいほう:
    変わった行だけを出す。< が前の行、> が新しい行

変わったのは、足したコメント1行と、wget・zip・最後の logger の行だけです。続けて、cron と同じく root で一度動かしました。

Bash
[root@almalinux ~]# /root/wp-html-backup.sh; echo "rc=$?"
rc=0
[root@almalinux ~]# journalctl -t wp-html-backup.sh --since "15 min ago" --no-pager
10月 31 10:17:59 myserver wp-html-backup.sh[125108]: html backup ended.
  • /root/wp-html-backup.sh; echo "rc=$?":
    直したスクリプトを動かし、終わったら戻り値を出す。rc=0 なら最後まで正常に終わった
  • journalctl -t wp-html-backup.sh --since "15 min ago" --no-pager:
    システムの記録から、logger で残した行だけを、ここ15分の分だけ出す

動いている間、画面には何も出ず、rc=0 と記録の1行だけが出ました。次の朝は、4時の cron のメールが来ず、記録には「11月 01 04:01:02 … html backup ended.」が残っていました。

2026年11月には、ZIP の作り方も直しました。前は前回の ZIP に中身を足していく作りだったので、下書きに戻した記事や消した記事の HTML も、ZIP の中に残り続けていました。今は、新しい名前で ZIP を一から作ってから、前回の ZIP と入れ替えています(上のスクリプトの「# 4.」の下の2行)。

4. サーバー全体を1つのファイルにまとめる(backup.sh)

/root/backuplist に書いたフォルダを rsync で集めて、/backup/backup.tar.bz2 の1つのファイルにまとめます。失敗したときは、root宛てにメールが届くようにしています(root宛てのメールは、AlmaLinux 9の初期設定でGmailに転送しています)。スクリプトは長いので、ここでは対象のリストだけ載せます。

Plaintext
[root@almalinux ~]# cat /root/backuplist  ※バックアップの対象
/home
/root
/var/www
/backup/mariadb
/backup/wordpress
/etc
/usr/local/sbin

[root@almalinux ~]# cat /root/backupnolist  ※対象から外すもの
/var/www/error
/var/www/icons
/var/www/manual
/home/devuser/.vscode-server

/etc と /usr/local/sbin は、2026年10月に足しました。それまでは、Apache・MariaDB・cronなどの設定ファイルがバックアップに入っておらず、サーバーを作り直すときは、設定を一から思い出すことになっていました。

外すものの /home/devuser/.vscode-server は、2026年10月に足しました。VS Code でサーバーにつなぐと、サーバーの側に VS Code の部品が入り、版が上がるたびに約600MB ずつたまっていきます。VS Code が入れ直せるものなので、バックアップからは外しました。

バックアップには、ブログの全データやユーザーのパスワードのハッシュが入るので、置き場所はrootだけが入れるようにしておきます。

Bash
[root@almalinux ~]# chmod 700 /backup

5. NASに日付付きで送る(backup_to_rclone.sh)

まとめたファイルを、rcloneでNASに送ります。NASのSFTPを、rcloneに sftp という名前で登録してある前提です(rclone config で登録します)。

送るときに日付付きの名前にして、8日より古いものを消すので、NASには7日分が残ります。

Bash
[root@almalinux ~]# vi /root/backup_to_rclone.sh
#!/bin/bash
# バックアップを日付付きの名前でNASに送り、7日より古いものを消す
BACKUPFILE=/backup/backup.tar.bz2
DEST=sftp:/ServerBackup/myserver

rclone copyto "${BACKUPFILE}" "${DEST}/backup-$(date +%Y%m%d).tar.bz2" --ignore-checksum || exit 1
rclone delete "${DEST}" --include "backup-*.tar.bz2" --min-age 8d

exit 0

[root@almalinux ~]# chmod 700 /root/backup_to_rclone.sh
[root@almalinux ~]# /root/backup_to_rclone.sh && rclone lsl sftp:/ServerBackup/myserver  ※手で動かして確認
2980346633 2026-10-09 04:15:30.000000000 backup-20261009.tar.bz2

以前は、毎日同じ名前(backup.tar.bz2)で上書きしていたので、NASにも前日の分しか残っていませんでした。おかしくなったデータに気づかないまま1日たつと、正常だったときに戻せなくなります。日付を付けて数日分残すようにしたのは、そのためです。私のバックアップは1日あたり約2.3〜2.7GB(2026年10月に .vscode-server を外してから)なので、NASでは約16〜19GBを使います。

6. 毎日自動で動かす(cron)

4時にサーバーの中でバックアップを作り、5時にNASに送ります。

Plaintext
[root@almalinux ~]# vi /etc/cron.d/backup
0 4 * * * root /root/mariadb-backup.sh; /root/wp-html-backup.sh; /root/backup.sh
0 5 * * * root /root/backup_to_rclone.sh

以前は、3つのスクリプトを && でつないでいました。&& は「前が成功したら次を動かす」という意味なので、静的HTMLの作成で1ページでも失敗すると、サーバー全体のまとめ(backup.sh)が動かず、NASに送るファイルも古いままになります。; にすると、前が失敗しても次が動きます。

7. もう1本:UpdraftPlus

サーバー側のバックアップとは別に、WordPressのプラグイン「UpdraftPlus」でも、毎日バックアップを取っています。設定は次のとおりです。

項目設定
ファイルのバックアップ毎日(Daily)、2回分を残す
データベースのバックアップ毎日(Daily)、2回分を残す
保存先FTP(家のNASの /ServerBackup/Wordpress)
対象プラグイン、テーマ、アップロード、wp-content のほかのフォルダ

2本立てにしているのは、保存先も方法も別なので、片方が失敗していても、もう片方で戻せるからです。それに、WordPressだけがおかしくなったときは、UpdraftPlusなら管理画面の「復元」ボタンで戻せるので、こちらのほうが手軽です。サーバーごと作り直すときは、サーバー側のバックアップを使います。

なお、無料版で使えるFTPは暗号化されない通信なので、パスワードとバックアップの中身が、家のLANの中をそのまま流れます。家の中だけの通信なので、私はこのまま使っています。

8. 毎日動いているかの確認

バックアップは、動いていないことに気づきにくいので、ときどき次のコマンドで確かめています。

Bash
[root@almalinux ~]# journalctl -t backup.sh --since "3 days ago" --no-pager | grep -E "started|ended|aborted"  ※毎日最後まで動いたか
10月 07 04:01:18 myserver backup.sh[1424944]: backup started.
10月 07 04:16:20 myserver backup.sh[1425053]: backup ended.
10月 08 04:01:11 myserver backup.sh[1595673]: backup started.
10月 08 04:16:18 myserver backup.sh[1595788]: backup ended.
10月 09 04:01:09 myserver backup.sh[1726386]: backup started.
10月 09 04:15:32 myserver backup.sh[1726492]: backup ended.

[root@almalinux ~]# journalctl -t wp-html-backup.sh --since today --no-pager  ※静的HTMLが最後まで作れたか
11月 01 04:01:02 myserver wp-html-backup.sh[129481]: html backup ended.

[root@almalinux ~]# rclone lsl sftp:/ServerBackup/myserver  ※NASに日付ごとに届いているか

[root@almalinux ~]# tar -tjf /backup/backup.tar.bz2 | grep -m3 "/etc/httpd"  ※設定ファイルが入っているか
  • journalctl -t backup.sh --since "3 days ago" --no-pager | grep -E "started|ended|aborted":
    backup.sh が残した記録のうち、ここ3日分の始まり・終わり・中断の行だけを出す
  • journalctl -t wp-html-backup.sh --since today --no-pager:
    静的HTMLのスクリプトが今日残した記録を出す
  • rclone lsl sftp:/ServerBackup/myserver:
    NAS のフォルダのファイルを、大きさ・日時・名前つきで一覧にする
  • tar -tjf … | grep -m3 "/etc/httpd":
    まとめたファイルの中身の一覧から、Apache の設定の行を3つだけ出す

毎日「started」と「ended」が並び、静的HTMLの「html backup ended.」が出ていて、NASに日付付きのファイルが増えていれば、正しく動いています。「aborted」が出ていたり、静的HTMLの記録がなかったりしたら、root宛てのメールで原因を確かめます。静的HTMLのスクリプトは、うまくいった日はメールを出さないので、メールが来ないのがふつうです。

2026年10月に、NASのバックアップをサーバーに取り出して、データベースを試験用のデータベースに入れてみたところ、記事のデータが問題なく読めました。静的HTMLのZIPも、535ファイルがそろっていて開けました。確認が終わったら、試験用のデータベースと取り出したファイルは消しています。

まとめ

自宅サーバーのWordPressを、データベース・静的HTML・サーバーの設定ごと毎日NASに送り、7日分を残すようにしました。2026年10月に見直したときに直したのは、次の5つです。

  • スクリプトにMariaDBのパスワードを書かない(unix_socketで接続)
  • NASに日付付きで7日分を残す(以前は毎日上書きで1日分だけ)
  • /etc と /usr/local/sbin をバックアップの対象に加える
  • cronを && から ; にして、途中で失敗しても次が動くようにする
  • 静的HTMLのスクリプトを、成功した日は何も出さず、失敗した日だけメールが来る形にする

どれも、設定したときは動いていたので気づかず、見直して初めて分かったことでした。バックアップは、ときどき中身まで確かめておくのがおすすめです。

コメント