WordPressサイトのバックアップをAWSで自動化する(S3+cron)

Posted by Akkey on 2026/03/28

先日、Wordpress6.9.4がリリースされたようで、管理画面に更新の案内が出てきました。

とりあえず更新するかなって更新しようとしたら「更新する前にファイルとデータベースをバックアップしてください」と。

そういやバックアップについてなにも考えてないな・・・というわけで当サイトのバックアップの仕組みを考えていきたいと思います!


当サイトの構成について

このサイトの現在の構成は。

インターネット
   ↓
EC2(Apache + WordPress + MariaDB)
   ↑
SSM(管理)

GitHub → GitHub Actions → S3 → EC2(デプロイ)

という単純構成。前はALBが入っていましたがコストが高いので外しました。(その時の記事はこちら!)

現在の構成は、1台のEC2上にApache・WordPress・MariaDBを配置したシンプルな構成です。また、GitHub Actionsからデプロイを行い、管理の際はSSMでサーバーに接続しています。

今はEC2 1台にApache・WordPress・MariaDB と全部入りなので、EC2が壊れたら終わりです。いずれDBを外出し(RDS)しようかなとか考えていますが、今はその時にあらず。逆に今はEC2だけバックアップを取ればいいので、現在の構成にバックアップ用のS3バケットを追加してバックアップを定期的に取る仕組みを構築したいと思います!

バックアップ構成イメージ

EC2 → cron → backup.sh(シェル) → S3(バックアップ)

バックアップ用S3バケットの作成

まずはバックアップ用にS3バケットを作成します。AWSコンソールにログインして、S3からバケットを作成します。

バケットの名前は適当でOK。私は「akkeys-lifework-lab-backup」にしました。

  • バケットタイプ = 汎用
  • Bucket namespace = Global namespace
  • このバケットのブロックパブリックアクセス設定 = パブリックアクセスをすべて ブロック
  • バケットのバージョニング = 有効

バージョニングだけ有効にしてあとはデフォルト値で作成します。


EC2のIAMロールにポリシーを追加する

EC2のインスタンス見て、EC2にアタッチされているIAMロールを確認します。以前SSMを使えるようにした際にすでにIAMロールはアタッチしていました。その時の記事はこちら。アタッチされていない場合はアタッチする必要があります。

