Back to tutorials
Tutorial

Server Migration Tutorial: Move a Website from Shared Hosting to a VPS (DNS, SSL, Email, and Rollback) in 2026

Server migration tutorial for moving from shared hosting to a VPS with DNS, SSL, email, and a rollback plan in 2026.

By Anurag Singh
Updated on Sep 08, 2026
Category: Tutorial
Share article
Server Migration Tutorial: Move a Website from Shared Hosting to a VPS (DNS, SSL, Email, and Rollback) in 2026

A shared hosting account works—until it slows you down. The warning signs are boring but consistent: CPU throttling, a sluggish admin area, cron jobs that drift, and support replies that end with “upgrade recommended.” This server migration tutorial gives you a safe, repeatable path from shared hosting to a VPS. It covers DNS cutover, SSL, email choices, and a rollback plan you can follow under pressure.

The workflow assumes a typical PHP/WordPress site. The same sequence works for most small business sites.

You’ll stage the new server, verify everything off-DNS, then switch traffic with minimal downtime. You’ll also avoid common traps like broken mail, mixed content, and “stuck” DNS caches.

What you’ll migrate (and what you should decide first)

Before you touch the VPS, define what “finished” looks like. A clean migration has four parts:

  • Web: files, web server config, and PHP runtime.
  • Database: MySQL/MariaDB export/import plus credentials.
  • DNS: records, TTL strategy, and the cutover window.
  • Email: keep it on the old host, move it, or use a relay/provider.

If your shared host handles email for the domain, treat mail as a first-class workload.

“Fix email later” is how leads disappear and invoices bounce.

Pre-migration checklist (15 minutes that saves hours)

  • Confirm the domain registrar login and where DNS is hosted (registrar DNS, Cloudflare, cPanel DNS, etc.).
  • List current DNS records: A/AAAA, CNAME, MX, SPF, DKIM, DMARC, and any subdomains.
  • Lower DNS TTL ahead of cutover (ideally 300 seconds) if you control the zone.
  • Capture current site size and DB size (helps pick VPS plan and estimate copy time).
  • Pick the VPS OS (Ubuntu 24.04 LTS is a safe default in 2026) and whether you want a control panel.

If you’re planning a DNS switch, use a checklist and follow it step by step.

This cutover workflow pairs well with the DNS cutover checklist tutorial.

Provision your VPS and lock down access (before you copy a single file)

For migrations, predictable beats clever. Size the VPS for your peak, not your monthly average.

If you’re leaving shared hosting because you keep hitting limits, the jump to a VPS usually feels immediate. That’s especially true with NVMe-backed storage.

If you want to run the server yourself, spin up a HostMyCode VPS. If you’d rather not spend migration week also thinking about patching and baseline hardening, managed VPS hosting keeps ops simpler while you focus on the site.

Baseline access hardening

On Ubuntu, create a non-root admin user. Then switch to SSH keys and disable password logins.

adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
systemctl restart ssh

If you want a clean, repeatable key setup (without locking yourself out), keep this open in another tab: SSH key setup guide tutorial.

Choose your stack: control panel vs. a lean web stack

This decision drives the rest of the migration.

If you’re used to cPanel and rely on its workflows (mailboxes, backups, file manager, reseller features), a cPanel-based VPS keeps the move familiar.

If you host one or two sites and prefer fewer layers, a lean stack like Nginx + PHP-FPM is easier to reason about. It’s also quicker to tune.

  • Similar to shared hosting: cPanel/WHM on VPS (best for multiple sites, email-heavy domains, reseller needs).
  • Lean and fast: Nginx + PHP-FPM + MariaDB (best for devs, single-site WordPress, fewer moving parts).

Below, you’ll set up the lean stack to keep the steps portable.

If you’re migrating into cPanel, the sequence stays the same—copy, verify, cut over. Only the tools change.

Install Nginx, PHP-FPM, and MariaDB on Ubuntu 24.04

Update packages first:

sudo apt update
sudo apt -y upgrade

Install the web and PHP stack:

sudo apt -y install nginx mariadb-server
sudo apt -y install php8.3-fpm php8.3-mysql php8.3-cli php8.3-curl php8.3-gd php8.3-xml php8.3-mbstring php8.3-zip php8.3-intl

Enable and start services:

sudo systemctl enable --now nginx
sudo systemctl enable --now mariadb
sudo systemctl enable --now php8.3-fpm

Create a database and user

