The fear of leaving a VPS is rarely about any one feature. A small server quietly does ten jobs at once — serves a site, renews certificates, answers DNS, redirects old URLs, runs a cron script, forwards mail, keeps a database, stores uploads, hosts a small API, rate limits a scraper — and the migration question is really ten questions asked as one. Ask “can Cloudflare replace my VPS” and you get advocacy in both directions. Ask it per job and you get answers you can check.
So here is the job by job mapping, every number read off the live documentation on 29 July 2026, with the allowance, the price of lifting it, and the honest rows where the answer is “keep the server.” At the end: two systems that already live this way, one of them a production SaaS.
The mapping
| VPS job | On the free plan | The allowance | Where it bites |
|---|---|---|---|
| Serve a static site | Workers static assets | asset requests “free and unlimited”; 20,000 files, 25 MiB each | paths routed through Worker code count against 100,000 requests a day |
| TLS certificates | Universal SSL | 90 day certs, auto renewed from 30 days out | proxied hostnames only |
| DNS | free, with unmetered DDoS protection | 200 records per zone (zones created since September 2024; older free zones keep 1,000) | nameservers must move to Cloudflare |
| Redirects | Single + Bulk Redirects | 10 rules; 10,000 bulk URLs | the bulk quota may lag in your account |
| Cron scripts | Cron Triggers on a Worker | 5 per account documented, minimum interval 1 minute | see the next section |
| Small APIs, dynamic bits | Workers | 100,000 requests a day, 10 ms CPU each | computing breaks the CPU budget; serving does not |
| Key value storage | Workers KV | 1 GB, 100,000 reads / 1,000 writes a day | 1,000 writes is less than it sounds |
| A real database | D1 (SQLite) | 5 GB, 5 million reads / 100,000 writes a day | daily caps error out, not throttle |
| Object storage | R2 | 10 GB, free egress | free tier covers Standard storage only |
| Mail forwarding | Email Routing | free on all plans; 200 rules, 200 destinations | forwarding, not sending |
| Firewall, rate limits | WAF free tier | 5 custom rules, 1 rate limiting rule | one rate limit means choosing what to protect |
| Request logs | Workers Logs, Analytics Engine | logs with sampling; 100,000 data points a day | Logpush is Enterprise; Workers Trace Events unlock at $5 |
Three of those rows deserve more than a cell.
The cron entry that should not fire, and does
The documentation says the free plan allows 5 Cron Triggers per account. The account this blog runs on executes 7, every day, across five distribution Workers — and has for a week, posting to five platforms on schedule. We did not negotiate anything; the limit simply is not enforced against this account.
That is not a loophole to build on. It is the same phenomenon we documented when the Bulk Redirects quota said 10,000 and dashboards enforced 20: Cloudflare’s documented numbers and per account entitlements drift apart, in both directions, sometimes for months. Read the number, then test the number. On a migration that habit costs you an afternoon and saves you an architecture built around a limit that was never real for you — or one that assumed an allowance you do not actually have.
Certificates are the quiet argument
On a VPS the TLS routine was a yearly renewal, or a certbot timer. That era is ending on a schedule: since 15 March 2026 the CA/Browser Forum rules cap public certificates at 200 days, in March 2027 the cap drops to 100 days, and in March 2029 to 47 days with domain validation reuse down to 10 days. Manual renewal stops being a viable habit and becomes an incident generator — a portfolio of parked domains on a VPS meets that wave at its first short renewal this autumn.
Behind the proxy, Universal SSL already issues 90 day certificates and renews them starting 30 days out, which sits below every step of that schedule. Of everything in the table, this is the row where the free plan is not a cheaper version of the VPS job but a categorically better one.
The ceiling is real, and it is measurable
The 10 ms CPU budget is the free plan’s one hard wall, and we have measured both sides of it on this site. A Worker that serves — our MCP server answering from static assets — spends 0 to 2 ms of the budget, because waiting on I/O does not count as CPU. A Worker that computes — the template engine we measured in the agent readiness audit — blew through the same budget by a factor of eight. That is the honest split for a migration: routing, redirecting, serving, forwarding all fit with room to spare; parsing, rendering and hashing at volume do not.
Per this site’s house rule, the price of the lift sits next to the limit: the Workers Paid plan at $5 a month raises the per request cap to 30 seconds by default and includes 10 million requests and 30 million CPU milliseconds a month.
What honestly stays on the server
- Long running processes. Anything that holds a socket open for hours, speaks a protocol that is not HTTP, or needs SSH. Arbitrary TCP proxying exists (Spectrum) but only as an Enterprise extra — that is not a migration, that is procurement.
- Heavy compute, per the measurement above, unless $5 and 30 seconds cover it.
- The paid tier gaps. Snippets are absent from Free entirely, Logpush is Enterprise, Load Balancing and Argo are paid extras. If your VPS job maps to one of these, the free plan answer is “no”, not “yes with effort”.
- Control you did not know you had. On Cloudflare Registrar you cannot change nameservers at all, and renewal is an instruction, not a guarantee. A migration hands real levers to one vendor; that is a decision, not a detail.
And there is a bridge for the undecided: Cloudflare Tunnel is available on all plans, so the VPS can stay exactly where it is, hidden behind the edge with no open ports, while jobs migrate off it one row at a time. Nothing about this table is all or nothing.
Two systems that already live like this
This blog is the small case: six Workers — the site plus five distribution posters — seven cron firings a day, a shared KV namespace, 317 static files, an MCP server, at a running cost of exactly zero, with the measurements published as articles.
The larger case is 301.st, the platform this blog belongs to: a production SaaS for domains, redirects and traffic distribution, built as a serverless application on Cloudflare Workers with D1 as the source of truth and KV for cache and sessions. Its architecture documentation states the design goal plainly: customers do not need a paid Cloudflare plan — everything runs on free Workers, and Workers Paid is the growth path, not the entry fee. A platform whose job is other people’s domains chose the same table you just read. That is as honest an endorsement of the free plan as we can offer. And where a portfolio outgrows the rows you can run yourself, taking that work over is exactly what the platform exists for.