How to Migrate from Shared Hosting to a VPS Without Downtime: WordPress Step-by-Step
Migrating a WordPress site from shared hosting to a VPS is one of the highest-impact infrastructure changes you can make for a growing website — but the prospect of downtime, broken links, and lost data understandably makes many site owners hesitant. Done correctly, a WordPress migration to VPS is achievable with zero user-facing downtime. This guide walks through the complete process: preparing the VPS, transferring files and database, testing the new environment before switching DNS, and a safe DNS cutover that minimizes any remaining risk.
Why Migrate from Shared Hosting to VPS?
The migration is typically triggered by one or more of these conditions:
- Shared hosting resource limits are causing slow load times or HTTP 503 errors during traffic spikes
- Your host has suspended the account temporarily due to resource overuse
- Plugin or theme requirements need a PHP version or extension the shared host does not offer
- Security concerns about shared hosting environments
- The site has grown to a point where the cost of managed WordPress hosting exceeds VPS pricing
Before You Start: What You Need
- Your new VPS provisioned and accessible via SSH (Ubuntu 22.04 LTS recommended)
- SSH/SFTP access to your shared hosting account, or cPanel/FTP credentials
- Access to your domain registrar’s DNS management panel
- WP-CLI installed on your local machine (optional but helpful)
- Approximately 2–4 hours for a typical WordPress site
Phase 1: Set Up the VPS Server Stack
Before transferring any data, prepare the VPS with the same software stack your WordPress site needs:
# Update system
sudo apt update && sudo apt upgrade -y
# Install Nginx, PHP 8.2, MariaDB, Redis
sudo add-apt-repository ppa:ondrej/php -y && sudo apt update
sudo apt install nginx php8.2-fpm php8.2-mysql php8.2-curl php8.2-gd \
php8.2-mbstring php8.2-xml php8.2-zip php8.2-redis php8.2-intl \
php8.2-imagick mariadb-server redis-server certbot python3-certbot-nginx -y
Configure MariaDB and create the WordPress database:
sudo mysql_secure_installation
sudo mysql -u root -p
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Create the web root directory:
sudo mkdir -p /var/www/yourdomain.com
sudo chown -R www-data:www-data /var/www/yourdomain.com
Configure Nginx for WordPress:
sudo nano /etc/nginx/sites-available/yourdomain.com
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/yourdomain.com;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Phase 2: Export WordPress Files from Shared Hosting
Method A: Via cPanel File Manager and phpMyAdmin
- In cPanel → File Manager, navigate to your WordPress root (usually
public_htmlor a subdirectory) - Select all files and compress to a ZIP archive
- Download the ZIP to your local machine
- In cPanel → phpMyAdmin, select your WordPress database, click Export → Quick → Go
- Save the
.sqlfile locally
Method B: Via SSH from Shared Host (Faster for Large Sites)
# SSH into shared host (if SSH access is available)
ssh username@sharedhost.com
# Create a compressed archive of your WordPress installation
cd public_html # or your WordPress directory
tar czf /tmp/wordpress-backup.tar.gz .
# Create database dump
mysqldump -u db_user -p database_name > /tmp/wordpress-db.sql
gzip /tmp/wordpress-db.sql
Method C: Using Duplicator Plugin (Easiest for Non-Technical Users)
- Install and activate the Duplicator plugin on your existing WordPress site
- In Duplicator → Packages → Create New, run through the wizard
- Download the generated installer.php and the ZIP archive package
Phase 3: Transfer Files to the VPS
# Upload files to VPS via rsync (fastest for large sites)
rsync -avz --progress /local/path/to/wordpress-backup.tar.gz \
user@YOUR_VPS_IP:/tmp/
# Or via scp
scp wordpress-backup.tar.gz user@YOUR_VPS_IP:/tmp/
scp wordpress-db.sql.gz user@YOUR_VPS_IP:/tmp/
On the VPS, extract the files:
ssh user@YOUR_VPS_IP
cd /var/www/yourdomain.com
sudo tar xzf /tmp/wordpress-backup.tar.gz -C .
sudo chown -R www-data:www-data .
sudo find . -type d -exec chmod 755 {} \;
sudo find . -type f -exec chmod 644 {} \;
Phase 4: Import the Database
# Decompress if gzipped
gunzip /tmp/wordpress-db.sql.gz
# Import into the new database
sudo mysql -u root -p wordpress < /tmp/wordpress-db.sql
Phase 5: Update WordPress Configuration
Edit wp-config.php on the VPS to use the new database credentials:
sudo nano /var/www/yourdomain.com/wp-config.php
define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'SecurePassword123!');
define('DB_HOST', 'localhost');
// Add these for security
define('DISALLOW_FILE_EDIT', true);
define('WP_DEBUG', false);
Phase 6: Test the New Site Before DNS Cutover
This is the most important step for zero-downtime migration — you test the new VPS site without affecting the live site.
Option A: Modify Your Local /etc/hosts
sudo nano /etc/hosts
Add:
YOUR_VPS_IP yourdomain.com www.yourdomain.com
Your local machine now resolves the domain to the VPS instead of shared hosting. Test everything — homepage, admin login, posts, contact forms, WooCommerce checkout — while everyone else still sees the live shared hosting site.
Option B: Test Using the VPS IP Directly
# Access WordPress admin via VPS IP (add this to wp-config.php temporarily)
define('WP_HOME', 'http://YOUR_VPS_IP');
define('WP_SITEURL', 'http://YOUR_VPS_IP');
Common Issues to Check
- All images and media loading correctly
- WordPress admin accessible at
/wp-admin/ - Contact forms submitting successfully
- WooCommerce products and checkout functional (if applicable)
- Plugin functionality (SEO plugins, security plugins, etc.)
- PHP error log clean:
sudo tail -f /var/log/nginx/error.log
Phase 7: Issue SSL Certificate
Once DNS cutover is complete (or to issue the certificate, temporarily point DNS to the VPS):
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot automatically updates your Nginx configuration to redirect HTTP to HTTPS and sets up automatic renewal.
Phase 8: DNS Cutover
Step 1: Lower DNS TTL (24–48 Hours Before)
In your domain registrar or DNS provider, lower the A record TTL to 300 seconds (5 minutes) or lower. This ensures that after you switch the IP address, the change propagates to most visitors within 5 minutes rather than hours.
Step 2: Perform a Final Sync
Sync any content changes made to the shared hosting site after your initial migration:
# Sync uploads directory (new images added since initial migration)
rsync -avz --progress username@sharedhost.com:public_html/wp-content/uploads/ \
/var/www/yourdomain.com/wp-content/uploads/
# Export and import only rows changed since your initial export
# (For WordPress, this is typically the wp_posts, wp_comments tables)
mysqldump -u db_user -p database_name wp_posts wp_comments wp_options \
--where="post_modified > '2025-01-01'" > /tmp/incremental.sql
Step 3: Update the DNS A Record
In your DNS management panel, change the A record for yourdomain.com and www.yourdomain.com from the old shared hosting IP to your VPS IP. The change will propagate to most visitors within the TTL window (5 minutes if you lowered it in Step 1).
Step 4: Monitor for Issues
# Watch Nginx access logs in real time during cutover
sudo tail -f /var/log/nginx/access.log
# Monitor PHP errors
sudo tail -f /var/log/nginx/error.log
Phase 9: Post-Migration Checklist
- ☐ All pages load correctly with no 404 or 500 errors
- ☐ SSL certificate active (padlock shown in browser)
- ☐ WordPress admin login working
- ☐ Emails sending correctly (check WordPress mail settings)
- ☐ Search console still showing correct data (submit updated sitemap)
- ☐ Analytics tracking code present on all pages
- ☐ UptimeRobot or similar monitoring configured for the VPS
- ☐ VPS automated backups configured
- ☐ Remove the
/etc/hoststest entries from your local machine - ☐ Cancel shared hosting after confirming site runs well (keep for 30 days as a safety net)
Getting Started
The VPS setup for WordPress migration typically requires a 2 vCPU / 2 GB RAM plan as a minimum, with 4 GB RAM recommended for sites with active traffic. USA VPS plans at VPS.DO and Hong Kong VPS plans include KVM virtualization, NVMe storage, and a 7-day refund policy — making it easy to test your migration before fully committing. The NVMe storage is particularly valuable for WordPress sites where MySQL query performance directly affects page load time.
Conclusion
A WordPress migration from shared hosting to VPS with zero downtime is entirely achievable when you follow the correct order of operations: set up the VPS stack first, transfer data second, test thoroughly using /etc/hosts before DNS cutover, then switch DNS with a reduced TTL already in place. The 30-minute DNS propagation window is the only period of uncertainty — and with proper testing beforehand, even visitors who reach the old server during this window experience continuity of service.