Basics

Shared hosting vs VPS: signs you have outgrown shared hosting, and how to move

Shared hosting vs VPS as a terminal card: the shared side with maxed-out quotas and a 508 error, the VPS side with dedicated KVM RAM and cores, an NVMe disk and full root access

"Shared hosting vs VPS?" is not a question with one answer for all time. The answer changes on the day your site starts getting real traffic, a 503 error shows up every day at noon, and support only tells you "your CPU usage is high". This article lists the signs that you have outgrown shared hosting, shows which quota has filled up and where to see it, and gives a practical migration checklist for PHP and WordPress sites, including the two traps, SSL and email, that ruin most migrations.

Signs that you have outgrown shared hosting

Shared hosting is like an apartment in a crowded building: cheap and hassle-free, as long as the neighbors stay quiet. Dozens (sometimes hundreds) of sites sit side by side on one server, and the host uses tools such as CloudLinux to put a usage ceiling on each of them. These are the signs that you are hitting that ceiling:

  • 503 errors or 508 (Resource Limit Is Reached) errors at busy hours: requests exceed your quota, and visitors are left standing at the door.
  • Unexplained, intermittent slowdowns: the site has not changed, yet some days it is sluggish. This is the "neighbor effect": a resource-hungry site next door swallows the shared disk and CPU.
  • A wall of restrictions: a fixed PHP version, a short max_execution_time, modules that cannot be installed, and on some hosts, cron jobs that cannot run more often than every 15 minutes.
  • No root access: Redis for WordPress caching? Node.js alongside PHP? The answer is always the same: "not available on your plan".
  • A shared IP address: if one of your neighbors sends spam, the IP gets blacklisted and your emails start landing in spam too.
  • An inode ceiling: besides disk space, the number of files (inodes) is counted as well; a site with tens of thousands of thumbnail images hits this ceiling long before the gigabytes run out.

If more than two of these sound familiar, the problem is not your site; it is the container it lives in. But before you swap the container, find out which wall you are pushing against: that one number decides the size of your next server.

Where do 508 and 503 errors come from? Which quota is full?

On hosts managed with CloudLinux, whether the panel is cPanel or DirectAdmin, each account lives inside its own isolated container called an LVE (Lightweight Virtual Environment), with several independent limits; these are the six that matter. So "your usage is high" means practically nothing: each limit has its own symptom and its own fix. The table below is based on CloudLinux's documentation on limits:

QuotaWhat it limitsSymptom when it is fullWhat to do next
SPEEDCPU share, as a percentage of one coreSlowness, with no errorFind the heavy query or plugin
EPNumber of concurrent dynamic requests (entry processes)508 errors at busy hoursEnable page caching or get a higher EP limit
PMEMPhysical RAM used by the account's processesA process gets killed; 500 or 503 errorCut the memory each PHP request uses
NPROCTotal number of processes and threadsNew processes cannot start; 500 or 503Run fewer cron jobs at the same time
IODisk read and write speed (KB/s)Slowness during uploads and backupsMove heavy jobs to quiet hours
IOPSNumber of disk operations per secondShort pauses with no patternFix queries that have no index

The biggest misunderstanding concerns the first two rows: a 508 error almost always comes from EP, not from CPU. Even with an idle processor, twenty visitors loading an uncached page at the same time fill the ceiling, which is why "upgrading to a bigger plan" sometimes makes no difference at all.

So that you do not have to guess, open the resource usage report in your control panel: next to the usage of each quota, the number of faults tells you how many times you have hit that ceiling. A column with non-zero faults is your wall; the rest is noise. CloudLinux's documentation suggests these values for a typical account: 100 percent of one core, 1 GB of memory, 20 concurrent requests and 100 processes.

💡 Take a screenshot of your faults before you migrate. It is the only evidence of what your next server needs more of: faults on EP mean caching and more PHP processes, not more cores; faults on PMEM mean RAM; faults on IO and IOPS mean a real NVMe disk.

