Complete Website Migration Checklist: Zero-Downtime Guide (2025)
Step-by-step website migration checklist to ensure zero downtime, preserve SEO, and avoid data loss. Essential guide for developers and site owners.
Complete Website Migration Checklist: Zero-Downtime Guide
Website migrations are high-risk operations that can result in data loss, downtime, and SEO damage if not executed properly. This comprehensive checklist ensures a smooth migration with zero downtime.
Why Website Migrations Fail
Common migration failures include:
- Incomplete backups: Missing files or database tables - Broken URLs: Forgetting to set up redirects - DNS misconfiguration: Extended downtime or routing issues - Database connection errors: Wrong credentials or permissions - Missing dependencies: Libraries, plugins, or system requirements - SSL certificate issues: HTTPS not working post-migration - Email disruption: Mail server configuration forgotten
A proper checklist prevents these disasters.
Pre-Migration Phase (1-2 Weeks Before)
1. Audit Current Website
Inventory everything:
```bash
Document all components
- Domain registrar and nameservers - Hosting provider and plan details - CMS version and plugins - Database size and structure - File system size and structure - Email hosting setup - SSL certificates - Third-party integrations - Cron jobs and scheduled tasks - Environment variables ```Performance baseline: - Record current load times - Document traffic patterns - Note peak usage times - Export analytics data
2. Create Complete Backups
Files backup:
```bash
Full file system backup
tar -czf website-backup-$(date +%Y%m%d).tar.gz /var/www/html/Or use rsync for incremental
rsync -avz --progress /var/www/html/ ./backup/ ```Database backup:
```bash
MySQL/MariaDB
mysqldump -u user -p database_name > db-backup-$(date +%Y%m%d).sqlPostgreSQL
pg_dump -U user -d database_name -F c -f db-backup-$(date +%Y%m%d).dumpMongoDB
mongodump --db database_name --out ./backup/ ```Static snapshot with WebZip:
1. Visit WebZip.org 2. Enter your current website URL 3. Download complete static archive 4. Store as emergency rollback option
Why multiple backup types? - File backups: Restore files and themes - Database backups: Restore content and user data - Static snapshots: Emergency fallback if migration fails
3. Document Configuration
Create configuration document:
```yaml Current Setup: Domain: example.com Registrar: NameCheap DNS Provider: Cloudflare Hosting: DigitalOcean Droplet IP Address: 192.0.2.1
Web Server: Type: Nginx 1.24 PHP Version: 8.2 Document Root: /var/www/html SSL: Let's Encrypt
Database: Type: MySQL 8.0 Name: production_db User: db_user Host: localhost
Email: Provider: G Suite MX Records: [list them]
Integrations: - Google Analytics: UA-XXXXX - Stripe: Live keys in .env - AWS S3: Media storage - Sendgrid: Transactional email ```
4. Test Backup Restoration
Critical step that most skip:
```bash
Create test environment
Restore backup there
Verify everything works
If restoration fails in test,
it will fail in production!
```Test checklist: - [ ] Site loads correctly - [ ] Database connected - [ ] Images display - [ ] Forms submit - [ ] User login works - [ ] Admin panel accessible
5. Create Migration Timeline
Sample timeline:
``` Friday 11:00 PM - Start migration (low traffic time) Friday 11:15 PM - DNS TTL reduced to 300 seconds Saturday 12:00 AM - Files transferred Saturday 12:30 AM - Database migrated Saturday 1:00 AM - Testing on new server Saturday 1:30 AM - DNS updated Saturday 2:00 AM - Monitoring begins Saturday 8:00 AM - Team review ```
Choose migration window: - Lowest traffic period - When support team available - Not before major holidays/events - Allow 3x expected time
Migration Day: Execution Phase
Step 1: Reduce DNS TTL (24 Hours Before)
```bash
Lower TTL to 300 seconds (5 minutes)
This allows faster DNS propagation
In your DNS panel:
A Record: example.com → Current IP (TTL: 300) CNAME: www → example.com (TTL: 300) ```Why? Default TTLs are often 3600+ seconds (1 hour). Lowering TTL before migration means DNS changes propagate in 5 minutes instead of hours.
Step 2: Enable Maintenance Mode
```php // WordPress: Create .maintenance file
// Laravel: Run command php artisan down --message="Migrating to new server"
// Custom: Show maintenance page RewriteEngine On RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.0 RewriteRule ^(.*)$ /maintenance.html [R=503,L] ```
Best practices: - Show estimated completion time - Provide status page or Twitter updates - Allow admin IP addresses through - Return proper HTTP 503 status code
Step 3: Final Backup
```bash
One more backup right before migration
This is your last known-good state
timestamp=$(date +%Y%m%d_%H%M%S) mysqldump -u user -p db > final-backup-$timestamp.sql tar -czf files-final-$timestamp.tar.gz /var/www/html/ ```
Step 4: Transfer Files to New Server
Using rsync (recommended):
```bash
Rsync to new server (maintains permissions)
rsync -avz --progress \ -e "ssh -i ~/.ssh/migration-key.pem" \ /var/www/html/ \ user@new-server-ip:/var/www/html/ ```Using SCP:
```bash
Copy compressed archive
scp -i key.pem website-backup.tar.gz user@new-server:/tmp/ ssh user@new-server cd /var/www/html tar -xzf /tmp/website-backup.tar.gz ```Using hosting control panel: - Upload via FTP/SFTP - Use cPanel backup restore - Hosting provider migration tools
Step 5: Migrate Database
```bash
On NEW server:
Create database
mysql -u root -p CREATE DATABASE production_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'strong_password'; GRANT ALL PRIVILEGES ON production_db.* TO 'db_user'@'localhost'; FLUSH PRIVILEGES; EXIT;Import backup
mysql -u db_user -p production_db < final-backup.sqlVerify import
mysql -u db_user -p production_db -e "SHOW TABLES;" ```For large databases:
```bash
Use --compress for faster transfer
mysqldump -u user -p --compress db | ssh new-server mysql -u user -p dbOr use mydumper/myloader for parallel processing
mydumper -u user -p password -B db -o /backup/Transfer files
myloader -u user -p password -d /backup/ -o ```Step 6: Update Configuration Files
Update database connection:
```php // WordPress wp-config.php define('DB_HOST', 'localhost'); // or new DB host define('DB_USER', 'db_user'); define('DB_PASSWORD', 'new_password');
// Laravel .env DB_HOST=localhost DB_DATABASE=production_db DB_USERNAME=db_user DB_PASSWORD=new_password
// Drupal settings.php $databases['default']['default'] = array ( 'host' => 'localhost', 'database' => 'production_db', 'username' => 'db_user', 'password' => 'new_password', ); ```
Update file paths:
```bash
Check for hardcoded paths
grep -r "/old/path/" /var/www/html/Update as needed
```Update API keys and URLs: - Base URL / Site URL - CDN URLs - API endpoints - Payment gateway endpoints (use test mode first!)
Step 7: Test on New Server
Before changing DNS, test directly:
```bash
Edit local hosts file to point to new server
Linux/Mac: /etc/hosts
Windows: C:\Windows\System32\drivers\etc\hosts
192.0.2.100 example.com www.example.com ```
Comprehensive testing:
- [ ] Homepage loads - [ ] All major pages load - [ ] Images and media display - [ ] CSS and JavaScript load - [ ] Forms submit correctly - [ ] User login/logout works - [ ] Database reads/writes work - [ ] Search functionality works - [ ] Admin panel accessible - [ ] Cron jobs configured - [ ] SSL certificate valid - [ ] Email sending works - [ ] Payment processing (test mode) - [ ] Mobile responsive - [ ] Page speed acceptable
Step 8: Update DNS
Point domain to new server:
```bash
In DNS control panel:
A Record: example.com → NEW_SERVER_IP (TTL: 300) A Record: www.example.com → NEW_SERVER_IP (TTL: 300)Or if using CNAME:
CNAME: www → example.comDon't forget:
- Mail records (MX, SPF, DKIM) - Subdomain records - API subdomains ```Verify DNS propagation:
```bash
Check DNS from multiple locations
dig example.com +short nslookup example.com host example.comOnline tools:
- whatsmydns.net
- dnschecker.org
```Step 9: Monitor During Propagation
For next 2-24 hours:
```bash
Monitor both servers
Some users hit old, some hit new
Check traffic:
tail -f /var/log/nginx/access.logMonitor errors:
tail -f /var/log/nginx/error.logWatch resource usage:
htop ```Analytics monitoring: - Real-time visitors - Error rate - Conversion rate - Page load times
Step 10: Disable Old Server (After 48 Hours)
```bash
Don't immediately delete!
Keep old server running but disabled
for 1-2 weeks as backup
Stop web server
sudo systemctl stop nginx sudo systemctl stop apache2Keep server accessible via SSH
for emergency data recovery
```Post-Migration Phase (Week 1)
Day 1-2: Intensive Monitoring
Watch for issues: - 404 errors in server logs - Database connection errors - Slow queries - Failed payment transactions - Email delivery failures - User complaints
Tools: - Google Search Console (crawl errors) - Error tracking (Sentry, Rollbar) - Uptime monitoring (Pingdom, UptimeRobot) - Application performance (New Relic)
Day 3-7: Optimization
Performance tuning:
```bash
Enable caching
Optimize database queries
Configure CDN
Enable compression
Implement Redis/Memcached
```SEO verification: - Verify Google Search Console - Submit updated sitemap - Check all redirects working - Monitor ranking changes - Review structured data
Week 2-4: Stability Period
Complete remaining tasks:
- [ ] Update TTL back to normal (3600) - [ ] Review and optimize performance - [ ] Update documentation - [ ] Train team on new environment - [ ] Delete old server (after verified stable) - [ ] Update disaster recovery plan - [ ] Archive migration documentation
Common Migration Scenarios
WordPress Migration
Specific considerations:
```bash
Update site URLs in database
wp search-replace 'https://old-site.com' 'https://new-site.com' \ --all-tables --dry-runIf looks good, run without --dry-run
wp search-replace 'https://old-site.com' 'https://new-site.com' \ --all-tablesRegenerate .htaccess
Settings > Permalinks > Save
Clear cache
wp cache flush ```E-commerce Migrations
Critical considerations:
1. Payment gateway testing: - Use sandbox/test mode first - Process test transaction - Verify webhook endpoints - Test refund processing
2. Order management: - Verify order history migrated - Check customer accounts - Test checkout flow end-to-end - Verify email notifications
3. Inventory sync: - Confirm stock levels accurate - Test inventory updates - Verify product variants
Database-Heavy Applications
For large databases (>1GB):
```bash
Use parallel processing
mydumper -u user -p pass -B database -o /backup/ -t 8Compress during dump
mysqldump -u user -p db | gzip > backup.sql.gzTransfer compressed
rsync -avz backup.sql.gz new-server:/tmp/Restore with progress
pv backup.sql | mysql -u user -p database ```Migration Tools & Services
Automated Migration Tools
CMS-specific: - WordPress: All-in-One WP Migration, Duplicator - Drupal: Backup and Migrate module - Joomla: Akeeba Backup - Shopify: Built-in migration tools
Hosting provider tools: - cPanel Transfer Tool - Plesk Migration Manager - SiteGround Migrator - Kinsta WordPress migrations
Manual Migration Tools
File transfer: - FileZilla (FTP/SFTP client) - Rsync (command-line sync) - WinSCP (Windows SFTP)
Database tools: - phpMyAdmin - MySQL Workbench - pgAdmin (PostgreSQL) - TablePlus
DNS management: - Cloudflare - Route 53 (AWS) - DNS Made Easy
Emergency Rollback Tools
Quick rollback methods:
1. DNS rollback: Point back to old server 2. Static snapshot: Deploy archived version 3. Database restore: Reload old database 4. File rollback: Restore old files
WebZip emergency restore: 1. Use archived snapshot from WebZip.org 2. Deploy to static hosting (Netlify, Vercel) 3. Update DNS to emergency host 4. Site back online in minutes
Troubleshooting Common Issues
Issue: White Screen of Death
Cause: PHP errors, memory limit, or plugin conflicts
Solution: ```bash
Enable error reporting
error_reporting(E_ALL); ini_set('display_errors', 1);Check error logs
tail -f /var/log/php-fpm/error.logIncrease memory limit
ini_set('memory_limit', '256M'); ```Issue: Database Connection Error
Cause: Wrong credentials, firewall, or wrong host
Solution: ```bash
Test database connection
mysql -u user -p -h hostname database_nameCheck MySQL is running
systemctl status mysqlVerify permissions
mysql -u root -p SHOW GRANTS FOR 'user'@'localhost'; ```Issue: 404 Errors Everywhere
Cause: Mod_rewrite not enabled, .htaccess not loaded
Solution: ```bash
Enable mod_rewrite (Apache)
sudo a2enmod rewrite sudo systemctl restart apache2Nginx: Verify rewrite rules in config
Check AllowOverride in Apache config
```Issue: SSL Certificate Invalid
Cause: Certificate not transferred or not configured
Solution: ```bash
Install Let's Encrypt
sudo certbot --nginx -d example.com -d www.example.comOr import existing certificate
Copy cert files to new server
Update web server SSL config
```Issue: Images Not Displaying
Cause: Wrong file paths, permissions, or missing files
Solution: ```bash
Check file permissions
chmod -R 755 /var/www/html/wp-content/uploads/Verify ownership
chown -R www-data:www-data /var/www/html/Check if files exist
ls -la /path/to/uploads/ ```Migration Checklist Summary
Pre-Migration
- [ ] Audit current website completely - [ ] Create multiple backup types - [ ] Document all configuration - [ ] Test backup restoration - [ ] Create migration timeline - [ ] Lower DNS TTL 24 hours beforeMigration Day
- [ ] Enable maintenance mode - [ ] Final backup of current site - [ ] Transfer files to new server - [ ] Migrate database - [ ] Update configuration files - [ ] Test thoroughly on new server - [ ] Update DNS records - [ ] Monitor both serversPost-Migration
- [ ] Monitor errors and performance - [ ] Verify SEO not impacted - [ ] Test all functionality - [ ] Update documentation - [ ] Keep old server as backup (2 weeks) - [ ] Restore DNS TTL to normal - [ ] Archive migration documentationConclusion
Website migrations don't have to be stressful. With proper planning, comprehensive backups, and systematic execution, you can achieve zero-downtime migrations that preserve SEO value and user experience.
Key success factors:
1. Plan thoroughly: Document everything before starting 2. Backup everything: Multiple backup types in multiple locations 3. Test extensively: Both backups and the new environment 4. Time it right: Migrate during low-traffic periods 5. Monitor closely: Watch for issues during propagation 6. Keep rollback options: Don't delete old server immediately
Start your next migration with confidence using WebZip.org to create a complete static backup of your site before making any changes. It's your insurance policy against migration disasters.