Host Your Own Blog for Free with Hugo and Cloudflare Pages

Copied to clipboard! Copies a prompt to paste into ChatGPT, Claude, etc.

This blog runs on Hugo and Cloudflare Pages. Total cost: $0/month. No servers to maintain, no databases to back up, no security patches to apply. Just markdown files that become a fast, globally-distributed website.

Here’s exactly how to set it up.

Why This Stack?

  • Hugo: Blazing fast static site generator written in Go. Builds this entire blog in under 100ms
  • Cloudflare Pages: Free hosting with global CDN, automatic HTTPS, and unlimited bandwidth
  • Markdown: Write posts in your favorite editor, version control with git
  • No JavaScript required: The site works without JS, loads instantly

Step 1: Install Hugo

# macOS
brew install hugo

# Linux
sudo apt install hugo

# Windows
choco install hugo-extended

# Verify installation
hugo version

You need the extended version for SCSS support (most themes use it).

Step 2: Create Your Blog

# Create a new site
hugo new site my-blog
cd my-blog

# Initialize git
git init

Step 3: Add a Theme

I use hugo-coder, a clean developer-focused theme:

# Add theme as git submodule
git submodule add https://github.com/luizdepra/hugo-coder.git themes/hugo-coder

Other great themes:

Browse more at themes.gohugo.io.

Step 4: Configure Your Site

Create config.toml:

baseURL = "https://yourdomain.com/"
languageCode = "en-us"
title = "Your Name"
theme = "hugo-coder"

# Code highlighting
pygmentscodefences = true
pygmentsstyle = "dracula"

[pagination]
  pagerSize = 20

[markup.goldmark.renderer]
  unsafe = true  # Allow raw HTML in markdown

[params]
  author = "Your Name"
  description = "My coding blog"
  colorscheme = "dark"  # or "light", "auto"

  # Social links
  [[params.social]]
    name = "GitHub"
    icon = "fa fa-2x fa-github"
    url = "https://github.com/yourusername"

  [[params.social]]
    name = "Twitter"
    icon = "fa fa-2x fa-twitter"
    url = "https://twitter.com/yourusername"

[menu]
  [[menu.main]]
    name = "Posts"
    url = "/post/"
    weight = 10

Step 5: Write Your First Post

hugo new post/my-first-post.md

This creates content/post/my-first-post.md:

---
title: "My First Post"
date: "2025-12-14"
draft: true
---

Hello, world! This is my first blog post.

## Code Example

```python
def hello():
    print("Hello from my blog!")

An Image

Alt text


Put images in `static/images/` and reference them with `/images/filename.png`.

## Step 6: Preview Locally

```bash
# Start local server with drafts
hugo serve --buildDrafts

# Open http://localhost:1313

Hugo has live reload—edit a file and the browser updates instantly.

Step 7: Deploy to Cloudflare Pages

Option A: Connect GitHub (Easiest)

  1. Push your blog to GitHub
  2. Go to Cloudflare Pages
  3. Create a project → Connect to Git
  4. Select your repository
  5. Build settings:
    • Build command: hugo
    • Build output directory: public
    • Environment variable: HUGO_VERSION = 0.140.0

Cloudflare rebuilds and deploys automatically on every push.

Option B: Deploy with Wrangler (More Control)

# Install wrangler
npm install -g wrangler

# Login to Cloudflare
wrangler login

# Build your site
hugo --destination=public

# Deploy
npx wrangler pages deploy public --project-name=my-blog

I use a Makefile to simplify this:

.PHONY: serve build deploy

serve:
	hugo serve --buildDrafts

build:
	hugo --destination=public-prod

deploy: build
	npx wrangler pages deploy public-prod --project-name=my-blog --branch=main

Now make deploy builds and deploys in one command.

Step 8: Custom Domain (Optional)

  1. In Cloudflare Pages dashboard, go to your project
  2. Custom domains → Add custom domain
  3. Enter your domain (e.g., blog.yourdomain.com)
  4. If domain is on Cloudflare DNS, it auto-configures
  5. Otherwise, add the CNAME record it provides

HTTPS is automatic and free.

My Workflow

# 1. Create new post
cat > content/post/$(date +%Y-%m-%d)-my-new-post.md << 'EOF'
---
title: "My New Post"
date: "$(date +%Y-%m-%d)"
---

Content here...
EOF

# 2. Preview locally
make serve
# Check http://localhost:1313

# 3. Deploy when ready
make deploy

# 4. Commit to git
git add .
git commit -m "Add post: My New Post"
git push

Tips

Syntax Highlighting

Hugo uses Chroma for syntax highlighting. Set your style in config.toml:

pygmentsstyle = "dracula"  # or monokai, github, etc.

Preview styles at xyproto.github.io/splash/docs/.

Custom CSS

Create static/css/custom.css and reference it:

[params]
  customCSS = ["css/custom.css"]

RSS Feed

Hugo generates /index.xml automatically. Link to it:

[[params.social]]
  name = "RSS"
  icon = "fa fa-2x fa-rss"
  url = "/index.xml"

Remove Draft Status

When ready to publish, either:

  • Remove draft: true from front matter
  • Or delete the line entirely

Only non-draft posts appear in production builds.

Cost Breakdown

Service Cost
Hugo Free (open source)
Cloudflare Pages Free (unlimited sites, bandwidth)
Custom domain ~$10/year (optional)
Total $0-10/year

Compare to:

  • Medium: Free but they own your content
  • Substack: Free but paywalled features
  • Ghost: $9-25/month
  • WordPress.com: $4-25/month

Why Not [X]?

Why not Medium/Substack? You don’t own your content. They can change terms, add paywalls, or shut down.

Why not WordPress? Overkill for a blog. Databases, PHP, security updates, hosting costs.

Why not GitHub Pages? Also great! Cloudflare Pages has faster global CDN and easier custom domains.

Why not Netlify? Also excellent. I use Cloudflare because my DNS is already there.

Conclusion

A Hugo + Cloudflare Pages blog gives you:

  • Full ownership of your content
  • Version-controlled posts in git
  • Sub-second build times
  • Global CDN distribution
  • Zero monthly costs
  • No maintenance burden

The entire setup takes about 30 minutes. Your posts live forever in markdown files you control.

Copied to clipboard!