Shared hosting vs VPS at a glance

The difference between shared hosting and a VPS fits in one sentence: with shared hosting you rent "space on someone else's server"; with a VPS you rent "a server of your own". A VPS is built with KVM virtualization: the RAM and CPU cores really are yours, you choose the operating system yourself and you have root access.

CriterionShared hostingVirtual server (VPS)
Resources (CPU/RAM)Shared with dozens of sitesDedicated and isolated (KVM)
AccessControl panel and FTPFull root + SSH
SoftwareThe host's fixed listAnything you like: Redis, Node.js, Docker
IP addressSharedDedicated
Linux kernelShared; sysctl tuning and modules not allowedYour own kernel; any module and any tuning
Server management and securityThe host's jobYour job
ScalabilityChange plans, within limitsAdd resources in a few clicks
Billing unitUsually monthly or yearlyCan be hourly

So the answer to "hosting or VPS?" comes down to two things: how many resources you need, and how much responsibility you are willing to take on. The sixth row is the main price you pay for that freedom.

What is KVM, and why is not every "virtual server" the same?

The term "virtual server" is used for two different technologies. With container virtualization (OpenVZ and LXC), all the machines run on one shared Linux kernel: kernel modules cannot be loaded, some sysctl settings are out of reach, there is no real swap, and the figures that free shows are sometimes the host's RAM rather than your share of it. With KVM, each machine boots its own kernel and, as far as the operating system is concerned, is a complete server. Two commands are enough to be sure:

systemd-detect-virt
kvm

lscpu | grep -iE 'hypervisor|virtualization'
Hypervisor vendor:                    KVM
Virtualization type:                  full

An output of kvm means a real, separate machine; lxc or openvz means that what you bought is not what you thought it was. Check the disk while you are at it:

lsblk -d -o NAME,ROTA,SIZE
NAME  ROTA   SIZE
vda      0    50G

nproc
2
free -m | head -2
               total        used        free      shared  buff/cache   available
Mem:            3936         512        2870          12         554        3180

A ROTA value of 0 means SSD or NVMe, and 1 means a mechanical hard drive. Check these three numbers in the first minute after the server is delivered, not after you have moved the site.

What you gain on a VPS, and what responsibility you take on

Freedoms

On a VPS you assemble the software stack yourself: Nginx with PHP-FPM, object caching with Redis, whatever PHP version you want, and a cron job every minute if you need one. More important than all that, though, is the freedom to "measure": on shared hosting you are at the mercy of an invisible ceiling, while on a VPS you can see what is eating your RAM and which query is slow, and then change exactly that.

Responsibilities

In return, the jobs that until yesterday were "the host's responsibility" are now yours; our guide to Linux server security walks through all of them step by step. The day-one minimum is four tasks, about half an hour of work in total: logging in with an SSH key instead of a password, a firewall with only three open ports (22, 80 and 443), automatic security updates, and a nightly backup cron job whose output is stored off the server:

ufw default deny incoming
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable

sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
⚠️ Backups on a VPS are not "automatic" by default. Before moving your main site, set up a daily backup cron job for the files and the database, and keep the output somewhere other than the server itself. A backup that stays on the same disk disappears together with the server in exactly the scenarios where you really need it: a disk failure or a server deleted by mistake.

Measure these two numbers before you decide

Migrating without numbers turns a well-defined problem into a vague one. First, get the real size of your files and database; that determines both the disk size you need and how long the transfer will take:

du -sh public_html
3.4G    public_html

mysql -u DB_USER -p -e "SELECT table_schema AS db,
  ROUND(SUM(data_length+index_length)/1024/1024,1) AS mb
  FROM information_schema.tables GROUP BY table_schema;"
+-------+-------+
| db    | mb    |
+-------+-------+
| wp_db | 412.6 |
+-------+-------+

Second, the RAM each PHP request consumes. The rule for tuning PHP-FPM is simple: the number of concurrent processes equals the RAM you can allocate, divided by the average RAM per process. The average is something you can measure:

