The short story is:

  • nginx
  • acme.sh

Installing acme.sh is very simple:

curl https://get.acme.sh | sh -s email=my@example.com

or

wget -O -  https://get.acme.sh | sh -s email=my@example.com

Issuing certificates is also relatively simple. I suggest using the DNS API mode to make things as seamless and interruption free as possible. DNS API also allows for wildcard certificates to be issued.

DNS API mode and all the supported DNS providers are documented here: https://github.com/acmesh-official/acme.sh/wiki/dnsapi

The official acme.sh documentation for my DNS provider (CloudDNS) looks like this:

export CLOUDNS_AUTH_ID=XXXXX
export CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"

acme.sh --issue --dns dns_cloudns -d example.com -d www.example.com

The exact command line I use looks like this:

acme.sh --issue --dns dns_cloudns --ecc  -d 'www.sapphic.biz' -d 'sapphic.biz' --fullchain-file /etc/ssl/sapphic.biz.crt --key-file /etc/ssl/private/sapphic.biz.key --reloadcmd 'systemctl reload nginx' --keylength ec-384 --dnssleep 60 --server zerossl

Let’s break down the parameters:

  • --issue That’s what we want to do
  • --dns dns_cloudns selects the DNS API module for my provider (ClouDNS)
  • --ecc –keylength ec-384 tells acme.sh to use harder, better, faster, stronger ecliptic curve based keys ( https://en.wikipedia.org/wiki/Elliptic-curve_cryptography)
  • -d ‘sapphic.biz tells acme.sh what domains to include in its acme request. You can use as many domains as you like or just use a wildcard -d ‘*.sapphic.biz’ * --fullchain-file /etc/ssl/sapphic.biz.crt and --key-file /etc/ssl/private/sapphic.biz.key tell acme.sh to deposit the certificate and key in a pre-determined location. I will use these paths in my nginx config later.
  • --reloadcmd 'systemctl reload nginx' tells acme.sh to reload the nginx config after having issued a certificate. This ensures that the new issue will be used by nginx.
  • --dnssleep 60 sleep for at least 60 seconds after setting up the DNS proof to allow the new DNS entries to propagate to all the servers. ClouDNS is kind of slow in this regard, CloudFlare was usually pretty fast and didn’t need this.
  • lastly --server zerossl which is entirely optional. acme.sh opted [https://github.com/acmesh-official/acme.sh/wiki/Change-default-CA-to-ZeroSSL] to make ZeroSSL [https://zerossl.com/features/acme/] the new standard ACME server. You can of course switch back to LetsEncrypt at any point or even just for one single certificate request.

That’s it for the encryption side of things. Now let’s look at how it’s hooked up with nginx:

server {
	listen		80;
	listen		[::]:80;
	listen		443 ssl http2;
	listen		[::]:443 ssl http2;
	server_name	blog.catgirl.biz;

	ssl_certificate		/etc/ssl/blog.catgirl.biz.crt;
	ssl_certificate_key	/etc/ssl/private/blog.catgirl.biz.key;
	add_header Strict-Transport-Security "max-age=31536000;" always;

	access_log /var/log/nginx/blog.catgirl.biz-access.log;
	error_log /var/log/nginx/blog.catgirl.biz-error.log;

	root /var/www/blog;
}

(This is a sample configuration and should only be used as a starting point for your own customised config)

access_log, error_log and add_header directives are entirely optional but useful. ssl_certificate and ssl_certificate_key point to the paths I specified earlier.

This configuration is sufficient to make nginx serve HTTP over TLS with acme.sh. Everything is automated from here on out, acme.sh will periodically check for expiration of certificates and re-issue as needed.