Most of us developers reach that point in time where we think:
I should have a website/blog…
I’m not here to say that you need one. But creating and hosting a site is definitely a good learning experience (at least). That’s why I decided to write down what I have learned while creating this very website. The code is available on GitHub.
In this post, you will learn how to build a website using Markdown and host it on GitHub Pages using a custom domain.
(If you already know how to create a website, feel free to jump to my takeaways🦘.)
Where to start
If you are not a web developer (like me), the number of options you have to build a website can be quite overwhelming. As I did not want to write it purely myself using plain HTML, CSS, and JavaScript, I decided to use Hugo, a static site generator that builds websites based on a theme and some configuration. Then, I can focus on the content which I can write in Markdown.
The Hugo documentation has a great article on how to get started in a few minutes. After going through the quick start, you should have a basic site up and running locally.
Theme
Now it is time for the most critical decision: Which theme do I use?
The good thing is that there are a lot of themes out there. Which can also be the bad thing. Either way, picking a theme took me quite a while… I ended up with Poison 💀.
But feel free to experiment and try out different themes! I guess you can also switch themes later on if you mainly added your content and did not change too many theme-specific things.
Overriding theme templates
You might want to customize your theme of choice – e.g., rearrange some elements in HTML, add new ones, or change the style in CSS. For this, you don’t need to fork the theme and add your fork as a submodule (yes… this is what I did 🆘).
Likely, you are better off1 by overriding the template or partial that you want to change.
For this, create a template with the same path in the layouts
directory in your project root. For example, to override
themes/poison/layouts/partials/post/info.html
, create layouts/partials/post/info.html
as a copy of the original file and modify it.
Same goes for CSS or JavaScript files — except that those files are usually in the assets
directory.
For example, you could overwrite themes/poison-fork/assets/css/codeblock.css
by creating the file assets/css/codeblock.css
.
Note that themes usually provide a documented way to add custom CSS, e.g., the custom CSS file in Poison
or the customCSS
parameter in Coder.
Favicon
You probably also want a favicon2 for your website. If you have an image of choice, it is very easy to generate all the favicon data you need.
For example, I used RealFaviconGenerator. After uploading your image, you can adapt the size, background, and corners,
and specify the name under which your site will appear on mobile devices when added to the home screen.
Finally, use /
for your Favicon path and download the ZIP file. Extract the contents into the static/
folder (this will be copied to the root of your website).
You also need to add some <link/>
tags in the <head>
section for your site. For this, find the partial3 that creates the <head>
and check if
it also specifies a favicon. Maybe your theme has a separate partial for the favicon, which you can override.
If you are curious how I did it, here is the commit.
You can check whether your favicon is correctly configured later via a favicon checker.
Deployment and Hosting
The Hugo documentation includes articles on how to host websites on various platforms. Again, I wanted to keep it simple and decided to use GitHub Pages.
This is the point where you should have a GitHub repository with the code for your website. You can either use a user/organization or a project repository4.
After pushing your code, follow the steps described in Host on GitHub Pages
to create a GitHub Action that builds and publishes your site.
The next time you push changes to your repository’s main branch, the site will be built for you
and should be up and running at https://<username-or-org>.github.io
or https://<username-or-org>.github.io/<repo-name>/
4! 🐦🔥
Custom Domain
You might want to host your site on a custom domain. Maybe you already own a domain or you want to buy one because you have a genius idea for a domain name (this is me again 🐻). Either way, you can configure GitHub Pages to work with a custom domain.
There are two different types of domains you can use: apex domains and subdomains.
An apex domain (or base, bare domain) is a domain name that does not include any subdomains5. This is typically the name of the domain you are buying, e.g., python.org
.
A subdomain is — as the name suggests — a part of another domain, i.e. docs
is a subdomain of docs.python.org
.
Together with the apex domain, it forms the fully qualified domain name docs.python.org
.
Note that www
is also a subdomain.
One tip before you start messing around with your DNS configuration: the propagation of DNS records can take up to 24 hours to complete. If you are used to getting instant feedback — e.g., when you write code, you usually can change something and run the program to get immediate feedback — it can be hard to force yourself to change one thing and then wait for some hours (usually it is faster). Nevertheless, I recommend you to be patient with DNS configuration changes ⌛. Avoid making too many changes at once, because that way you won’t find out what setting you actually need. While waiting, you can start with the write-up of your first post. Or spend some time off the computer.
Verify your domain
Before you start configuring your repository to use a custom domain, I recommend verifying it. This ensures that only repositories owned by you can publish a GitHub Pages site to the verified custom domain. Follow the documentation to add a TXT record in your DNS configuration of your hosting provider.
❗Some hosting providers will automatically add your domain to the end of the record.
For example, I first created the TXT record with the full name _github-pages-challenge-rafaelwo.rawomb.at.
but this resulted in the record name being _github-pages-challenge-rafaelwo.rawomb.at.rawomb.at.
, i.e. the domain was duplicated.
Hence, I had to use the name without the domain: _github-pages-challenge-rafaelwo
.
You can confirm the existence of the new record by running the dig
command or an online DNS checker:
dig _github-pages-challenge-<username-or-org>.<your-apex.com> +nostats +nocomments +nocmd TXT
Configuring your repository to use your domain
To configure Pages to use your custom domain instead of the default one, you first have to enter your domain in the settings for Pages in your repository. The GitHub docs describe this procedure for apex and subdomains.
If you use a GitHub Action for publishing (like the one from Hugo), use GitHub Actions as the source for the build and deployment of Pages. Note that you don’t need a CNAME record in your GitHub repository if you use a GitHub Action to deploy your site.
Then, you have to add the following DNS record(s) in your domain/hosting provider’s DNS settings.
apex domain
ALIAS
orANAME
record with name@
(your root domain) and value<username-or-org>.github.io.
(default domain of your site)
ORA
records with name@
and the IP addresses for GitHub Pages as the value (one record per IP)- (optional)
CNAME
record with namewww.<your-apex.com>.
and value<username-or-org>.github.io.
(default domain of your site)- this automatically redirects from
www.<your-apex.com>
to<your-apex.com>
if you configure the latter as your custom domain, or vice versa
- this automatically redirects from
subdomain
CNAME
record with name<your.subdomain.com>.
and value<username-or-org>.github.io.
(default domain of your site)
❗Notice the trailing dot/period .
at the end of domain values.
This indicates a complete or absolute domain name and is required6 when creating DNS records.
You can confirm your DNS configuration via dig
:
dig <your-apex.com> +nostats +nocomments +nocmd
# or
dig <your.subdomain.com> +nostats +nocomments +nocmd
Finally, go back to your repository settings for Pages and check the status of the DNS check.
Wait for the DNS check to pass. If it fails, although you correctly configured your DNS record, try to Remove and add the domain again. (In my case, the DNS check failed on the day after I configured my DNS records but this procedure fixed it.)
If you still have troubles with your custom domain, check the documentation on troubleshooting your custom domain.
I also strongly recommend to Enforce HTTPS by checking the corresponding box. Note that you can only check the box after the DNS check is successful.
Otherwise, you are done! 🆒
My DNS Configuration
Name | Record type | Address | TTL |
---|---|---|---|
_github-pages-challenge-rafaelwo.rawomb.at. | TXT | 2424ab0b0c8fc97c5529cbe81b8894 | 3600 |
rawomb.at. | A | 185.199.108.153 | 3600 |
rawomb.at. | A | 185.199.109.153 | 3600 |
rawomb.at. | A | 185.199.110.153 | 3600 |
rawomb.at. | A | 185.199.111.153 | 3600 |
www.rawomb.at. | CNAME | rafaelwo.github.io. | 3600 |
Takeaways
- 🍱 Hugo makes it very easy to set up a static website and comes with a ton of free themes to choose from
- 💄 Customize your theme by overriding the template or partial instead of forking the theme – unless you want to contribute to the theme, of course
- 💸 You can easily host your website for free using GitHub Pages. If you use Hugo, check the docs on how to deploy to Pages
- ✅ If you want to host your website on a custom domain, verify it first to mitigate domain takeovers
- ⌛ Be patient with modifying your DNS configuration as changes can take up to 24 hours to propagate
- 🔁 If your GitHub pages DNS check is failing, try to remove and add your custom domain
- 😵💫 Read the troubleshooting documentation if you have further issues with your custom domain and GitHub pages
There is nothing wrong with forking a theme, e.g., to contribute to it, of course. ↩︎
This is the small icon that you see in an open tab in your browser. ↩︎
A partial is a template to render a component or part of your site (see also docs). ↩︎
Some providers might add the trailing dot automatically, e.g., AWS Route 53. ↩︎