---
title: Mailcow Backup and Restore Strategy
description: Mailcow backup
published: true
date: 2026-02-20T04:15:25.924Z
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 <snapshot-id> /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 <snapshot-id> /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 <snapshot-id> /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 <vmail-snapshot-id> /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 <snapshot-id> /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 <config-snapshot-id> /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 <snapshot-id> /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
