Moving from shared hosting to a virtual dedicated server (VDS/VPS) is a natural step once a site outgrows its resource limits. A VDS gives you full root access, dedicated CPU/RAM resources, and the ability to fine-tune the environment to your needs.
When it's time to move from shared to a VDS
| Symptom | Cause | Solution |
|---|---|---|
| Site slows down at peak hours | Competing for resources with neighbors | VDS with dedicated resources |
| 503 errors / limits exceeded | Shared CPU/RAM quotas | VDS with no host-imposed limits |
| Can't install the PHP/Python version you need | Shared hosting controls the environment | Full root access on a VDS |
| Need cron to run every minute | Shared hosting blocks frequent jobs | Any cron schedule on a VDS |
| Multiple projects | Extra sites are expensive | Unlimited sites on a VDS |
Preparing the VDS before migration
# Update the system (Ubuntu/Debian)
apt update && apt upgrade -y
# Install the web stack
apt install nginx php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip mariadb-server -y
# Start the services
systemctl enable --now nginx php8.3-fpm mariadb
Step 1: Create a backup on the shared hosting
# Via cPanel: Backup Wizard → Full Backup
# Or manually via SSH (if available)
tar -czf ~/backup-site.tar.gz ~/public_html/
mysqldump -u dbuser -p dbname > ~/backup-db.sql
Step 2: Transfer files to the VDS
># Download the archive from shared hosting to your local PC, then upload it to the VDS
scp backup-site.tar.gz root@YOUR-VDS-IP:/var/www/
# Or directly from shared hosting to the VDS via rsync
rsync -avz --progress user@shared-host:~/public_html/ root@YOUR-VDS-IP:/var/www/example.com/
# Extract
cd /var/www/
tar -xzf backup-site.tar.gz
Step 3: Restore the database
# Create the database and user
mysql -u root -p <<'SQL'
CREATE DATABASE mysite CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'StrongPass123';
GRANT ALL ON mysite.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;
SQL
# Import the dump
mysql -u myuser -p mysite < backup-db.sql
Step 4: Configure Nginx
# /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;
}
}
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
Step 5: Test before switching DNS
># Add to /etc/hosts on your PC for testing
YOUR-VDS-IP example.com www.example.com
# Check the site in a browser without changing DNS
# After a successful test — revert hosts and switch DNS
Step 6: Switch DNS with zero downtime
Only change your DNS records after successfully testing the site on the VDS:
- Lower the A-record TTL to 300 seconds 24 hours before the migration
- Make sure the site works on the VDS (via /etc/hosts)
- Update the A record to point to your VDS IP
- Wait for DNS propagation (5–30 minutes with a TTL of 300)
- Keep the old hosting active for another 48 hours as a fallback
Zero downtime: With the TTL lowered properly and testing done via /etc/hosts, the DNS switch happens seamlessly for users — the site stays available the whole time.
Update the application config! After the migration, update
wp-config.php (WordPress), .env, or other configs with the new database details. The old credentials from the shared hosting won't work.
Why move from shared hosting to VDS
Shared hosting limits CPU/RAM resources, forbids running background processes, and doesn't allow fine-tuning of PHP/MySQL. A VDS gives you full control.
💡 Signs it's time for a VDS: the site goes down at peak hours, you need cron jobs every minute, or you need PHP 8.2+ or Redis.
Step 1: Backup with cPanel
cPanel → Backup Wizard → Full Backup. Download the archive (.tar.gz) from the server.
Step 2: Installing the stack on the VDS
apt update && apt install -y nginx mysql-server php8.2-fpm php8.2-mysql php8.2-gd php8.2-xml php8.2-mbstring php8.2-curl php8.2-zip
systemctl enable --now nginx mysql php8.2-fpm
Step 3: Importing the database
mysql -u root -p -e "CREATE DATABASE mydb CHARACTER SET utf8mb4;"
mysql -u root -p -e "CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'pass';"
mysql -u root -p -e "GRANT ALL ON mydb.* TO 'myuser'@'localhost';"
mysql -u root -p mydb < backup.sql
Step 4: Configuring Nginx + PHP-FPM
server {
listen 80;
server_name mysite.com www.mysite.com;
root /var/www/mysite;
index index.php index.html;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Checklist before switching DNS
| Check | Command |
|---|---|
| Site opens by IP | curl http://NEW_IP |
| PHP works | php -r "echo phpinfo();" | head |
| MySQL is accessible | mysql -u myuser -p mydb -e "SHOW TABLES;" |
| SSL is configured | certbot --nginx -d mysite.com |
⚠️ Lower the DNS record TTL to 300 seconds 24 hours before the move — this speeds up propagation after changing the A record.