Disclosure: we may earn a commission or referral reward from CloudCone, Contabo, DigitalOcean (account credit, not cash), Hostwinds, InterServer, RackNerd, VPSDime and Vultr if you sign up through our links. It does not change the price you pay. Every other provider pays us nothing. Prices in this guide are as of the date shown and may have changed; see the comparison pages for the latest checked prices.

Guides · BLOG

How to move from shared hosting to a VPS in a weekend (2026)

Some prices quoted in this guide are out of date. It is being rebuilt on our price index; for current prices use the comparison pages, which show when each price was checked.

This is the compressed version of the shared-hosting-to-VPS story. If you're technical enough to Google Linux errors, you can do this in a weekend for a WordPress or PHP-based site. This guide breaks it into a Saturday afternoon (setup) and a Sunday morning (cutover) with realistic time estimates.

Prices as of 2026-09-22.

Prerequisites (30 minutes Friday evening)

  • A VPS account. Hetzner CX22 at $4.60/mo is the recommended default. Sign up at console.hetzner.cloud.
  • SSH key on your local machine. ssh-keygen -t ed25519 if you don't have one.
  • A backup of your shared hosting site (via cPanel → Backups, or via WordPress plugin like Duplicator).
  • A quiet weekend where you can afford 30 minutes of scheduled downtime.

Saturday afternoon: build the VPS (3-4 hours)

Hour 1: Provision and harden

Log into Hetzner Cloud Console. Create a server:

  • Ubuntu 24.04 LTS
  • Type: CX22 (Falkenstein for EU, Ashburn for US)
  • Add your SSH key.
  • Create.

SSH in as root. Basic hardening:

```bash

adduser deploy

usermod -aG sudo deploy

mkdir -p /home/deploy/.ssh

cp /root/.ssh/authorized_keys /home/deploy/.ssh/

chown -R deploy:deploy /home/deploy/.ssh

chmod 700 /home/deploy/.ssh

sed -i 's/^#PermitRootLogin./PermitRootLogin no/' /etc/ssh/sshd_config

sed -i 's/^#PasswordAuthentication./PasswordAuthentication no/' /etc/ssh/sshd_config

systemctl restart ssh

ufw allow OpenSSH

ufw allow 80

ufw allow 443

ufw --force enable

apt update && apt upgrade -y

apt install unattended-upgrades -y

```

Hour 2: LEMP stack

```bash

apt install -y nginx php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip mariadb-server certbot python3-certbot-nginx

mysql_secure_installation

```

Create the WordPress database:

```bash

mysql -e "CREATE DATABASE wp; \

CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'CHANGEME_strong_password'; \

GRANT ALL ON wp.* TO 'wpuser'@'localhost';"

```

Hour 3: Nginx config

Create /etc/nginx/sites-available/yourdomain.com:

```nginx

server {

server_name yourdomain.com www.yourdomain.com;

root /var/www/yourdomain.com;

index index.php;

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;

}

location ~ /\.ht { deny all; }

}

```

ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/

nginx -t && systemctl reload nginx

Hour 4: Import your site

Download your shared hosting backup to your local machine. Extract the public_html folder and the SQL dump.

Upload to VPS:

```bash

scp -r ~/Downloads/public_html deploy@vps-ip:/tmp/

scp ~/Downloads/db.sql deploy@vps-ip:/tmp/

```

On the VPS:

```bash

sudo mv /tmp/public_html /var/www/yourdomain.com

sudo chown -R www-data:www-data /var/www/yourdomain.com

mysql wp < /tmp/db.sql

```

Update /var/www/yourdomain.com/wp-config.php with the new DB name (wp), user (wpuser), password, and host (localhost).

Test with hosts file (before DNS cutover)

Add to your local machine's /etc/hosts:

```

YOUR.VPS.IP.HERE yourdomain.com www.yourdomain.com

```

Visit yourdomain.com in your browser. If the site loads correctly, you're ready to cutover tomorrow.

Remove the hosts entry when done testing.

Sunday morning: DNS cutover (30 minutes downtime max)

30 minutes before: drop DNS TTL

At your DNS provider (Cloudflare, Namecheap, wherever): change the TTL for your A and AAAA records to 300 seconds (5 minutes). Save.

Wait 30 minutes for the old TTL to fully expire from resolvers.

Cutover time

1. Take a final backup on shared hosting. cPanel → Backups → Download.

2. Put the shared hosting into read-only mode or a maintenance page (optional; helps prevent split-brain writes).

3. Change DNS A records at your DNS provider to point at the Hetzner IP.

4. Wait 5 minutes for the low TTL to propagate.

SSL

Once DNS is pointing at Hetzner:

```bash

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

```

Certbot will detect the Nginx config, issue Let's Encrypt certs, and configure HTTPS redirect. Auto-renewal is set up automatically.

Verify

Visit yourdomain.com (in a new incognito window to avoid stale DNS cache). Site should load with a green lock. Check:

  • Homepage.
  • Login.
  • Comments / contact form.
  • Any password-protected areas.

If everything works: you're done. Total downtime: 5-15 minutes.

After the migration

Set up backups

Cron a nightly backup:

```bash

sudo nano /etc/cron.d/wp-backup

```

```

0 3 * root mysqldump wp | gzip > /root/backups/db-$(date +\%Y\%m\%d).sql.gz

0 3 * root tar czf /root/backups/files-$(date +\%Y\%m\%d).tgz /var/www/yourdomain.com

0 4 * root find /root/backups -mtime +14 -delete

```

Better: install rclone and sync backups to Backblaze B2 or DO Spaces so they survive VPS destruction.

Uptime monitoring

Sign up for UptimeRobot (free). Set a monitor for https://yourdomain.com. You will now know if the site is down.

Cancel shared hosting

  • Download a final backup for insurance.
  • Cancel the shared hosting.
  • Keep the backup for 60 days.

Total cost comparison

  • Shared hosting (Bluehost Choice Plus renewal): $18/mo → $216/year.
  • Hetzner VPS after migration: $4.60/mo → $55/year.

Annual saving: $161 for a weekend of work. And every subsequent year saves another $161.

Related guides

Prices as of 2026-09-22.