Back to tutorials
Tutorial

Web Hosting Migration Tutorial (2026): Move Sites from Shared Hosting to a VPS with a Staging Cutover

Web hosting migration tutorial (2026) to move from shared hosting to a VPS using staging, rsync, DB sync, and a safe DNS cutover.

By Anurag Singh
Updated on Jul 08, 2026
Category: Tutorial
Share article
Web Hosting Migration Tutorial (2026): Move Sites from Shared Hosting to a VPS with a Staging Cutover

A clean migration isn’t “copy files, update DNS, hope for the best.” Build a staging copy on your VPS first. Sync changes. Flip DNS only after you’ve confirmed the new stack serves the same site (and email) correctly.

This web hosting migration tutorial walks you through that workflow for 2026. You’ll get practical commands, clear verification checks, and a rollback plan.

This guide covers the most common commercial move: shared hosting → VPS (or VPS → bigger VPS/dedicated). You’ll use rsync for files. You’ll dump and restore the database for content. Then you’ll do a controlled DNS cutover.

If you’re moving WordPress, this workflow helps you avoid common issues. That includes mixed content, broken logins, missing uploads, and cache surprises.

What you’ll migrate in this web hosting migration tutorial (and what you won’t)

Before you touch a domain, write down the moving pieces. Most “mysterious downtime” comes from one forgotten dependency.

  • Website files (public_html, uploads, assets, .htaccess, custom config)
  • Database (MySQL/MariaDB exports, users, privileges)
  • Runtime (PHP version/modules, Nginx/Apache config, cron jobs)
  • DNS (A/AAAA, CNAME, TXT, MX, SPF/DKIM/DMARC, validation records)
  • Email (either keep it with your current provider or move it deliberately)

You will not recreate a heavily customized shared-hosting control-panel environment perfectly. Instead, rebuild what matters. Focus on versions, vhosts, SSL, and scheduled jobs.

Then confirm behavior with real requests.

Prerequisites: VPS sizing, OS choice, and access

For most small business sites and WordPress installs in 2026, a VPS with 2 vCPU / 4 GB RAM is a sensible starting point. If you expect heavy admin usage, WooCommerce, or lots of PHP workers, step up to 4 vCPU / 8 GB RAM.

Choose unmanaged if you want full control and you’re comfortable maintaining the OS. Go managed if you’d rather pay for patching, tuning, and a support backstop.

OS recommendation: Ubuntu Server 24.04 LTS is a practical default in 2026. Debian 12 is also a great choice if you prefer conservative packages.

Access checklist:

  • SSH access to the VPS (root or sudo user)
  • Shared-hosting access: cPanel, SFTP/SSH (if offered), or at least File Manager + phpMyAdmin
  • Domain DNS control (registrar or DNS provider)

Step 1 — Reduce DNS TTL (without breaking anything)

Lower TTL ahead of time so the cutover propagates quickly. Do this 12–24 hours before the switch. Don’t do it five minutes before.

  1. Find the current A/AAAA records for your site (and www).
  2. Set TTL to 300 seconds (5 minutes) for:
    • @ A/AAAA
    • www CNAME (or www A/AAAA)

If you want a step-by-step DNS cutover playbook (TTL, verification, rollback), follow our dedicated guide: DNS cutover tutorial for low downtime.

Step 2 — Prepare the VPS: accounts, firewall, and web stack

Start from a known-good baseline. Don’t migrate onto a server you haven’t secured.

Create a non-root admin user (recommended even if you keep root available):

adduser deploy
usermod -aG sudo deploy

Then follow the full hardening steps from: Sudo setup guide tutorial.

Firewall baseline (UFW):

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

If you need a safer checklist that includes email ports (only when you actually host mail), see: UFW firewall configuration tutorial.

Install your web stack. Two common routes cover most migrations:

  • WordPress-focused: Nginx + PHP-FPM (fast, predictable, easy to cache)
  • Compatibility-focused: Apache + PHP (close to many shared hosts)

If you’re undecided, use Nginx + PHP-FPM for a fresh VPS build. You can still handle .htaccess-style behavior. Translate rules into Nginx server blocks.

Example (Ubuntu 24.04) Nginx + PHP-FPM install:

sudo apt update
sudo apt -y install nginx php-fpm php-cli php-curl php-gd php-mbstring php-xml php-zip php-mysql
sudo systemctl enable --now nginx

