Back in 2016 I wrote some notes on issuing and renewing certificates through Let’s Encrypt and using EFF’s CertBot to facilitate this. Today I revisited this after seeing acme.sh on OPNsense. What’s super impressive with acme.sh is that it’s a shell script. And it’s super easy to use.
Installing acme.sh is simple. After following these instructions you’re all set. Note that acme.sh is installed in to $HOME. It’s not installed globally. Depending on your use case you therefore may wish to change to root and install so that in the future you can run acme.sh as a cronjob as root to be able to reload services if a certificate is renewed.
The first thing to do is register your account and optionally provide an email address so that Let’s Encrypt can contact you about your certificates:
acme.sh --register-account acme.sh --update-account --accountemail firstname.lastname@example.org
Now start to issue your certificates. Let’s Encrypt needs to verify you own the address in the Common Name field of the certificate being issued, so you’re not going to be able to issue a certificate for www.google.com for example. There are a number of ways Let’s Encrypt does this. One of these methods is through DNS record verification. And acme.sh can use APIs provided by many different providers to automate the creation and removal of the required DNS records for the verification process. Check out all the scripts inside $HOME/.acme.sh/dnsapi. You’ll see providers such as CloudFlare and fortunately for me, DigitalOcean, who I’m using to provide DNS for my domains.
If you’re using DigitalOcean the next step is to create an API key. Best practice is to create an API key for each application so create an API key specifically for acme.sh. Take the API key and create an environment variable called DO_API_KEY. This is specific for the DigitalOcean integration:
You can now issue a certificate using acme.sh which will automatically create the required DNS records with DigitalOcean for the Let’s Encrypt verification process and clean up afterwards:
acme.sh --test --dns dns_dgon --cert-home /etc/certs --renew-hook "service apache2 reload" --issue -d www.domain.com -d sub1.domain.com
I’ll break this command down:
- –test: Uses Let’s Encrypt staging service. You will get a certificate but the root authority is not trusted. Remove this parameter once everything looks good.
- –dns dns_dgon: Use the DNS verification method using the “dns_dgon” (DigitalOcean) API (see files in $HOME/.acme.sh/dnsapi for other providers).
- –cert-home /etc/certs: Store issued certificates and configuration under /etc/certs, otherwise the default is $HOME/.acme.sh which may not be desirable.
- –renew-hook “service apache2 reload”: When this certificate is successfully renewed in the future, the command “service apache2 reload” will be run.
- –issue: Request that the certificate gets issued.
- -d www.domain.com -d sub1.domain.com: Issue the certificate for www.domain.com and create a SAN (Subject Alternative Name) for sub1.domain.com.
If all goes well you will end up with the certificate, keys and configuration required to renew that certificate under /etc/certs/www.domain.com.
Renewing certificates is now very easy:
acme.sh --renew-all --cert-home /etc/certs
That’s it. Just remember that by default acme.sh will look under $HOME/.acme.sh for your certificates so you’ll need to always specify –cert-home or alternatively add “export CERT_HOME=/etc/certs” to $HOME/.acme.sh/acme.sh.env.
acme.sh can install a cronjob to automatically renew your certificates and of course the renew-hook specified when requesting the certificate to be issued ensures that after a successful renewal of a certificate the appropriate daemon can be reloaded automatically too. If the cronjob does not exist (crontab -l):
If you didn’t add CERT_HOME to $HOME/.acme.sh/acme.sh.env, edit the cronjob (crontab -e) and add the –cert-home argument.
You can list all your certificates and show issue date, renewal date with:
acme.sh --list --cert-home /etc/certs
There’s absolutely no excuse for transmitting anything in plaintext anymore. Get encrypting.