#!/bin/bash # JARVIS Full Backup — websites + databases # Runs daily via cron, also triggered on-demand from admin portal BACKUP_DIR="/var/backups/jarvis" LOCK_FILE="$BACKUP_DIR/backup.lock" LOG_FILE="$BACKUP_DIR/backup.log" MANIFEST="$BACKUP_DIR/manifest.json" KEEP_DAYS=7 DB_USER="root" DB_PASS="b71e5c1a8c7457541b9c1db822de37adfa271926a38b6c20" DATABASES="jarvis_db toms_tjj_db tomt_ttg_db epic_parkersling epic_epic_db parker_db" SITES=( "/home/epictravelexpeditions.com/public_html" "/home/epictravelexpeditions.com/parkerslingshot" "/home/jarvis.orbishosting.com/public_html" "/home/orbishosting.com/public_html" "/home/orbis.orbishosting.com/public_html" "/home/parkerslingshotrentals.com/public_html" "/home/tomsjavajive.com/public_html" "/home/tomtomgames.com/public_html" ) mkdir -p "$BACKUP_DIR" # Prevent concurrent runs if [ -f "$LOCK_FILE" ]; then AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_FILE") )) if [ "$AGE" -lt 3600 ]; then echo "$(date): Backup already running (lock age ${AGE}s)" >> "$LOG_FILE" exit 1 fi rm -f "$LOCK_FILE" fi TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S) WORK_DIR=$(mktemp -d) BACKUP_NAME="jarvis_backup_${TIMESTAMP}" FINAL_FILE="$BACKUP_DIR/${BACKUP_NAME}.tar.gz" echo "$(date): Starting backup $TIMESTAMP" > "$LOG_FILE" echo "$TIMESTAMP" > "$LOCK_FILE" trap "rm -f '$LOCK_FILE'; rm -rf '$WORK_DIR'" EXIT mkdir -p "$WORK_DIR/sql" "$WORK_DIR/sites" # ── SQL Dumps ──────────────────────────────────────────────────────────────── echo "$(date): Dumping databases..." >> "$LOG_FILE" for DB in $DATABASES; do mysqldump -u"$DB_USER" -p"$DB_PASS" --single-transaction --quick \ "$DB" 2>/dev/null > "$WORK_DIR/sql/${DB}.sql" if [ $? -eq 0 ]; then SIZE=$(du -sh "$WORK_DIR/sql/${DB}.sql" | cut -f1) echo "$(date): $DB — $SIZE" >> "$LOG_FILE" else echo "$(date): $DB — FAILED (may not exist)" >> "$LOG_FILE" rm -f "$WORK_DIR/sql/${DB}.sql" fi done # ── Website Files ──────────────────────────────────────────────────────────── echo "$(date): Archiving website files..." >> "$LOG_FILE" for SITE in "${SITES[@]}"; do if [ -d "$SITE" ]; then SLUG=$(echo "$SITE" | sed 's|/home/||;s|/|_|g') tar -czf "$WORK_DIR/sites/${SLUG}.tar.gz" -C "$(dirname "$SITE")" "$(basename "$SITE")" 2>/dev/null SIZE=$(du -sh "$WORK_DIR/sites/${SLUG}.tar.gz" | cut -f1) echo "$(date): $SITE — $SIZE" >> "$LOG_FILE" fi done # ── Final Archive ──────────────────────────────────────────────────────────── echo "$(date): Creating final archive..." >> "$LOG_FILE" tar -czf "$FINAL_FILE" -C "$WORK_DIR" sql sites 2>/dev/null FINAL_SIZE=$(du -sh "$FINAL_FILE" | cut -f1) FINAL_BYTES=$(stat -c %s "$FINAL_FILE") echo "$(date): Done — $FINAL_FILE ($FINAL_SIZE)" >> "$LOG_FILE" # ── Update Manifest ─────────────────────────────────────────────────────────── BACKUPS_JSON="[" FIRST=1 for F in $(ls -t "$BACKUP_DIR"/jarvis_backup_*.tar.gz 2>/dev/null); do FNAME=$(basename "$F") FSIZE=$(stat -c %s "$F") FDATE=$(stat -c %y "$F" | cut -d. -f1) [ $FIRST -eq 0 ] && BACKUPS_JSON+="," BACKUPS_JSON+="{\"file\":\"$FNAME\",\"size\":$FSIZE,\"date\":\"$FDATE\"}" FIRST=0 done BACKUPS_JSON+="]" echo "{\"backups\":$BACKUPS_JSON,\"updated\":\"$(date -Iseconds)\"}" > "$MANIFEST" # ── Cleanup old backups ─────────────────────────────────────────────────────── find "$BACKUP_DIR" -name "jarvis_backup_*.tar.gz" -mtime +$KEEP_DAYS -delete echo "$(date): Backup complete. Kept last $KEEP_DAYS days." >> "$LOG_FILE"