--- title: Mailcow Backup and Restore Strategy description: Mailcow backup published: true date: 2026-02-13T22:23:40.797Z tags: editor: markdown dateCreated: 2026-02-11T01:20:59.127Z --- # Mailcow Backup and Recovery Guide ## Overview This document provides comprehensive backup and recovery procedures for Mailcow email server. Since Mailcow is **not running on ZFS or BTRFS**, snapshots are not available and we rely on Mailcow's native backup script combined with Kopia for offsite storage in vaults. ## Quick Reference ### Common Backup Commands ```bash # Run a manual backup (all components) cd /opt/mailcow-dockerized MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \ ./helper-scripts/backup_and_restore.sh backup all --delete-days 7 # Backup with multithreading (faster) THREADS=4 MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \ ./helper-scripts/backup_and_restore.sh backup all --delete-days 7 # List Kopia snapshots kopia snapshot list --tags mailcow # View backup logs tail -f /var/log/mailcow-backup.log ``` ### Common Restore Commands ```bash # Restore using mailcow native script (interactive) cd /opt/mailcow-dockerized ./helper-scripts/backup_and_restore.sh restore # Restore from Kopia to new server kopia snapshot list --tags tier1-backup kopia restore /opt/mailcow-backups/ # Check container status after restore docker compose ps docker compose logs -f ``` ## Critical Components to Backup ### 1. Docker Compose File - **Location**: `/opt/mailcow-dockerized/docker-compose.yml` (or your installation path) - **Purpose**: Defines all containers, networks, and volumes - **Importance**: Critical for recreating the exact container configuration ### 2. Configuration Files - **Primary Config**: `/opt/mailcow-dockerized/mailcow.conf` - **Additional Configs**: - `/opt/mailcow-dockerized/data/conf/` (all subdirectories) - Custom SSL certificates if not using Let's Encrypt - Any override files (e.g., `docker-compose.override.yml`) ### 3. Database - **MySQL/MariaDB Data**: Contains all mailbox configurations, users, domains, aliases, settings - **Docker Volume**: `mailcowdockerized_mysql-vol` - **Container Path**: `/var/lib/mysql` ### 4. Email Data - **Maildir Storage**: All actual email messages - **Docker Volume**: `mailcowdockerized_vmail-vol` - **Container Path**: `/var/vmail` - **Size**: Typically the largest component ### 5. Additional Important Data - **Redis Data**: `mailcowdockerized_redis-vol` (cache and sessions) - **Rspamd Data**: `mailcowdockerized_rspamd-vol` (spam learning) - **Crypt Data**: `mailcowdockerized_crypt-vol` (if using mailbox encryption) - **Postfix Queue**: `mailcowdockerized_postfix-vol` (queued/deferred mail) ## Backup Strategy ### Two-Tier Backup Approach We use a **two-tier approach** combining Mailcow's native backup script with Kopia for offsite storage: 1. **Tier 1 (Local)**: Mailcow's `backup_and_restore.sh` script creates consistent, component-level backups 2. **Tier 2 (Offsite)**: Kopia snapshots the local backups and syncs to vaults #### Why This Approach? - **Best of both worlds**: Native script ensures mailcow-specific consistency, Kopia provides deduplication and offsite protection - **Component-level restore**: Can restore individual components (just vmail, just mysql, etc.) using mailcow script - **Disaster recovery**: Full system restore from Kopia backups on new server - **Efficient storage**: Kopia's deduplication reduces storage needs for offsite copies #### Backup Frequency - **Daily**: Mailcow native backup runs at 2 AM - **Daily**: Kopia snapshot of backups runs at 3 AM - **Retention (Local)**: 7 days of mailcow backups (managed by script) - **Retention (Kopia/Offsite)**: 30 daily, 12 weekly, 12 monthly ### Mailcow Native Backup Script Mailcow includes `/opt/mailcow-dockerized/helper-scripts/backup_and_restore.sh` which handles: - **vmail**: Email data (mailboxes) - **mysql**: Database (using mariabackup for consistency) - **redis**: Redis database - **rspamd**: Spam filter learning data - **crypt**: Encryption data - **postfix**: Mail queue **Key Features:** - Uses `mariabackup` (hot backup without stopping MySQL) - Supports multithreading for faster backups - Architecture-aware (handles x86/ARM differences) - Built-in cleanup with `--delete-days` parameter - Creates compressed archives (.tar.zst or .tar.gz) ### Setting Up Mailcow Backups #### Prereq: Make sure you are connected to the repository, ```bash sudo kopia repository connect server --url=https://192.168.5.10:51516 --override-username=admin --server-cert-fingerprint=696a4999f594b5273a174fd7cab677d8dd1628f9b9d27e557daa87103ee064b2 ``` #### Step 1: Configure Backup Location Set the backup destination via environment variable or in mailcow.conf: ```bash # Option 1: Set environment variable (preferred for automation) export MAILCOW_BACKUP_LOCATION="/opt/mailcow-backups" # Option 2: Add to cron job directly (shown in automated script below) ``` Create the backup directory: ```bash mkdir -p /opt/mailcow-backups chown -R root:root /opt/mailcow-backups chmod 777 /opt/mailcow-backups ``` #### Step 2: Manual Backup Commands ```bash cd /opt/mailcow-dockerized # Backup all components, delete backups older than 7 days MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \ ./helper-scripts/backup_and_restore.sh backup all --delete-days 7 # Backup with multithreading (faster for large mailboxes) THREADS=4 MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \ ./helper-scripts/backup_and_restore.sh backup all --delete-days 7 # Backup specific components only MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \ ./helper-scripts/backup_and_restore.sh backup vmail mysql --delete-days 7 ``` **What gets created:** - Backup directory: `/opt/mailcow-backups/mailcow-YYYY-MM-DD-HH-MM-SS/` - Contains: `.tar.zst` compressed archives for each component - Plus: `mailcow.conf` copy for restore reference #### Step 3: Automated Backup Script Create `/opt/scripts/backup-mailcow.sh`: ```bash #!/bin/bash # Mailcow Automated Backup Script # This creates mailcow native backups, then snapshots them with Kopia for offsite storage set -e BACKUP_DATE=$(date +%Y%m%d_%H%M%S) LOG_FILE="/var/log/mailcow-backup.log" MAILCOW_DIR="/opt/mailcow-dockerized" BACKUP_DIR="/opt/mailcow-backups" THREADS=4 # Adjust based on your CPU cores KEEP_DAYS=7 # Keep local mailcow backups for 7 days echo "[${BACKUP_DATE}] ========================================" | tee -a "$LOG_FILE" echo "[${BACKUP_DATE}] Starting Mailcow backup process" | tee -a "$LOG_FILE" # Step 1: Run mailcow's native backup script echo "[${BACKUP_DATE}] Running mailcow native backup..." | tee -a "$LOG_FILE" cd "$MAILCOW_DIR" # Run the backup with multithreading THREADS=${THREADS} MAILCOW_BACKUP_LOCATION=${BACKUP_DIR} \ ./helper-scripts/backup_and_restore.sh backup all --delete-days ${KEEP_DAYS} \ 2>&1 | tee -a "$LOG_FILE" BACKUP_EXIT=${PIPESTATUS[0]} if [ $BACKUP_EXIT -ne 0 ]; then echo "[${BACKUP_DATE}] ERROR: Mailcow backup failed with exit code ${BACKUP_EXIT}" | tee -a "$LOG_FILE" exit 1 fi echo "[${BACKUP_DATE}] Mailcow native backup completed successfully" | tee -a "$LOG_FILE" # Step 2: Create Kopia snapshot of backup directory echo "[${BACKUP_DATE}] Creating Kopia snapshot..." | tee -a "$LOG_FILE" kopia snapshot create "${BACKUP_DIR}" \ --tags mailcow:tier1-backup \ --description "Mailcow backup ${BACKUP_DATE}" \ 2>&1 | tee -a "$LOG_FILE" KOPIA_EXIT=${PIPESTATUS[0]} if [ $KOPIA_EXIT -ne 0 ]; then echo "[${BACKUP_DATE}] WARNING: Kopia snapshot failed with exit code ${KOPIA_EXIT}" | tee -a "$LOG_FILE" echo "[${BACKUP_DATE}] Local mailcow backup exists but offsite copy may be incomplete" | tee -a "$LOG_FILE" exit 2 fi echo "[${BACKUP_DATE}] Kopia snapshot completed successfully" | tee -a "$LOG_FILE" # Step 3: Also backup the mailcow installation directory (configs, compose files) echo "[${BACKUP_DATE}] Backing up mailcow installation directory..." | tee -a "$LOG_FILE" kopia snapshot create "${MAILCOW_DIR}" \ --tags mailcow,config,docker-compose \ --description "Mailcow config ${BACKUP_DATE}" \ 2>&1 | tee -a "$LOG_FILE" echo "[${BACKUP_DATE}] Backup process completed successfully" | tee -a "$LOG_FILE" echo "[${BACKUP_DATE}] ========================================" | tee -a "$LOG_FILE" # Optional: Send notification on completion # Add your notification method here (email, webhook, etc.) ``` Make it executable: ```bash chmod +x /opt/scripts/backup-mailcow.sh ``` Add to crontab (daily at 2 AM): ```bash # Edit root's crontab crontab -e # Add this line: 0 2 * * * /opt/scripts/backup-mailcow.sh 2>&1 | logger -t mailcow-backup ``` ### Offsite Backup to Vaults After local Kopia snapshots are created, sync to your offsite vaults: ```bash # Option 1: Kopia repository sync (if using multiple Kopia repos) kopia repository sync-to filesystem --path /mnt/vault/mailcow-backup # Option 2: Rsync to vault rsync -avz --delete /backup/kopia-repo/ /mnt/vault/mailcow-backup/ # Option 3: Rclone to remote vault rclone sync /backup/kopia-repo/ vault:mailcow-backup/ ``` ## Recovery Procedures ### Understanding Two Recovery Methods We have **two restore methods** depending on the scenario: 1. **Mailcow Native Restore** (Preferred): For component-level or same-server recovery 2. **Kopia Full Restore**: For complete disaster recovery to a new server ### Method 1: Mailcow Native Restore (Recommended) Use this method when: - Restoring on the same/similar server - Restoring specific components (just email, just database, etc.) - Recovering from local mailcow backups #### Step 1: List Available Backups ```bash cd /opt/mailcow-dockerized # Run the restore script ./helper-scripts/backup_and_restore.sh restore ``` The script will prompt: ``` Backup location (absolute path, starting with /): /opt/mailcow-backups ``` #### Step 2: Select Backup The script displays available backups: ``` Found project name mailcowdockerized [ 1 ] - /opt/mailcow-backups/mailcow-2026-02-09-02-00-14/ [ 2 ] - /opt/mailcow-backups/mailcow-2026-02-10-02-00-08/ ``` Enter the number of the backup to restore. #### Step 3: Select Components Choose what to restore: ``` [ 0 ] - all [ 1 ] - Crypt data [ 2 ] - Rspamd data [ 3 ] - Mail directory (/var/vmail) [ 4 ] - Redis DB [ 5 ] - Postfix data [ 6 ] - SQL DB ``` **Important**: The script will: - Stop mailcow containers automatically - Restore selected components - Handle permissions correctly - Restart containers when done #### Example: Restore Only Email Data ```bash cd /opt/mailcow-dockerized ./helper-scripts/backup_and_restore.sh restore # When prompted: # - Backup location: /opt/mailcow-backups # - Select backup: 2 (most recent) # - Select component: 3 (Mail directory) ``` #### Example: Restore Database Only ```bash cd /opt/mailcow-dockerized ./helper-scripts/backup_and_restore.sh restore # When prompted: # - Backup location: /opt/mailcow-backups # - Select backup: 2 (most recent) # - Select component: 6 (SQL DB) ``` **Note**: For database restore, the script will modify `mailcow.conf` with the database credentials from the backup. Review the changes after restore. ### Method 2: Complete Server Rebuild (Kopia Restore) Use this when recovering to a completely new server or when local backups are unavailable. #### Step 1: Prepare New Server ```bash # Update system apt update && apt upgrade -y # Install Docker curl -fsSL https://get.docker.com | sh systemctl enable docker systemctl start docker # Install Docker Compose apt install docker-compose-plugin -y # Install Kopia curl -s https://kopia.io/signing-key | apt-key add - echo "deb https://packages.kopia.io/apt/ stable main" | tee /etc/apt/sources.list.d/kopia.list apt update apt install kopia -y # Create directory structure mkdir -p /opt/mailcow-dockerized mkdir -p /opt/mailcow-backups/database ``` #### Step 2: Restore Kopia Repository ```bash # Connect to your offsite vault # If vault is mounted: kopia repository connect filesystem --path /mnt/vault/mailcow-backup # If vault is remote: kopia repository connect s3 --bucket=your-bucket --access-key=xxx --secret-access-key=xxx # List available snapshots kopia snapshot list --tags mailcow ``` #### Step 3: Restore Configuration ```bash # Find and restore the config snapshot kopia snapshot list --tags config # Restore to the Mailcow directory kopia restore /opt/mailcow-dockerized/ # Verify critical files ls -la /opt/mailcow-dockerized/mailcow.conf ls -la /opt/mailcow-dockerized/docker-compose.yml ``` #### Step 4: Restore Mailcow Backups Directory ```bash # Restore the entire backup directory from Kopia kopia snapshot list --tags tier1-backup # Restore the most recent backup kopia restore /opt/mailcow-backups/ # Verify backups were restored ls -la /opt/mailcow-backups/ ``` #### Step 5: Run Mailcow Native Restore Now use mailcow's built-in restore script: ```bash cd /opt/mailcow-dockerized # Run the restore script ./helper-scripts/backup_and_restore.sh restore # When prompted: # - Backup location: /opt/mailcow-backups # - Select the most recent backup # - Select [ 0 ] - all (to restore everything) ``` The script will: 1. Stop all mailcow containers 2. Restore all components (vmail, mysql, redis, rspamd, postfix, crypt) 3. Update mailcow.conf with restored database credentials 4. Restart all containers **Alternative: Manual Restore** (if you prefer more control) ```bash cd /opt/mailcow-dockerized # Start containers to create volumes docker compose up -d --no-start docker compose down # Find the most recent backup directory LATEST_BACKUP=$(ls -td /opt/mailcow-backups/mailcow-* | head -1) echo "Restoring from: $LATEST_BACKUP" # Extract each component manually cd "$LATEST_BACKUP" # Restore vmail (email data) docker run --rm \ -v mailcowdockerized_vmail-vol:/backup \ -v "$PWD":/restore \ debian:bookworm-slim \ tar --use-compress-program='zstd -d' -xvf /restore/backup_vmail.tar.zst # Restore MySQL docker run --rm \ -v mailcowdockerized_mysql-vol:/backup \ -v "$PWD":/restore \ mariadb:10.11 \ tar --use-compress-program='zstd -d' -xvf /restore/backup_mysql.tar.zst # Restore Redis docker run --rm \ -v mailcowdockerized_redis-vol:/backup \ -v "$PWD":/restore \ debian:bookworm-slim \ tar --use-compress-program='zstd -d' -xvf /restore/backup_redis.tar.zst # Restore other components similarly (rspamd, postfix, crypt) # ... # Copy mailcow.conf from backup cp "$LATEST_BACKUP/mailcow.conf" /opt/mailcow-dockerized/mailcow.conf ``` #### Step 6: Start and Verify Mailcow ```bash cd /opt/mailcow-dockerized # Pull latest images (or use versions from backup if preferred) docker compose pull # Start all services docker compose up -d # Monitor logs docker compose logs -f ``` #### Step 7: Post-Restore Verification ```bash # Check container status docker compose ps # Test web interface curl -I https://mail.yourdomain.com # Check mail log docker compose logs -f postfix-mailcow # Verify database docker compose exec mysql-mailcow mysql -u root -p$(grep DBROOT mailcow.conf | cut -d'=' -f2) -e "SHOW DATABASES;" # Check email storage docker compose exec dovecot-mailcow ls -lah /var/vmail/ ``` ### Scenario 2: Restore Individual Mailbox To restore a single user's mailbox without affecting others: #### Option A: Using Mailcow Backups (If Available) ```bash cd /opt/mailcow-dockerized # Temporarily mount the backup BACKUP_DIR="/opt/mailcow-backups/mailcow-YYYY-MM-DD-HH-MM-SS" # Extract just the vmail archive to a temporary location mkdir -p /tmp/vmail-restore cd "$BACKUP_DIR" tar --use-compress-program='zstd -d' -xvf backup_vmail.tar.zst -C /tmp/vmail-restore # Find the user's mailbox # Structure: /tmp/vmail-restore/var/vmail/domain.com/user/ ls -la /tmp/vmail-restore/var/vmail/yourdomain.com/ # Copy specific mailbox rsync -av /tmp/vmail-restore/var/vmail/yourdomain.com/user@domain.com/ \ /var/lib/docker/volumes/mailcowdockerized_vmail-vol/_data/yourdomain.com/user@domain.com/ # Fix permissions docker run --rm \ -v mailcowdockerized_vmail-vol:/vmail \ debian:bookworm-slim \ chown -R 5000:5000 /vmail/yourdomain.com/user@domain.com/ # Cleanup rm -rf /tmp/vmail-restore # Restart Dovecot to recognize changes docker compose restart dovecot-mailcow ``` #### Option B: Using Kopia Snapshot (If Local Backups Unavailable) ```bash # Mount the vmail snapshot temporarily mkdir -p /mnt/restore kopia mount /mnt/restore # Find the user's mailbox # Structure: /mnt/restore/domain.com/user/ ls -la /mnt/restore/yourdomain.com/ # Copy specific mailbox rsync -av /mnt/restore/yourdomain.com/user@domain.com/ \ /var/lib/docker/volumes/mailcowdockerized_vmail-vol/_data/yourdomain.com/user@domain.com/ # Fix permissions chown -R 5000:5000 /var/lib/docker/volumes/mailcowdockerized_vmail-vol/_data/yourdomain.com/user@domain.com/ # Unmount kopia unmount /mnt/restore # Restart Dovecot to recognize changes docker compose restart dovecot-mailcow ``` ### Scenario 3: Database Recovery Only If only the database is corrupted but email data is intact: #### Option A: Using Mailcow Native Restore (Recommended) ```bash cd /opt/mailcow-dockerized # Run the restore script ./helper-scripts/backup_and_restore.sh restore # When prompted: # - Backup location: /opt/mailcow-backups # - Select the most recent backup # - Select [ 6 ] - SQL DB (database only) ``` The script will: 1. Stop mailcow 2. Restore the MySQL database from the mariabackup archive 3. Update mailcow.conf with the restored database credentials 4. Restart mailcow #### Option B: Manual Database Restore from Kopia If local backups are unavailable: ```bash cd /opt/mailcow-dockerized # Stop Mailcow docker compose down # Start only MySQL docker compose up -d mysql-mailcow # Wait for MySQL sleep 30 # Restore from Kopia database dump kopia snapshot list --tags database kopia restore /tmp/db-restore/ # Import the dump LATEST_DUMP=$(ls -t /tmp/db-restore/mailcow_*.sql | head -1) docker compose exec -T mysql-mailcow mysql -u root -p$(grep DBROOT mailcow.conf | cut -d'=' -f2) < "$LATEST_DUMP" # Start all services docker compose down docker compose up -d # Verify docker compose logs -f ``` ### Scenario 4: Configuration Recovery Only If you only need to restore configuration files: #### Option A: From Mailcow Backup ```bash # Find the most recent backup LATEST_BACKUP=$(ls -td /opt/mailcow-backups/mailcow-* | head -1) # Stop Mailcow cd /opt/mailcow-dockerized docker compose down # Backup current config (just in case) cp mailcow.conf mailcow.conf.pre-restore cp docker-compose.yml docker-compose.yml.pre-restore # Restore mailcow.conf from backup cp "$LATEST_BACKUP/mailcow.conf" ./mailcow.conf # If you also need other config files from data/conf/, # you would need to extract them from the backup archives # Restart docker compose up -d ``` #### Option B: From Kopia Snapshot ```bash # Restore config snapshot to temporary location kopia restore /tmp/mailcow-restore/ # Stop Mailcow cd /opt/mailcow-dockerized docker compose down # Backup current config (just in case) cp mailcow.conf mailcow.conf.pre-restore cp docker-compose.yml docker-compose.yml.pre-restore # Restore specific files cp /tmp/mailcow-restore/mailcow.conf ./ cp /tmp/mailcow-restore/docker-compose.yml ./ cp -r /tmp/mailcow-restore/data/conf/* ./data/conf/ # Restart docker compose up -d ``` ## Verification and Testing ### Regular Backup Verification Perform monthly restore tests to ensure backups are valid: ```bash # Test restore to temporary location mkdir -p /tmp/backup-test kopia snapshot list --tags mailcow kopia restore /tmp/backup-test/ # Verify files exist and are readable ls -lah /tmp/backup-test/ cat /tmp/backup-test/mailcow.conf # Cleanup rm -rf /tmp/backup-test/ ``` ### Backup Monitoring Script Create `/opt/scripts/check-mailcow-backup.sh`: ```bash #!/bin/bash # Check last backup age LAST_BACKUP=$(kopia snapshot list --tags mailcow --json | jq -r '.[0].startTime') LAST_BACKUP_EPOCH=$(date -d "$LAST_BACKUP" +%s) NOW=$(date +%s) AGE_HOURS=$(( ($NOW - $LAST_BACKUP_EPOCH) / 3600 )) if [ $AGE_HOURS -gt 26 ]; then echo "WARNING: Last Mailcow backup is $AGE_HOURS hours old" # Send alert (email, Slack, etc.) exit 1 else echo "OK: Last backup $AGE_HOURS hours ago" fi ``` ## Disaster Recovery Checklist When disaster strikes, follow this checklist: - [ ] Confirm scope of failure (server, storage, specific component) - [ ] Gather server information (hostname, IP, DNS records) - [ ] Access offsite backup vault - [ ] Provision new server (if needed) - [ ] Install Docker and dependencies - [ ] Connect to Kopia repository - [ ] Restore configurations first - [ ] Restore database - [ ] Restore email data - [ ] Start services and verify - [ ] Test email sending/receiving - [ ] Verify webmail access - [ ] Check DNS records and update if needed - [ ] Document any issues encountered - [ ] Update recovery procedures based on experience ## Important Notes 1. **DNS**: Keep DNS records documented separately. Recovery includes updating DNS if server IP changes. 2. **SSL Certificates**: Let's Encrypt certificates are in the backup but may need renewal. Mailcow will handle this automatically. 3. **Permissions**: Docker volumes have specific UID/GID requirements: - vmail: `5000:5000` - mysql: `999:999` 4. **Testing**: Always test recovery procedures in a lab environment before trusting them in production. 5. **Documentation**: Keep this guide and server details in a separate location (printed copy, password manager, etc.). 6. **Retention Policy**: Review Kopia retention settings periodically to balance storage costs with recovery needs. ## Backup Architecture Notes ### Why Two Backup Layers? **Mailcow Native Backups** (Tier 1): - ✅ Component-aware (knows about mailcow's structure) - ✅ Uses mariabackup for consistent MySQL hot backups - ✅ Fast, selective restore (can restore just one component) - ✅ Architecture-aware (handles x86/ARM differences) - ❌ No deduplication (full copies each time) - ❌ Limited to local storage initially **Kopia Snapshots** (Tier 2): - ✅ Deduplication and compression - ✅ Efficient offsite replication to vaults - ✅ Point-in-time recovery across multiple versions - ✅ Disaster recovery to completely new infrastructure - ❌ Less component-aware (treats as files) - ❌ Slower for granular component restore ### Storage Efficiency Using this two-tier approach: - **Local**: Mailcow creates ~7 days of native backups (may be large, but short retention) - **Offsite**: Kopia deduplicates these backups for long-term vault storage (much smaller) Example storage calculation (10GB mailbox): - Local: 7 days × 10GB = ~70GB (before compression) - Kopia (offsite): First backup ~10GB, subsequent backups only store changes (might be <1GB/day after dedup) ### Compression Formats Mailcow's script creates `.tar.zst` (Zstandard) or `.tar.gz` (gzip) files: - **Zstandard** (modern): Better compression ratio, faster (recommended) - **Gzip** (legacy): Wider compatibility with older systems Verify your backup compression: ```bash ls -lh /opt/mailcow-backups/mailcow-*/ # Look for .tar.zst (preferred) or .tar.gz ``` ### Cross-Architecture Considerations **Important for ARM/x86 Migration**: Mailcow's backup script is architecture-aware. When restoring: - **Rspamd data** cannot be restored across different architectures (x86 ↔ ARM) - **All other components** (vmail, mysql, redis, postfix, crypt) are architecture-independent If migrating between architectures: ```bash # Restore everything EXCEPT rspamd # Select components individually: vmail, mysql, redis, postfix, crypt # Skip rspamd - it will rebuild its learning database over time ``` ### Testing Your Backups **Monthly Test Protocol**: 1. **Verify local backups exist**: ```bash ls -lh /opt/mailcow-backups/ # Should see recent dated directories ``` 2. **Verify Kopia snapshots**: ```bash kopia snapshot list --tags mailcow # Should see recent snapshots ``` 3. **Test restore in lab** (recommended quarterly): - Spin up a test VM - Restore from Kopia - Run mailcow native restore - Verify email delivery and webmail access ## Additional Resources - [Mailcow Official Backup Documentation](https://docs.mailcow.email/backup_restore/b_n_r-backup/) - [Kopia Documentation](https://kopia.io/docs/) - [Docker Volume Backup Best Practices](https://docs.docker.com/storage/volumes/#back-up-restore-or-migrate-data-volumes) ## Revision History | Date | Version | Changes | |------|---------|---------| | 2026-02-10 | 1.1 | Integrated mailcow native backup_and_restore.sh script as primary backup method | | 2026-02-10 | 1.0 | Initial documentation | --- **Last Updated**: February 10, 2026 **Maintained By**: System Administrator **Review Schedule**: Quarterly