Letsencrypt SSL certificates generation using dnsrobocert

Letsencrypt is an amazing new (launched in april 2016, so not all that new really) Certificate Authority that issues SSL certificates for free, that can then be used for protecting your websites with https free of charge. Yes – we the people get free SSL certificates, and then together we can help make internet more secure.

It was maybe questionable practice in the very beginning, but we’ve come a long ways since -> nowadays there are some fairly high profiles sites using letsencrypt (such as pcgamer, wikipedia and oh so many others) so I’d say I won’t be going out on a limb claiming it’s a trusted and reliable CA at this point.

Letsencrypt caveats

a) you will need automation – period.

It is for some very good reasons that letsencrypt certificate lifetime is only 90 days – basically forcing us to implement some sort of an automation for certificate renewals.

But hey – is that really a bad thing? I dont think so, but something to solve anyways (topic of this article).

b) Those on residential internet lines will likely have to use DNS-01 method of validation.

There are 2 different validation methods letsencrypt provides – so you can prove to them you indeed own the domain you are trying to get certificate for: HTTP-01 and DNS-01.

HTTP-01 – method works if you can expose port 80/443 to letsecnrypt. Issue with this – most residential internet providers won’t let you do that for “safety reasons” which brings us to second method.

DNS-01 – works by us adding DNS TXT records with specific values to our domain’s DNS records. Then letsencrypt checks these values on their end and if they match – voila – a certificate is being issued or renewed for you. To be honest – I much prefer this method anyways as I see this as simpler to automate.

Now that “we settled” on DNS-01, we don’t want to be doing all the brute manual labor adding these txt records to DNS manually right? and setting up some homegrown certbot automation right? where is the fun in that – we can spend our time more productively.

This bring us to dnsrobocert.

What is dnsrobocert?

You feed it a domains config, it runs (as a docker container) in the backround, generates ssl certs as defined in config, periodically checks for cert expiration and refreshes SSL certs before they expire.

Basically – you give it config and you get always up-to-date certs and dont have to worry about certs updates ever. Neat – right?

Example config

a) For starters – make sure your DNS provider is on the lexicon DNS providers list. Lexicon is an extremely popular library to handle DNS updates across many providers -and dnsrobocert uses it under the hood.

Your DNS provider is not on the list? – me personally? – I’d just switch provider.

b) Login to your DNS admin panel and generate an access token – dnsrobocert will need that to access your DNS records and make temporary changes (adding temp TXT records to prove letsencrypt you own the domain).

I’ve added example config below – it’s fairly simple and straightforward. Make sure to set draft: false when practicing so not to trip letsencrypt rate limits.

draft: false
acme:
  email_account: jane.doe@gmail.com
  api_version: 2
  staging: false
  certs_permissions:
    files_mode: "0664"
    dirs_mode: "0775"
    user: 1000
    group: 1000

profiles:
- name: gandi_profile
  provider: gandi
  provider_options:
    auth_token: "my-api-token"
  #in my tests - 3 tries by 5 minutes were not enough for DNS propagation.
  #So I decided to up it to 14
  max_checks: 14
  sleep_time: 200
  ttl: 7200

certificates:
- domains:
  - "*.example.net"
  - "example.net"
  profile: gandi_profile
  pfx:
    export: true
- domains:
  - "*.example.org"
  - "example.org"
  profile: gandi_profile
  pfx:
    export: true
- domains:
  - "*.example.edu"
  - "example.edu"
  profile: gandi_profile
  pfx:
    export: true
- domains:
  - "*.example.com"
  - "example.com"
  profile: gandi_profile
  pfx:
    export: true

Refer to dnsrobocert official documentation for full explanation of all the options.

Launch dnsrobocert docker service

Create directories:

mkdir -p /mnt/4tb_drive/dockervolumes/dnsrobocert/{letsencrypt,config}

Launch dnsrobocert container:

docker run -d \
--name dnsrobocert \
--restart=unless-stopped \
--label=com.centurylinklabs.watchtower.enable=false \
-v /mnt/480g_drive/dockervolumes/dnsrobocert/config:/etc/dnsrobocert \
-v /mnt/480g_drive/dockervolumes/dnsrobocert/letsencrypt:/etc/letsencrypt \
adferrand/dnsrobocert:3.7.5

Please note – since DNS-01 uses DNS records for a proof and DNS records take some time to propagate – it can easily take an hour for all the DNS challenges to succeed. I the config above we’ve configure to try checking DNS up to 14 times with 200 second interval between checks.

You may need to adjust intervals to fit your usecase.

Certs are ready

When let’s encrypt finishes generating your certificates (may take a while – depends on DNS propogation time) -> you can find them in directory you defined in docker configuration above, for example:

tree dnsrobocert/letsencrypt/live
.
├── example.net
│   ├── cert.pem -> ../../archive/example.net/cert1.pem
│   ├── cert.pfx
│   ├── chain.pem -> ../../archive/example.net/chain1.pem
│   ├── fullchain.pem -> ../../archive/example.net/fullchain1.pem
│   ├── privkey.pem -> ../../archive/example.netprivkey1.pem
│   └── README
├── example.edu
│   ├── cert.pem -> ../../archive/example.edu/cert1.pem
│   ├── cert.pfx
│   ├── chain.pem -> ../../archive/example.edu/chain1.pem
│   ├── fullchain.pem -> ../../archive/example.edu/fullchain1.pem
│   ├── privkey.pem -> ../../archive/example.edu/privkey1.pem
│   └── README
├── example.org
│   ├── cert.pem -> ../../archive/example.org/cert3.pem
│   ├── cert.pfx
│   ├── chain.pem -> ../../archive/example.org/chain3.pem
│   ├── fullchain.pem -> ../../archive/example.org/fullchain3.pem
│   ├── privkey.pem -> ../../archive/example.org/privkey3.pem
│   └── README
├── README
└── example.com
    ├── cert.pem -> ../../archive/example.com/cert2.pem
    ├── cert.pfx
    ├── chain.pem -> ../../archive/example.com/chain2.pem
    ├── fullchain.pem -> ../../archive/example.com/fullchain2.pem
    ├── privkey.pem -> ../../archive/example.com/privkey2.pem
    └── README

4 directories, 29 files

Bundle certificates

This may be an optional step depending on your use case.

I tend to use haproxy as my preferred reverse-proxy choice (there are many many others). Haproxy prefers combined certificate files for TLS termination use-cases. So I tend to run this script (as a cron job) to automatically bundle my certificates for me:

#!/usr/bin/env bash

for dir in $(ls -d dnsrobocert/letsencrypt/live/*); do

    if [ ! -d "$dir" ]; then
        continue;
    fi

    echo "Bundling: $dir/fullkeychain.pem"

    #remove previous bundle
    rm $dir/fullkeychain.pem
    
    #create new one
    cat $dir/privkey.pem $dir/fullchain.pem > $dir/fullkeychain.pem
    chmod 666 $dir/fullkeychain.pem
done

What above script will do – is add fullkeychain.pem files to every site certificate directory.

This concludes this mini tutorial – at this point you should have dnsrobocert running in automatic mode, checking certificate expirations nightly (you can change schedule as desired), cracking out SSL certificates ready for you to use directly, or be distributed to wherever remote servers/systems your heart desires. 👍

Leave a Comment