ps -ylC php-fpm8.3 --sort:rss | awk 'NR>1 {s+=$8; n++} END {printf "%.0f MB avg over %d procs\n", s/n/1024, n}'
61 MB avg over 8 procs

A back-of-the-envelope calculation: on a server with 4 GB of RAM, set aside 1 to 1.5 GB for the operating system, Nginx, MariaDB and a safety margin; at an average of 60 MB, the rest gives you about 40 concurrent processes. Compare that number with the EP faults on your current host, and you will know what size of server solves the problem and what size is just extra money.

Checklist: moving a PHP or WordPress site from shared hosting to a VPS

Migration sounds scary, but it comes down to seven well-defined steps, and if you keep to the order, you do not need a single minute of downtime:

  1. Take inventory. Write down the PHP version and the active extensions (from phpinfo), the cron jobs and the .htaccess settings. Get the same list on the new server with php -m and compare the two; a missing module is the most common cause of a 500 error in the first hour.
  2. Take a full backup. Do it from the control panel or, if your host gives you SSH:
    # on the old shared host
    mysqldump --single-transaction --default-character-set=utf8mb4 \
      -u DB_USER -p DB_NAME > site-db.sql
    tar -czf site-files.tar.gz public_html/
    --single-transaction takes an InnoDB dump without locking the site, and utf8mb4 keeps non-Latin text, such as Persian, from being corrupted.
  3. Prepare the new server. Create an Ubuntu VPS and set up the Nginx + PHP-FPM + MariaDB stack; our guide to setting up a website with Nginx on Ubuntu follows exactly this path.
  4. Move the files and the database. Copy the backup across and restore it:
    # on the new VPS
    mysql -u wp_user -p wp_db < site-db.sql
    tar -xzf site-files.tar.gz -C /var/www/example.com/
    chown -R www-data:www-data /var/www/example.com/
    Then update the connection details in wp-config.php. For sites of several gigabytes, rsync is the better tool: the first run copies everything and later runs copy only the differences, so move the initial copy a week ahead and sync only the changes on migration night:
    rsync -az --delete -e ssh public_html/ root@203.0.113.10:/var/www/example.com/
  5. Test before changing DNS. Edit the hosts file on your own computer so that the domain temporarily points to the new server, without the rest of the world noticing:
    # local hosts file (Linux/Mac: /etc/hosts)
    # Windows: C:\Windows\System32\drivers\etc\hosts
    203.0.113.10   example.com www.example.com
    Now go through the whole site: pages, forms, logging in to the admin dashboard, uploading an image. In the terminal, curl's --resolve option applies the same mapping to a single request:
    curl -sI --resolve example.com:80:203.0.113.10 http://example.com/ \
      | grep -Ei 'HTTP/|^server|^x-powered-by'
    HTTP/1.1 200 OK
    Server: nginx/1.24.0
    X-Powered-By: PHP/8.3.14
  6. Switch DNS. A day or two ahead, set the TTL of the A record to something like 300 seconds; then change the IP address and enable SSL. The rest of the zone matters more than the A record: if you are rebuilding the zone from scratch, carry over the MX and TXT records (SPF, DKIM and DMARC) and every ownership-verification record exactly as they are. Our guide to DNS records covers them in detail.
  7. Do not rush to close the old hosting account. Keep both running for a few days; going back is then just one DNS change. But as long as both are live, some visitors will still reach the old server, so if the site takes orders, stop writes to the old copy after the switch so that your data does not end up split in two.
💡 Tip: The trick in step 5 is the most important insurance for this migration: you find the errors while not a single visitor has reached the new server yet.
⚠️ .htaccess rules do not run on Nginx, and they do not raise an error either; they are silently ignored. That means rewrites, old redirects and security headers stop working without any warning. Before switching DNS, translate every rule into its equivalent inside the server block; on Apache, move the file over as it is.

