
How I Built JoRap's World: My Journey from Expensive Hosting to Free (and Better!)
- June 14, 2024
- Website, Technology, Web Development, Tutorial
TL;DR: I lost my old PHP hosting and a chunk of my work with it. After a weekend of fumbling around, I landed on Hugo + GitHub + Cloudflare Pages, and the result is genuinely better than what I was paying $12/month for. Here’s exactly how I did it - including the parts I messed up.
The short backstory
For years I had a basic PHP hosting plan, about $12 a month, that I shared with a client. When that client moved on, suddenly I was paying the whole bill for what was effectively just my personal blog. It didn’t make sense.
I’d been hearing about static site generators and the whole “JAMstack” thing for a while but never had a reason to try them. Losing my hosting setup turned out to be exactly that reason. Sometimes you don’t fix something until you have to.
What I ended up using
Three pieces, all free, all working together:
- Hugo generates the site.
- GitHub stores the code.
- Cloudflare Pages builds and serves it.
That’s it. There’s no database, no admin panel, no PHP, no cron jobs. When I want to publish, I write a Markdown file, push it to GitHub, and ninety seconds later it’s live.
Hugo, in plain English
Hugo takes a folder of Markdown files and a theme, and spits out a folder of plain HTML. That’s the whole job. No database to back up, no server-side code to keep patched, nothing to break.
Coming from years of WordPress, the speed difference was the first thing I noticed. Pages don’t load - they just appear. There’s nothing to wait for.
Setup on Windows took me about thirty minutes from download to first running page. On a Mac it’s basically one command. Either way, write down your Hugo version number the moment you install it. Cloudflare needs to match it exactly later, and a mismatch is the most boring possible reason to spend an hour debugging a deploy.
Cloudflare Pages, the part that surprised me
Cloudflare Pages hosts static sites for free. Not “free trial.” Free, forever, for personal use. It connects directly to GitHub, watches the branch you tell it to, and rebuilds the site every time you push.
Months in, I still haven’t paid them a cent. I keep waiting for the catch. I haven’t found one yet.
GitHub, the place I sometimes forget to push to
Standard Git workflow. Commit, push, deployed. The bonus is that GitHub is also my backup - every version of every post lives in the repo history, so I can revert anything I’ve ever written.
Is this setup actually right for you?
Be honest with yourself before you start.
This is great for personal sites, blogs, portfolios, project pages, small documentation sites. Anything that’s mostly text and images, mostly written by you, where “publishing” can reasonably mean “running a Git command.”
This is a bad fit for anything with user accounts, shopping carts, real-time data, or a non-technical team that needs to update content without touching code. A marketing team is not going to learn Git to fix a typo. They shouldn’t have to.
So: small personal stuff, yes. A company site with a non-technical team behind it, no. Pick something with an admin panel instead.
Building the site, step by step
Getting Hugo running
On Windows, the steps that worked for me:
- Download Hugo from the GitHub releases page.
- Extract it to
C:\hugo\bin. - Add that folder to your Windows PATH.
- Open PowerShell and run
hugo versionto confirm.
On Mac:
brew install hugo
Either way, note your version number. You’ll thank yourself later.
Creating the site
hugo new site joraps-world
cd joraps-world
git init
That creates a basic skeleton. The two folders you’ll actually care about are content/ (your posts) and themes/ (how it looks).
Picking a theme (where I lost a Saturday)
I will not pretend I made a quick decision here. There are hundreds of Hugo themes, they all look beautiful in their screenshots, and you can lose half a weekend “evaluating” them.
I eventually settled on Hugoplate. It’s modern, well-maintained, and - the thing that sold me - it ships with Tailwind CSS v4 baked in. Most Hugo themes are still on older CSS approaches, and I really didn’t want to spend my time fighting a custom theme styling system every time I wanted to change a color.
What you get out of the box with Hugoplate:
- Dark mode
- Multi-author support
- A working search
- Contact form integration
- Pre-configured SEO
- A bunch of ready-made pages (About, Contact, Blog, etc.)
- A responsive design that actually holds up on mobile
To add it:
git submodule add https://github.com/zeon-studio/hugoplate.git themes/hugoplate
Then edit hugo.toml - Hugoplate uses TOML, not YAML:
baseURL = 'https://jorapdotcom.pages.dev'
languageCode = 'en-us'
title = "JoRap's World"
theme = 'hugoplate'
[params]
author = "JoRap"
description = "My corner of the internet"
logo = "/images/logo.png"
logo_darkmode = "/images/logo-darkmode.png"
(Note the lowercase hugoplate. Theme names are case-sensitive. I learned this one the embarrassing way, with a perfectly broken site and “HugoPlate” sitting smugly in my config.)
Writing content
Markdown is the whole interface:
# Big Heading## Smaller Heading**bold text***italic text*[link text](https://example.com)
To create a new post:
hugo new posts/my-post-name.md
Previewing locally
hugo server -D
Opens at http://localhost:1313. The -D flag includes drafts.
Putting it on the internet
Push to GitHub
Create a new repo, then:
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/yourusername/yoursite.com.git
git push -u origin main
I have forgotten the git remote add origin step more times than I’d like to admit. Git’s error messages when this happens are not, let’s say, beginner-friendly.
Hook up Cloudflare Pages
- Sign up at
pages.cloudflare.com. - Connect your GitHub account.
- Select the repo.
- Set the build command to
hugoand the output directory topublic. - Add an environment variable
HUGO_VERSIONand set it to your exact local Hugo version.
Hit deploy. About two minutes later, your site is live at some something.pages.dev URL.
The things that broke (and how I fixed them)
This is the section I needed when I was starting out, so it’s the longest one here.
Site looks like raw HTML. The theme isn’t loading. Nine times out of ten, the theme name in hugo.toml doesn’t match the folder name exactly - case included.
Cloudflare build fails. Almost always a Hugo version mismatch. Set HUGO_VERSION to whatever hugo version prints locally.
“Module not found” during the build. Cloudflare Pages isn’t pulling Git submodules. Turn submodule cloning on in the Pages project settings.
Site deploys but every link is broken. Check baseURL in hugo.toml. It needs to match the actual URL Cloudflare gave you.
Images won’t show up. Put them in static/images/ and reference them in your Markdown as /images/filename.jpg. Not static/images/... - Hugo handles that.
Can’t push to GitHub. GitHub no longer accepts passwords. You need a personal access token: Settings → Developer settings → Personal access tokens. Use the token as the password when Git prompts you.
hugo server says command not found. Hugo isn’t on your PATH. On Windows, add the hugo.exe folder to the PATH environment variable and restart your terminal.
Changes don’t show up in the browser. Cache. Hard refresh, or run hugo server --disableFastRender.
The day-to-day workflow
Once everything is set up, posting feels almost too simple:
hugo new posts/post-name.md
# write the post in Markdown
hugo server -D # preview it
git add .
git commit -m "New post about whatever"
git push
About two minutes after the push, the site updates. No logging in, no clicking “Publish,” no waiting for the WordPress dashboard to load. It’s the part I missed most about old-school static publishing and didn’t realize until I had it again.
Backups (you don’t really have to think about it)
This is the quiet superpower of the whole setup:
- Everything I write lives in GitHub. That’s already a backup.
- Every change is in Git history. I can roll anything back.
- Cloudflare keeps a copy of every build.
I also occasionally download a zip of the repo just to be doubly safe, and I keep my images on Google Drive as well. But honestly, with everything in Git, I worry about backups way less than I did when I was managing a WordPress database.
If my computer died tomorrow, I could clone the repo to a new machine and be writing again in five minutes.
What it costs me
Monthly: $0.
Breakdown:
- Hugo: free, open source
- GitHub: free for public repos (fine for a personal site)
- Cloudflare Pages: free for personal use, with SSL and a global CDN included
- Custom domain: ~$12/year, the only thing I actually pay for
If you want your own domain, point it at Cloudflare from your registrar (Namecheap, GoDaddy, etc.), add it under Custom Domains in Cloudflare Pages, and wait for DNS to settle. Usually within a day.
The *.pages.dev URL is perfectly fine if you don’t want to spend the $12.
Why I’m sticking with it
Compared to the old PHP setup, this one is faster, more reliable, simpler to update, and free. The only thing I traded away is a built-in comments system, and I don’t really miss it. If I ever wanted comments back, Disqus or a small Worker would do the job.
If you have the patience for an evening of setup, I genuinely think this beats most paid hosting for personal use. The first time you push a typo fix and see it live a minute later, you’ll get it.
You’re reading the result right now. The whole thing - every page, every post, every image - is built and served exactly the way I described above. Pretty hard to argue with free.
A couple of useful links
- Hugo Quick Start - start here
- Hugo Themes - yes, you’ll lose hours
- Markdown Guide - ten minutes and you know it
- Git Handbook - for when Git gets weird
Share


