
Frappe Ops Backup
- 23 installs
- 159 repo stars
- Updated July 8, 2026
- openaec-foundation/frappe_claude_skill_package
Helps with ai & agent building tasks.
About
frappe-ops-backup is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- frappe-ops-backup
- AI & Agent Building
- AI-coding skill
Frappe Ops Backup by the numbers
- 23 all-time installs (skills.sh)
- Ranked #9,994 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/frappe_claude_skill_package --skill frappe-ops-backupAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 23 |
|---|---|
| repo stars | ★ 159 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/frappe_claude_skill_package ↗ |
What it does
Helps with ai & agent building tasks.
Files
Backup & Disaster Recovery
Frappe provides built-in backup and restore commands via bench. ALWAYS back up before updates, migrations, or any destructive operation. A backup that has never been test-restored is NOT a backup.
Quick Reference
# Database-only backup (default)
bench backup
# Full backup with public + private files
bench backup --with-files
# Backup specific site
bench --site mysite.com backup --with-files
# Backup with compression (.tgz instead of .tar)
bench backup --with-files --compress
# Backup only specific DocTypes
bench backup --only "Sales Invoice,Purchase Invoice"
# Backup excluding specific DocTypes
bench backup --exclude "Error Log,Activity Log"
# Custom backup path
bench backup --backup-path /mnt/backups/
# Restore from backup
bench --site mysite.com restore /path/to/backup.sql.gz
# Restore with files
bench --site mysite.com restore /path/to/backup.sql.gz \
--with-public-files /path/to/files.tar \
--with-private-files /path/to/private-files.tar
# Setup automated backups (cron)
bench setup backupsWhat Gets Backed Up
| Component | Default | With --with-files | Location |
|---|---|---|---|
| Database (SQL dump) | YES | YES | sites/{site}/private/backups/ |
| Site config | YES | YES | sites/{site}/private/backups/ |
| Public files | NO | YES | sites/{site}/public/files/ |
| Private files | NO | YES | sites/{site}/private/files/ |
Backup file naming: {datetime}_{hash}_{site}-database.sql.gz
---
Backup Decision Tree
What do you need to back up?
|
+-- Quick database snapshot before a change?
| +-- bench backup (database only, fast)
|
+-- Full backup before upgrade or migration?
| +-- bench backup --with-files --compress
|
+-- Automated daily backups?
| +-- bench setup backups (cron-based)
| +-- OR S3 Backup Settings (cloud storage)
|
+-- Offsite / cloud backup?
| +-- S3 Backup Settings DocType (built-in)
| +-- OR custom script with rclone/aws-cli
|
+-- Partial backup (specific DocTypes)?
| +-- bench backup --only "DocType1,DocType2"
|
+-- Disaster recovery?
| +-- Full backup + files + tested restore procedure
| +-- See Disaster Recovery section below---
bench backup: All Options
bench backup [OPTIONS]
# Path options
--backup-path PATH # Save all backup files to this directory
--backup-path-db PATH # Custom path for database dump
--backup-path-conf PATH # Custom path for site config backup
--backup-path-files PATH # Custom path for public files archive
--backup-path-private-files PATH # Custom path for private files archive
# Filter options
--only, --include, -i DOCTYPES # Include ONLY these DocTypes (comma-separated)
--exclude, -e DOCTYPES # Exclude these DocTypes (comma-separated)
--ignore-backup-conf # Ignore include/exclude from site config
# Flags
--with-files # Include public and private files
--compress # Use .tgz format (gzip compressed tar)
--verbose # Show detailed outputSafety feature: If backup fails (any exception), partial files are automatically deleted to avoid consuming disk space with incomplete backups.
---
bench restore: All Options
bench --site [site-name] restore [OPTIONS] SQL_FILE_PATH
# SQL_FILE_PATH: path to .sql or .sql.gz file
# Can be relative to sites/ directory or absolute path
# Options
--db-root-username USERNAME # MariaDB/PostgreSQL root username
--db-root-password PASSWORD # MariaDB/PostgreSQL root password
--db-name NAME # Use custom database name
--admin-password PASSWORD # Set administrator password after restore
--install-app APP_NAME # Install app after restore
--with-public-files PATH # Restore public files (.tar or .tgz)
--with-private-files PATH # Restore private files (.tar or .tgz)
# Flags
--force # Bypass downgrade warnings (NOT recommended)CRITICAL: Downgrades are NOT supported. Restoring a backup from a newer version onto an older version triggers a warning. NEVER use --force to bypass this unless you understand the consequences.
---
Automated Backups
Cron-Based (bench setup backups)
# Sets up daily backup cron job
bench setup backups
# This adds to crontab:
# 0 */6 * * * cd /home/frappe/frappe-bench && bench backup --with-filesS3 Backup Settings (Built-in DocType)
Configure in ERPNext: Settings > S3 Backup Settings
| Field | Description |
|---|---|
| Enable | Toggle automated S3 backups |
| S3 Bucket Name | Target bucket |
| AWS Access Key ID | IAM credentials |
| AWS Secret Access Key | IAM secret |
| Region | AWS region (e.g., eu-west-1) |
| Frequency | Daily, Weekly |
| Backup Files | Include public/private files |
# Programmatic S3 backup trigger
from frappe.integrations.offsite_backup_utils import send_email
import frappe
# The S3 backup runs via scheduled job when enabled
# To trigger manually:
from frappe.integrations.doctype.s3_backup_settings.s3_backup_settings import take_backups_s3
take_backups_s3()Custom Backup Script
#!/bin/bash
# custom-backup.sh — Daily backup with rotation and offsite copy
set -e
BENCH_DIR="/home/frappe/frappe-bench"
BACKUP_DIR="/mnt/backups/frappe"
RETENTION_DAYS=30
S3_BUCKET="s3://my-frappe-backups"
DATE=$(date +%Y-%m-%d_%H%M)
cd $BENCH_DIR
# Create backup
bench backup --with-files --compress --backup-path "$BACKUP_DIR/$DATE/"
# Sync to S3
aws s3 sync "$BACKUP_DIR/$DATE/" "$S3_BUCKET/$DATE/"
# Remove local backups older than retention period
find "$BACKUP_DIR" -type d -mtime +$RETENTION_DAYS -exec rm -rf {} +
# Verify latest backup exists on S3
aws s3 ls "$S3_BUCKET/$DATE/" || echo "WARNING: S3 sync failed!"---
Backup Encryption
Encrypt Backups at Rest
# Encrypt backup with GPG (symmetric)
bench backup --with-files --compress
gpg --symmetric --cipher-algo AES256 \
sites/mysite/private/backups/latest-database.sql.gz
# Decrypt for restore
gpg --decrypt backup.sql.gz.gpg > backup.sql.gz
bench --site mysite.com restore backup.sql.gzEncrypt with OpenSSL
# Encrypt
openssl enc -aes-256-cbc -salt -pbkdf2 \
-in backup.sql.gz -out backup.sql.gz.enc
# Decrypt
openssl enc -d -aes-256-cbc -pbkdf2 \
-in backup.sql.gz.enc -out backup.sql.gzALWAYS store encryption keys/passwords separately from backups. NEVER store the decryption key in the same location as the encrypted backup.
---
Restore Procedures
Full Site Restore
# 1. Stop services (traditional deployment)
sudo supervisorctl stop all
# 2. Restore database
bench --site mysite.com restore \
/path/to/20240115_backup-database.sql.gz \
--db-root-password YOUR_DB_ROOT_PASSWORD \
--admin-password NEW_ADMIN_PASSWORD
# 3. Restore files
bench --site mysite.com restore \
/path/to/20240115_backup-database.sql.gz \
--with-public-files /path/to/20240115_backup-files.tar \
--with-private-files /path/to/20240115_backup-private-files.tar
# 4. Run migrations (if version differs)
bench --site mysite.com migrate
# 5. Clear cache
bench --site mysite.com clear-cache
# 6. Restart services
sudo supervisorctl start allRestore to New Site
# Create new site from backup (useful for staging/testing)
bench new-site staging.example.com \
--db-root-password YOUR_DB_ROOT_PASSWORD \
--admin-password STAGING_PASSWORD
bench --site staging.example.com restore \
/path/to/production-backup.sql.gz \
--with-public-files /path/to/files.tar \
--with-private-files /path/to/private-files.tar
bench --site staging.example.com migrateDocker Restore
# Copy backup into container
docker cp backup.sql.gz frappe-backend:/tmp/
# Restore
docker compose exec backend \
bench --site mysite.com restore /tmp/backup.sql.gz \
--db-root-password $DB_ROOT_PASSWORD
# Cleanup
docker compose exec backend rm /tmp/backup.sql.gz---
Backup Verification
ALWAYS test restores regularly. A backup is only valid if it can be successfully restored.
#!/bin/bash
# verify-backup.sh — Test restore to verify backup integrity
set -e
BACKUP_SQL="/mnt/backups/frappe/latest/database.sql.gz"
TEST_SITE="backup-test.localhost"
BENCH_DIR="/home/frappe/frappe-bench"
cd $BENCH_DIR
# Create temporary test site
bench new-site $TEST_SITE --db-root-password $DB_ROOT_PASSWORD --admin-password test
# Restore backup
bench --site $TEST_SITE restore $BACKUP_SQL --db-root-password $DB_ROOT_PASSWORD
# Run basic verification
bench --site $TEST_SITE migrate
bench --site $TEST_SITE console <<'EOF'
import frappe
count = frappe.db.count("User")
print(f"User count: {count}")
assert count > 0, "No users found — backup may be corrupt"
print("Backup verification PASSED")
EOF
# Cleanup test site
bench drop-site $TEST_SITE --db-root-password $DB_ROOT_PASSWORD --force
echo "Backup verification complete"---
Multi-Site Backup Strategy
#!/bin/bash
# backup-all-sites.sh — Backup every site in the bench
set -e
BENCH_DIR="/home/frappe/frappe-bench"
cd $BENCH_DIR
for site in $(bench --site all list-apps 2>/dev/null | grep -oP '^\S+'); do
echo "Backing up $site..."
bench --site "$site" backup --with-files --compress
done---
Disaster Recovery Plan Template
1. PREVENTION
- Automated daily backups (bench setup backups OR S3)
- Offsite copies (S3, GCS, or remote server)
- Encrypted backups for sensitive data
- Backup retention: minimum 30 days
2. DETECTION
- Monitor backup cron job (check /var/log/syslog)
- Verify backup file sizes (alert if < expected)
- Weekly automated restore test
3. RECOVERY (RTO target: < 4 hours)
a. Provision new server (or use standby)
b. Install Frappe/ERPNext (same version as backup)
c. Restore from latest verified backup
d. Run migrations
e. Update DNS to point to new server
f. Verify functionality
4. DOCUMENTATION
- Backup locations and credentials
- Encryption key storage (separate from backups)
- Step-by-step restore procedure
- Contact list for escalation---
Version Differences
| Feature | v14 | v15 | v16 |
|---|---|---|---|
--compress flag | Yes | Yes | Yes |
--only / --exclude | Yes | Yes | Yes |
| S3 Backup Settings | Yes | Yes | Yes |
| Site-level logs | v13+ | Yes | Yes |
partial-restore command | No | Yes | Yes |
---
Reference Files
| File | Contents |
|---|---|
| examples.md | Complete backup/restore scripts |
| anti-patterns.md | Common backup mistakes |
| workflows.md | Step-by-step backup workflows |
Related Skills
frappe-ops-deployment— Production deployment (includes backup in update workflow)frappe-ops-performance— Performance tuningfrappe-ops-bench— Bench CLI referencefrappe-ops-upgrades— Version upgrade procedures (backup required)
Backup Anti-Patterns
1. Never testing restore from backups
# WRONG — assuming backups work because the command succeeded
bench backup --with-files
# "We have backups!" — but have you ever restored one?
# CORRECT — ALWAYS test restore regularly
bench new-site test-restore.localhost --db-root-password $DB_ROOT_PW --admin-password test
bench --site test-restore.localhost restore /path/to/backup.sql.gz --db-root-password $DB_ROOT_PW
bench --site test-restore.localhost migrate
# Verify data, then drop the test site
bench drop-site test-restore.localhost --db-root-password $DB_ROOT_PW --forceWhy: Corrupt backups, incompatible versions, and missing files are only discovered during restore. A backup that cannot be restored is worthless.
2. Database-only backup before major changes
# WRONG — forgetting --with-files before upgrade
bench backup
bench update
# CORRECT — ALWAYS include files before upgrades
bench backup --with-files --compress
bench update --pull --patch --build --requirementsWhy: Without --with-files, uploaded documents, images, and private attachments are not backed up. Restoring database without files creates broken file references.
3. Storing backups only on the same server
# WRONG — backups in sites/{site}/private/backups/ only
# Server disk failure = data AND backups lost
# CORRECT — offsite copies
bench backup --with-files --compress
aws s3 sync sites/mysite.com/private/backups/ s3://my-backups/
# OR use S3 Backup Settings DocType for automated offsite backups4. No backup rotation / unlimited retention
# WRONG — backups accumulate until disk is full
bench setup backups
# Months later: disk full, site down
# CORRECT — implement retention policy
# Delete local backups older than 7 days
find sites/mysite.com/private/backups/ -type f -mtime +7 -delete
# Keep 30 days on S3, then delete5. Storing encryption keys with the backups
# WRONG — key stored next to encrypted backup
gpg --symmetric backup.sql.gz
echo "password123" > /mnt/backups/encryption-key.txt
# Attacker who accesses backups also gets the key
# CORRECT — store keys in separate location
# Use a password manager, HSM, or separate secrets vault
# NEVER store decryption keys in the same storage as encrypted backups6. Using --force on restore to bypass version warnings
# WRONG — forcing a downgrade restore
bench --site mysite.com restore backup-from-v15.sql.gz --force
# Database schema incompatible, site broken
# CORRECT — ALWAYS restore to matching version
# Install same Frappe/ERPNext version as the backup source
# Then restore, then upgrade if neededWhy: Downgrades are NOT supported. Schema changes between versions are one-directional. Forcing a downgrade corrupts data.
7. Not backing up site_config.json separately
# WRONG — only backing up database
bench backup
# site_config.json contains DB credentials, encryption key, custom settings
# CORRECT — bench backup includes site_config automatically
bench backup --with-files
# Verify: ls sites/mysite.com/private/backups/*site_config*8. Running backups during peak hours
# WRONG — backup during business hours
# 0 9 * * * bench backup --with-files (9 AM — peak usage)
# Large database locks can slow the application
# CORRECT — schedule during off-peak hours
# 0 2 * * * bench backup --with-files (2 AM — minimal usage)9. Ignoring backup failures silently
# WRONG — no error handling in backup scripts
bench backup --with-files
aws s3 cp backup.sql.gz s3://bucket/
# If either fails, nobody knows
# CORRECT — check exit codes, send alerts
bench backup --with-files || {
echo "BACKUP FAILED" | mail -s "Frappe Backup Alert" admin@example.com
exit 1
}10. Not excluding unnecessary DocTypes for faster backups
# WRONG — backing up everything including logs
bench backup # Includes Error Log (millions of rows), Activity Log, etc.
# CORRECT — exclude log DocTypes for faster, smaller backups
bench backup --exclude "Error Log,Activity Log,Route History,Access Log,Scheduled Job Log"
# Keep full backups weekly, exclude logs for daily backupsBackup & Restore Examples
Basic Backup Commands
# Database-only backup (fastest)
bench --site mysite.com backup
# Output: sites/mysite.com/private/backups/20240115_120000_abc123-database.sql.gz
# Full backup with files
bench --site mysite.com backup --with-files
# Creates:
# - *-database.sql.gz (database dump)
# - *-site_config_backup.json (site configuration)
# - *-files.tar (public files)
# - *-private-files.tar (private files)
# Compressed backup (.tgz)
bench --site mysite.com backup --with-files --compress
# Files archives use .tgz instead of .tar
# Selective backup — only specific DocTypes
bench --site mysite.com backup --only "Sales Invoice,Purchase Invoice,Journal Entry"
# Exclude large/unnecessary DocTypes
bench --site mysite.com backup --exclude "Error Log,Activity Log,Route History"
# Custom backup directory
bench --site mysite.com backup --with-files --backup-path /mnt/external/backups/Restore Examples
# Basic restore (database only)
bench --site mysite.com restore \
sites/mysite.com/private/backups/20240115_120000_abc123-database.sql.gz
# Full restore with files
bench --site mysite.com restore \
/path/to/20240115_120000_abc123-database.sql.gz \
--with-public-files /path/to/20240115_120000_abc123-files.tar \
--with-private-files /path/to/20240115_120000_abc123-private-files.tar
# Restore with new admin password
bench --site mysite.com restore \
/path/to/backup.sql.gz \
--admin-password NewSecurePassword123
# Restore with custom database name
bench --site mysite.com restore \
/path/to/backup.sql.gz \
--db-name custom_db_name \
--db-root-password YOUR_ROOT_PASSWORD
# Restore and install apps
bench --site mysite.com restore \
/path/to/backup.sql.gz \
--install-app erpnext \
--install-app custom_appAutomated Backup Script with S3 Upload
#!/bin/bash
# frappe-backup-to-s3.sh
# Run via cron: 0 2 * * * /home/frappe/scripts/frappe-backup-to-s3.sh
set -euo pipefail
BENCH_DIR="/home/frappe/frappe-bench"
SITE="mysite.com"
S3_BUCKET="s3://company-frappe-backups"
RETENTION_DAYS=30
LOG="/var/log/frappe-backup.log"
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG"; }
cd "$BENCH_DIR"
log "Starting backup for $SITE"
# Create backup
bench --site "$SITE" backup --with-files --compress 2>> "$LOG"
# Find latest backup files
BACKUP_DIR="sites/$SITE/private/backups"
LATEST_DB=$(ls -t "$BACKUP_DIR"/*-database.sql.gz 2>/dev/null | head -1)
LATEST_FILES=$(ls -t "$BACKUP_DIR"/*-files.tgz 2>/dev/null | head -1)
LATEST_PRIVATE=$(ls -t "$BACKUP_DIR"/*-private-files.tgz 2>/dev/null | head -1)
LATEST_CONFIG=$(ls -t "$BACKUP_DIR"/*-site_config_backup.json 2>/dev/null | head -1)
# Upload to S3
DATE_DIR=$(date +%Y-%m-%d)
for f in "$LATEST_DB" "$LATEST_FILES" "$LATEST_PRIVATE" "$LATEST_CONFIG"; do
if [ -n "$f" ] && [ -f "$f" ]; then
aws s3 cp "$f" "$S3_BUCKET/$SITE/$DATE_DIR/" >> "$LOG" 2>&1
fi
done
# Cleanup old local backups
find "$BACKUP_DIR" -type f -mtime +7 -delete
# Cleanup old S3 backups
aws s3 ls "$S3_BUCKET/$SITE/" | while read -r line; do
DIR=$(echo "$line" | awk '{print $2}' | tr -d '/')
if [ -n "$DIR" ]; then
DIR_DATE=$(date -d "$DIR" +%s 2>/dev/null || echo 0)
CUTOFF=$(date -d "$RETENTION_DAYS days ago" +%s)
if [ "$DIR_DATE" -lt "$CUTOFF" ] && [ "$DIR_DATE" -gt 0 ]; then
aws s3 rm --recursive "$S3_BUCKET/$SITE/$DIR/"
log "Removed old backup: $DIR"
fi
fi
done
log "Backup complete for $SITE"Backup Verification Script
#!/bin/bash
# verify-backup.sh — Automated backup integrity test
set -euo pipefail
BENCH_DIR="/home/frappe/frappe-bench"
TEST_SITE="backup-verify.localhost"
DB_ROOT_PASSWORD="your_root_password"
BACKUP_SQL="$1" # Pass backup file as argument
cd "$BENCH_DIR"
echo "Creating test site..."
bench new-site "$TEST_SITE" \
--db-root-password "$DB_ROOT_PASSWORD" \
--admin-password "testpass" \
--no-mariadb-socket
echo "Restoring backup..."
bench --site "$TEST_SITE" restore "$BACKUP_SQL" \
--db-root-password "$DB_ROOT_PASSWORD" \
--force
echo "Running migration..."
bench --site "$TEST_SITE" migrate
echo "Verifying data integrity..."
bench --site "$TEST_SITE" console <<'PYEOF'
import frappe
# Check critical tables exist and have data
checks = {
"User": frappe.db.count("User"),
"DocType": frappe.db.count("DocType"),
}
for dt, count in checks.items():
assert count > 0, f"FAIL: {dt} has 0 records"
print(f" {dt}: {count} records")
print("\nAll integrity checks PASSED")
PYEOF
echo "Cleaning up test site..."
bench drop-site "$TEST_SITE" \
--db-root-password "$DB_ROOT_PASSWORD" \
--force
echo "Backup verification COMPLETE"Multi-Site Backup Script
#!/bin/bash
# backup-all-sites.sh — Backup all sites in bench
set -euo pipefail
BENCH_DIR="/home/frappe/frappe-bench"
cd "$BENCH_DIR"
SITES=$(ls sites/*/site_config.json 2>/dev/null | xargs -I {} dirname {} | xargs -I {} basename {})
for site in $SITES; do
[ "$site" = "assets" ] && continue
echo "Backing up $site..."
bench --site "$site" backup --with-files --compress || {
echo "WARNING: Backup failed for $site"
continue
}
echo " Done: $site"
done
echo "All site backups complete"Docker Backup and Restore
# Backup from Docker container
docker compose exec backend bench --site mysite.com backup --with-files --compress
# Copy backup out of container
CONTAINER=$(docker compose ps -q backend)
docker cp "$CONTAINER:/home/frappe/frappe-bench/sites/mysite.com/private/backups/" ./backups/
# Restore into Docker container
docker cp ./backups/backup.sql.gz "$CONTAINER:/tmp/"
docker compose exec backend bench --site mysite.com restore /tmp/backup.sql.gz \
--db-root-password "$DB_ROOT_PASSWORD"
docker compose exec backend rm /tmp/backup.sql.gzBackup Workflows
Workflow 1: Setup Automated Daily Backups
1. Choose backup strategy
|
+-- Simple (cron only)?
| $ bench setup backups
| (adds cron entry for every-6-hour backups)
|
+-- Offsite (S3)?
Go to Setup > S3 Backup Settings in ERPNext
Configure: bucket, credentials, frequency
Enable and test
|
2. Verify backup runs
$ ls -la sites/mysite.com/private/backups/
(check timestamps match expected schedule)
|
3. Setup retention cleanup
Add to cron:
0 3 * * * find ~/frappe-bench/sites/*/private/backups/ -mtime +7 -delete
|
4. Setup backup monitoring
Add to cron:
0 8 * * * /home/frappe/scripts/check-backup-age.sh
(alert if latest backup is > 24 hours old)
|
5. Schedule weekly restore test
0 4 * * 0 /home/frappe/scripts/verify-backup.shWorkflow 2: Pre-Update Backup
1. Create full backup with files
$ bench --site mysite.com backup --with-files --compress
|
2. Verify backup was created
$ ls -la sites/mysite.com/private/backups/ | tail -5
|
3. Copy backup to safe location
$ cp sites/mysite.com/private/backups/latest* /mnt/safe-backup/
|
4. Proceed with update
$ bench update --pull --patch --build --requirements
|
5. If update fails — restore
$ bench --site mysite.com restore /mnt/safe-backup/backup.sql.gz \
--with-public-files /mnt/safe-backup/files.tar \
--with-private-files /mnt/safe-backup/private-files.tarWorkflow 3: Disaster Recovery
SCENARIO: Production server lost (hardware failure, ransomware, etc.)
1. Provision new server
Same OS, install Docker or bench dependencies
|
2. Install Frappe/ERPNext (SAME version as backup)
$ bench init frappe-bench --frappe-branch version-15
$ cd frappe-bench
$ bench get-app erpnext --branch version-15
|
3. Create blank site
$ bench new-site mysite.com --db-root-password $DB_PW --admin-password temp
|
4. Download latest backup from offsite storage
$ aws s3 cp s3://backups/mysite.com/latest/ /tmp/restore/ --recursive
|
5. Decrypt if encrypted
$ gpg --decrypt /tmp/restore/backup.sql.gz.gpg > /tmp/restore/backup.sql.gz
|
6. Restore
$ bench --site mysite.com restore /tmp/restore/backup.sql.gz \
--with-public-files /tmp/restore/files.tar \
--with-private-files /tmp/restore/private-files.tar \
--db-root-password $DB_PW
|
7. Run migrations
$ bench --site mysite.com migrate
|
8. Setup production
$ sudo bench setup production $(whoami)
|
9. Update DNS to point to new server
|
10. Setup SSL
$ sudo -H bench setup lets-encrypt mysite.com
|
11. Verify functionality
Login as Administrator, check key workflows
|
12. Post-mortem
Document what happened, update DR planWorkflow 4: Clone Production to Staging
1. Backup production
$ bench --site prod.example.com backup --with-files --compress
|
2. Copy backup to staging server
$ scp sites/prod.example.com/private/backups/latest* staging:/tmp/
|
3. On staging server — create site from backup
$ bench new-site staging.example.com \
--db-root-password $DB_PW --admin-password staging123
$ bench --site staging.example.com restore /tmp/backup.sql.gz \
--with-public-files /tmp/files.tgz \
--with-private-files /tmp/private-files.tgz \
--db-root-password $DB_PW
|
4. Sanitize staging data (CRITICAL for privacy)
$ bench --site staging.example.com console
>>> frappe.db.sql("UPDATE tabUser SET email = CONCAT(name, '@staging.local') WHERE name != 'Administrator'")
>>> frappe.db.commit()
|
5. Clear sensitive settings
$ bench --site staging.example.com set-config \
mail_server "" mail_login "" mail_password ""Workflow 5: Migrate Site Between Servers
1. Backup source site
$ bench --site mysite.com backup --with-files --compress
|
2. Transfer backup to destination
$ rsync -avz sites/mysite.com/private/backups/latest* \
destination:/home/frappe/frappe-bench/
|
3. On destination — restore
$ bench new-site mysite.com --db-root-password $DB_PW --admin-password temp
$ bench --site mysite.com restore /home/frappe/frappe-bench/backup.sql.gz \
--with-public-files /home/frappe/frappe-bench/files.tgz \
--with-private-files /home/frappe/frappe-bench/private-files.tgz \
--db-root-password $DB_PW
|
4. Run migrations and build
$ bench --site mysite.com migrate
$ bench build
|
5. Setup production on new server
$ sudo bench setup production $(whoami)
|
6. Update DNS to point to new server
Wait for propagation (check with dig mysite.com)
|
7. Verify and decommission old server