Step 3 — Create a staging vhost on the VPS (don’t point DNS yet)

Staging on the destination server lets you test real PHP, real permissions, and real caching behavior. It also helps you catch problems before the public does.

Create a directory layout:

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

Create an Nginx server block at /etc/nginx/sites-available/example.com:

server {
  listen 80;
  server_name example.com www.example.com;

  root /var/www/example.com/public;
  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;
  }
}

Enable it:

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

Staging access without DNS: edit your local hosts file to map the domain to the VPS IP. On macOS/Linux, add this to /etc/hosts:

203.0.113.10 example.com www.example.com

Now your browser hits the VPS for that domain, while everyone else still hits shared hosting.

Step 4 — Copy website files from shared hosting to the VPS

File transfer options depend on what your shared host exposes. Use the best method you can access.

Option A: rsync over SSH (fastest, preserves permissions)

If your shared hosting provides SSH access:

rsync -avz --progress \
  user@shared-host.example:/home/user/public_html/ \
  /var/www/example.com/public/

Run it twice. The first pass copies everything. The second pass captures changes made during the initial copy.

Option B: SFTP download/upload (works almost everywhere)

Use an SFTP client (WinSCP, FileZilla, Cyberduck). Download public_html locally, then upload to /var/www/example.com/public. It’s slower, but it works reliably.

Option C: cPanel File Manager + archive (often faster than clicking folders)

  1. In cPanel File Manager, select public_html → Compress to site.tar.gz
  2. Download the archive
  3. Upload to VPS and extract:
sudo tar -xzf site.tar.gz -C /var/www/example.com/public --strip-components=1

Permissions sanity check:

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

Step 5 — Move the database (export, import, and fix credentials)

Most shared hosting runs MySQL/MariaDB. You’ll export the database. Then you’ll create a new DB/user on the VPS. Finally, you’ll import the dump.

Export from shared hosting

If you have phpMyAdmin, export SQL as “Custom” and include:

  • DROP TABLE / DROP VIEW (optional, helps repeat imports)
  • Routines/events if your app uses them
  • Compression: gzip

If SSH is available on the source, use mysqldump:

mysqldump -u dbuser -p --single-transaction --quick dbname | gzip > db.sql.gz

Create DB and import on the VPS

Install MySQL server (or MariaDB) if your application expects a local DB. If you’re using a managed database service, import there instead.

sudo apt -y install mysql-server
sudo mysql
CREATE DATABASE exampledb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'exampleuser'@'localhost' IDENTIFIED BY 'use-a-strong-password';
GRANT ALL PRIVILEGES ON exampledb.* TO 'exampleuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Import:

gunzip -c db.sql.gz | mysql -u exampleuser -p exampledb

Update app config (WordPress: wp-config.php):

define('DB_NAME', 'exampledb');
define('DB_USER', 'exampleuser');
define('DB_PASSWORD', 'use-a-strong-password');
define('DB_HOST', 'localhost');

Step 6 — Fix URL/domain edge cases (WordPress and common PHP apps)

If the domain stays the same, you usually don’t need a site-wide search/replace. Still, staging tests can surface surprises. Common sources are plugins, hardcoded URLs, or old http assets.

WordPress check: confirm home and siteurl are correct:

wp option get home
wp option get siteurl

If you have WP-CLI installed and need to fix them:

wp option update home 'https://example.com'
wp option update siteurl 'https://example.com'

Mixed content quick test: load the homepage in browser dev tools. Filter for “mixed content.” Then fix the offenders (often theme assets or older builder content).

Step 7 — Add SSL on the VPS and verify the certificate chain

Don’t leave SSL until the end. The moment DNS flips, browsers will request HTTPS. If HTTPS fails, users bounce.

If you’re using Nginx on the VPS, follow our complete Let’s Encrypt walkthrough: SSL setup guide tutorial.

After issuing the cert, validate from your workstation:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject -dates

If you see handshake errors, the wrong cert, or missing intermediates, follow this troubleshooting flow: TLS handshake troubleshooting tutorial.

Step 8 — Decide what to do about email (keep it, move it, or split it)

Email is where migrations tend to get messy. For many sites, the safest move is to keep email where it is during the website cutover. Then migrate mail later, on purpose.

