3 min read

WordPress Backup Tool (FTP & SSH)

This utility automates the backup of a WordPress site. It uses a hybrid approach for efficiency:

  1. SSH (paramiko): Connects to the server to run mysqldump (for the database) and tar (to compress site files into a single archive).
  2. FTP (ftplib): Connects to download the large backup files.
  3. SSH: Connects again to delete the temporary backup files from the server.

Modules Used:

  • paramiko: For SSH connections and command execution.
  • ftplib: For downloading files via FTP.
  • argparse: To handle command-line arguments.

Prerequisites

  1. SSH Access: You must have SSH access enabled on your hosting account.
  2. Database Credentials: You need the DB name, user, and password (found in wp-config.php).

Installation

pip install paramiko

The Code

Save this as wp_backup.py.

import paramiko
import ftplib
import argparse
import sys
import time
from datetime import datetime

def ssh_exec(ssh, command):
    """Executes a command via SSH and checks for errors."""
    print(f"  [SSH] Executing: {command.split()[0]}...") # Print command name only for brevity
    stdin, stdout, stderr = ssh.exec_command(command)
    exit_status = stdout.channel.recv_exit_status()

    if exit_status != 0:
        print(f"  [Error] Command failed: {command}")
        print(stderr.read().decode())
        return False
    return True

def perform_backup(args):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    sql_file = f"db_{args.db_name}_{timestamp}.sql"
    archive_file = f"files_{timestamp}.tar.gz"

    # 1. SSH: Create Backups
    print(f"--- Step 1: Creating Backups on Server ({args.host}) ---")
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(args.host, username=args.ssh_user, password=args.ssh_pass)

        # Dump Database
        # Note: -p{password} (no space) is required for mysqldump
        dump_cmd = f"mysqldump -u {args.db_user} -p'{args.db_pass}' {args.db_name} > {sql_file}"
        if not ssh_exec(ssh, dump_cmd): return

        # Compress Site Files
        # tar -czf archive.tar.gz folder_to_backup
        tar_cmd = f"tar -czf {archive_file} {args.remote_dir}"
        if not ssh_exec(ssh, tar_cmd): return

        ssh.close()
    except Exception as e:
        print(f"SSH Connection Error: {e}")
        return

    # 2. FTP: Download Files
    print(f"\n--- Step 2: Downloading via FTP ---")
    try:
        ftp = ftplib.FTP(args.host)
        ftp.login(args.ftp_user, args.ftp_pass)

        for filename in [sql_file, archive_file]:
            print(f"  [FTP] Downloading {filename}...")
            with open(filename, 'wb') as f:
                ftp.retrbinary(f"RETR {filename}", f.write)

        ftp.quit()
        print("  Downloads complete.")
    except Exception as e:
        print(f"FTP Error: {e}")
        return

    # 3. SSH: Cleanup
    print(f"\n--- Step 3: Cleaning up Remote Files ---")
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(args.host, username=args.ssh_user, password=args.ssh_pass)

        ssh_exec(ssh, f"rm {sql_file}")
        ssh_exec(ssh, f"rm {archive_file}")
        ssh.close()
        print("  Cleanup complete.")
    except Exception as e:
        print(f"Cleanup Error: {e}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="WordPress Backup Tool (FTP & SSH)")

    # Server Credentials
    parser.add_argument("--host", required=True, help="Server Hostname/IP")
    parser.add_argument("--ssh-user", required=True, help="SSH Username")
    parser.add_argument("--ssh-pass", required=True, help="SSH Password")
    parser.add_argument("--ftp-user", required=True, help="FTP Username")
    parser.add_argument("--ftp-pass", required=True, help="FTP Password")

    # Site Details
    parser.add_argument("--db-name", required=True, help="Database Name")
    parser.add_argument("--db-user", required=True, help="Database User")
    parser.add_argument("--db-pass", required=True, help="Database Password")
    parser.add_argument("--remote-dir", default="public_html", help="Remote directory to backup (default: public_html)")

    args = parser.parse_args()
    perform_backup(args)

Usage

python wp_backup.py \
  --host example.com \
  --ssh-user myuser --ssh-pass "ssh_password" \
  --ftp-user myuser --ftp-pass "ftp_password" \
  --db-name wp_database --db-user wp_user --db-pass "db_password" \
  --remote-dir public_html

programming/python/python