How to Migrate a Website from Shared Hosting to a VPS (Step-by-Step)

How to Migrate a Website from Shared Hosting to a VPS (Step-by-Step)

Moving from shared hosting to a VPS is one of the most impactful upgrades a website owner can make — but the migration itself is what stops most people from doing it. The fear of downtime, broken databases, or misconfigured servers keeps sites stuck on sluggish shared hosting for years.

This guide removes that barrier. You’ll migrate your website from shared hosting to a VPS with zero downtime — testing everything on the new server before a single DNS change touches your live site.

Migration Strategy Overview

The key to zero-downtime migration is testing on the VPS before switching DNS:

  1. Set up the VPS with the full stack (Nginx, PHP, MariaDB)
  2. Copy files and database from shared hosting to VPS
  3. Test the site on the VPS using your local hosts file (your domain temporarily points to the new server only on your computer)
  4. Fix any issues found in testing
  5. Lower DNS TTL on the live site
  6. Switch DNS — site goes live on VPS
  7. Keep shared hosting active for 48 hours as rollback option

Requirements

  • Access to your shared hosting (FTP/SFTP + phpMyAdmin or SSH)
  • A VPS with Ubuntu 22.04 or 24.04 (VPS.DO KVM recommended)
  • Your domain name’s DNS control panel access

💡 VPS.DO Tip: Use the 7-day money-back guarantee to test migration without financial risk. View USA VPS Plans →


Phase 1: Set Up Your VPS

Step 1: Initial server setup

sudo apt update && sudo apt upgrade -y
sudo apt install nginx mariadb-server php8.3-fpm \
  php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl \
  php8.3-zip php8.3-gd php8.3-intl php8.3-bcmath \
  certbot python3-certbot-nginx rsync unzip -y

sudo systemctl enable nginx mariadb php8.3-fpm
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable

Step 2: Create the database

sudo mysql -u root
CREATE DATABASE migration_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'migration_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON migration_db.* TO 'migration_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 3: Create the web root

sudo mkdir -p /var/www/yourdomain.com
sudo chown -R www-data:www-data /var/www/yourdomain.com

Phase 2: Copy Files from Shared Hosting

Method A: Via SFTP/rsync (fastest)

If your shared host allows SSH/SFTP (most do):

# From your VPS, pull files directly from shared hosting
rsync -avz --progress \
  username@sharedhost.example.com:/home/username/public_html/ \
  /var/www/yourdomain.com/

Method B: Via FTP download + upload

# On your local machine, download all files from shared hosting via FTP
# Then upload to VPS:
rsync -avz ./public_html/ username@YOUR_VPS_IP:/var/www/yourdomain.com/

Method C: Using an archive (for large sites)

# On shared hosting (via SSH or file manager), create an archive
cd ~/public_html
tar -czf ~/site-backup.tar.gz .

# On your VPS, download and extract
wget -O /tmp/site-backup.tar.gz "https://sharedhost.example.com/~username/site-backup.tar.gz"
tar -xzf /tmp/site-backup.tar.gz -C /var/www/yourdomain.com/

Set correct permissions

sudo chown -R www-data:www-data /var/www/yourdomain.com
sudo find /var/www/yourdomain.com -type d -exec chmod 755 {} \;
sudo find /var/www/yourdomain.com -type f -exec chmod 644 {} \;

Phase 3: Export and Import the Database

Export from shared hosting

Via phpMyAdmin (most common on shared hosting):

  1. Log in to phpMyAdmin
  2. Select your database
  3. Click Export → Quick → Format: SQL → Go
  4. Save the .sql file

Via SSH on shared hosting (if available):

mysqldump -u dbuser -p database_name > /tmp/site-database.sql

Transfer database to VPS

# Upload via SCP
scp site-database.sql username@YOUR_VPS_IP:/tmp/

# Or via rsync
rsync -avz site-database.sql username@YOUR_VPS_IP:/tmp/

Import on VPS

sudo mysql -u migration_user -p migration_db < /tmp/site-database.sql

Phase 4: Configure WordPress (or your CMS)

Update wp-config.php with new database credentials

sudo nano /var/www/yourdomain.com/wp-config.php
define( 'DB_NAME', 'migration_db' );
define( 'DB_USER', 'migration_user' );
define( 'DB_PASSWORD', 'SecurePassword123!' );
define( 'DB_HOST', 'localhost' );

