Linux cesa-www-main 6.1.0-49-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64
Apache/2.4.68 (Debian)
Server IP : 10.218.0.2 & Your IP : 216.73.216.28
Domains :
Cant Read [ /etc/named.conf ]
User : www-data
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
var /
www /
cesa.co.za /
scripts /
wordpress /
Delete
Unzip
Name
Size
Permission
Date
Action
wp-dev-post-migrate-fix.sh
3.53
KB
-rw-r--r--
2026-07-20 12:58
wp-files-backup.sh
9.16
KB
-rw-r--r--
2026-07-20 13:03
Save
Rename
#!/usr/bin/env bash # Backup WordPress application files (core, themes, plugins, mu-plugins, drop-ins). # Does NOT include uploaded media (wp-content/uploads) or the database. # # Purpose: roll back a broken plugin/theme/core upgrade without restoring media. # Database backups are handled separately. # # ============================================================================= # HOW TO RUN THE BACKUP # ============================================================================= # Run on the WordPress server (SSH). Archives go to /var/backups/wp-files by default. # # One-liner (recommended): # # bash /var/www/cesa.co.za/scripts/wordpress/wp-files-backup.sh backup # # Same thing with explicit paths (must be on the SAME line as bash, or use export): # # WP_PATH=/var/www/cesa.co.za BACKUP_DIR=/var/backups/wp-files \ # bash /var/www/cesa.co.za/scripts/wordpress/wp-files-backup.sh backup # # Or export first, then run: # # export WP_PATH=/var/www/cesa.co.za # export BACKUP_DIR=/var/backups/wp-files # bash /var/www/cesa.co.za/scripts/wordpress/wp-files-backup.sh backup # # NOTE: These do NOT pass variables into the script (child process never sees them): # WP_PATH=/var/www/cesa.co.za # assignment only — not exported # BACKUP_DIR=/var/backups/wp-files # assignment only — not exported # bash .../wp-files-backup.sh backup # script ignores the vars above # # First-time setup (once, as root if needed): # # sudo mkdir -p /var/backups/wp-files # sudo chown otto:otto /var/backups/wp-files # or whatever deploy user # sudo chmod 750 /var/backups/wp-files # # Output: # - Archive: /var/backups/wp-files/cesa-wp-files-<host>-<YYYYMMDD-HHMMSS>.tar.gz # - Manifest: same name with .txt (paths, WP version, sha256) # - Keeps the newest KEEP archives (default 10; set KEEP=0 to keep all) # # ============================================================================= # HOW TO RESTORE (after a bad plugin upgrade) # ============================================================================= # Overwrites core / themes / plugins / mu-plugins from the archive. # Does NOT touch wp-content/uploads or the database. # # bash /var/www/cesa.co.za/scripts/wordpress/wp-files-backup.sh restore \ # /var/backups/wp-files/cesa-wp-files-HOST-20260720-144800.tar.gz # # Non-interactive: # # FORCE=1 bash /var/www/cesa.co.za/scripts/wordpress/wp-files-backup.sh restore \ # /var/backups/wp-files/cesa-wp-files-HOST-20260720-144800.tar.gz # # Env: # WP_PATH WordPress root (default: /var/www/cesa.co.za if present, else cwd) # BACKUP_DIR Where archives are written (default: /var/backups/wp-files) # KEEP Number of archives to retain (default: 10; 0 = keep all) # LABEL Optional label in the archive name (default: short hostname) # FORCE=1 Skip restore confirmation prompt set -euo pipefail CMD="${1:-backup}" if [[ -z "${WP_PATH:-}" ]]; then if [[ -f /var/www/cesa.co.za/wp-config.php ]]; then WP_PATH=/var/www/cesa.co.za else WP_PATH="$(pwd)" fi fi BACKUP_DIR="${BACKUP_DIR:-/var/backups/wp-files}" KEEP="${KEEP:-10}" LABEL="${LABEL:-$(hostname -s 2>/dev/null || echo wp)}" TIMESTAMP="$(date +%Y%m%d-%H%M%S)" die() { echo "ERROR: $*" >&2 exit 1 } require_wp_root() { [[ -f "$WP_PATH/wp-config.php" ]] || die "wp-config.php not found in WP_PATH=$WP_PATH" [[ -d "$WP_PATH/wp-admin" && -d "$WP_PATH/wp-includes" ]] || die "Does not look like a WordPress root: $WP_PATH" } resolve_backup_dir() { if ! mkdir -p "$BACKUP_DIR" 2>/dev/null; then die "Cannot create BACKUP_DIR=$BACKUP_DIR (permission denied). Run once: sudo mkdir -p $BACKUP_DIR sudo chown $(id -un):$(id -gn) $BACKUP_DIR sudo chmod 750 $BACKUP_DIR" fi [[ -w "$BACKUP_DIR" ]] || die "BACKUP_DIR=$BACKUP_DIR is not writable by $(id -un)" BACKUP_DIR="$(cd "$BACKUP_DIR" && pwd)" } wp_version() { if [[ -f "$WP_PATH/wp-includes/version.php" ]]; then sed -n "s/^\\\$wp_version *= *'\\([^']*\\)'.*/\\1/p" "$WP_PATH/wp-includes/version.php" | head -1 fi } prune_old_backups() { local keep="$1" [[ "$keep" =~ ^[0-9]+$ ]] || return 0 [[ "$keep" -eq 0 ]] && return 0 mapfile -t archives < <(ls -1t "$BACKUP_DIR"/cesa-wp-files-*.tar.gz 2>/dev/null || true) local i for ((i = keep; i < ${#archives[@]}; i++)); do echo " prune: ${archives[$i]}" rm -f "${archives[$i]}" rm -f "${archives[$i]%.tar.gz}.txt" 2>/dev/null || true done } # Optional root files — only add those that exist so tar does not fail. collect_root_files() { local -a candidates=( index.php wp-activate.php wp-blog-header.php wp-comments-post.php wp-config.php wp-config-sample.php wp-cron.php wp-links-opml.php wp-load.php wp-login.php wp-mail.php wp-settings.php wp-signup.php wp-trackback.php xmlrpc.php license.txt readme.html .htaccess ) ROOT_FILES=() local f for f in "${candidates[@]}"; do [[ -e "$WP_PATH/$f" ]] && ROOT_FILES+=("$f") done } do_backup() { require_wp_root WP_PATH="$(cd "$WP_PATH" && pwd)" resolve_backup_dir collect_root_files local archive="$BACKUP_DIR/cesa-wp-files-${LABEL}-${TIMESTAMP}.tar.gz" local manifest="$BACKUP_DIR/cesa-wp-files-${LABEL}-${TIMESTAMP}.txt" local ver ver="$(wp_version || true)" echo "==> WordPress path : $WP_PATH" echo "==> Backup dir : $BACKUP_DIR" echo "==> Archive : $archive" echo "==> WP version : ${ver:-unknown}" echo "==> Excluding : uploads, cache, upgrade/temp, logs, SQL/zip dumps" local -a excludes=( --exclude='wp-content/uploads' --exclude='wp-content/Uploads' --exclude='wp-content/cache' --exclude='wp-content/upgrade' --exclude='wp-content/upgrade-temp-backup' --exclude='wp-content/temp' --exclude='wp-content/tmp' --exclude='wp-content/backups' --exclude='wp-content/backup*' --exclude='wp-content/updraft' --exclude='wp-content/ai1wm-backups' --exclude='wp-content/wflogs' --exclude='wp-content/debug.log' --exclude='wp-content/**/*.log' --exclude='*.sql' --exclude='*.sql.gz' --exclude='node_modules' --exclude='.git' ) # If BACKUP_DIR lives under WP_PATH, exclude it from the archive if [[ "$BACKUP_DIR" == "$WP_PATH"/* ]]; then excludes+=(--exclude="${BACKUP_DIR#"$WP_PATH"/}") fi local -a tar_extra=() if tar --help 2>&1 | grep -q -- '--warning='; then tar_extra+=(--warning=no-file-changed) fi # Core + full wp-content tree with uploads/caches excluded above. # Exit 1 from tar (file changed while reading) is tolerated on busy sites. set +e tar "${tar_extra[@]}" -czf "$archive" \ "${excludes[@]}" \ -C "$WP_PATH" \ wp-admin \ wp-includes \ wp-content \ "${ROOT_FILES[@]}" local tar_rc=$? set -e # GNU tar: 0 ok, 1 some files changed/differed while reading if [[ "$tar_rc" -ne 0 && "$tar_rc" -ne 1 ]]; then die "tar failed with exit code $tar_rc" fi [[ -s "$archive" ]] || die "Archive was not created or is empty: $archive" { echo "CESA WordPress file backup (no uploads, no database)" echo "created: $(date -Is)" echo "host: $(hostname -f 2>/dev/null || hostname)" echo "wp_path: $WP_PATH" echo "wp_version: ${ver:-unknown}" echo "archive: $archive" echo "sha256: $(sha256sum "$archive" | awk '{print $1}')" echo "size_bytes: $(wc -c <"$archive" | tr -d ' ')" echo "" echo "Included: WordPress core, wp-config.php, .htaccess (if present)," echo " wp-content/themes, plugins, mu-plugins, languages, drop-ins" echo "Excluded: wp-content/uploads, caches, upgrade temps, logs, SQL dumps" echo "" echo "Restore:" echo " WP_PATH=$WP_PATH bash $0 restore $archive" } >"$manifest" prune_old_backups "$KEEP" echo "" echo "Done." echo " archive : $archive" echo " manifest: $manifest" echo " size : $(du -h "$archive" | awk '{print $1}')" } do_restore() { local archive="${2:-}" [[ -n "$archive" ]] || die "Usage: $0 restore /path/to/cesa-wp-files-....tar.gz" [[ -f "$archive" ]] || die "Archive not found: $archive" require_wp_root WP_PATH="$(cd "$WP_PATH" && pwd)" archive="$(cd "$(dirname "$archive")" && pwd)/$(basename "$archive")" echo "==> Restore WordPress files (core / themes / plugins) from:" echo " $archive" echo "==> Target WP_PATH: $WP_PATH" echo "==> Uploads and database are NOT touched." echo "" echo "This will overwrite matching files under WP_PATH." if [[ -t 0 && "${FORCE:-}" != "1" ]]; then read -r -p "Type YES to continue: " confirm [[ "$confirm" == "YES" ]] || die "Aborted." fi tar -xzf "$archive" -C "$WP_PATH" echo "" echo "Restore complete." echo " Next: clear object/page caches; verify Plugins / Themes." echo " Database was not restored — use your DB backup if needed." } usage() { # Print the leading comment block (instructions) until the first non-comment line. awk ' NR == 1 { next } /^#/ { sub(/^# ?/, ""); print; next } { exit } ' "$0" } case "$CMD" in backup) do_backup ;; restore) do_restore "$@" ;; -h|--help|help) usage ;; *) die "Unknown command: $CMD (use backup|restore|help)" ;; esac