homelab-brain/arakava-news/scripts/wp-mirror-sync.sh
Homelab Cursor e41bb43024 add wp-mirror nightly sync CT101 to CT600
Read-only mysqldump and tar pull; safe for production WordPress on CT101.
2026-06-28 19:09:30 +02:00

120 lines
4.1 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Pull WordPress CT101 (pve-hetzner) → CT600 wp-mirror (pve-mu-3)
# CT101 impact: read-only mysqldump (--single-transaction) + read-only tar. No restarts.
set -euo pipefail
HETZNER_HOST="${HETZNER_HOST:-root@100.88.230.59}"
HETZNER_CT="${HETZNER_CT:-101}"
MIRROR_CT="${MIRROR_CT:-600}"
STAGING="${STAGING:-/opt/wp-mirror-sync/staging}"
LOG="${LOG:-/var/log/wp-mirror-sync.log}"
LOCK_FILE="/var/run/wp-mirror-sync.lock"
FAILOVER_FLAG="/opt/wp-mirror-sync/FAILOVER_ACTIVE"
MIRROR_SITEURL="http://192.168.178.142"
MYSQL_USER="wordpress"
MYSQL_PASS="astral66"
MYSQL_DB="wordpress"
WP_VOL="/var/lib/docker/volumes/wordpress_wp_data/_data"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"
}
tar_sync_files() {
rm -rf "${STAGING}/wpfiles"
mkdir -p "${STAGING}/wpfiles"
ssh -o BatchMode=yes -o ConnectTimeout=30 "$HETZNER_HOST" \
"ionice -c3 nice -n 19 pct exec ${HETZNER_CT} -- tar c -C ${WP_VOL} \
--exclude=wp-content/cache \
--exclude=wp-content/debug.log \
--exclude=wp-content/upgrade \
. 2>/dev/null" | tar x -C "${STAGING}/wpfiles"
}
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log "SKIP: another sync is running"
exit 0
fi
if [[ -f "$FAILOVER_FLAG" ]]; then
log "SKIP: ${FAILOVER_FLAG} present (manual failover)"
exit 0
fi
if ! command -v pct >/dev/null 2>&1; then
log "ABORT: must run on Proxmox host with pct (pve-mu-3)"
exit 1
fi
mkdir -p "$STAGING" "$(dirname "$LOG")"
log "Checking CT101 health..."
if ! ssh -o BatchMode=yes -o ConnectTimeout=15 "$HETZNER_HOST" \
"pct exec ${HETZNER_CT} -- curl -sf -o /dev/null --max-time 15 http://127.0.0.1/"; then
log "ABORT: CT101 does not respond on http://127.0.0.1/"
exit 1
fi
log "START sync CT101 → CT600"
DB_FILE="${STAGING}/wordpress.sql.gz"
log "DB dump (single-transaction, read-only)..."
if ! ssh -o BatchMode=yes -o ConnectTimeout=30 "$HETZNER_HOST" \
"ionice -c3 nice -n 19 pct exec ${HETZNER_CT} -- docker exec wordpress-mysql mysqldump \
-u${MYSQL_USER} -p${MYSQL_PASS} \
--single-transaction --quick --skip-lock-tables \
--add-drop-table ${MYSQL_DB} 2>/dev/null" | gzip > "${DB_FILE}.tmp"; then
log "ABORT: mysqldump failed"
rm -f "${DB_FILE}.tmp"
exit 1
fi
mv "${DB_FILE}.tmp" "$DB_FILE"
log "DB dump size: $(du -h "$DB_FILE" | awk '{print $1}')"
log "File sync via tar (read-only, ~58 min)..."
tar_sync_files
log "Files staged: $(du -sh "${STAGING}/wpfiles" | awk '{print $1}')"
log "Starting CT600 for import..."
if [[ "$(pct status "$MIRROR_CT" | awk '{print $2}')" != "running" ]]; then
pct start "$MIRROR_CT"
fi
for _ in $(seq 1 45); do
if pct exec "$MIRROR_CT" -- docker info >/dev/null 2>&1; then
break
fi
sleep 2
done
pct exec "$MIRROR_CT" -- docker stop wordpress-app 2>/dev/null || true
log "Import DB into CT600..."
gunzip -c "$DB_FILE" | pct exec "$MIRROR_CT" -- docker exec -i wordpress-mysql \
mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB"
log "Import files into CT600..."
tar c -C "${STAGING}/wpfiles" . 2>/dev/null | pct exec "$MIRROR_CT" -- tar x -C "$WP_VOL"
log "Reset mirror idle siteurl/home..."
pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" "$MYSQL_DB" -e \
"UPDATE wp_options SET option_value='${MIRROR_SITEURL}' WHERE option_name IN ('siteurl','home');"
pct exec "$MIRROR_CT" -- docker start wordpress-app
sleep 5
POSTS="$(pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -N -e \
"SELECT COUNT(*) FROM wp_posts WHERE post_status='publish' AND post_type='post';" "$MYSQL_DB" 2>/dev/null)"
LAST="$(pct exec "$MIRROR_CT" -- docker exec wordpress-mysql mysql -u"$MYSQL_USER" -p"$MYSQL_PASS" -N -e \
"SELECT MAX(post_date) FROM wp_posts WHERE post_type='post';" "$MYSQL_DB" 2>/dev/null)"
log "Mirror verified: ${POSTS} published posts, latest ${LAST}"
if ! ssh -o BatchMode=yes -o ConnectTimeout=15 "$HETZNER_HOST" \
"pct exec ${HETZNER_CT} -- curl -sf -o /dev/null --max-time 15 http://127.0.0.1/"; then
log "WARN: CT101 health check failed AFTER sync — investigate immediately"
exit 1
fi
log "Stopping CT600 (standby)..."
pct stop "$MIRROR_CT"
log "DONE"