SSL and email: two traps that ruin migrations

You cannot get the SSL certificate before switching DNS

Many people want everything ready before the DNS switch, HTTPS included, and run into a dead end. Let's Encrypt's default challenge, HTTP-01, places a file under /.well-known/acme-challenge/ on port 80 and fetches it from outside, so the name being validated must reach that very server at that moment. According to Let's Encrypt's documentation on challenge types, this challenge follows up to 10 redirects, but its starting point is whatever the DNS record says right now.

You have two options: accept the order (DNS first, then the certificate), or use the DNS-01 challenge, which asks for a TXT record at _acme-challenge.example.com instead of a file and does not care about the IP address. The steps for both are in our guide to installing free SSL with Certbot.

⚠️ Do not run certbot in a loop while you practice. Let's Encrypt's rate limits are explicit: 5 certificates for the same set of names every 7 days, 50 certificates per registered domain every 7 days, and 5 failed validations per name, per account, per hour. For testing, the dry-run mode does not use up your quota:
certbot certonly --nginx -d example.com -d www.example.com --dry-run
Simulating a certificate request for example.com and www.example.com
The dry run was successful.

A VPS does not send email by default

Shared hosting comes with a ready-made mail server; a bare VPS does not. If your contact form and order emails stop arriving after the migration, nothing broke: something was simply never installed. But a missing mail server is not the only issue: many cloud providers block outbound port 25 on new accounts. Hetzner's cloud documentation says ports 25 and 465 are blocked by default on all cloud servers and can be unblocked once the account is a month old and its first invoice has been paid; port 587 stays open in the meantime:

timeout 5 bash -c '</dev/tcp/gmail-smtp-in.l.google.com/25' && echo open || echo blocked
blocked

The low-hassle approach: leave the MX records alone, and for the site's outgoing email (password resets, invoices, notifications) use an authenticated sending service on port 587. That way the reputation of a brand-new IP never becomes an issue, and the domain's SPF and DKIM do not get scrambled.

What breaks after a migration, and how to fix it

The list of things that break after a migration is short and predictable; with one review before the DNS switch, most of them never happen at all:

SymptomLikely causeWhat to do next
500 error on every pageA PHP extension is not installedCompare php -m with the old host's list
Home page opens, everything else is 404The .htaccess rewrite was not translated for NginxAdd the try_files block
Images and uploads return 403File ownership changed after tarchown -R www-data:www-data on the site folder
Database connection errorThe values in wp-config.php are the old onesUpdate the host, user and password
Email to the domain no longer arrivesThe zone was rebuilt and MX was not carried overRecreate the previous MX and TXT records exactly
Scheduled tasks do not runThe old cron jobs were not movedDefine them with crontab -e under the right user

One WordPress-specific note: if you bring the site up on a temporary domain for practice, do not change the URLs inside the database by hand, because some of them sit inside serialized PHP data. The official wp search-replace tool understands this case, and with --dry-run it reports what it would change without saving anything:

wp search-replace 'https://example.com' 'https://staging.example.com' --all-tables --dry-run
Success: 412 replacements to be made.

With hourly billing, rehearse the migration first

The biggest fear about migrating is paying for a month of server time and finding out halfway through that you are not ready. The hourly model removes that fear: you create the server, rehearse the whole checklist above on a copy of the site, and if it does not work out, you delete it. Because the billing unit is the hour, a rehearsal of a few hours costs a small fraction of that server's monthly price. The details of this model are in what is an hourly cloud server.

Two points turn the rehearsal into real work. First, rehearse on the same size of server you plan to buy; what you are measuring is how fast the site runs under load, not whether it starts at all. Second, powering the server off does not stop the billing; deleting it does, and deletion takes the disk and all its data with it. So before you delete the rehearsal server, copy out the configuration you arrived at (the server block, the PHP-FPM settings, the cron jobs).

Shared hosting or VPS at Mehran Host?

