# Create a timestamped backup
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
tar -czf ~/openclaw-backup-$TIMESTAMP.tar.gz \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null echo "Backup saved to ~/openclaw-backup-$TIMESTAMP.tar.gz"
ls -lh ~/openclaw-backup-$TIMESTAMP.tar.gz
# Create a timestamped backup
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
tar -czf ~/openclaw-backup-$TIMESTAMP.tar.gz \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null echo "Backup saved to ~/openclaw-backup-$TIMESTAMP.tar.gz"
ls -lh ~/openclaw-backup-$TIMESTAMP.tar.gz
# Create a timestamped backup
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
tar -czf ~/openclaw-backup-$TIMESTAMP.tar.gz \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null echo "Backup saved to ~/openclaw-backup-$TIMESTAMP.tar.gz"
ls -lh ~/openclaw-backup-$TIMESTAMP.tar.gz
# Copy to another machine via SCP
scp ~/openclaw-backup-$TIMESTAMP.tar.gz user@backup-server:/backups/ # Or copy to a USB drive
cp ~/openclaw-backup-$TIMESTAMP.tar.gz /Volumes/USB-Drive/backups/
# Copy to another machine via SCP
scp ~/openclaw-backup-$TIMESTAMP.tar.gz user@backup-server:/backups/ # Or copy to a USB drive
cp ~/openclaw-backup-$TIMESTAMP.tar.gz /Volumes/USB-Drive/backups/
# Copy to another machine via SCP
scp ~/openclaw-backup-$TIMESTAMP.tar.gz user@backup-server:/backups/ # Or copy to a USB drive
cp ~/openclaw-backup-$TIMESTAMP.tar.gz /Volumes/USB-Drive/backups/
# List volumes
-weight: 500;">docker volume ls | grep openclaw # Back up a named volume to a tar file
-weight: 500;">docker run --rm \ -v openclaw_data:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-data-$(date +%Y%m%d).tar.gz -C /source . # Back up another volume
-weight: 500;">docker run --rm \ -v openclaw_config:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-config-$(date +%Y%m%d).tar.gz -C /source .
# List volumes
-weight: 500;">docker volume ls | grep openclaw # Back up a named volume to a tar file
-weight: 500;">docker run --rm \ -v openclaw_data:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-data-$(date +%Y%m%d).tar.gz -C /source . # Back up another volume
-weight: 500;">docker run --rm \ -v openclaw_config:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-config-$(date +%Y%m%d).tar.gz -C /source .
# List volumes
-weight: 500;">docker volume ls | grep openclaw # Back up a named volume to a tar file
-weight: 500;">docker run --rm \ -v openclaw_data:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-data-$(date +%Y%m%d).tar.gz -C /source . # Back up another volume
-weight: 500;">docker run --rm \ -v openclaw_config:/source:ro \ -v ~/backups:/backup \ alpine tar -czf /backup/openclaw-config-$(date +%Y%m%d).tar.gz -C /source .
cd ~/openclaw # Initialize -weight: 500;">git
-weight: 500;">git init # Create .gitignore to exclude sensitive files and large binaries
cat > .gitignore << 'EOF'
# Never commit API keys
.env # Exclude logs
logs/ # Exclude large binary files in data (optional)
data/*.db-wal
data/*.db-shm # Exclude Docker files
-weight: 500;">docker-compose.yml
EOF # Initial commit
-weight: 500;">git add -A
-weight: 500;">git commit -m "Initial OpenClaw backup"
cd ~/openclaw # Initialize -weight: 500;">git
-weight: 500;">git init # Create .gitignore to exclude sensitive files and large binaries
cat > .gitignore << 'EOF'
# Never commit API keys
.env # Exclude logs
logs/ # Exclude large binary files in data (optional)
data/*.db-wal
data/*.db-shm # Exclude Docker files
-weight: 500;">docker-compose.yml
EOF # Initial commit
-weight: 500;">git add -A
-weight: 500;">git commit -m "Initial OpenClaw backup"
cd ~/openclaw # Initialize -weight: 500;">git
-weight: 500;">git init # Create .gitignore to exclude sensitive files and large binaries
cat > .gitignore << 'EOF'
# Never commit API keys
.env # Exclude logs
logs/ # Exclude large binary files in data (optional)
data/*.db-wal
data/*.db-shm # Exclude Docker files
-weight: 500;">docker-compose.yml
EOF # Initial commit
-weight: 500;">git add -A
-weight: 500;">git commit -m "Initial OpenClaw backup"
# Create a private repo on GitHub, GitLab, or Gitea
# Then add as remote
-weight: 500;">git remote add origin -weight: 500;">git@github.com:your-username/openclaw-backup.-weight: 500;">git
-weight: 500;">git push -u origin main
# Create a private repo on GitHub, GitLab, or Gitea
# Then add as remote
-weight: 500;">git remote add origin -weight: 500;">git@github.com:your-username/openclaw-backup.-weight: 500;">git
-weight: 500;">git push -u origin main
# Create a private repo on GitHub, GitLab, or Gitea
# Then add as remote
-weight: 500;">git remote add origin -weight: 500;">git@github.com:your-username/openclaw-backup.-weight: 500;">git
-weight: 500;">git push -u origin main
# Add to crontab: commit and push daily at 2 AM
0 2 * * * cd ~/openclaw && -weight: 500;">git add -A && -weight: 500;">git commit -m "Daily backup $(date +\%Y\%m\%d)" 2>/dev/null && -weight: 500;">git push origin main 2>/dev/null
# Add to crontab: commit and push daily at 2 AM
0 2 * * * cd ~/openclaw && -weight: 500;">git add -A && -weight: 500;">git commit -m "Daily backup $(date +\%Y\%m\%d)" 2>/dev/null && -weight: 500;">git push origin main 2>/dev/null
# Add to crontab: commit and push daily at 2 AM
0 2 * * * cd ~/openclaw && -weight: 500;">git add -A && -weight: 500;">git commit -m "Daily backup $(date +\%Y\%m\%d)" 2>/dev/null && -weight: 500;">git push origin main 2>/dev/null
# Encrypt .env before backing up
gpg --symmetric --cipher-algo AES256 -o ~/openclaw/.env.gpg ~/openclaw/.env # Add .env.gpg to -weight: 500;">git (encrypted version is safe to commit)
-weight: 500;">git add .env.gpg
-weight: 500;">git commit -m "Update encrypted .env backup"
# Encrypt .env before backing up
gpg --symmetric --cipher-algo AES256 -o ~/openclaw/.env.gpg ~/openclaw/.env # Add .env.gpg to -weight: 500;">git (encrypted version is safe to commit)
-weight: 500;">git add .env.gpg
-weight: 500;">git commit -m "Update encrypted .env backup"
# Encrypt .env before backing up
gpg --symmetric --cipher-algo AES256 -o ~/openclaw/.env.gpg ~/openclaw/.env # Add .env.gpg to -weight: 500;">git (encrypted version is safe to commit)
-weight: 500;">git add .env.gpg
-weight: 500;">git commit -m "Update encrypted .env backup"
# Linux/macOS
-weight: 500;">curl https://rclone.org/-weight: 500;">install.sh | -weight: 600;">sudo bash # Or via Homebrew on macOS
-weight: 500;">brew -weight: 500;">install rclone
# Linux/macOS
-weight: 500;">curl https://rclone.org/-weight: 500;">install.sh | -weight: 600;">sudo bash # Or via Homebrew on macOS
-weight: 500;">brew -weight: 500;">install rclone
# Linux/macOS
-weight: 500;">curl https://rclone.org/-weight: 500;">install.sh | -weight: 600;">sudo bash # Or via Homebrew on macOS
-weight: 500;">brew -weight: 500;">install rclone
rclone config
# Follow the interactive setup to add a Google Drive remote
# Name it "gdrive" or similar
rclone config
# Follow the interactive setup to add a Google Drive remote
# Name it "gdrive" or similar
rclone config
# Follow the interactive setup to add a Google Drive remote
# Name it "gdrive" or similar
# Sync backup directory to cloud
rclone sync ~/backups/openclaw gdrive:openclaw-backups/ # Or sync directly from the OpenClaw directory (excluding .env)
rclone sync ~/openclaw gdrive:openclaw-backups/ \ --exclude ".env" \ --exclude "logs/**" \ --exclude "node_modules/**"
# Sync backup directory to cloud
rclone sync ~/backups/openclaw gdrive:openclaw-backups/ # Or sync directly from the OpenClaw directory (excluding .env)
rclone sync ~/openclaw gdrive:openclaw-backups/ \ --exclude ".env" \ --exclude "logs/**" \ --exclude "node_modules/**"
# Sync backup directory to cloud
rclone sync ~/backups/openclaw gdrive:openclaw-backups/ # Or sync directly from the OpenClaw directory (excluding .env)
rclone sync ~/openclaw gdrive:openclaw-backups/ \ --exclude ".env" \ --exclude "logs/**" \ --exclude "node_modules/**"
rclone sync ~/backups/openclaw s3:my-bucket/openclaw-backups/
rclone sync ~/backups/openclaw s3:my-bucket/openclaw-backups/
rclone sync ~/backups/openclaw s3:my-bucket/openclaw-backups/
cat > ~/openclaw-backup.sh << 'SCRIPT'
#!/bin/bash
set -e BACKUP_DIR=~/backups/openclaw
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ARCHIVE=$BACKUP_DIR/openclaw-$TIMESTAMP.tar.gz # Create backup directory
mkdir -p $BACKUP_DIR # Create compressed archive
tar -czf $ARCHIVE \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null # Remove backups older than 30 days
find $BACKUP_DIR -name "openclaw-*.tar.gz" -mtime +30 -delete # Optional: sync to cloud
# rclone copy $ARCHIVE gdrive:openclaw-backups/ echo "$(date): Backup created at $ARCHIVE" >> ~/backups/openclaw-backup.log
SCRIPT chmod +x ~/openclaw-backup.sh
cat > ~/openclaw-backup.sh << 'SCRIPT'
#!/bin/bash
set -e BACKUP_DIR=~/backups/openclaw
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ARCHIVE=$BACKUP_DIR/openclaw-$TIMESTAMP.tar.gz # Create backup directory
mkdir -p $BACKUP_DIR # Create compressed archive
tar -czf $ARCHIVE \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null # Remove backups older than 30 days
find $BACKUP_DIR -name "openclaw-*.tar.gz" -mtime +30 -delete # Optional: sync to cloud
# rclone copy $ARCHIVE gdrive:openclaw-backups/ echo "$(date): Backup created at $ARCHIVE" >> ~/backups/openclaw-backup.log
SCRIPT chmod +x ~/openclaw-backup.sh
cat > ~/openclaw-backup.sh << 'SCRIPT'
#!/bin/bash
set -e BACKUP_DIR=~/backups/openclaw
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ARCHIVE=$BACKUP_DIR/openclaw-$TIMESTAMP.tar.gz # Create backup directory
mkdir -p $BACKUP_DIR # Create compressed archive
tar -czf $ARCHIVE \ -C ~/openclaw \ data/ config/ .env skills/ -weight: 500;">docker-compose.yml 2>/dev/null # Remove backups older than 30 days
find $BACKUP_DIR -name "openclaw-*.tar.gz" -mtime +30 -delete # Optional: sync to cloud
# rclone copy $ARCHIVE gdrive:openclaw-backups/ echo "$(date): Backup created at $ARCHIVE" >> ~/backups/openclaw-backup.log
SCRIPT chmod +x ~/openclaw-backup.sh
# Edit crontab
crontab -e # Add daily backup at 3 AM
0 3 * * * ~/openclaw-backup.sh
# Edit crontab
crontab -e # Add daily backup at 3 AM
0 3 * * * ~/openclaw-backup.sh
# Edit crontab
crontab -e # Add daily backup at 3 AM
0 3 * * * ~/openclaw-backup.sh
# Stop OpenClaw
-weight: 500;">docker compose down # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">stop openclaw # Remove current data (or move it aside)
mv ~/openclaw/data ~/openclaw/data.old
mv ~/openclaw/config ~/openclaw/config.old # Extract backup
tar -xzf ~/backups/openclaw/openclaw-20260324-030000.tar.gz -C ~/openclaw # Restore .env if needed
# cp ~/backups/openclaw/.env.backup ~/openclaw/.env # Start OpenClaw
-weight: 500;">docker compose up -d # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start openclaw # Verify
-weight: 500;">docker compose logs -f --tail=20 openclaw
# Stop OpenClaw
-weight: 500;">docker compose down # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">stop openclaw # Remove current data (or move it aside)
mv ~/openclaw/data ~/openclaw/data.old
mv ~/openclaw/config ~/openclaw/config.old # Extract backup
tar -xzf ~/backups/openclaw/openclaw-20260324-030000.tar.gz -C ~/openclaw # Restore .env if needed
# cp ~/backups/openclaw/.env.backup ~/openclaw/.env # Start OpenClaw
-weight: 500;">docker compose up -d # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start openclaw # Verify
-weight: 500;">docker compose logs -f --tail=20 openclaw
# Stop OpenClaw
-weight: 500;">docker compose down # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">stop openclaw # Remove current data (or move it aside)
mv ~/openclaw/data ~/openclaw/data.old
mv ~/openclaw/config ~/openclaw/config.old # Extract backup
tar -xzf ~/backups/openclaw/openclaw-20260324-030000.tar.gz -C ~/openclaw # Restore .env if needed
# cp ~/backups/openclaw/.env.backup ~/openclaw/.env # Start OpenClaw
-weight: 500;">docker compose up -d # or: -weight: 600;">sudo -weight: 500;">systemctl -weight: 500;">start openclaw # Verify
-weight: 500;">docker compose logs -f --tail=20 openclaw
# Stop OpenClaw
-weight: 500;">docker compose down # Restore to a specific commit
cd ~/openclaw
-weight: 500;">git log --oneline # find the commit you want
-weight: 500;">git checkout abc1234 -- data/ config/ skills/ # Decrypt .env if using gpg backup
gpg --decrypt .env.gpg > .env # Start OpenClaw
-weight: 500;">docker compose up -d
# Stop OpenClaw
-weight: 500;">docker compose down # Restore to a specific commit
cd ~/openclaw
-weight: 500;">git log --oneline # find the commit you want
-weight: 500;">git checkout abc1234 -- data/ config/ skills/ # Decrypt .env if using gpg backup
gpg --decrypt .env.gpg > .env # Start OpenClaw
-weight: 500;">docker compose up -d
# Stop OpenClaw
-weight: 500;">docker compose down # Restore to a specific commit
cd ~/openclaw
-weight: 500;">git log --oneline # find the commit you want
-weight: 500;">git checkout abc1234 -- data/ config/ skills/ # Decrypt .env if using gpg backup
gpg --decrypt .env.gpg > .env # Start OpenClaw
-weight: 500;">docker compose up -d
# Stop containers
-weight: 500;">docker compose down # Restore volume from backup
-weight: 500;">docker run --rm \ -v openclaw_data:/target \ -v ~/backups:/backup \ alpine sh -c "rm -rf /target/* && tar -xzf /backup/openclaw-data-20260324.tar.gz -C /target" # Start containers
-weight: 500;">docker compose up -d
# Stop containers
-weight: 500;">docker compose down # Restore volume from backup
-weight: 500;">docker run --rm \ -v openclaw_data:/target \ -v ~/backups:/backup \ alpine sh -c "rm -rf /target/* && tar -xzf /backup/openclaw-data-20260324.tar.gz -C /target" # Start containers
-weight: 500;">docker compose up -d
# Stop containers
-weight: 500;">docker compose down # Restore volume from backup
-weight: 500;">docker run --rm \ -v openclaw_data:/target \ -v ~/backups:/backup \ alpine sh -c "rm -rf /target/* && tar -xzf /backup/openclaw-data-20260324.tar.gz -C /target" # Start containers
-weight: 500;">docker compose up -d
# On old server: create backup and transfer
tar -czf /tmp/openclaw-migration.tar.gz -C ~/openclaw data/ config/ .env skills/ -weight: 500;">docker-compose.yml
scp /tmp/openclaw-migration.tar.gz user@new-server:/tmp/ # On new server: -weight: 500;">install and restore
mkdir -p ~/openclaw && cd ~/openclaw
tar -xzf /tmp/openclaw-migration.tar.gz
-weight: 500;">docker compose up -d
# On old server: create backup and transfer
tar -czf /tmp/openclaw-migration.tar.gz -C ~/openclaw data/ config/ .env skills/ -weight: 500;">docker-compose.yml
scp /tmp/openclaw-migration.tar.gz user@new-server:/tmp/ # On new server: -weight: 500;">install and restore
mkdir -p ~/openclaw && cd ~/openclaw
tar -xzf /tmp/openclaw-migration.tar.gz
-weight: 500;">docker compose up -d
# On old server: create backup and transfer
tar -czf /tmp/openclaw-migration.tar.gz -C ~/openclaw data/ config/ .env skills/ -weight: 500;">docker-compose.yml
scp /tmp/openclaw-migration.tar.gz user@new-server:/tmp/ # On new server: -weight: 500;">install and restore
mkdir -p ~/openclaw && cd ~/openclaw
tar -xzf /tmp/openclaw-migration.tar.gz
-weight: 500;">docker compose up -d - Back up on the old server: Create a full backup archive including data, config, .env, skills, and -weight: 500;">docker-compose.yml.
- Transfer to the new server: Use scp, rsync, or a cloud storage intermediary to move the backup file.
- Install OpenClaw on the new server: Follow the installation guide for your preferred method (Docker or -weight: 500;">npm).
- Restore the backup: Extract the backup archive into the new OpenClaw directory.
- Update configurations: Change any server-specific settings (IP addresses, domain names, ports) in the .env file and config.
- Start and verify: Start OpenClaw and verify all integrations, cron jobs, and skills are working. - Follow the 3-2-1 rule: Keep 3 copies of your data, on 2 different storage types, with 1 copy off-site. For example: local disk + external drive + cloud storage.
- Test your restores. A backup you have never tested restoring from is not a reliable backup. Every few months, spin up a test instance and restore from backup to verify the process works.
- Encrypt sensitive backups. Backups containing your .env file have your API keys. Encrypt before storing off-site.
- Automate everything. Manual backups are backups you will forget to make. Set up a cron job and cloud sync so backups happen without your intervention.
- Monitor your backups. Check that backup files are being created (the backup log helps). Set up an alert if backups -weight: 500;">stop running — a silent failure is the worst kind.
- Keep retention reasonable. 30 days of daily backups is sufficient for most operators. Longer retention for weekly snapshots (keep 12 weeks) provides deeper history without using excessive storage.