sudo mysql
CREATE DATABASE site_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site_user'@'localhost' IDENTIFIED BY 'use-a-long-random-password';
GRANT ALL PRIVILEGES ON site_db.* TO 'site_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Save the DB name, user, and password somewhere safe. You’ll use them during import and in wp-config.php.

Copy website files from shared hosting to the VPS

Your copy method depends on what your shared host allows.

If you have SSH, use rsync. It’s faster and resumable.

If you don’t have SSH, pull an archive over SFTP/HTTPS. Then extract it on the VPS.

Option A: rsync over SSH (fast, resumable)

On the VPS, copy the web root (example path shown; adjust for your shared host):

sudo mkdir -p /var/www/example.com
sudo rsync -avz --progress shareduser@sharedhost:/home/shareduser/public_html/ /var/www/example.com/

If you want a reusable rsync pattern you can keep for backups later, see the rsync backup tutorial.

Option B: download a cPanel backup/archive

On shared hosting, create a full backup or compress the site directory into a tarball.

Upload it to the VPS, then extract:

sudo tar -xvf site-backup.tar -C /var/www/example.com

After extraction, set sane permissions:

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

Export and import the database safely

On WordPress moves, the database is where small mistakes turn into weird breakage.

Export and import in a way that preserves character sets. Also avoid long-running locks.

Export from shared hosting

If you have SSH on shared hosting:

mysqldump --single-transaction --routines --triggers --default-character-set=utf8mb4 -u dbuser -p dbname > db.sql

Compress it for faster transfer:

gzip -9 db.sql

Import on the VPS

Copy the dump to the VPS, then import:

gunzip -c db.sql.gz | mysql -u site_user -p site_db

Quick sanity checks:

mysql -u site_user -p -e "SHOW TABLES;" site_db | head

Configure Nginx server block and test locally before DNS

The goal is simple: the site must work on the VPS before you touch public DNS.

Create an Nginx server block:

sudo nano /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;

  access_log /var/log/nginx/example.com.access.log;
  error_log  /var/log/nginx/example.com.error.log;

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

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
  }

  location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|webp|avif)$ {
    expires 30d;
    add_header Cache-Control "public, max-age=2592000";
  }
}

Enable it and reload Nginx:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo nginx -t
sudo systemctl reload nginx

Test the site without touching public DNS

Use a hosts-file override on your laptop. It forces your browser to resolve the domain to the new VPS IP.

  • macOS/Linux: edit /etc/hosts
  • Windows: edit C:\Windows\System32\drivers\etc\hosts

Add:

203.0.113.10  example.com www.example.com

Then browse the site like a normal visitor.

Log into WordPress. Open a few key templates. Check media uploads and search results.

Fix WordPress configuration (URLs, wp-config, and permissions)

If the domain stays the same, you usually don’t need a URL search/replace.

You do need correct database credentials in wp-config.php:

define('DB_NAME', 'site_db');
define('DB_USER', 'site_user');
define('DB_PASSWORD', 'use-a-long-random-password');
define('DB_HOST', 'localhost');

Two checks catch most “it kind of loads, but it’s broken” situations:

  • Uploads directory writable: /var/www/example.com/wp-content/uploads owned by www-data.
  • Pretty permalinks: your Nginx try_files rule is present (above).

SSL: issue a Let’s Encrypt certificate and enforce HTTPS

Do SSL only after the site works over HTTP using the hosts override.

Install Certbot:

sudo apt -y install certbot python3-certbot-nginx

Request the certificate:

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

Confirm auto-renew:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

If you want a deeper SSL checklist (and the usual renewal footguns), keep this guide handy: VPS SSL setup guide tutorial.

Email: choose a migration strategy that won’t break deliverability

Email isn’t required for the site to load. It is required for the business to function.

During a shared-to-VPS move, you typically choose one of these:

  1. Keep email on the old provider (short-term simplest): leave MX records unchanged; migrate only the website.
  2. Move email to the VPS: you’ll configure mail services, migrate mailboxes, and update MX/SPF/DKIM/DMARC.
  3. Use an SMTP relay/provider for outbound mail from the VPS: keep inbound mail wherever you like; improve reliability for transactional sends.

For many small teams, option 1 plus option 3 is the cleanest path.

Move the website now. Keep inbound mail stable. Send outbound mail through a trusted channel.

If you’ve dealt with spam flags or bounces, don’t hand-wave authentication. This guide is practical and straight to the point: email deliverability troubleshooting tutorial.

DNS cutover: do it in a controlled window with a rollback plan

DNS changes are quick to make and slow to “un-make” if you didn’t lower TTL.

That’s why the prep step matters.

