How to Plan a Zero-Downtime Server Migration
A zero-downtime migration is the gold standard for moving services to a new Breeze instance without any interruption to your users. It requires careful planning, parallel infrastructure, and a controlled DNS cutover. This guide provides a comprehensive framework for achieving it.
Phase 1: Assessment and Planning
Begin by creating a detailed inventory of everything that needs to migrate:
- Applications — web apps, APIs, background workers, cron jobs
- Databases — MySQL, PostgreSQL, Redis, MongoDB
- Storage — uploaded files, media assets, backups
- Services — email, DNS, SSL certificates, monitoring agents
- Network — firewall rules, load balancer configs, IP whitelists
Create a migration runbook that documents every step, the expected duration, and rollback procedures. Assign a responsible person for each step and establish a communication plan for your team.
Phase 2: Prepare the New Breeze
Set up the new Breeze as a mirror of the source server. Install all required software, apply the same security hardening, and replicate configuration files:
# Install the same packages
sudo apt install -y nginx php8.2-fpm mariadb-server redis-server
# Copy configuration files
rsync -avz user@old-server:/etc/nginx/sites-available/ /etc/nginx/sites-available/
rsync -avz user@old-server:/etc/php/8.2/ /etc/php/8.2/
Phase 3: Data Synchronization
Set up continuous data replication between the old server and the new Breeze. For databases, configure replication:
# MySQL replication - on the source server
CHANGE MASTER TO MASTER_HOST='new-breeze-ip', MASTER_USER='repl', MASTER_PASSWORD='replpass';
START SLAVE;
For file-based data, use rsync on a cron schedule to keep the Breeze in sync:
# Run every 5 minutes
*/5 * * * * rsync -az --delete user@old-server:/var/www/uploads/ /var/www/uploads/
Phase 4: Testing on the New Breeze
Test everything before cutting over DNS. Edit your local /etc/hosts to point domains to the Breeze IP and run through all critical user workflows:
- Homepage and key landing pages load correctly
- User login and registration work
- API endpoints return expected responses
- File uploads and downloads function
- Background jobs and cron tasks execute
- Email sending and receiving operates normally
Phase 5: DNS Cutover Strategy
Lower DNS TTL values to 60 seconds at least 48 hours before the migration. This ensures clients will pick up the new IP quickly when you switch:
# 48 hours before migration
example.com A old-ip TTL=60
When ready to cut over, perform a final data sync, then update DNS:
# Final sync
rsync -az --delete user@old-server:/var/www/ /var/www/
mysqldump --source-data=2 ... | mysql ...
# Update DNS
example.com A new-breeze-ip TTL=60
Phase 6: Monitoring and Rollback
After the cutover, monitor the new Breeze closely for at least 24 hours:
- Watch error logs in real time:
tail -f /var/log/nginx/error.log - Monitor application logs for exceptions
- Check response times and throughput metrics
- Verify database connections are stable
Keep the old server running for at least 72 hours as a fallback. If critical issues arise, rolling back is as simple as reverting the DNS A record to the old IP. Once satisfied that the migration is stable, increase the DNS TTL back to normal values and decommission the old server.
Key Tips for Success
- Always have a rollback plan documented before starting
- Perform the cutover during low-traffic hours
- Use a checklist and verify each step before proceeding to the next
- Communicate the maintenance window to stakeholders even if you expect zero downtime