Robin Laurén

Exploring my way out of Imposter Syndrome

Hugo, Custon Domain, Letsencrypt Certificate and Gitlab Pages

Setting up https on a hugo site on Gitlab pages with your custom domain requires some manual work, but if i can do it, so can you.

The process includes the following components

  • A Hugo site on your computer
  • Gitlab pages with above site
  • Let’s Encrypt certbot
  • In my case, a Mac with homebrew (you can do this with Linux as well)
  • A public DNS server or service
  • Your favourite terminal
  • No much fear
  • Patience

I should have taken some screenshots, but i’ll try to explain things well enough so that you can do without. Please ask using the comments (if they work) or Twitter, or the MacAdmins Slack, if i left something out.

I’ll assume that you, like me, already are running your Hugo site on Gitlab Pages. You may or may not have set up a custom domain name for your pages. I did, because i’m curious, and i like to take things in iterative steps.

The whole thing is a bit of a circular chase, where every chicken needs to eggsist before its egg, which in practice means that you’ll have to do a few things in parallel. Have faith. Think of parallel universes. It’s not that complicated.

These instructions are probably valid for other platforms than Hugo. The only really Hugo-specific bit is that i’ll post a validation file into Hugo’s static directory which means it will be presented to the users as-is.

DNS records

The first parallel bit is to create a custom domin for your site on Gitlab pages and on your DNS server/service. To make things silly, you’ll first need to set your Gitlab pages domain without a certificate. Later, you’ll delete this domain. Yeah, i know, it’s a bit convoluted, but as i said, some things are a bit chicken-and-egg here.

From the Gitlab user interface, within your Hugo pages project, go Settings > Pages > + New Domain. Type the domain name of your site in the Domain box. Leave the Certificate and Key boxes bland. Click the inviting green Create New Domain button.

Gitlab will warn you that This domain is not verified so let’s do that now.

Head over to your friendly DNS server/service and create two records:

  • a CNAME record (sometimes called an “alias” record) for your site
  • a TXT record to prove to Gitlab that it’s you

Copy and paste the relevant bits from the page into your DNS config. Exactly how you do this depends on your DNS provider, which is a terribly lazy way of saying that i can’t really help you here. I use ZoneEdit, which allows me to host one domain for free, and Amazon Route 53, which costs a penny a day per domain name. Since i’m scared, i haven’t moved my free entry on ZoneEdit to Amazon.

Be careful with the TXT record. On the “left” side, paste in all of _gitlab-pages-verification-code.your.site.tld and on the “right” side, gitlab-pages-verification-code=string-of-hexadecimals.

Also, note the dot at the end of the CNAME. It’s there for a reason. When you’re done with the DNS stuff, click the green Verify ownership button. If all goes well, your domain name is now verified. To verify, you may want to curl http://your.site.tld and celebrate.

DNS records may take a little while to propagate around the Internet, so don’t panic. You may want to dig your.site.tld from your command line.

The crypto bits

Now, let’s install Let’s Encrypt Certbot. On a Mac with homebrew, that’s as easy as

brew install certbot

See the Certbot site for info on other platforms. In the Software dropdown, choose none of the above and whatever your OS is in the System dropdown.

Now change into the directory of your computer which contains your hugo site – let’s call this $yoursite, – and create a few magic directories

% cd $yoursite
% cd static
% mkdir -p .well-known/acme-challenge
% cd .well-known/acme-challenge

OK. Now let’s create all the certificate stuff, ie the private key and the keychain. I’ll probably write something about certificates one day, because they can be a bit confusing. You’ll need to sudo this, as the process involves touching some files which are out of bounds for the regular user. If you’re like me, you’ll first need to su into your admin user, and if you’re like old-me, you just use sudo as if nothing’s happened.

Replace your.site.tld with your custom domain.

Open up a new terminal tab for the Certbot stuff, since you’ll need to do two things in parallel again. I’ll call this new tab the Certbot tab and the previous one the User tab.

you % su admin-you
admin-you % sudo certbot certonly --manual -d your.site.tld

And this is where it starts to get tricky.

The verification file

Certbot will now ask you to Create a file containing just this data:, which is a long and seemingly random string of characters into a file containing those same characters and more seemingly random characters. As hugo will serve files from the static hierarchy as-is, this is the place to create a file containing just this data.

Keep certbot running in the Certbot tab and switch to your User tab. There,

% cd $yoursite/.well-known/acme-challenge # unless you're there already
% echo ThoseRandomCharactersCertbotGenerated.AndThenSome > ThoseRandomCharactersCertbotGenerated

Push these to Gitlab:

% git add .
% git commit -am "Add Certbot validation file"
% git push

And wait.

Then wait some more. Stand up, walk around the chair. Breathe. Sit down.

Still in your User tab, curl http://your.site.tld/.well-known/acme-challenge/ThoseRandomCharactersCertbotGenerated. Repeat until you get a response containing only ThoseRandomCharactersCertbotGenerated.AndThenSome. The first few times, you’ll probably get the 404 error page. That’s because Gitlab is still processing your site.

If you get errors, there are two reasons i can think of. First test whether the file was actually pushed into production. Substituting your username for yourusername below, curl https://yourusername.gitlab.io/.well-known/acme-challenge/ThoseRandomCharactersCertbotGenerated (or http). If you got the validation file, good. If not, push harder.

The second reason is probably DNS, because “everything’s a DNS problem”. Your DNS records may still point to your old site (you got a 404) or your site was not found (DNS records haven’t propagated yet). Go back to the bit about DNS.

Switch to your Certbot tab, which is just waiting to verify the file you sent above. Press Enter to let it, and fill yourself with joy as you read the Congratulations! text. The certbot has now created two files which you’ll need soon.

Switch to Secure

We’re nearly there, and trust me, it’s taken a lot longer time to write this than what it took me to get my site running in glorious https.

You’re now going to remove your previously created custom domain on Gitlab. Sick, yeh? This is because (currently?), you can’t add a certificate to an already existing custom domain on Gitlab. Maybe that’ll change one day and that means i’ll have to change this write-up, but until then, that’s life.

From your Gitlab pages’ Settings > Pages, see your previously created domain name and press the slightly intimidating (it’s designed that way) Remove button. There’ll be a dialogue box. Click OK, because you are sure. Now press the green + New Domain button again.

In the Domain field, enter your.domain.tld again. Paste the contents of the cerbot-generated certificate file (in my case, /etc/letsencrypt/live/robin.lauren.fi/fullchain.pem) into the Certificate field and the key file (me, /etc/letsencrypt/live/robin.lauren.fi/fullchain.pem) into the Key text field. As a note to all you aspiring devops-style sysadmins, you usually want to keep your private key very private and be very, very careful with where you put it. A healthy dose of paranoia is probably good for you.

Press the green Create New Domain button and rejoice!

OK, nearly there. You’ll still need to edit your Hugo site’s main configuration file, $yoursite/config.toml. Change the baseurl to reflect

baseurl = "https://your.domain.tld/"

Commit all your changes. Push to Gitlab. Give it a while to generate. And surf to your newly https’isised site! Yay!

In three months, your certificate will expire. Before that, you should sudo certbot renew, or even better, set up an automation to do that.