Lets Encrypt certificates for GitLab Pages sites

After checking up on my own website, I noticed my certificate had expired which generated warnings for visitors. GitLab has blogged about just this topic, but the choosen static site generator was Jekyll. My blog runs on Hugo, so the same steps wouldn’t have worked. The following steps should work regardless of the way you generate your content.

For starters, for acquiring the certificate, I’m using certbot. Certbot can run on your server and generate the needed file there, however with GitLab pages you don’t have access to that so it has to be done in manual mode.

$ sudo certbot certonly -m nospam@zjvandeweg.nl --manual -d www.zjvandeweg.nl -d zjvandeweg.nl
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for www.zjvandeweg.nl
http-01 challenge for zjvandeweg.nl

NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
(Y)es/(N)o: Y

Create a file containing just this data:


And make it available on your web server at this URL:


Press Enter to Continue

Create a file containing just this data:


And make it available on your web server at this URL:


Press Enter to Continue

You don’t want to press the Enter key right now, first you’d need to expose the challenge data. For the certificate, you need to prove you have control over the domain you want the certificate. The easiest way to create that file is by appending some commands to your .gitlab-ci.yml.

# Example Hugo .gitlab-ci.yml
# Works with other static site generators too
image: monachus/hugo:latest

  - hugo
  - mkdir -p public/.well-known/acme-challenge
  - echo "CXEimV9hW7wnan0gO1Pnau9Bwr4JWjSJ9bfx4-AVwOk.boZZAeHCIe1JJjgET_PZmMAi4fbgcTRTfE6sToEU5yE" > public/.well-known/acme-challenge/CXEimV9hW7wnan0gO1Pnau9Bwr4JWjSJ9bfx4-AVwOk
  - echo "-k0_KI9aMPc73w4B37PPrmwB3EDuuV3a3T5gqehTh1w.boZZAeHCIe1JJjgET_PZmMAi4fbgcTRTfE6sToEU5yE" > public/.well-known/acme-challenge/-k0_KI9aMPc73w4B37PPrmwB3EDuuV3a3T5gqehTh1w
    - public

Using this script you add data after generating your website, but given no one usually uses the .well-known directory this is ok.

Commit and push your changes, and make sure they’re deployed on GitLab pages. You should be able to check out the web pages yourself or just curl them. If this works hit enter on the certbot command. This will request the same well known pages so Lets Encrypt can verify you control the domain.

The files you’re interested in are located in /etc/letsencrypt/live/<your.domain>. Copy fullchain.pem into the Certificate box in the GitLab Pages setting on your repository. The privkey.pem contents needs to be uploaded as key. After saving your settings might take up to 10 minutes to propegate. Afterwards your website will correctly serve content with a secure connection!