This tutorial details how to set up a blog using Hugo, intall the PaperMod theme, and host it all on GitHub Pages (for free!). This is how I set up this blog you’re reading.
1. Install Hugo
If you’re on macOS, and have homebrew installed, in your terminal:
brew install hugo
For other OSes, and detailed install instructions see here
2. Create new site
Navigate to the folder where you will want the project to reside. The following command will create the folder for the project, and initiate it with the base files:
hugo new site my-hugo-blog
3. Install PaperMod theme
Navigate into the folder for the site you just created, and then clone the PaperMod Theme into your project
cd my-hugo-blog git clone https://github.com/adityatelange/hugo-PaperMod themes/PaperMod --depth=1
now get rid of the default config.toml, and create an empty config.yml. YAML is much nicer to read and work with IMO.
rm config.toml touch config.yml
Copy-paste the following settings into
config.yml (adapted from the PaperMod example site)
baseURL: https://entra.ca languageCode: "en-us" title: My Blog paginate: 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: My Blog description: "Example website, built on Hugo." keywords: [Hugo, Blog] author: Joe Bloggs # author: ["Me", "You"] # multiple authors images: ["<link or path of image for opengraph, twitter-cards>"] DateFormat: "January 2, 2006" defaultTheme: dark # dark, light, auto disableThemeToggle: false ShowReadingTime: true ShowShareButtons: true ShowPostNavLinks: true ShowBreadCrumbs: false 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: "entra.ca" icon: /apple-touch-icon.png iconHeight: 35 # profile-mode profileMode: enabled: false # needs to be explicitly set title: Example Blog Site 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: linkedin url: "https://www.linkedin.com/" - name: twitter url: "https://www.twitter.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 keys: ["title", "permalink", "summary", "content"] menu: main: - name: Home identifier: home url: / weight: 1 - name: Blog identifier: blog url: blog/ weight: 2 #- identifier: projects # name: Projects #url: projects/ # weight: 3 #- name: Services # identifier: hiring # name: Services # url: services/ # weight: 4 # 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
You’ll definitely want to adjust the settings in
config.yml, you can do that now or later.
If you had any troubles, there are detailed instruction for installing the PaperMod theme here.
4. Create a blog post
You can author content in Hugo using Markdown. Navigate to the
/content folder, create a new folder for your blog post, and create a new
cd content mkdir blog cd blog touch first-post.md
Now in your text editor, open
first-post.md and add the following:
--- title: "First Post" date: 2023-03-15T22:57:04+05:30 draft: false category: Blogging slug: first-post summary: First Blog post description: First Blog post ---
This is metadata that Hugo will use to build your blog. The most important items are
slug will be used to form the URL.
Below the metadata section, you can add some text. For example:
... description: First Blog post --- Hello, world. This is my first blog post!
Now you’re ready to preview! Start up the server from the project root
cd ../.. hugo server
If all goes well, you should be able to see your site at http://localhost:1313/ (or whichever port hugo tells you on the command line that it’s serving from)
You should be able to see your blog post at http://localhost:1313/blog/first-post
One really nice thing about running
hugo server is that it does hot-reloading. This means any time you change a file in your project and save, the server updates the state of the current page to the client using websockets.
Now you might take the time to customize the settings in
config.yml, and honing that perfect blog post. Once you’re ready to deploy, you can proceed to build the static site.
Build your static website with this simple command:
So fast! So easy! This command will build all of your site into the
/public folder. It will now contain all of the static assets that make up your built Hugo website. This is all the stuff that we want to put on the web.
We want people to be able to read this blog, so it needs to go on the web. We’re going to use GitHub’s free GitHub Pages service to do that. You’ll needa github account.
In GitHub, create a new repository. I’ve been doing this using the GUI on the GitHub website, but the CLI (Command Line Interface) looks nice and would be better suited to a tutorial like this.
Yu can follow these instructions up until the part that says
Congratulations! You’ve successfully created your first repository, and initialized it with a README file.
Now that you’ve set up your repo, go back to your terminal and navigate to the freshly built
/public folder. You’re going to set this up to be tracked using git.
cd public git init git add . git commit -m "My first commit" git remote add origin firstname.lastname@example.org:my-user-name/hello-world.git git pull origin master # this should cause the README.txt and anything else that github just created to merge in git push origin master
Great! Your code is up on github. Now we just need to set it up to deploy to GitHub Pages!
Next you need to adjust the settings on your GitHub repo to publish your project to GitHub Pages.
Follow these instructions
Sometimes it takes a few minutes to deploy. Your site will be visible at on the github domain, at a URL similar to
However, with GitHub pages, you can use your own domain. This is what I’m doing with my
entra.ca domain. Even better!
Instructions for using a custom domain here
8. Profit 📈
Congratulations, you now have your very own blog! Now you can watch the profits pour in.
You deserve a break. Why not grab a glass of lemonade and bask in the glory?
Ahh.. that was nice.
Next time you want to post a blog, all you have to do is write another
.md and place it in the
/blog folder, then do the following from the root of your project
hugo # rebuild the static site, including your latest post cd public git add . git commit -m "posting a blog" git push origin master # deploy!
Before adding this Hugo blog, my webpage was just a simple html single page portfolio site. I wanted to keep that in place as the homepage, and simply tack on the blog to it.
The way I achieved this was to put my old single pager in
/layouts/index.html. Hugo simply uses this file as the template for the homepage when you go to https://entra.ca.
I had to hack a replica of the top menu directly into that template, but it does the trick well enough for now. I plan to make it behave more like a normal Hugo template down the road, by including the menu properly from the Hugo source.