Manage Let's Encrypt certificates with Digital Ocean Spaces
Introduction
Managing and distributing Let's Encrypt SSL certificates can be tedious. In this article, I will share my strategy for obtaining, renewing and distributing my SSL certificates with let's encrypt. I wanted to have to type only one command to:
- get a new certificate for a subdomain
- renew all my certificates that needed renewal
- publish the certificates to Digital Ocean spaces or S3
- pull the certificates on my webservers
To issue and renew let's encrypt certificate we will use DNS verification using lego (with Digital Ocean's DNS). We will distribute the certificates using Digital Ocean spaces, an equivalent of S3.
All four commands are in a makefile that you can find at: https://github.com/charignon/certificates.
Prerequisites
- Digital ocean spaces or S3 access key and secret
- aws cli installed http://docs.aws.amazon.com/cli/latest/userguide/installing.html
- lego, to issue/renew certificates with DNS: https://github.com/xenolf/lego
- DNS set up with Digital Ocean or another provider supported by
lego
for your domain name
Step 1 — Set up the aws cli and creating a bucket
In this step, we will be creating a bucket domain-certificates
to hold our certificates.
Let's start by setting up the aws cli credentials and bucket:
export AWS_ACCESS_KEY_ID="YYYY" # change with your key id
export AWS_SECRET_ACCESS_KEY="XXXX" # change with your key
export BUCKET=domain-certificates
If like me you are using digital ocean spaces, you need to specify an endpoint when using the aws cli.
To avoid repeatedly typing the --endpoint
argument, I created an alias.
If instead, you use S3, just use aws
instead of awscli in all of the future commands:
alias awscli="aws --endpoint-url=https://nyc3.digitaloceanspaces.com"
Now let's use this alias to create a new bucket and check that it exists:
awscli s3api create-bucket --bucket $BUCKET --region nyc3
awscli s3api list-buckets
We can also check that lego can be invoked as well:
lego --version # prints "lego version 0.4.0" for me
If this does not work for you, you might want to adjust your $GOPATH
environment variable so that your shell can find lego.
Step 2 — Generating and uploading a certificate for a subdomain
Let's assume that you own the domain foobar.com
and want to generate a new certificate for prod.foobar.com
.
To generate a new certificate for your subdomain, we can use lego
.
The instructions vary depending on your DNS provider. Here is what I am doing for Digital Ocean's DNS:
export DO_AUTH_TOKEN=XXX
lego --accept-tos --email [email protected] --dns digitalocean -d prod.foobar.com run
If all goes well, this will create a new certificate in the ".lego"
folder.
We can now upload this folder to the bucket that we created (in a acme
folder):
aws s3 sync $(pwd)/.lego s3://domain-certificates/acme
Voila! You just issued a new certificate and stored it online.
Step 3 — Downloading the certificate on another host
On your webserver you can download the certificate we just issued by using the following command:
aws s3 sync s3://domain-certificates/acme $(pwd)/.lego
Step 4 - Renewing domains
To renew a previously issued certificate stored in the ".lego"
folder, you can use:
lego -d prod.foobar.com renew --days 30
Step 5 - Automating with a Makefile
Let's automate all these steps in a Makefile.
Let's first create a rule to add a new domain by calling lego
:
LEGO=lego --accept-tos --email [email protected] --dns digitalocean
new:
@$(if ${DOMAIN}, echo "Setting up ${DOMAIN}", echo "Please set DOMAIN env var" ; exit 1 )
${LEGO} -d ${DOMAIN} run
We can invoke it like this:
DOMAIN=staging.foobar.com make new
Next we need a way to upload and download certificates to and from our bucket. Let's create two rules for that:
ENDPOINT=--endpoint-url https://nyc3.digitaloceanspaces.com
LOCAL_PATH=${PWD}/.lego
S3_PATH="s3://domain-certificates/acme"
AWS=aws ${ENDPOINT}
upload:
@echo "uploading"
${AWS} s3 sync ${LOCAL_PATH} ${S3_PATH}
download:
@echo "Download"
${AWS} s3 sync ${S3_PATH} ${LOCAL_PATH}
Finally, to renew all of the domains, we need to be able to query a list of domain in ".lego"
:
DOMAINS=`ls .lego/certificates | grep key | sed "s/.key$$//"`
And loop through all of the subdomains, which leads to the following makefile rule:
DOMAINS=`ls .lego/certificates | grep key | sed "s/.key$$//"`
renew:
@echo "Renewing ${DOMAINS}"
@for d in ${DOMAINS};do ${LEGO} -d $$d renew --days 30 ; done
I can use the rules we just defined to download and renew all of my certificates:
make download && make renew && make upload
The final touch is to make the rules phony because they don't produce files:
.PHONY: new renew upload download
Putting it all together, the makefile looks like:
.PHONY: new renew upload download
ENDPOINT=--endpoint-url https://nyc3.digitaloceanspaces.com
AWS=aws ${ENDPOINT}
LEGO=lego --accept-tos --email [email protected] --dns digitalocean
S3_PATH="s3://domain-certificates/acme"
LOCAL_PATH=${PWD}/.lego
DOMAINS=`ls .lego/certificates | grep key | sed "s/.key$$//"`
new:
@$(if ${DOMAIN}, echo "Setting up ${DOMAIN}", echo "Please set DOMAIN env var" ; exit 1 )
${LEGO} -d ${DOMAIN} run
renew:
@echo "Renewing ${DOMAINS}"
@for d in ${DOMAINS};do ${LEGO} -d $$d renew --days 30 ; done
upload:
@echo "uploading"
${AWS} s3 sync ${LOCAL_PATH} ${S3_PATH}
download:
@echo "Download"
${AWS} s3 sync ${S3_PATH} ${LOCAL_PATH}
This makefile makes it a lot easier to manage your certificates! You can now quickly create, renew, upload and download certificates. I hope that it makes your life easier!
The code is available on Github at https://github.com/charignon/certificates.