// Add these for VPS security
define('DISALLOW_FILE_EDIT', true);
define('FORCE_SSL_ADMIN', true);

Update the site URL in the database (if you’re changing domains or protocols)

sudo mysql -u migration_user -p migration_db << 'SQL'
UPDATE wp_options SET option_value = 'https://yourdomain.com'
  WHERE option_name IN ('siteurl', 'home');
SQL

Phase 5: Configure Nginx

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 index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(ht|git|env) { deny all; }
    location = /xmlrpc.php       { deny all; }

    location ~* \.(css|gif|ico|jpeg|jpg|js|png|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    client_max_body_size 64M;
    access_log /var/log/nginx/yourdomain.com.access.log;
    error_log  /var/log/nginx/yourdomain.com.error.log;
}
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Phase 6: Test Before Switching DNS

This is the critical step that makes zero-downtime migration possible. Edit your local hosts file to point your domain to the new VPS — only on your computer:

On Mac/Linux

sudo nano /etc/hosts
# Add this line (replace with your actual VPS IP and domain)
203.0.113.1   yourdomain.com www.yourdomain.com

On Windows

Open Notepad as Administrator → Open C:\Windows\System32\drivers\etc\hosts → Add the same line.

Test your site

Open your browser and visit http://yourdomain.com. Your browser connects to the VPS while the rest of the world still reaches your shared hosting. Test thoroughly:

  • ✅ Homepage loads correctly
  • ✅ Internal links work
  • ✅ Images display
  • ✅ Contact form submits
  • ✅ Login works (for CMS sites)
  • ✅ All pages return 200 (no 404s or 500s)
  • ✅ Database-driven content displays

Fix any issues before proceeding. When the site is working perfectly on the VPS, remove the hosts file entry and continue.


Phase 7: Install SSL on the VPS

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot issues certificates and configures HTTPS automatically. Test renewal:

sudo certbot renew --dry-run

Phase 8: Switch DNS

Lower TTL first (24 hours before switching)

Log in to your domain registrar or DNS provider. Change your A record TTL to 300 seconds (5 minutes). This ensures the switch propagates quickly when you make it.

Switch the A record

Update your domain’s A record to point to your VPS IP address:

Type Name Value TTL
A @ YOUR_VPS_IP 300
A www YOUR_VPS_IP 300

Monitor propagation

# Watch DNS propagation from your VPS
watch -n 10 "dig yourdomain.com +short"

Most regions see the new IP within 5–15 minutes with a 300-second TTL.


Phase 9: Post-Migration Checklist

  • ✅ Site loads correctly from multiple devices/networks
  • ✅ HTTPS certificate is valid (no browser warnings)
  • ✅ HTTP redirects to HTTPS automatically
  • ✅ WordPress admin accessible at /wp-admin
  • ✅ Email sending works (configure SMTP plugin if needed)
  • ✅ Google Search Console updated with new server (no action needed — the domain is the same)
  • ✅ Set up automated backups on the VPS
  • ✅ Install monitoring (UptimeRobot)
  • ✅ Keep shared hosting active for 48 hours, then cancel

Common Migration Issues and Fixes

Images not loading after migration

Usually a permissions issue. Run:

sudo chown -R www-data:www-data /var/www/yourdomain.com/wp-content/uploads/

WordPress redirecting to old hosting IP

The site URL in the database still points to the old server. Fix:

sudo mysql -u migration_user -p migration_db -e \
  "UPDATE wp_options SET option_value='https://yourdomain.com' WHERE option_name IN ('siteurl','home');"

Plugin/theme files not working after migration

Some plugins cache absolute paths. Clear all caches from the WordPress admin, then deactivate and reactivate the affected plugins.

Mixed content warnings (some images using HTTP)

Install the Better Search Replace plugin and replace http://yourdomain.com with https://yourdomain.com across all database tables.


Final Thoughts

Migrating from shared hosting to a VPS is a half-day project for a typical WordPress site — and the performance improvement is immediately noticeable. Pages that took 3 seconds to load on shared hosting often load in under 0.8 seconds on a properly configured VPS with Redis and Nginx caching.

VPS.DO’s USA VPS 500SSD plan is the ideal destination for sites migrating from shared hosting — dedicated resources, 500 GB SSD, 1 Gbps port, and a 7-day money-back guarantee that lets you verify the migration is successful before committing.

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!