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.

2025-10-14

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).sql

PostgreSQL

pg_dump -U user -d database_name -F c -f db-backup-$(date +%Y%m%d).dump

MongoDB

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.sql

Verify 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 db

Or 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.com

Don'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.com

Online 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.log

Monitor errors:

tail -f /var/log/nginx/error.log

Watch 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 apache2

Keep 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-run

If looks good, run without --dry-run

wp search-replace 'https://old-site.com' 'https://new-site.com' \ --all-tables

Regenerate .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 8

Compress during dump

mysqldump -u user -p db | gzip > backup.sql.gz

Transfer 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.log

Increase 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_name

Check MySQL is running

systemctl status mysql

Verify 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 apache2

Nginx: 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.com

Or 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 before

Migration 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 servers

Post-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 documentation

Conclusion

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.