Mail Server Migration (Postfix/Dovecot): Complete Zero-Downtime Guide
Migrating a mail server is one of the most critical and sensitive operations in server administration. Unlike website or database migrations, email services handle continuous, real-time communication where any data loss or extended downtime can have severe business consequences. This comprehensive guide provides step-by-step instructions for migrating Postfix and Dovecot mail servers with minimal downtime and zero email loss.
Understanding Mail Server Migration Complexity
Mail server migration presents unique challenges:
- Zero Tolerance for Email Loss: Every email must be preserved and delivered
- Continuous Service: Email flows 24/7 without predictable quiet periods
- Multiple Components: MTA (Postfix), MDA (Dovecot), DNS (MX records), authentication
- User Data: Mailboxes, folders, settings, filters, and preferences
- Reputation Management: IP reputation and SPF/DKIM/DMARC records
- Protocol Complexity: SMTP, IMAP, POP3, submission, and authentication protocols
- Stateful Connections: Active IMAP sessions and ongoing email transfers
A successful migration requires coordinating all these elements while maintaining service availability.
Pre-Migration Planning Phase
Current Environment Assessment
Document your existing mail server configuration:
# Check Postfix version and configuration
postconf -n > /tmp/postfix-config.txt
postconf -d | grep -E "version|mail_version"
# Check Dovecot version and configuration
dovecot -n > /tmp/dovecot-config.txt
doveconf -n > /tmp/dovecot-detailed.txt
# List all email domains
postconf -h virtual_mailbox_domains
postconf -h mydestination
# Check mailbox locations
postconf -h virtual_mailbox_base
postconf -h home_mailbox
# Count mailboxes and get sizes
find /var/mail -type d -name "cur" | wc -l
du -sh /var/mail
du -sh /var/vmail
# Check active connections
netstat -an | grep :25 | grep ESTABLISHED | wc -l
netstat -an | grep :993 | grep ESTABLISHED | wc -l
# Review queue
mailq | tail -1
Document DNS Records
# Check current MX records
dig +short MX yourdomain.com
# Check SPF record
dig +short TXT yourdomain.com | grep "v=spf1"
# Check DKIM records
dig +short TXT default._domainkey.yourdomain.com
# Check DMARC record
dig +short TXT _dmarc.yourdomain.com
# Check reverse DNS
dig +short -x your-server-ip
Inventory Mail Components
- Email domains and virtual domains
- User accounts and passwords
- Mailbox sizes and total storage
- Spam filtering (SpamAssassin, rspamd)
- Antivirus (ClamAV)
- Aliases and forwarding rules
- Mailing lists
- SSL/TLS certificates
- Authentication methods (SASL, virtual users)
- Database backend (if using MySQL/PostgreSQL)
Pre-Migration Checklist
Complete these tasks before migration:
- Document all Postfix and Dovecot configurations
- Export all email accounts and passwords
- Record all DNS settings (MX, SPF, DKIM, DMARC, PTR)
- Calculate total mailbox storage requirements
- Verify backup and restoration procedures
- Test email delivery and reception on source server
- Set up new server with same OS version
- Install identical or newer versions of Postfix/Dovecot
- Configure firewall rules (25, 465, 587, 993, 995)
- Obtain SSL certificates for new server
- Configure reverse DNS for new server IP
- Prepare monitoring tools for both servers
- Create detailed migration timeline
- Notify users of potential brief service interruption
- Schedule migration during low-email-volume period
- Prepare rollback procedures
Step-by-Step Migration Process
Step 1: Prepare the New Mail Server
Install and configure the base system:
# Update system
sudo apt update && sudo apt upgrade -y
# Install Postfix and Dovecot
sudo apt install postfix dovecot-core dovecot-imapd \
dovecot-pop3d dovecot-lmtpd -y
# Install additional tools
sudo apt install postfix-mysql dovecot-mysql \
spamassassin clamav clamav-daemon -y
# Install mail utilities
sudo apt install mailutils swaks mutt -y
Step 2: Transfer Configuration Files
Copy configurations from source server:
# On source server: Create configuration backup
sudo tar czf /tmp/mail-configs.tar.gz \
/etc/postfix \
/etc/dovecot \
/etc/aliases \
/etc/mailname
# Transfer to new server
scp /tmp/mail-configs.tar.gz user@new-server:/tmp/
# On new server: Extract and review
cd /tmp
tar xzf mail-configs.tar.gz
# Review and adjust for new server
# Check for IP addresses and hostnames that need updating
grep -r "old-server-ip" etc/
# Backup default configs and install transferred ones
sudo cp -r /etc/postfix /etc/postfix.original
sudo cp -r /etc/dovecot /etc/dovecot.original
sudo cp -r /tmp/etc/postfix/* /etc/postfix/
sudo cp -r /tmp/etc/dovecot/* /etc/dovecot/
# Update hostname and IP references
sudo sed -i 's/old-server-ip/new-server-ip/g' /etc/postfix/main.cf
sudo sed -i 's/old.hostname.com/new.hostname.com/g' /etc/postfix/main.cf
Step 3: Configure SSL/TLS Certificates
Set up certificates for secure mail:
# Install Certbot
sudo apt install certbot -y
# Obtain certificates
sudo certbot certonly --standalone \
-d mail.yourdomain.com \
--agree-tos \
--email [email protected]
# Or copy existing certificates
scp -r user@old-server:/etc/letsencrypt /tmp/
sudo cp -r /tmp/letsencrypt /etc/
# Configure Postfix to use certificates
sudo nano /etc/postfix/main.cf
# Add or update:
# smtpd_tls_cert_file=/etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
# smtpd_tls_key_file=/etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
# smtpd_tls_security_level=may
# smtp_tls_security_level=may
# Configure Dovecot certificates
sudo nano /etc/dovecot/conf.d/10-ssl.conf
# ssl = yes
# ssl_cert = </etc/letsencrypt/live/mail.yourdomain.com/fullchain.pem
# ssl_key = </etc/letsencrypt/live/mail.yourdomain.com/privkey.pem
Step 4: Migrate User Accounts
Transfer user authentication data:
# If using virtual users with MySQL
# On source server: Export users database
mysqldump -u root -p mail_db > /tmp/mail_users.sql
# Transfer to new server
scp /tmp/mail_users.sql user@new-server:/tmp/
# On new server: Import users
mysql -u root -p << 'EOF'
CREATE DATABASE mail_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'mailuser'@'localhost' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON mail_db.* TO 'mailuser'@'localhost';
FLUSH PRIVILEGES;
EOF
mysql -u root -p mail_db < /tmp/mail_users.sql
# If using system users or password files
# Copy password files
sudo scp user@old-server:/etc/dovecot/users /etc/dovecot/
Step 5: Synchronize Email Data
This is the most critical step. Use multiple synchronization passes:
# Method 1: Direct filesystem sync with rsync
# Create initial sync (can run while old server is active)
sudo rsync -avz --progress \
user@old-server:/var/vmail/ \
/var/vmail/
# Set correct permissions
sudo chown -R vmail:vmail /var/vmail
sudo chmod -R 700 /var/vmail
# Method 2: Using dsync (Dovecot's replication tool)
# On new server: Configure dsync
sudo nano /etc/dovecot/conf.d/10-mail.conf
# mail_location = maildir:/var/vmail/%d/%n
# Sync individual mailbox
doveadm -o mail_fsync=never sync \
-u [email protected] \
-R -l 30 -N \
tcp:old-server.ip:12345
# Sync all mailboxes script
cat > /root/sync-all-mailboxes.sh << 'EOF'
#!/bin/bash
USERS=$(mysql -u mailuser -ppassword mail_db -sN \
-e "SELECT email FROM users WHERE active=1")
for USER in $USERS; do
echo "Syncing $USER..."
doveadm sync -u $USER \
-l 30 -N \
tcp:old-server-ip:12345
done
EOF
chmod +x /root/sync-all-mailboxes.sh
Step 6: Configure DKIM Signing
Set up DKIM on the new server:
# Install OpenDKIM
sudo apt install opendkim opendkim-tools -y
# Generate DKIM keys
sudo mkdir -p /etc/opendkim/keys/yourdomain.com
cd /etc/opendkim/keys/yourdomain.com
sudo opendkim-genkey -s default -d yourdomain.com
sudo chown opendkim:opendkim default.private
# Configure OpenDKIM
sudo nano /etc/opendkim.conf
# Add:
# Domain yourdomain.com
# KeyFile /etc/opendkim/keys/yourdomain.com/default.private
# Selector default
# Socket inet:8891@localhost
# Configure Postfix to use OpenDKIM
sudo nano /etc/postfix/main.cf
# Add:
# milter_default_action = accept
# milter_protocol = 6
# smtpd_milters = inet:localhost:8891
# non_smtpd_milters = inet:localhost:8891
# Start services
sudo systemctl restart opendkim postfix
# Display public key for DNS
sudo cat /etc/opendkim/keys/yourdomain.com/default.txt
Step 7: Set Up Continuous Synchronization
Maintain synchronization during migration:
# Create continuous sync script
cat > /root/continuous-mail-sync.sh << 'EOF'
#!/bin/bash
LOG="/var/log/mail-sync.log"
while true; do
echo "=== Sync started at $(date) ===" >> $LOG
# Sync mail data
rsync -avz --delete \
--exclude 'dovecot.index*' \
--exclude 'dovecot-uidlist*' \
user@old-server:/var/vmail/ \
/var/vmail/ >> $LOG 2>&1
# Fix permissions
chown -R vmail:vmail /var/vmail
echo "=== Sync completed at $(date) ===" >> $LOG
sleep 300 # Sync every 5 minutes
done
EOF
chmod +x /root/continuous-mail-sync.sh
nohup /root/continuous-mail-sync.sh &
Step 8: Testing the New Server
Before DNS changes, thoroughly test the new server:
# Test SMTP submission (port 587)
swaks --to [email protected] \
--from [email protected] \
--server new-server-ip:587 \
--auth LOGIN \
--auth-user [email protected] \
--auth-password userpassword \
--tls
# Test IMAP connection
openssl s_client -connect new-server-ip:993 -crlf
# a1 LOGIN [email protected] password
# a2 LIST "" "*"
# a3 SELECT INBOX
# a4 LOGOUT
# Test using mail client with hosts file override
echo "new-server-ip mail.yourdomain.com" | sudo tee -a /etc/hosts
# Configure mail client to connect to mail.yourdomain.com
# Verify:
# - Login works
# - Folder list displays
# - Messages are visible
# - Can send email
# - Can receive email
sudo sed -i '/mail.yourdomain.com/d' /etc/hosts
Step 9: DNS Preparation
Lower TTL values 24-48 hours before migration:
# Check current TTL
dig MX yourdomain.com | grep -A1 "ANSWER SECTION"
# Update MX record TTL to 300 seconds (5 minutes)
# This allows faster propagation during cutover
# Current MX record (example):
# MX 10 mail.yourdomain.com. 86400 IN -> old-server-ip
# Update to:
# MX 10 mail.yourdomain.com. 300 IN -> old-server-ip
Step 10: The Cutover Process
Execute the final migration:
# Step 1: Final synchronization
# Stop continuous sync
pkill -f continuous-mail-sync.sh
# Perform final rsync
sudo rsync -avz --delete \
user@old-server:/var/vmail/ \
/var/vmail/
# Or using dsync for active mailboxes
/root/sync-all-mailboxes.sh
# Step 2: Configure new server to accept mail
# Ensure services are running
sudo systemctl start postfix dovecot opendkim
sudo systemctl enable postfix dovecot opendkim
# Verify services
sudo systemctl status postfix dovecot
# Check ports are listening
sudo netstat -tulpn | grep -E "(25|587|993)"
# Step 3: Update DNS records
# Update MX record: mail.yourdomain.com -> new-server-ip
# Update A record: mail.yourdomain.com -> new-server-ip
# Step 4: Monitor both servers
# On old server: Watch for incoming connections
sudo tail -f /var/log/mail.log | grep "status=sent"
# On new server: Watch for incoming connections
sudo tail -f /var/log/mail.log
# Step 5: Parallel operation period
# Keep both servers running for 24-48 hours
# Some mail servers may cache DNS for longer periods
Step 11: Queue Management
Handle mail queue during migration:
# On old server: Monitor queue
mailq
# Process remaining queue
sudo postqueue -f
# If needed, relay queue to new server
sudo postconf -e "relayhost = [new-server-ip]"
sudo systemctl reload postfix
sudo postqueue -f
# Watch queue drain
watch -n 10 'mailq | tail -1'
# On new server: Monitor incoming relayed mail
sudo tail -f /var/log/mail.log | grep relay
Post-Migration Verification
Comprehensive Testing
# Test inbound email delivery
echo "Test from external" | mail -s "Inbound Test" [email protected]
# Test outbound email delivery
echo "Test to external" | mail -s "Outbound Test" [email protected]
# Test IMAP functionality
# Connect with Thunderbird/Outlook and verify:
# - Folder structure intact
# - All messages visible
# - Can move/delete messages
# - Can create new folders
# - Search functionality works
# Check mail logs for errors
sudo tail -100 /var/log/mail.log | grep -i error
sudo tail -100 /var/log/mail.log | grep -i warning
# Verify DKIM signing
echo "DKIM test" | mail -s "DKIM Test" [email protected]
# Check reply for DKIM=pass
# Test SPF
dig +short TXT yourdomain.com | grep spf
# Monitor server load
htop
iostat -x 1 5
# Check disk space
df -h /var/vmail
Email Deliverability Checks
# Test against major providers
echo "Test to Gmail" | mail -s "Deliverability Test" [email protected]
echo "Test to Outlook" | mail -s "Deliverability Test" [email protected]
# Check blacklist status
host new-server-ip
# Then check IP at: mxtoolbox.com/blacklists.aspx
# Verify SPF, DKIM, DMARC
# Send test email to: [email protected]
# Or use: mail-tester.com
Rollback Procedures
If issues occur, execute rollback:
# Emergency rollback steps
# 1. Revert DNS records
# Change MX record back to old-server-ip
# Update A record for mail.yourdomain.com
# 2. Ensure old server is operational
# On old server:
sudo systemctl start postfix dovecot
sudo systemctl status postfix dovecot
# 3. Process any queued mail on new server
# Relay queue to old server
sudo postconf -e "relayhost = [old-server-ip]"
sudo systemctl reload postfix
sudo postqueue -f
# 4. Sync any new mail back to old server (if users connected)
rsync -avz /var/vmail/ user@old-server:/var/vmail/
# 5. Notify users
echo "Mail service has been restored to previous configuration" | \
mail -s "Service Notice" [email protected]
# 6. Document issues for analysis
echo "Rollback executed at $(date): [reason]" >> /var/log/migration.log
Risk Mitigation Strategies
Split-Horizon DNS
# Use different mail servers for sending/receiving temporarily
# Receiving: Keep MX pointing to old server
# Sending: Configure SMTP clients to use new server
# This allows testing outbound mail while receiving stays stable
Gradual User Migration
# Migrate users in batches
# Create user groups
cat > /root/migrate-group1.txt << 'EOF'
[email protected]
[email protected]
[email protected]
EOF
# Sync specific users
while read email; do
doveadm sync -u $email tcp:old-server-ip:12345
done < /root/migrate-group1.txt
# Update MX records for specific domains if hosting multiple
# Or use email client reconfiguration for specific users
Email Gateway Solution
# Use a third-party email gateway during migration
# Configure MX to point to gateway
# Gateway delivers to both old and new servers
# Provides redundancy during migration
Monitoring and Alerting
# Create monitoring script
cat > /root/monitor-mail-server.sh << 'EOF'
#!/bin/bash
LOG="/var/log/mail-monitor.log"
while true; do
echo "=== $(date) ===" >> $LOG
# Check services
systemctl is-active postfix dovecot opendkim >> $LOG
# Check queue size
QUEUE=$(mailq | tail -1 | awk '{print $5}')
echo "Queue size: $QUEUE" >> $LOG
# Check disk space
DISK=$(df -h /var/vmail | awk 'NR==2 {print $5}' | sed 's/%//')
echo "Disk usage: $DISK%" >> $LOG
# Alert if issues
if [ "$DISK" -gt 85 ]; then
echo "ALERT: Disk usage above 85%" | \
mail -s "Mail Server Alert" [email protected]
fi
if [ "$QUEUE" -gt 100 ]; then
echo "ALERT: Mail queue has $QUEUE messages" | \
mail -s "Mail Queue Alert" [email protected]
fi
sleep 300
done
EOF
chmod +x /root/monitor-mail-server.sh
nohup /root/monitor-mail-server.sh &
Performance Optimization
# Postfix optimization
sudo nano /etc/postfix/main.cf
# Add optimizations:
# default_process_limit = 100
# smtpd_client_connection_count_limit = 50
# smtpd_client_connection_rate_limit = 100
# anvil_rate_time_unit = 60s
# Dovecot optimization
sudo nano /etc/dovecot/conf.d/10-master.conf
# service imap-login {
# process_min_avail = 4
# service_count = 1
# process_limit = 100
# }
# service imap {
# process_limit = 1024
# }
# MySQL optimization for virtual users
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# innodb_buffer_pool_size = 512M
# query_cache_size = 0
# max_connections = 200
sudo systemctl restart postfix dovecot mysql
Decommissioning the Old Server
After 1-2 weeks of stable operation:
# 1. Verify no mail is arriving at old server
sudo tail -100 /var/log/mail.log
# 2. Archive old server logs
sudo tar czf /backup/old-mail-server-logs-$(date +%F).tar.gz \
/var/log/mail* \
/var/log/dovecot* \
/var/log/syslog*
# 3. Final backup of old mailboxes
sudo tar czf /backup/old-vmail-final-$(date +%F).tar.gz /var/vmail
# 4. Stop services
sudo systemctl stop postfix dovecot opendkim spamassassin clamav-daemon
# 5. Remove from DNS if separate hostname
# Delete A record for old.mail.domain.com
# 6. Keep server accessible for 30 days for emergency data recovery
# 7. Document decommissioning
echo "Old mail server decommissioned on $(date)" >> /var/log/migration.log
Conclusion
Mail server migration is a complex but manageable process when approached methodically. Key success factors include:
- Comprehensive Planning: Document everything before starting
- Thorough Testing: Test all components before DNS changes
- Continuous Synchronization: Keep mailboxes in sync during migration
- DNS Management: Lower TTLs early and monitor propagation
- Parallel Operation: Run both servers during transition period
- Monitoring: Watch both servers for issues during migration
- User Communication: Keep users informed of any potential impacts
- Gradual Cutover: Don't rush the process; allow time for verification
By following this guide and adapting it to your specific environment, you can successfully migrate Postfix/Dovecot mail servers with minimal downtime and zero email loss. Remember that email is mission-critical infrastructure—plan conservatively, test thoroughly, and execute carefully.
The investment in proper migration procedures pays dividends in avoiding catastrophic email loss, maintaining user trust, and ensuring business continuity throughout the transition.


