Moving from shared hosting to a VPS is one of the highest-impact upgrades you can make for a growing WordPress site. More control, better performance, and often lower cost for the same resources. But it also means you are now responsible for the server. This guide covers the entire migration from start to finish.
Before you start
Is a VPS right for your site?
A VPS makes sense when:
- Your shared hosting is slow, especially during traffic spikes
- You need custom server software (Redis, specific PHP versions, Elasticsearch)
- You hit arbitrary limits (file count, inodes, cron jobs, concurrent connections)
- You want to run multiple sites on one server more efficiently
- Your hosting bill is >$30/month for shared/reseller hosting
A VPS might NOT make sense when:
- You do not want to manage a server (managed VPS is an option — see below)
- Your site is static or nearly static (consider static hosting)
- You are not comfortable with SSH and the Linux command line
Choosing a VPS provider
For a single WordPress site starting out:
| Provider | Starting price | RAM | CPU | Notes |
|---|---|---|---|---|
| Hetzner | €4.50/mo | 4 GB | 2 vCPU | Best value in Europe |
| DigitalOcean | $6/mo | 1 GB | 1 vCPU | Best docs, easy interface |
| Linode | $5/mo | 1 GB | 1 vCPU | Long-running, reliable |
| Vultr | $6/mo | 1 GB | 1 vCPU | Many global locations |
For WordPress: minimum 1 GB RAM with Nginx, 2 GB RAM with Apache/cPanel. More RAM gives you room for object caching (Redis) and future growth.
Step 1: Set up the new VPS
# Update and install essentials
apt update && apt upgrade -y
apt install -y nginx mariadb-server php8.3-fpm php8.3-mysql \
php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip \
php8.3-imagick redis-server certbot python3-certbot-nginx
# Secure MariaDB
mysql_secure_installation
# Create the site database
mysql -u root -e "CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -e "CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'strong-password';"
mysql -u root -e "GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';"
mysql -u root -e "FLUSH PRIVILEGES;"
Step 2: Configure Nginx and PHP-FPM
# /etc/nginx/sites-available/example.com
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\. {
deny all;
}
}
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Step 3: Migrate the files
On the old shared host, create an archive:
# On the old server (via SSH or cPanel File Manager)
cd /home/username/public_html
tar -czf /home/username/site-backup.tar.gz .
Transfer to the new VPS:
# From your local machine or the new VPS
scp username@old-server:/home/username/site-backup.tar.gz /tmp/
# Or if cPanel: download from File Manager, then scp to new VPS
On the new VPS:
mkdir -p /var/www/example.com
cd /var/www/example.com
tar -xzf /tmp/site-backup.tar.gz
chown -R www-data:www-data /var/www/example.com
Step 4: Migrate the database
On the old host:
# Via SSH
mysqldump -u username -p database_name > /home/username/db-backup.sql
# Or via phpMyAdmin: Export → Custom → Add DROP TABLE → Go
Import on the new VPS:
mysql -u root wordpress < /tmp/db-backup.sql
Step 5: Update wp-config.php
// /var/www/example.com/wp-config.php
define('DB_NAME', 'wordpress');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'strong-password');
define('DB_HOST', 'localhost');
// Add these for the migration test
define('WP_HOME', 'http://new-server-ip');
define('WP_SITEURL', 'http://new-server-ip');
Step 6: Test before DNS cutover
Access your site via the VPS IP to test everything works before switching DNS. Edit /etc/hosts on your local machine:
123.123.123.123 example.com www.example.com
Clear your browser cache and visit example.com. It will load from the new VPS without any DNS changes.
Things to check:
- Homepage loads correctly
- Login to /wp-admin/ works
- Permalinks work (re-save in Settings → Permalinks)
- Plugin functionality works
- Media library images load
- Contact forms send email
Step 7: DNS cutover
Once tested, update your domain’s A record:
- Get the new VPS IP address
- Log into your DNS provider (Cloudflare, registrar, etc.)
- Update the A record for
example.comandwww.example.com - Set TTL to 300 (5 minutes) if you plan to test and potentially roll back
Wait for DNS propagation (typically minutes with low TTL, up to 48 hours for old TTL values).
Step 8: SSL certificate
certbot --nginx -d example.com -d www.example.com
Certbot auto-renews via a systemd timer. Verify:
systemctl status certbot.timer
Step 9: Post-migration cleanup
Redirect www to non-www (or vice versa)
# In the server block for the non-preferred domain
server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
Set up backups (see the backup guide)
Install monitoring (see the monitoring guide)
Remove the test defines from wp-config.php
// Remove or comment out these lines
// define('WP_HOME', 'http://new-server-ip');
// define('WP_SITEURL', 'http://new-server-ip');
What breaks during migration
Email delivery: If your old host handled email (cPanel email, etc.), you need a separate email solution. Options: Google Workspace, MXroute, Migadu, or set up your own mail server.
Absolute URLs in content: Some plugins and themes hardcode the domain in serialized data. Use WP-CLI search-replace:
wp search-replace 'http://old-domain.com' 'https://new-domain.com' --all-tables
Custom PHP configs: Your old host may have had custom php.ini values. Check max_execution_time, upload_max_filesize, post_max_size, and memory_limit on the new server.
Cron jobs: Recreate any cron jobs that were set up on the old host.
Managed VPS: the middle ground
If you want VPS performance without managing the server:
- Cloudways: Managed cloud VPS on DigitalOcean/Linode/Vultr/AWS. Server management included, ~$14/month for 1 GB.
- RunCloud: Server management panel for your own VPS (~$8/month + VPS cost).
- SpinupWP: WordPress-focused server management for your own VPS (~$12/month + VPS cost).
These give you VPS flexibility with someone else handling updates, security, and server configuration.