Zero Hosting Costs: Moving My Jamstack Sites to Cloudflare Pages

Zero Hosting Costs: Moving My Jamstack Sites to Cloudflare Pages

In my last post, I wrote about moving my sites from WordPress to Jamstack — Jekyll for this blog, Astro for a more component-heavy site. Both ended up on a self-hosted VPS: nginx serving pre-built static files, GitHub Actions pushing updates via rsync. It worked well. It was fast. It was dramatically better than WordPress.

But I was still paying for a server. Still responsible for OS updates. Still the person who gets paged if the disk fills up or nginx crashes at 2am. For sites that are nothing but static files, that felt like unnecessary weight.

So I moved everything to Cloudflare Pages. The hosting cost dropped to zero. The VPS is gone. Here is how it went.

What Self-Hosting Was Actually Costing

The VPS itself was modest — a small instance running Ubuntu, nginx, and a GitHub Actions runner. Monthly cost: around €5–10 depending on the provider and region. Not a lot of money. But money is not the only cost.

There was also:

  • Time spent on OS maintenance. Security patches, kernel updates, the occasional apt upgrade that breaks something subtle.
  • nginx configuration. Redirect rules, MIME types, cache headers, gzip settings — all hand-written, all mine to maintain.
  • Uptime responsibility. If the server goes down, the sites go down. I was the on-call engineer for a blog.
  • Backups and disaster recovery. Not complex, but something that had to exist and be tested.

For a side project or a personal blog, this is real overhead. Every hour spent keeping the server healthy is an hour not spent writing or building.

The fundamental mismatch was this: Jamstack sites are stateless, immutable, and infinitely cacheable. They are perfectly shaped for a CDN — and yet I was hosting them on a single server in one data centre, serving traffic sequentially from one geographic location. The architecture was Jamstack in name but not in practice.

Why Cloudflare Pages

Cloudflare Pages is a platform specifically designed for deploying static sites and Jamstack applications. It has a few properties that made it the obvious choice:

A generous free tier. Unlimited sites, 3,000 worker build minutes per month, and 100,000 requests per day. For a handful of personal sites updated a few times a week, these limits are more than comfortable. For the traffic levels of my sites, the cost is genuinely €0.

Global edge network. Cloudflare operates over 300 data centres worldwide. When a visitor loads one of my pages, they are served from the edge node closest to them — not from a single VPS in one city. The latency improvement for visitors outside my VPS’s home region is significant.

Git-native deployment. Connect a GitHub repository, configure the build command, and every push to the main branch triggers a build and deployment automatically. No rsync scripts. No GitHub Actions runner to maintain. The CI/CD pipeline is managed by Cloudflare.

Built-in preview deployments. Every pull request gets its own preview URL — a full deployment of the branch at a unique subdomain. Reviewing content changes or testing a theme update before merging to production is a single click.

Automatic HTTPS. SSL certificates provisioned and renewed automatically. Not something I ever had to think about with the VPS either, but here it is genuinely zero configuration.

The Migration, Step by Step

Moving from the self-hosted setup to Cloudflare Pages was the most straightforward migration I have done in years.

1. Connect the repository. In the Cloudflare dashboard, Pages → Create a project → Connect to Git. Select the GitHub repository. Done.

2. Configure the build. Cloudflare has built-in presets for Jekyll and Astro. For Jekyll: build command jekyll build, output directory _site. For Astro: build command npm run build, output directory dist. Set the Ruby or Node version if you need a specific one via environment variables.

3. Set environment variables. Any secrets or configuration values that were previously in the server environment move here. For my sites this was minimal — Jekyll’s JEKYLL_ENV=production and nothing else.

4. Migrate redirects. This was the one area that required some thought. My nginx redirect rules were in a server block configuration file. Cloudflare Pages uses a _redirects file in the output directory — a simple text format where each line is old-path new-path status-code. I converted the nginx rules to this format and committed the file to the repository so it gets included in every build.

5. Update DNS. Point the domain’s nameservers to Cloudflare (if they were not already there), then configure the custom domain in the Pages project. Cloudflare handles the SSL certificate automatically. Traffic starts flowing through the CDN immediately after DNS propagates.

6. Decommission the VPS. Once I confirmed the sites were live and healthy on Cloudflare Pages — a few days of monitoring, a quick check of Google Search Console for any crawl errors — I cancelled the VPS subscription. That was satisfying.

What Changed for the Better

TTFB improved noticeably. From my self-hosted VPS in a single region, Time to First Byte was around 15–40ms for visitors in the same region and considerably higher for visitors further away. From Cloudflare’s edge, it is consistently under 10ms regardless of where the visitor is located. Lighthouse scores stayed in the 98–100 range but the real-world experience for international visitors got meaningfully better.

Deployment got simpler. The GitHub Actions workflow that handled jekyll build + rsync is gone. The Cloudflare Pages build pipeline does the same work with less configuration and nothing to maintain on my side. I push to Git; the site updates. That was always the goal, and it is now cleaner.

Preview deployments are a genuine quality-of-life improvement. Before, testing a change meant either running the site locally or pushing to production and checking. Now every branch gets a preview URL. Writing a long post, I can share a preview link with someone to read before it goes live.

The €0 bill is real. My traffic levels are modest enough that I will likely stay on the free tier indefinitely. If traffic ever grows to the point where it matters, Cloudflare’s pricing is transparent and the paid tiers are priced for real traffic, not padded with minimums.

What to Watch For

Build minutes. The free tier gives 3,000 worker build minutes per month and 100,000 requests per day. For a few personal sites each updated a handful of times a week, build minutes are rarely a concern. Requests per day is the limit more likely to become relevant if a post goes viral — worth keeping an eye on.

The _redirects format is not nginx. The conversion from nginx redirect blocks to the _redirects file format is straightforward but requires attention. Regex redirects in particular have slightly different syntax. Test your redirect rules with Cloudflare’s Pages preview deployments before cutting DNS.

Functions are available if you need them. Cloudflare Pages Functions let you add server-side logic — form handling, API proxying, personalisation — without leaving the platform. I have not needed them yet, but they are there if a site grows beyond pure static content.

The New Setup

The full pipeline now looks like this:

Write post in Markdown
     ↓
git push to GitHub
     ↓
Cloudflare Pages builds (Jekyll / Astro)
     ↓
Deployed to 300+ edge locations globally
     ↓
Visitor gets HTML from nearest edge node

No server to manage. No certificates to renew. No rsync scripts. No on-call responsibility for a blog.

Is Self-Hosting Ever the Right Choice?

Absolutely — for the right use case. If you need full control over the server environment, specific compliance requirements, or you are running something more complex than static sites, self-hosting on a VPS is a legitimate and sometimes necessary choice.

For purely static Jamstack sites, though, the trade-off is clear. Self-hosting gives you control over infrastructure you mostly do not need to control. A platform like Cloudflare Pages gives you global distribution, automatic deployments, and preview environments — all for less money than a small VPS, or in my case, no money at all.

The sites are faster for more visitors. The maintenance burden is gone. The monthly invoice is €0.

For a personal blog, that is a very easy trade to make.

Mohanjith Sudirikku Hannadige
Mohanjith Sudirikku Hannadige Spreading Smiles & Rhythms. I am a dancer and a software engineer. I am passionate about dance, technology, and business. I am a joyful jotter.