On the shared hosting side, plans run on cPanel or DirectAdmin and are offered in both locations, Iran and abroad. Day-to-day work is not done inside the cPanel or DirectAdmin interface itself: in Mehran Host's own panel, each hosting service has separate tabs for Files, Database, FTP, Domains, DNS, Cron jobs, Backups, SSL certificate (for requesting a free certificate) and Email. The Email tab does what its name says and nothing more: creating and deleting mailboxes, changing passwords, quotas and forwarding. Creating SPF, DKIM and DMARC is not this tab's job; you enter those in the DNS tab as TXT records. The plans are listed on our Iran web hosting page.

On the VPS side, machines inside Iran are built on KVM with NVMe disks and are charged by the hour from your wallet; servers abroad are in Hetzner datacenters and are paid from the same wallet in Iranian currency; being Hetzner servers, they are subject to the port 25 restriction described above. What comes to your rescue on a bad day is the VNC console inside the panel: even if you have cut off the server's network with a wrong firewall rule, you can see the server's screen and fix it. Alongside it you get an OS reinstall, a root password change, adding IP addresses, usage graphs and the automatic backup add-on. One limitation, stated plainly: resources can only be increased; reducing them, especially the disk, is not possible.

Two services make the migration simpler whichever way you choose. DNS management covers A, AAAA, CNAME, MX, TXT, NS, SRV and CAA records, and the minimum TTL is 60 seconds, so lowering the TTL before the switch works without restrictions. And next to every A record there is a CDN switch: turning it on hides the origin IP and changes the public answer to the nearest edge node, including nodes inside Iran, with 1 TB of free traffic on a domain whose DNS is managed here. Measure where your site stands today with the free website speed test; just bear in mind that it runs from the service's own server, not from inside Iran. The bottom line: shared hosting is great for getting started, but once 503 errors and the wall of quotas appear, a VPS is the natural next step. Create an account and rehearse the migration without risk.

Frequently asked questions

Should I choose shared hosting or a VPS?

If you have a new site and do not want to spend time managing a server, shared hosting is the right choice, because the provider maintains and secures the operating system. A VPS becomes worthwhile when you have hit the resource ceiling, need software outside the host's list, or want a dedicated IP address; the price of that freedom is taking responsibility for updates, the firewall and backups.

What are the signs that it is time to move off shared hosting?

The most important sign is repeated 508 or 503 errors at peak hours, which means you are hitting the account's ceiling on concurrent requests or memory. Next come intermittent slowdowns with no change to the site, requests to install software such as Redis being refused, and the shared IP getting blacklisted. Before deciding, open the resource usage report in your control panel and see which quota has recorded faults.

Does moving a site from shared hosting to a VPS cause downtime?

It does not have to. In the right order, downtime is effectively zero: first bring the site fully up on the new server, then test it for yourself only, by editing your computer's hosts file or with curl's resolve option, then lower the TTL of the A record, and finally change the IP address. Keep the old hosting for a few days so that going back is just one DNS change.

How much RAM does a WordPress VPS need?

There is no fixed number, but you can calculate it: the number of concurrent PHP requests times the average RAM per process, plus 1 to 1.5 GB for the operating system, the database and the web server. Each WordPress process takes about 50 to 80 MB, so a site with ten to fifteen concurrent requests is comfortable on 2 to 4 GB of RAM, and with page caching it can need even less.

What happens to my domain's email after moving to a VPS?

Nothing, as long as you leave the MX records alone: a VPS has no mail server by default, so if you change only the A record, your domain's email keeps working where it always has. Problems start when you rebuild the DNS zone from scratch and do not carry over MX and TXT. For the site's outgoing email, use an authenticated sending service on port 587 instead of installing a mail server, because port 25 is blocked on many cloud servers.

Related tutorials

Ready for some hands-on practice?

A Mehran Host hourly cloud server is ready in under 60 seconds. Practice as much as you like and pay only for the hours you use. Estimate the cost with the pricing calculator before you sign up.