My Webhosting Stack
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.