Step 1: identify what needs to change

  • If the website uses A records, you’ll point example.com and www to the VPS IPv4.
  • If you use AAAA (IPv6), ensure your VPS is ready for it, or remove AAAA temporarily.
  • If you keep email on the old provider, do not change MX.

Step 2: update DNS records

At your DNS host, update:

  • example.com → A → 203.0.113.10
  • www → CNAME → example.com (or A record to the same IP)

Step 3: verify propagation from multiple networks

From your workstation:

dig +short example.com A
dig +short www.example.com A

From a different resolver (Google):

dig @8.8.8.8 +short example.com A

Keep the hosts-file override in place until public DNS consistently points to the new VPS.

Your rollback plan (write it down)

If something goes sideways, rollback should be boring:

  • Change A/AAAA records back to the shared host IP.
  • Keep TTL low until you’re confident the VPS is stable for 24 hours.
  • Do not delete the shared hosting account immediately. Keep it for at least a week.

Rollback only hurts when you’re guessing.

Save the old IPs before you cut over.

Post-migration verification (the checks that catch silent failures)

After DNS flips, verify in a fixed order.

It keeps you from chasing symptoms and missing the root cause.

  1. HTTP status and redirects: curl -I https://example.com should return 200/301 as expected.
  2. PHP health: visit a dynamic page and log into wp-admin.
  3. Forms and transactional mail: submit your contact form; check spam folders.
  4. Mixed content: open DevTools → Console; fix hard-coded http links if any.
  5. Performance: watch CPU/RAM during peak; enable caching only after stability.

Quick log diagnostics

sudo tail -n 100 /var/log/nginx/example.com.error.log
sudo journalctl -u php8.3-fpm --since "15 min ago" --no-pager | tail -n 80

Watch for 404 spikes right after cutover.

They usually mean missing assets, a partial copy, or rewrite rules that don’t match the old environment.

Hardening and stability steps you should do in the first week

Once the site is stable, tighten the server.

During the migration window, keep changes minimal and reversible.

  • Firewall: allow only 22 (or your custom SSH port), 80, 443.
  • Automatic security updates: enable unattended upgrades on Ubuntu.
  • Brute-force protection: add Fail2Ban for SSH and basic web abuse patterns.
  • Backups: implement offsite encrypted backups and run a restore test.

Two solid follow-ups once you’re live:

Performance tune without breaking the site

Shared hosting often applies caching behind the curtain. On a VPS, you own every dial.

That’s great—if you turn them one at a time.

  • Enable OPcache: it reduces PHP CPU by caching compiled scripts.
  • Add object caching for WordPress: Redis helps on admin-heavy sites and stores with many logged-in users.
  • Cache static assets at Nginx (headers are already in the sample config).

For most WordPress sites, Redis is the safest meaningful improvement after the move. This guide stays practical and production-minded: WordPress Redis object cache setup tutorial.

Summary: your repeatable migration workflow

  • Provision the VPS, secure SSH, and install a predictable web stack.
  • Copy files, import the database, and test via hosts override.
  • Issue SSL on the VPS and confirm renewal.
  • Make an explicit email decision; don’t accidentally change MX records.
  • Cut over DNS with low TTL and a written rollback plan.
  • Verify logs, forms, and performance; then harden and automate backups.

If you want a migration that feels controlled instead of risky, start with a HostMyCode VPS sized for your traffic. Or hand baseline server upkeep to managed VPS hosting and keep your attention on the application.

If you’re leaving shared hosting because you’ve hit limits, a VPS is usually the cleanest next step. HostMyCode offers HostMyCode VPS plans for hands-on admins, plus managed VPS hosting if you want help with hardening, updates, monitoring, and operational basics while you migrate.

FAQ

Should I migrate email at the same time as the website?

Not by default. If email is stable on the current provider, keep MX records unchanged and migrate only the website first. Move mail later in a separate window.

How low should I set DNS TTL before a migration?

300 seconds is a practical target for most zones. Set it at least a few hours before cutover so caches pick up the new TTL.

Can I cut over DNS before I install SSL on the VPS?

You can, but it’s a common mistake. Install and test SSL first so the moment DNS flips, HTTPS works and you avoid browser warnings.

How long should I keep the old shared hosting account?

At least 7 days. It gives you a rollback option and time to catch background issues like scheduled jobs, webhook callbacks, and forgotten subdomains.

What’s the fastest way to confirm I’m hitting the new server?

Check the public A record with dig, then verify on the VPS by watching access logs: sudo tail -f /var/log/nginx/example.com.access.log while you refresh the site.