As developers we default to raw VPS — it's cheaper and we can obviously manage a server. Sometimes that's right. But after doing 2am incident response on my own "cheap" infrastructure enough times, I built a decision framework for when self-managing is genuine value and when it's false economy.
TL;DR: it hinges on your restore time, not your setup skills. Anyone can follow a setup guide. The question is whether you can rebuild from a snapshot at 2am with revenue down and no coffee.
The category error at the root of this argument
Most "managed vs unmanaged" comparisons compare the wrong things. They put RAM against RAM and conclude the unmanaged box wins. It does — on that axis. It was never in question.
What's actually being purchased differs by layer, so it helps to name the layers precisely:
Layer 0 — Unmanaged IaaS. You get a hypervisor slice, a network, and a public IP. You own kernel, packages, firewall, TLS, backups, monitoring, and every minute of every incident. Vultr and RackNerd sell at this layer. So does DigitalOcean when you use it directly.
Layer 1 — Management layer over IaaS. A control plane sits on top of a VM you still size and still choose a provider for. Cloudways Flexible is the common example: it provisions onto DigitalOcean, Vultr, Linode, AWS, or GCP and takes over the panel, stack configuration, patching scope, staging/clone workflows, and first-line support. You keep provider choice and instance sizing. You lose unrestricted root.
Layer 2 — Application platform. The unit of deployment is an application, not a server. Kinsta and WP Engine operate here for WordPress specifically; Cloudways Autonomous is a WordPress autoscaling product in the same shape. You stop reasoning about instances entirely, and in exchange you inherit the platform's opinions about your stack.
These layers don't rank. They trade different things. A "best managed VPS" list that puts raw Vultr at #1 for managed WordPress has silently mixed Layer 0 with Layer 2, and the resulting ranking measures nothing.
The engineering question isn't which layer is better. It's which layer's failure modes you're equipped to own.
Restore time is the metric, and most of us have never measured ours
Here's the test I now run before I let myself choose Layer 0 for anything that matters.
The drill: pick a random Tuesday. Destroy a staging instance. Rebuild the full stack from your most recent snapshot and configuration — no reading the production box, no reconstructing from memory. Stop the clock when the app serves correct data at the right domain over valid TLS.
That number is your RTO. Not your estimated RTO. Your measured one.
Time it properly and write the number down. The point is the trend across drills, not a single heroic run:
#!/usr/bin/env bash
# restore-drill.sh — measure RTO end to end, not just "the snapshot booted"
set -euo pipefail
DOMAIN="staging.example.com"
START=$(date +%s)
# 1. provision from code, not from a running box
terraform apply -auto-approve -var="env=drill"
# 2. restore application state
ansible-playbook restore.yml -e "snapshot=$(date -d yesterday +%F)"
# 3. the clock stops on a real request, not on "instance running"
until curl -fsS --max-time 5 "https://${DOMAIN}/healthz" | grep -q '"db":"ok"'; do
sleep 5
done
# 4. TLS must actually validate — expired or self-signed does not count
echo | openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" 2>/dev/null \
| openssl x509 -noout -checkend 0
echo "RTO: $(( $(date +%s) - START ))s"
Three things reliably fall out of the first run:
- The snapshot restores, but the app doesn't. Cron entries, queue workers, a systemd unit someone wrote by hand, an env var that only ever lived in the shell history. Snapshot ≠ service.
- TLS is slower than expected. DNS propagation, ACME rate limits, a challenge that needs port 80 open on a box you just firewalled.
- Nobody documented the reverse proxy config. It works in production, which is why it was never written down.
Multiply the drill result by roughly 2.5 for the real thing, because production has revenue anxiety, no sleep, and Slack notifications attached.
If your measured RTO is under an hour and the stack is reproducible from version control, self-managing is genuine value — you have real capability and the cost savings are unencumbered. If your drill produced a number you'd rather not say out loud, the price gap between Layer 0 and Layer 1 isn't a saving. It's an unfunded liability sitting on your calendar, waiting.
The companion number: RPO
Restore time answers how long until service returns. RPO answers how much data doesn't come back. Nightly snapshots mean a worst case of ~24 hours of lost writes. For a content site that's an annoyance. For anything transactional it's a support incident with your customers' money in it.
A backup you have never restored is not a backup. It's a file. This is the single most common gap I find in otherwise competent self-managed setups, including several of my own.
The cheap version of verification — restore the dump somewhere disposable and assert on real rows, not on exit code 0:
# verify-backup.sh — a passing pg_dump job proves nothing about restorability
LATEST=$(ls -t /backups/*.dump | head -1)
pg_restore --clean --if-exists -d verify_target "$LATEST"
ROWS=$(psql -tAX -d verify_target -c 'select count(*) from orders')
AGE=$(psql -tAX -d verify_target -c "select extract(epoch from now() - max(created_at))/3600 from orders")
echo "rows=${ROWS} newest_record_age_hours=${AGE}"
# ROWS near zero, or AGE far above your snapshot interval, means your RPO
# is not what your backup schedule claims it is.
The toil budget nobody puts in the spreadsheet
Let's put honest hours against Layer 0. Steady state, one small production box, nothing on fire:
| Recurring work | Realistic cadence | Hours/month |
|---|---|---|
| Package and kernel updates, reboot coordination | Weekly-ish | 1–2 |
| Backup verification (actual restore, not "job succeeded") | Monthly | 1 |
| TLS renewal failures, cron drift, log rotation, disk pressure | As it breaks | 0.5–2 |
| Monitoring, alert tuning, and responding to noise | Ongoing | 1 |
| Security response to a CVE that actually touches your stack | A few times/year | 2–6 per event |
Call it 3–6 hours per month in calm conditions, plus spikes. Price your own hour honestly — not your billable rate, your opportunity rate — and the arithmetic against a $10–20/month management layer stops being interesting very quickly for a single box.
It gets interesting again at scale. Ten instances do not cost ten times the toil, because the work amortizes: one Ansible role, one monitoring config, one patching window. Toil scales sublinearly with servers; management-layer pricing scales linearly. That crossover is real, and it's why infrastructure teams eventually build inward. The mistake is assuming you're past the crossover when you're running two boxes.
Bus factor is part of the cost
One person who knows the stack is a bus factor of one. That's an availability risk you're carrying without pricing it. Layer 1 and Layer 2 don't eliminate it — you still own your application — but they move the OS-level half of it onto a vendor with a rotation and an SLA. If you're a solo developer or a two-person team, that transfer is often the actual product being sold, and it's worth more than the panel.
Failure modes, sorted by who owns them
This table is the framework compressed. It's about ownership boundaries, not vendor quality.
| Failure mode | Layer 0 (unmanaged) | Layer 1 (management layer) | Layer 2 (app platform) |
|---|---|---|---|
| Kernel / OS CVE | You, on the CVE's schedule | Vendor, within stated scope | Vendor |
| Config drift between boxes | You (unless it's in IaC) | Reduced — provisioning is templated | Not applicable |
| Backup exists but won't restore | You discover it during the incident | Vendor tooling, still verify it yourself | Vendor tooling |
| Bad deploy takes the site down | You (unless you built staging) | Staging/clone workflow provided | Staging provided |
| Traffic spike exceeds instance | You resize, manually, now | You resize, manually, but faster | Platform absorbs it |
| Application-level bug | You | You | You |
| Data loss from your own bad migration | You | You | You |
The bottom three rows are the honest part. No layer buys you out of your own application's failures. Managed hosting narrows the blast radius of infrastructure problems; it does nothing about the ones you write yourself.
Cost structures, described rather than ranked
Prices below were checked in August 2026 and will move. They're structural anchors, not quotes — the point is the shape of each bill, since that's what determines behavior at scale.
| Billing model | Representative | Cost anchor | What happens at 10 apps |
|---|---|---|---|
| Unmanaged per-instance | Vultr, RackNerd | Lowest $/GB RAM available | Cheapest sticker; toil grows sublinearly |
| Management layer per-server | Cloudways Flexible | ~$11/mo entry DO-class; ~$88/mo at ~8GB class; offsite backup ~$0.033/GB | One sized box until resources saturate |
| Per-site application platform | Kinsta, WP Engine | ~$35/mo class entry, per site | Ten floors, multiplied |
| Promotional shared, renewal-priced | SiteGround, Hostinger | ~$3 intro → ~$11–18 renewal class | Year two is the real number |
Two structural notes that matter more than any single figure:
Per-server billing rewards density. A mid-size Layer 1 instance hosting ten small PHP applications is a fundamentally different cost curve from ten per-site plans. If your workload is many small apps — the agency shape — the two models diverge sharply and fast.
Layer 1 pricing excludes things that look like they should be included. Mailboxes are typically not on the host; budget a third-party provider. Offsite backup storage is metered separately. The entry sticker is not the all-in number, and discovering that mid-migration is a bad time.
Renewal pricing is a structural property, not a gotcha. Promotional shared hosting is priced on a two-year model where year one subsidizes acquisition. That's a legitimate business model — it just means the intro figure is the wrong input for a TCO calculation. Use the renewal rate. Details are in the SiteGround comparison and the Hostinger comparison.
The framework, as conditions
No rankings here — these are conditional statements. Evaluate them against your own measured numbers.
Layer 0 is defensible when your stack is reproducible from version control, your measured restore drill came in under an hour, someone other than you can execute it, you need kernel modules or a runtime the managed layers don't support, or you're running enough instances that the toil has already amortized. Root access is the feature and the liability in the same breath.
Layer 1 fits when you want to keep provider and instance-size choice but stop owning OS maintenance, you're running multiple PHP-family applications per server, your bus factor is one or two, or your measured restore time is the number you don't want to say out loud. You're buying a shorter MTTR on infrastructure failures. You're giving up unrestricted root — which is only a real cost if you have a specific reason to need it.
Layer 2 fits when the deployment unit genuinely is one application, the platform's stack opinions match yours, and per-application pricing is acceptable at your site count. It stops fitting the moment you have ten quiet installs, because ten floors stack. The alternatives-by-situation breakdown covers where that boundary tends to sit.
None of them fit if the real problem is that nobody owns the system. Managed hosting narrows what you own. It doesn't create an owner.
A useful tiebreaker
When two layers look close on cost, ask: what breaks if the person who set this up is unreachable for two weeks?
If the answer is "nothing, it's documented and automated" — self-manage, the savings are real. If the answer involves a specific human's memory, you've found the thing you should be buying, and it isn't RAM.
What managed hosting does not buy you
Worth stating plainly, because the marketing is ambiguous and the assumptions are expensive:
- Not compliance. A management layer gives you a narrower blast radius and a vendor patching scope. It is not a SOC 2 or HIPAA attestation. Read the vendor's actual trust documentation if you need named audits.
- Not performance, directly. Throughput tracks the underlying instance and your caching strategy. For database-heavy workloads, object caching moves the needle far more than the logo on the invoice.
- Not application security. Your dependencies, your auth logic, your file upload handler. Entirely yours at every layer.
- Not freedom from capacity planning. Layer 1 still requires you to notice you're saturated and resize. Only Layer 2 autoscaling changes that, and it changes your billing predictability in return.
- Not email. Assume a separate mailbox provider unless the product page explicitly says otherwise.
If you stay self-managed, this is the minimum bar
Not aspirational — the floor at which Layer 0 is a defensible engineering decision rather than an accumulating debt:
- Provisioning is code. Ansible, Terraform, a Dockerfile, a shell script in git — the mechanism matters less than the property. If rebuilding requires reading the running box, you don't have a rebuild path.
- Restore is tested on a schedule. Quarterly minimum. Write down the measured time. Track whether it's getting worse.
- Unattended security upgrades are on, with a defined reboot window. The alternative is patching reactively, which means patching after the CVE is public and scanned for.
- Monitoring pages a human. A dashboard nobody looks at during business hours is not monitoring.
- Secrets live somewhere other than the box. Otherwise losing the instance means losing the ability to rebuild it.
- Someone else has the runbook and the access. This is the bus-factor fix, and it's the one most often skipped.
Item 3 takes about ninety seconds and is skipped constantly, so here it is with no excuse attached:
# Debian/Ubuntu — patch on the CVE's schedule, not on yours
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# reboot automatically, in a window you chose while awake
sudo tee /etc/apt/apt.conf.d/51custom-reboot >/dev/null <<'CONF'
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:30";
CONF
# confirm it is actually running, not merely installed
systemctl is-enabled unattended-upgrades
sudo unattended-upgrades --dry-run --debug | tail -20
Miss more than two of the six and the cost comparison you did was against a version of self-managing you aren't actually doing.
Quick answers
What does "managed VPS" actually mean?
A VM where a provider or control plane owns the panel, patching scope, and stack configuration, so you aren't the full sysadmin. A management layer over IaaS qualifies. A bare KVM instance you administer yourself does not, regardless of how the plan is marketed.
Is self-managing a VPS cheaper?
On instance price, yes, consistently. On total cost, only if your measured restore time is short and your provisioning is reproducible. The hours are the variable most comparisons omit.
How do I know if I should stop self-managing?
Run a restore drill and time it. If the number is bad, or only one person can produce it, you've quantified the reason.
Does managed hosting improve performance?
Not inherently. Performance follows the underlying instance and your caching layer. Management scope and throughput are independent axes.
Where does root access actually matter?
Custom kernel modules, non-standard runtimes, OS-level packages outside the vendor's supported stack, and specific compliance controls. If none of those apply, giving up root costs you less than it feels like it should.
The part that changed my mind
The framework isn't anti-DIY. I still run unmanaged boxes where the restore path is automated and the failure modes are ones I've rehearsed. What changed is that I stopped treating "I know how to configure nginx" as the qualifying skill. Configuration is the easy half. The qualifying skill is reconstruction under pressure — and that one is measurable, so measure it before the pricing page convinces you it doesn't matter.
The full comparison of managed and unmanaged options — including how Cloudways Flexible, Kinsta, WP Engine, Vultr, and RackNerd map onto these three layers — is on my site. No affiliate links in this piece; every link points to my own research pages.
Top comments (0)