Let's Encrypt meets GitLab
So, we already know how to host our website with GitLab pages, now we want our own domain with free SSL certificates, on this post we are going to show you how to quickly do this with Let's Encrypt.
Hosting a site in GitLab is as easy as it gets, you just need to have all the files inside of a directory called public
and add this section to your .gitlab-ci.yml
.
If you don't have yet your static website hosted on GitLab, I'll recommend you to follow their steps on how to do it, they have a good number of templates to choose from and start in no time.
After you are done, you will end up with a .gitlab-ci.yml
file similar to this:
stages:
- deploy
pages:
stage: deploy
script:
- echo whatever script you may have here
artifacts:
paths:
- public
only:
- master
Now, we want our website to be accessible with our own domain, for that we will need to get the necessary free SSL certificates, introducing Let's Encrypt.
Let's Encrypt is a free certificate authority that issue certificates only for 3 months, forcing everybody to update their certificates on an automated way. Luckily there is a ton of tools to help us do this, certbot is one of those tools and the one we will be using in this example.
To issue a certificate, Let's Encrypt needs to verify that we own the domain we are requesting the certificate for, this is called challenge, at the time of this writing there are 2 types of challenges, they are both explained here. We will use the DNS-01 challenge, which will create a TXT
record in our domain that Let's Encrypt checks to verify that we own that domain, this is pretty much how it works:
- We request a new certificate to Let's Encrypt for mydomain.com
- Let's Encrypt then ask us to create a TXT record with a token called _acme-challenge.mydomain.com, ending up with something like
_acme-challenge.mydomain.com = 123LetsEncryptTokenHere
- We add the TXT record in our DNS
- Let's Encrypt then verifies that the record with the token exists and validates that we own that domain
- After the validation is done, Let's Encrypt give us the certificates.
So let's think about it, to automate the generation of the certificates, we would need:
- A program to request the certs, update the DNS and download the certs, this is
certbot
- Credentials to update our DNS entries
- Credentials to upload the certs to GitLab
- A script to upload the requested certs to GitLab,
curl
will do
Certbot has DNS plugins for the most popular DNS providers, here is the list of them. In this example we are going use the plugin for OVH. Each of the plugins have their instructions on how to use them. Instead of installing certbot in our build box, we could just use one of the docker containers and simply give it our credentials to perform the necessary operations, ending up with a new section in our .gitlab-ci.yml
like this:
update_cert:
stage: update
image:
name: certbot/dns-ovh #1
entrypoint: [""] #2
variables:
DOMAIN: "mydomain.com" #3
CERT_FILE: "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" #4
KEY_FILE: "/etc/letsencrypt/live/$DOMAIN/privkey.pem" #4
before_script:
- apk add curl #5
script:
- certbot certonly -n --agree-tos --dns-ovh --dns-ovh-credentials ovh.ini --dns-ovh-propagation-seconds 60 -d $DOMAIN -m your@email.com #6
- "curl --silent --fail --show-error --request PUT --header \"Private-Token: $GITLAB_TOKEN\" --form \"certificate=@$CERT_FILE\" --form \"key=@$KEY_FILE\" https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pages/domains/$DOMAIN" #7
only:
- schedules #8
Let's analyze this file:
- The Docker image used is
certbot/dns-ovh
, which contains certbot with the OVH plugin already installed - The Docker
entrypoint
is set to empty so we can execute multiple commands inside that container, otherwise we would run only certbot - The domain we want to get the certs for
- Variables
CERT_FILE
andKEY_FILE
are set to the location where certbot is going to download the certificate and key. - We install
curl
before anything else, we are going to need it to upload the certs to GitLab - Run certbot with the following flags:
--dns-ovh-credentials ovh.ini
: we should have the ovh.ini file in the root of our project with the OVH credentials in it, if your project is public set this as build variables--dns-ovh-propagation-seconds 60
: is good practice to set 60 seconds or more to wait for DNS propagation-d $DOMAIN
: the domain we want to update-m your@email.com
: An email address where Let's Encrypt is going to notify us in case our cert is about to expire
- The
curl
command to upload our cert to GitLab, here we have a variable calledGITLAB_TOKEN
that we should set in the Project Settings > CI/CD > Environment Variables section. The value of that variable should be an access token with api scope access. - The last bit is a constraint to execute this job only when run scheduled, in my case I've created a schedule that runs every month.
That's it, this will update my website SSL certificates every month and I won't have to worry about updating them anymore. Hope this has been helpful to you and updating your certs automatically has been made easier. Thanks for reading and don't forget to leave comments if you have any questions or suggestions.