Move a site from shared hosting to a VPS

Copy your files and database across, test the site on the new server before anyone sees it, keep your email working, and switch DNS with no downtime.

To move a site from shared hosting to a VPS, set up the same software on the new server, copy the files and database across, test the site there through your own hosts file, then point DNS at the new server and keep the old account for a week. Done in that order, visitors never see a broken site.

The part people forget is email. If your mailboxes live on the shared host, read the email section before you change any DNS.

Before you start: take stock

Log in to your hosting control panel and write down:

  • What the site runs on: PHP version, database (MySQL or MariaDB), any PHP extensions it relies on. Most cPanel hosts show these under "Select PHP Version".
  • Every domain and subdomain pointing at the account.
  • Cron jobs, under "Cron Jobs". They won't move by themselves.
  • Email: mailboxes, forwarders and autoresponders on the account.
  • Where DNS is hosted. If your nameservers belong to the host, you'll need to move DNS too (see below).

Lower the DNS TTL a day ahead

The TTL on a DNS record is how long other servers may cache it. If it's a day, the switch takes a day to reach everyone. At your DNS provider, set the TTL on your site's A and AAAA records to 300 seconds (five minutes) a day before the move. Put it back up afterwards.

Build the new server

Set up the same stack on the VPS. For a WordPress or other PHP site, that's nginx, PHP-FPM and MariaDB: Host WordPress on a VPS walks through it, and for any PHP site the steps are the same apart from the WordPress download. Do the first hour checklist as well, so the server is secure before the site goes live.

Use the same major PHP version as the old host, or newer if your site supports it.

Copy the files

If your host gives you SSH access, rsync from the VPS is the quickest way. Replace the user, host and paths with yours:

bash
apt install -y rsync
rsync -avz --progress user@oldhost.example.net:public_html/ /var/www/example.com/

Without SSH, download the files from the control panel's file manager as a zip (or with an SFTP client such as FileZilla), upload it with scp, and unpack it:

bash
scp site.zip root@203.0.113.10:/var/www/
ssh root@203.0.113.10
apt install -y unzip
cd /var/www && unzip site.zip -d example.com
chown -R www-data:www-data /var/www/example.com

Copy the database

Export it from the old host with phpMyAdmin (Export, format SQL), or with mysqldump if you have SSH there:

bash
mysqldump --single-transaction --no-tablespaces -u olduser -p olddb > site.sql

--no-tablespaces stops the newer mysqldump asking for a privilege that shared hosting accounts don't have.

On the VPS, create an empty database and user (the WordPress guide has the commands), then import. If you picked the WordPress one-click app, they already exist: the database and user are both wordpress, and the password is in /root/wordpress-db.txt.

bash
mariadb newdb < site.sql

Update the app's config with the new database name, user and password. For WordPress that's wp-config.php; set DB_HOST to localhost.

Test before you switch

You want to see the site on the new server while the world still goes to the old one. Your computer's hosts file does that: it overrides DNS for you alone.

Add a line with the VPS's address and your domain:

  • Linux and macOS: /etc/hosts, edited with sudo.
  • Windows: C:\Windows\System32\drivers\etc\hosts, edited in Notepad run as administrator.
text
203.0.113.10  example.com www.example.com

Now your browser loads the site from the VPS. It'll be plain HTTP for now, since the certificate comes after the switch. Click through it properly: pages, forms, logins, uploads, anything with a payment. Check the logs on the server while you do:

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

Missing PHP extensions show up here. Install them (apt install php-<name>) and restart PHP-FPM.

Remove the line from your hosts file when you're done.

Keep email working

A VPS doesn't come with mailboxes. If your email is on the shared host, you have three options:

  1. Leave it there for now. Keep the hosting account and leave the MX records pointing at it. Only change the A records for the website. This is the safest choice for the move itself.
  2. Move it to an email provider (Fastmail, Proton, Google Workspace, Microsoft 365, or your registrar's mail). Set the provider up, copy old messages across with its import tool, then change the MX, SPF and DKIM records to theirs.
  3. Run your own mail server. Possible, but a lot of work to do well, and sending needs port 25, which is blocked by default on new VPSNine servers.

Most people pick option 2. Either way, don't cancel the shared hosting until email is sorted.

Your site still needs to send email itself, for contact forms and password resets. Use an SMTP relay or transactional email service on port 587 rather than sending directly; Sending email: port 25 explains why.

Switch DNS

If the host runs your DNS (your nameservers are theirs), first copy every record to a DNS provider you control, including MX and TXT, and switch nameservers to it. Then:

  1. Put the old site in maintenance mode, or stop making changes, so nothing is written there after the final copy.
  2. Run the database export and import again, and rsync the files again. rsync only sends what changed, so it's quick.
  3. Change the A record for the domain and www to the VPS's IPv4, and add AAAA records for its IPv6 if IPv6 works.
  4. Once getent hosts example.com on the VPS shows the new address, get the certificate: certbot --nginx -d example.com -d www.example.com. Serve a site with nginx and HTTPS has the details.

With a five-minute TTL, most visitors are on the new server within the hour.

Afterwards

  • Recreate the cron jobs on the VPS with crontab -e. For WordPress, a real cron job calling wp-cron.php is more reliable than WordPress's built-in one.
  • Set up backups on the new server. Shared hosts often did this quietly; on a VPS it's yours. Backups you should run covers it.
  • Put the DNS TTL back up to an hour or more.
  • Keep the old hosting account for a week, in case something turns up missing, then cancel it.

Doing it on VPSNine

If the site is WordPress, the WordPress one-click app builds nginx, PHP-FPM and MariaDB for you on the first boot. Skip its installer. Import your database into the one the app created, copy your wp-content over the new one, and keep the new wp-config.php, which has the right database details; just set $table_prefix in it to the one from your old wp-config.php. For other PHP sites, the LEMP stack app gives you the same stack without WordPress.

Budget, with 2 GB of memory, is plenty for most sites coming off shared hosting. The plans page has the sizes, and your first order has a 14-day money-back guarantee.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly, or a year up front in Bitcoin
  • 14-day money-back guarantee