Wordpress backup and restore - 2026

An introdction to Wordpress backup and restore. Everything you need to know about the company.

  1. Get the backup files, I used updraft plugin
  2. mysql and wordpress containers must be running
wordpress-bbct:
    image: wordpress:latest
    container_name: wordpress-bbct
    networks:
      - cloudflare_app_net
    ports:
      - "8089:80"
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: mysql-bbct:3306
      WORDPRESS_DB_NAME: bbct_wp
      WORDPRESS_DB_USER: bbct_user
      WORDPRESS_DB_PASSWORD: bbct_pass
      WORDPRESS_TABLE_PREFIX: wp_cce4ht_
    volumes:
      - wordpress_bbct_data:/var/www/html
      - ./clients/UpdraftPlus_bbct:/backup:ro
      - ./clients/restore_bbct_wp.sh:/restore.sh:ro
    depends_on:
      - mysql-bbct
  1. Restoring a managed WordPress site locally via UpdraftPlus into a Docker environment comes with several unexpected hurdles. First, beware of lingering managed hosting plugins like Object Cache Pro; without a configured Redis instance, you'll need to manually delete the object-cache.php drop-in and deactivate the plugin directly in the database. Don't expect standard command-line tools to save you, as the official WordPress Docker image lacks both WP-CLI and pdo_mysql, forcing you to rely on raw PHP with mysqli for ad-hoc database operations. Furthermore, Windows developers should avoid passing complex inline bash scripts to docker exec via PowerShell due to frustrating quoting limitations; writing local scripts and transferring them via docker cp is far more reliable. You'll also want to double-check your .htaccess file, as UpdraftPlus restores can sometimes leave out the standard mod_rewrite rules, breaking your pretty permalinks with 404 errors until manually replaced. Finally, if you're eventually taking the site live via a Cloudflare Tunnel, remember to update the siteurl and home database options, relying on the official Docker image's built-in X-Forwarded-Proto handling to seamlessly manage SSL detection.
  2. Below is the script to restore the backup files. Good luck!
#!/bin/bash
# ============================================================================
# UpdraftPlus Backup Restore Script for BBCT WordPress
# Run INSIDE the wordpress-bbct container:
#   docker exec -it wordpress-bbct bash /restore.sh
#
# Prerequisites: Both mysql-bbct and wordpress-bbct containers must be running
# and MySQL must have finished initialising (wait ~30s after first start).
# ============================================================================

set -e

BACKUP_DIR="/backup"
WP_DIR="/var/www/html"
WP_CONTENT="${WP_DIR}/wp-content"
DB_HOST="mysql-bbct"
DB_NAME="bbct_wp"
DB_USER="bbct_user"
DB_PASS="bbct_pass"

echo "============================================"
echo "  BBCT WordPress UpdraftPlus Restore"
echo "============================================"

# --- 0. Install required tools ---
echo ""
echo "[0/5] Installing unzip and mysql-client..."
apt-get update -qq && apt-get install -y -qq unzip default-mysql-client > /dev/null 2>&1
echo "  Done."

# --- 1. Restore Database ---
echo ""
echo "[1/5] Restoring database..."
DB_FILE=$(ls ${BACKUP_DIR}/*-db.gz 2>/dev/null | head -1)
if [ -z "$DB_FILE" ]; then
    echo "  ERROR: No database backup (*-db.gz) found in ${BACKUP_DIR}"
    exit 1
fi
echo "  Extracting: $(basename $DB_FILE)"
gunzip -c "$DB_FILE" | mysql --skip-ssl -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME"
echo "  Database restored."

# --- 2. Restore Plugins ---
echo ""
echo "[2/5] Restoring plugins..."
# Use grep -v to ensure we ignore mu-plugins.zip
PLUGINS_FILE=$(ls ${BACKUP_DIR}/*-plugins.zip 2>/dev/null | grep -v "mu-plugins" | head -1)
if [ -n "$PLUGINS_FILE" ]; then
    echo "  Extracting: $(basename $PLUGINS_FILE)"
    unzip -o -q "$PLUGINS_FILE" -d "${WP_CONTENT}/"
    echo "  Plugins restored."
else
    echo "  SKIP: No plugins backup found."
fi

# --- 3. Restore MU-Plugins ---
echo ""
echo "[3a/5] Restoring mu-plugins..."
MU_FILE=$(ls ${BACKUP_DIR}/*-mu-plugins.zip 2>/dev/null | head -1)
if [ -n "$MU_FILE" ]; then
    mkdir -p "${WP_CONTENT}/mu-plugins"
    echo "  Extracting: $(basename $MU_FILE)"
    # mu-plugins zip usually doesn't have a top level folder, or it's mu-plugins/
    unzip -o -q "$MU_FILE" -d "${WP_CONTENT}/"
    echo "  MU-plugins restored."
else
    echo "  SKIP: No mu-plugins backup found."
fi

# --- 3b. Restore Themes ---
echo ""
echo "[3b/5] Restoring themes..."
THEMES_FILE=$(ls ${BACKUP_DIR}/*-themes.zip 2>/dev/null | head -1)
if [ -n "$THEMES_FILE" ]; then
    echo "  Extracting: $(basename $THEMES_FILE)"
    unzip -o -q "$THEMES_FILE" -d "${WP_CONTENT}/"
    echo "  Themes restored."
else
    echo "  SKIP: No themes backup found."
fi

# --- 4. Restore Uploads (multiple split zips) ---
echo ""
echo "[4/5] Restoring uploads..."
UPLOAD_FILES=$(ls ${BACKUP_DIR}/*-uploads*.zip 2>/dev/null)
if [ -n "$UPLOAD_FILES" ]; then
    # mkdir -p "${WP_CONTENT}/uploads" # unzip will create it
    for UF in $UPLOAD_FILES; do
        echo "  Extracting: $(basename $UF)"
        unzip -o -q "$UF" -d "${WP_CONTENT}/"
    done
    echo "  Uploads restored ($(echo "$UPLOAD_FILES" | wc -l) archives)."
else
    echo "  SKIP: No uploads backup found."
fi

# --- 5. Restore Others ---
echo ""
echo "[5/5] Restoring others..."
OTHERS_FILE=$(ls ${BACKUP_DIR}/*-others.zip 2>/dev/null | head -1)
if [ -n "$OTHERS_FILE" ]; then
    echo "  Extracting: $(basename $OTHERS_FILE)"
    unzip -o -q "$OTHERS_FILE" -d "${WP_CONTENT}/"
    echo "  Others restored."
else
    echo "  SKIP: No others backup found."
fi

# --- 6. Fix ownership ---
echo ""
echo "Fixing file ownership..."
chown -R www-data:www-data "${WP_CONTENT}"
echo "Done."

# --- 7. Update site URL in database to localhost:8088 ---
echo ""
echo "Detecting database table prefix..."
OPTIONS_TABLE=$(mysql --skip-ssl -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -N -e "SHOW TABLES LIKE '%options';" | grep -v "pys_options" | head -1)

if [ -n "$OPTIONS_TABLE" ]; then
    echo "Updating status in $OPTIONS_TABLE to http://localhost:8088..."
    mysql --skip-ssl -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "
    UPDATE $OPTIONS_TABLE SET option_value = 'http://localhost:8088' WHERE option_name IN ('siteurl', 'home');
    "
    echo "Site URL updated in $OPTIONS_TABLE."
else
    echo "ERROR: Could find options table. Manual URL update required."
fi

echo ""
echo "============================================"
echo "  Restore complete!"
echo "  Visit: http://localhost:8088"
echo "============================================"

links

social