Three practical patterns:

  • Website moves, email stays: keep MX records pointing at your existing provider. Only change A/AAAA for the website.
  • Move everything to the VPS: only if you’re ready to manage deliverability (SPF/DKIM/DMARC, rDNS, queue monitoring).
  • Split email to a dedicated provider: common for businesses; simplifies deliverability and backups.

If you run cPanel on the destination server, get your mail routing right before the cutover. That avoids “local vs remote” confusion: cPanel email routing tutorial.

Step 9 — Final sync window (freeze changes, resync files, resync DB)

Schedule a short “content freeze” window. For small sites, 10–20 minutes is usually enough. The goal is simple. Don’t let orders, form submissions, or edits land only on the old server.

Files: run a second rsync to capture deltas:

rsync -avz --delete \
  user@shared-host.example:/home/user/public_html/ \
  /var/www/example.com/public/

Database: for WordPress, enable maintenance mode during the final export/import. If you can’t, assume you may lose the last few changes.

Export again and import again. The second pass should be quick.

Step 10 — Cut over DNS and verify from multiple networks

Switch A/AAAA (and possibly www) to the VPS IP. Keep TTL at 300 for the first few hours. This gives you room to react if something’s off.

Verification commands:

# Check what the public resolver sees
dig +short A example.com @1.1.1.1
dig +short A example.com @8.8.8.8

# Check HTTP and HTTPS responses
curl -I http://example.com
curl -I https://example.com

During propagation, some visitors will still hit the old hosting for a while. That’s expected.

What’s not expected is different content on old vs new because you missed the final sync.

Step 11 — Post-cutover checklist (first 60 minutes)

  • Browse key pages: homepage, contact form, checkout/login, search
  • Confirm admin login works and sessions persist
  • Check error logs: /var/log/nginx/example.com.error.log (or Apache vhost error log)
  • Confirm cron jobs exist (WordPress wp-cron or real server cron)
  • Validate SSL redirect behavior (no loops, no http-only assets)
  • Re-enable any caches/CDN you paused during cutover

Rollback plan (you should write this before you migrate)

Rollback stays painless if you keep the old hosting untouched for 24–48 hours.

  1. Revert A/AAAA records to the old IP
  2. Keep TTL low until stable
  3. Use logs to find what broke on the VPS (permissions, PHP version mismatch, missing extensions, firewall)

Common migration pitfalls and quick fixes

  • White screen / 502: PHP-FPM socket mismatch. Verify php-fpm is running. Confirm your Nginx config points to the right socket (example: /run/php/php8.3-fpm.sock).
  • 403 Forbidden: wrong ownership or directory permissions. Re-run the permission fix commands from Step 4.
  • Uploads missing: you copied the theme but not wp-content/uploads. Re-sync files.
  • Redirect loops: app thinks it’s HTTPS behind a proxy or forced redirects stack. Audit Nginx redirects and WordPress “home/siteurl”.
  • Email suddenly stops: you changed MX or mail routing unintentionally. Confirm DNS MX/TXT stayed the same during a “website-only” migration.

If you’re leaving shared hosting because you’ve hit its limits, a VPS gives you dedicated resources and more predictable performance. Start with an HostMyCode VPS for full control, or choose managed VPS hosting if you want the OS, patches, and core services handled for you.

FAQ: shared hosting to VPS migrations

How long does a shared hosting to VPS migration usually take?

For a typical WordPress site, plan 1–3 hours for build + staging tests. Then plan a 10–30 minute final sync and DNS cutover window. Large media libraries take longer.

Do I need to move email at the same time?

No. The lowest-risk path is website-first, email later. Keep MX records unchanged during the web cutover.

Can I migrate with zero downtime?

You can get very close. Low TTL + staging + final sync reduces user-visible impact. True zero downtime needs app-level replication and write coordination, which most small sites don’t use.

What’s the safest way to test before DNS changes?

Edit your local /etc/hosts to map the domain to the VPS IP. That tests the real hostname, cookies, and redirects without public DNS changes.

Summary: a migration workflow you can repeat

The pattern stays the same: lower TTL, build staging on the VPS, copy files and the database, validate via a hosts-file override, do a final sync during a short freeze, then switch DNS and watch logs.

If you’re doing this for multiple sites, standardize your vhost layout. Keep a written rollback plan.

If you’re ready to move off shared hosting, you can deploy your destination server in minutes with HostMyCode VPS, and keep the operational workload lighter with managed VPS hosting.