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:
- Set up the VPS with the full stack (Nginx, PHP, MariaDB)
- Copy files and database from shared hosting to VPS
- Test the site on the VPS using your local
hostsfile (your domain temporarily points to the new server only on your computer) - Fix any issues found in testing
- Lower DNS TTL on the live site
- Switch DNS — site goes live on VPS
- 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):
- Log in to phpMyAdmin
- Select your database
- Click Export → Quick → Format: SQL → Go
- 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.