IAM からEC2にアタッチされているロールを選択し、許可を追加から「インラインポリシーを作成」を選択。ポリシーエディタをJSONにして、↓を貼り付けます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListBackupBucket",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketLocation"
      ],
      "Resource": "arn:aws:s3:::バックアップ用S3の名前"
    },
    {
      "Sid": "UploadBackups",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::バックアップ用S3の名前/*"
    }
  ]
}

これでEC2にアタッチされているIAMロールからS3へのアクセス許可が出来たはずです。よってEC2からS3へのアクセスができるはず。


EC2からS3へのアップロードテスト

まずはEC2にSSMでログインします(SSMを使用しての接続設定はこちら。)。AWSコンソールから、EC2 > インスタンス > 対象のインスタンス から右上の「接続」ボタン。SSM Session Manager から接続で接続します。ssm_userでログインされるので、

cd /home/ssm-user
echo "test" > test.txt
aws s3 cp test.txt s3://S3の名前/

でファイルを作って、S3へコピーします。SSMでログインされるのが、ssm_userなので、ファイルの書き込みができる/home/ssm-user に移動してからやりましょう。特にエラーが出ていないようなら、

aws s3 ls s3://S3の名前/

でS3側のファイルを確認。ファイルが存在していればEC2からS3への接続はOK。


EC2にバックアップ用フォルダを作成

バックアップファイルを一時的に配置しておくフォルダをEC2に作ります。コマンドはこちら。

sudo mkdir -p /opt/wordpress-backup
sudo chown ssm-user:ssm-user /opt/wordpress-backup

バックアップファイルを一時的に置くだけなんで自分の好きなところでいいんですが、私は/opt/wordpress-backup に置くことにしました。sudoでフォルダを作ってssm-userに所有者を変更しておきます。


EC2にバックアップスクリプトを作成

バックアップスクリプトはチャッピー(AI)作です。スクリプトファイル作成のコードはこちら。

cat <<'EOF' > /opt/wordpress-backup/backup.sh
#!/bin/bash
set -euo pipefail

DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/opt/wordpress-backup"
WORK_DIR="${BACKUP_DIR}/${DATE}"

S3_BUCKET="バックアップ用S3名"
S3_PREFIX="wordpress"

WP_PATH="/var/www/html"

DB_NAME="データベース名"
DB_USER="データベースユーザー名"
DB_PASSWORD="データベースパスワード"
DB_HOST="localhost"

mkdir -p "${WORK_DIR}"

DB_FILE="${WORK_DIR}/db_${DATE}.sql"
DB_GZ="${DB_FILE}.gz"
FILES_ARCHIVE="${WORK_DIR}/wp_files_${DATE}.tar.gz"

echo "=== Backup start: ${DATE} ==="

echo "[1/4] Dump database..."
mysqldump -h "${DB_HOST}" -u "${DB_USER}" -p"${DB_PASSWORD}" "${DB_NAME}" > "${DB_FILE}"

echo "[2/4] Compress database dump..."
gzip "${DB_FILE}"

echo "[3/4] Archive wordpress files..."
tar --warning=no-file-changed -czf "${FILES_ARCHIVE}" \
  --exclude="${WP_PATH}/wp-content/cache" \
  --exclude="${WP_PATH}/wp-content/upgrade" \
  --exclude="${WP_PATH}/wp-content/uploads/cache" \
  "${WP_PATH}" || TAR_EXIT=$?

TAR_EXIT=${TAR_EXIT:-0}

if [ "${TAR_EXIT}" -ne 0 ] && [ "${TAR_EXIT}" -ne 1 ]; then
  echo "tar failed with exit code ${TAR_EXIT}"
  exit "${TAR_EXIT}"
fi

echo "[4/4] Upload to S3..."
aws s3 cp "${DB_GZ}" "s3://${S3_BUCKET}/${S3_PREFIX}/db/"
aws s3 cp "${FILES_ARCHIVE}" "s3://${S3_BUCKET}/${S3_PREFIX}/files/"

echo "=== Backup complete: ${DATE} ==="
EOF

バックアップスクリプトはここまで。

スクリプトが出来たら実行権限を付与しておきます。

chmod +x /opt/wordpress-backup/backup.sh

これでバックアップスクリプト周りは完了。


バックアップスクリプトをざっくり説明

処理フロー

1. 日付ディレクトリ作成
2. DBバックアップ(mysqldump)
3. DBを圧縮(gzip)
4. ファイルバックアップ(tar)
5. S3へアップロード

■ 日付ディレクトリの作成

バックアップファイルを整理するため、実行日時ごとにディレクトリを作成しています。

👉 ポイント

  • 上書き防止
  • 世代管理できる
  • ずっと出来ちゃうので削除サイクルはあとで考える

■ データベースのバックアップ

mysqldump コマンドを使用して、WordPressのデータベースをダンプしています。

👉 補足

  • 記事・設定・ユーザー情報などが含まれる
  • 最重要データ
  • mysqldumpコマンドが使えない場合はEC2にインストールが必要だと思う

■ 圧縮(gzip)

ダンプファイルはサイズが大きくなるため、gzipで圧縮しています。

👉 ポイント

  • S3コスト削減
  • 転送時間短縮

■ ファイルバックアップ(tar)

WordPressのファイルを tar.gz 形式でまとめてアーカイブしています。

■ ハマりポイント(重要)

WordPress稼働中に tar を実行すると、file changed as we read it というメッセージが出ることがありました。これはキャッシュや一時ファイルがバックアップ中に更新されるためです。今回はキャッシュディレクトリを除外し、安定してバックアップできるようにしました。

■ S3へのアップロード

aws s3 cp コマンドを使用して、バックアップファイルをS3へアップロードしています。

👉 ポイント

  • EC2ロールで認証(アクセスキー不要)
  • セキュア

■ 今回のポイント

  • DBとファイルの両方をバックアップ
  • S3に保存して冗長化
  • EC2内だけに依存しない構成
  • バックアップファイルのライフサイクルは未設定(今後の課題)

(おまけ)WordPressのDBの設定がわからない場合は

ちなみに、WordPressのDBの設定がわからない場合はWordPressの wp-config.php から確認します。確認するには下のコマンド。

sudo grep -E "DB_NAME|DB_USER|DB_PASSWORD|DB_HOST" /var/www/html/wp-config.php

wp-config.phpのパスは自分のパスに合わせてください。


バックアップ用のスクリプトを手動で実行してテスト

作成したバックアップスクリプトを実行してみます。

/opt/wordpress-backup/backup.sh

で、実行結果が

sh-4.2$ /opt/wordpress-backup/backup.sh
=== Backup start: 20260328_103115 ===
[1/4] Dump database...
[2/4] Compress database dump...
[3/4] Archive wordpress files...
tar: Removing leading `/' from member names
[4/4] Upload to S3...
upload: ../../opt/wordpress-backup/20260328_103115/db_20260328_103115.sql.gz to s3://akkeys-lifework-lab-backup/wordpress/db/db_20260328_103115.sql.gz
upload: ../../opt/wordpress-backup/20260328_103115/wp_files_20260328_103115.tar.gz to s3://akkeys-lifework-lab-backup/wordpress/files/wp_files_20260328_103115.tar.gz
=== Backup complete: 20260328_103115 ===

とログがでて最終的に、Backup complete が出ていればOK。「tar: Removing leading `/’ from member names」という警告?が出てますが、問題なく進みます。

続いてS3にアクセスして結果をみてみます。EC2から下のコマンドで、

aws s3 ls s3://バックアップ用S3の名前/wordpress/db/
aws s3 ls s3://バックアップ用S3の名前/wordpress/files/

ファイルが出てくればバックアップファイルを作ってS3まで転送がOK。手動でバックアップスクリプトが正しく動くことが確認できたので、これをCronで自動化していきます。


Cronでバックアップスクリプトの実行を自動化する

Cronを設定します。

crontab -e

で、Cronのエディタを出して、

0 3 * * * /opt/wordpress-backup/backup.sh >> /opt/wordpress-backup/backup.log 2>&1

を入れて保存。

これは

0 3 * * *   毎日 3:00
>> backup.log  標準出力をログに追記
2>&1          エラーも同じログに出す

というわけで毎日3時にバックアップスクリプトを動かしてログに追記するというCronです。

設定したら

crontab -l

で確認。さっきのCronの設定コードが出力されればCronの設定は完了です。


とりあえず今日はここまで。

ん?Cronの設定の3時ってひょっとしてUTCかも?特にタイムゾーン変えてないしデフォルトはUTCだよね・・・。ってことは日本時間は昼の12時に動くかな。明日の12時にまた見てみて、うまく行ったらタイムゾーンをJSTに変えたりバックアップファイルのライフサイクルを考えたりしていきたいと思います!ではまた。