This blog is built using Hugo, GitHub, and Cloudflare Pages. It’s a setup I’ve refined to be “zero maintenance”—once it’s configured, all I have to do is write a Markdown file, push it to GitHub, and the website updates itself within seconds.
– initially, I used fucking netlify, though they have a very annoying paywall, I am not sure what happened, but they charged me extra which I blocked it and then they just show me their fucking and annoying “update your credit card”, and basically I could not do anything in dashboard. So I switched to Cloudflare Pages, and it is just perfect, no paywall, no bullshit, just works.
So, with this setup, I add or edits post locally, push it to GitHub, and Cloudflare updates the website automatically. Very simple and efficient.
Let’s get started.
Why this specific tech stack?
- Hugo: Unlike WordPress which requires databases and PHP servers, Hugo takes your markdown files and generates plain HTML/CSS. This means your website is incredibly fast, extremely secure, and costs nothing to host.
- GitHub: It’s the standard for version control. Every change you make is tracked, and if something breaks, you can easily roll back.
- Cloudflare Pages: Cloudflare watches your GitHub repository. Every time you push a new blog post, Cloudflare automatically rebuilds your site and publishes it to the web in seconds across their massive global edge network.
Phase 1: Installing Hugo
Before we can build anything, you need Hugo on your computer.
On Linux (Debian/Ubuntu)
Use the standard package manager:
sudo apt-get install hugo
On MacOS or Windows
The easiest way is using a package manager like Chocolatey or Scoop:
#who cares! just go search on google how to install hugo on mac or windows.
Verify the installation: Open your terminal or command prompt and type:
hugo version
If you see version details, you are ready to go!
Phase 2: Creating Your Website
Navigate to the directory where you want to keep your project. Let’s call our website MyFreshWebsite and initialize it with YAML configuration format:
hugo new site MyFreshWebsite --format yaml
cd MyFreshWebsite
Hugo just scaffolded a directory structure for you. It includes folders like content (where your writing goes), layouts (for custom HTML templates), and static (for images and CSS).
Version Control (Git)
Initialize Git inside this new directory immediately. This allows us to track changes and push to GitHub later.
git init
Phase 3: Adding a Theme
A raw Hugo site looks like a blank white page. We need a theme. For this tutorial (and for my own website), I use the excellent and minimalist PaperMod theme.
The recommended way to install PaperMod is by adding it as a Git Submodule. Inside your Hugo site folder, run:
git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
Now, tell Hugo to use this theme. Open your site config (hugo.yml) and add:
theme: ["PaperMod"]
Phase 4: Basic Configuration
Let’s configure the basics using the standard PaperMod sample configuration. We use YAML format as it is easier to read. Here is a comprehensive hugo.yml structure you can use as a starting point:
baseURL: "https://examplesite.com/"
title: ExampleSite
pagination:
pagerSize: 5
theme: PaperMod
enableRobotsTXT: true
buildDrafts: false
buildFuture: false
buildExpired: false
minify:
disableXML: true
minifyOutput: true
params:
env: production # to enable google analytics, opengraph, twitter-cards and schema.
title: ExampleSite
description: "ExampleSite description"
keywords: [Blog, Portfolio, PaperMod]
author: Me
# author: ["Me", "You"] # multiple authors
images: ["<link or path of image for opengraph, twitter-cards>"]
DateFormat: "January 2, 2006"
defaultTheme: auto # dark, light
disableThemeToggle: false
ShowReadingTime: true
ShowShareButtons: true
ShowPostNavLinks: true
ShowBreadCrumbs: true
ShowCodeCopyButtons: false
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
disableSpecial1stPost: false
disableScrollToTop: false
comments: false
hidemeta: false
hideSummary: false
showtoc: false
tocopen: false
assets:
# disableHLJS: true # to disable highlight.js
# disableFingerprinting: true
favicon: "<link / abs url>"
favicon16x16: "<link / abs url>"
favicon32x32: "<link / abs url>"
apple_touch_icon: "<link / abs url>"
safari_pinned_tab: "<link / abs url>"
label:
text: "Home"
icon: /apple-touch-icon.png
iconHeight: 35
# profile-mode
profileMode:
enabled: false # needs to be explicitly set
title: ExampleSite
subtitle: "This is subtitle"
imageUrl: "<img location>"
imageWidth: 120
imageHeight: 120
imageTitle: my image
buttons:
- name: Posts
url: posts
- name: Tags
url: tags
# home-info mode
homeInfoParams:
Title: "Hi there \U0001F44B"
Content: Welcome to my blog
socialIcons:
- name: x
url: "https://x.com/"
- name: stackoverflow
url: "https://stackoverflow.com"
- name: github
url: "https://github.com/"
analytics:
google:
SiteVerificationTag: "XYZabc"
bing:
SiteVerificationTag: "XYZabc"
yandex:
SiteVerificationTag: "XYZabc"
cover:
hidden: true # hide everywhere but not in structured data
hiddenInList: true # hide on list pages and home
hiddenInSingle: true # hide on single page
editPost:
URL: "https://github.com/<path_to_repo>/content"
Text: "Suggest Changes" # edit text
appendFilePath: true # to append file path to Edit link
# for search
# https://fusejs.io/api/options.html
fuseOpts:
isCaseSensitive: false
shouldSort: true
location: 0
distance: 1000
threshold: 0.4
minMatchCharLength: 0
limit: 10 # refer: https://www.fusejs.io/api/methods.html#search
keys: ["title", "permalink", "summary", "content"]
menu:
main:
- identifier: categories
name: categories
url: /categories/
weight: 10
- identifier: tags
name: tags
url: /tags/
weight: 20
- identifier: example
name: example.org
url: https://example.org
weight: 30
# Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma
pygmentsUseClasses: true
markup:
highlight:
noClasses: false
# anchorLineNos: true
# codeFences: true
# guessSyntax: true
# lineNos: true
# style: monokai
Phase 5: Writing Your First Post
Let’s create something to publish. You can use PaperMod’s comprehensive frontmatter structure by placing a post.md in your archetypes/ directory to use as a template. Then, generate a new post using the Hugo CLI:
hugo new --kind post posts/my-1st-post.md
Open ./content/posts/my-1st-post.md in your text editor. You will see something called “frontmatter” at the top inside --- brackets. Ensure draft is set to false.
---
title: "My 1st post"
date: 2020-09-15T11:30:03+00:00
# weight: 1
# aliases: ["/first"]
tags: ["first"]
author: "Me"
# author: ["Me", "You"] # multiple authors
showToc: true
TocOpen: false
draft: false
hidemeta: false
comments: false
description: "Desc Text."
canonicalURL: "https://canonical.url/to/page"
disableHLJS: true # to disable highlightjs
disableShare: false
disableHLJS: false
hideSummary: false
searchHidden: true
ShowReadingTime: true
ShowBreadCrumbs: true
ShowPostNavLinks: true
ShowWordCount: true
ShowRssButtonInSectionTermList: true
UseHugoToc: true
cover:
image: "<image path/url>" # image path/url
alt: "<alt text>" # alt text
caption: "<text>" # display caption under cover
relative: false # when using page bundles set this to true
hidden: true # only hide on current single page
editPost:
URL: "https://github.com/<path_to_repo>/content"
Text: "Suggest Changes" # edit text
appendFilePath: true # to append file path to Edit link
---
This is my very first blog post using Hugo! It wasn’t as hard as I thought.
Previewing Your Site Locally
Let’s see what we built before releasing it to the world.
hugo serve -D
(The -D flag tells Hugo to include draft posts in the preview, just in case).
Open your browser and navigate to http://localhost:1313. You should see your new minimalist blog and your “Hello World” post!
Press Ctrl+C in your terminal to stop the local server.
Phase 6: Pushing to GitHub
Now we have a working site. We need to back it up and get it ready for Cloudflare.
- Go to GitHub and log in (or create an account).
- Click the
+icon in the top right and select New repository. - Name it
my-website(or whatever you prefer). Do not initialize it with a README. - Click Create repository.
Ignoring Unnecessary Files
Before pushing your code, it’s a best practice to tell Git to ignore files that are automatically generated (like the compiled site files). In the root directory of your site, create a .gitignore file and add the following lines to it:
public/
.hugo_build.lock
Back in your terminal, inside your MyFreshWebsite folder, run these commands to commit your code and push it to GitHub (replace the URL with your actual repository URL):
git add .
git commit -m "Initial commit of my Hugo blog"
git branch -M main
git remote add origin https://github.com/yourusername/my-website.git
git push -u origin main
Your code is now safe on GitHub!
Phase 7: Deploying to Cloudflare Pages
This is where the magic happens. We will connect Cloudflare to our GitHub repo so that every time we push a new Markdown file, the website updates automatically.
- Go to the Cloudflare Dashboard and sign up or log in. It’s free!
- Navigate to Workers & Pages -> Create application -> Pages -> Connect to Git.
- Choose GitHub.
- Authorize Cloudflare to access your GitHub repositories.
- Select your
my-websiterepository from the list.
Build Configuration
Cloudflare will detect you are using Hugo. Set these configurations:
- Build command:
hugo --minify - Build output directory:
public
Environment Variables
To ensure consistency, go to Settings -> Build & deployments -> Environment variables and add:
- Variable name:
HUGO_VERSION - Value:
0.146.0(or whatever version you are using)
Security Headers (_headers)
Instead of a configuration file in the UI, Cloudflare uses a simple text file named _headers inside your static/ directory to manage security. Create static/_headers:
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Once you commit these changes and click Save and Deploy, Cloudflare will trigger its first build. Everything is automated from here!
Cloudflare will take a few seconds to run the build command. Once it says “Success,” click the link provided (it will be something like my-website.pages.dev).
Boom! You are live on the internet!
Next Steps: Custom Domains
If you own a custom domain name (like yourname.com), you can easily add it in the Custom domains tab of your Pages project. Cloudflare provides full DNS proxying, free SSL, and CDN caching out of the box.
Conclusion
You now have a modern, ultra-fast website that costs $0 a month to host on one of the world’s most robust global networks.
To write a new post in the future, the workflow is brilliantly simple:
hugo new --kind post posts/my-new-idea.md- Write your content.
git add .->git commit -m "new post"->git push
Cloudflare handles the rest. Welcome to the independent web!