Setting up GitHub pages

Posted on Tue, Jul 15 2025 | Tags: web git bash

NOTE:

Because of some snags with whatever CDN GitHub uses for its Pages feature, I have switched to a more traditional Rsync + SSH setup. I posted this article for people who might have better luck.

Who doesn't like free hosting? GitHub Pages is easy to set up for a personal blog, but some people might be put off by the username.github.io web address it gives you by default. In an attempt to at least seem more professional, I decided to add a custom domain. The setup process for this could be explained better, and I hit a couple of snags along the way.

DNS config

The very first thing you need to do is configure the DNS settings for your domain. The exact steps you need to follow to find and change the settings are going to depend on your domain registrar, which is the site where you bought your domain. Check their documentation or contact their support team.

Once you find the page that allows you to change your DNS configuration, the very first thing you should do is verify your domain with GitHub. I can not stress this enough because apparently domain hijacking is a thing. The steps to follow are here and are generally correct, but adding a TXT record to your DNS configuration isn't enough. I found that verification will continue to fail until after you add the custom domain to your GitHub pages repository.

So the proper steps are:

  1. Add the TXT record for domain verification to your DNS config. Yes, it will only have a "copy this" (grey box with a copy symbol) around the part before .github.io. This is not a mistake. It will not work if you put the .github.io part in the HOST field of the TXT record. Oh, and keep this page open.
  2. Follow the custom domain setup guide and make sure you add the required A and AAA entries. I ran into a problem with the HOST fields and had to use the @ symbol to get them to work with my registrar, but yours may be different. For the CNAME record, I had to use "www". Again, your setup may be different.
  3. After your custom domain successfully resolves to your site, then go back to the verification page and click the green "Verify" button.
  4. NEVER, UNDER ANY CIRCUMSTANCES, REMOVE THE VERIFICATION TXT RECORD FROM YOUR DNS SETTINGS.

Also keep in mind that DNS updates may not be instant. You might have to wait a few minutes. In my case, the updates were pretty quick once I figured out what I was doing. But then I ran into a problem with URLs.

Fixing the base URL in my configuration

When my website finally became visible using my custom domain, I noticed that the links were broken and the CSS wouldn't load.

screenshot of my website with absolutely no styling

The problem turned out to be the base URL I set in my SSG. After trying my GitHub Pages URL and my custom domain, I said "screw it" and put an empty string in my SSG config file. Doing that worked, and I don't know why. I'll choc it up to server magic.

What wasn't fixed was my home link. Clicking the name of my site in the upper left corner was supposed to take visitors back to the home page. Instead, it just caused whatever page it was on to reload. The solution turned out to be modifying the link in my head.ms template to specifically target index.html like this:

  <header id="site-header">
    <h1 id="site-name"><a href="{{site.baseUrl}}/index.html">{{site.name}}</a></h1>
    <nav id="site-menu">
      <ul>
        {{# site.collections.menu.pages }}
        <li class="site-menu-item"><a href="{{url}}">{{title}}</a></li>
        {{/ site.collections.menu.pages }}
      </ul>
    </nav>
  </header>

Once I got that working, I still had to solve the puzzle of pushing updates to the GitHub repository backing my site. Using a plain cp -r dest ../<repo_name> command was a good start, but what about deleting content? And doing the git add blah; git commit -m "blah"; git push blah dance? This was a bit naive:

#!/bin/bash

# Generate the site.
python main.py publish

# Copy files
cp -r dest/* ../<the_repo>/

# CD to the publishing directory, add the files, prompt for a commit message, and push.
cd ../<the_repo>
git add *
read -p 'Commit msg: ' MSG
git commit -m "$MSG"
git push -u origin main

This works, but what if I wanted to delete stuff? The solution to that problem was a good old rsync -av --delete command, but that would wipe out the .git directory and the CNAME file. I had a hunch that an old staple like Rsync had an option to ignore certain files and directories. My hunch was correct.

#!/bin/bash

# Generate the site.
python main.py publish

# Use --exclude for each important file and directory to make Rsync ignore them.
rsync -avz --delete --exclude '/.git' --exclude '/README.md' --exclude '/CNAME' dest/ ../<the_repo>/

# CD to the publishing directory, add the files, prompt for a commit message, and push.
cd ../<the_repo>
git add *
read -p 'Commit msg: ' MSG
git commit -m "$MSG"
git push -u origin main

Now whenever I'm ready to publish, I only have to run bash publish.sh and enter the required information. The script above should be useful no matter which static site generator you use. Just change dest to the output directory of your SSG, and change <the_repo> to point to a local copy of your GH Pages repo.