Most of us, the developers, and also some of small businesses are using Let's Encrypt to generate our own certificates instead of buying one.
I have been using Let's encrypt for years, and unfortunately, I was using the manual way of doing DNS challenge, meaning I have to manually renew the certificates once every three month.
I happened to create new certificates for my new website yesterday and I figured a new way to doing the certificates automatically, we don't even need to touch the DNS record, apply for both direct domain and wildcard domain. And it also automatically renew before the expiration date.
I will guide you how to do it, step by step. This guide will demo on Cloudflare, but it also applicable for other DNS providers like: Digital Ocean, DNS Simple, DNS Made Easy, Gehirn, Google, Linode, LuaDNS, NS1 NSONE, OVH, RFC2136, AWS Route 53, Sakura Cloud.
How it works
To be able to generate the certificate, we need to prove the ownership of the domain by doing "challenges", as defined by the ACME standard. There are four challenge types as describe as Let's Encrypt docs: http-01
, dns-01
, tls-sni-01
, tls-alpn-01
.
We will use dns-01
challenge since it won't effect any running webserver, and also it support to create wildcard certificate. So we can just need to create a certificate that is signed for domain.com
and *.domain.com
and that will cover any use cases of domain we would use.
Previously, I do it manually, that I have to login the DNS server and adjust TXT records as needed every time I want to issue new certificate.
But now, with DNS plugin, it will automates the process of completing a dns-01
challenge (DNS01
) by creating, and subsequently removing, TXT records using the equivalent DNS API.
Step by step install
These steps assume you are using ubuntu server.
1.Install snapd
For ubuntu 18.04 and above, it is already installed in your system, for any other distros or version, follow the instruction here: install snapd
After install snap, ensure your version os snapd is up to date:
$ sudo snap install core; sudo snap refresh core
2.Remove certbot-auto and any certbot OS packages
$ sudo apt-get remove certbot
3.Install certbot
$ sudo snap install --classic certbot
Now, link command into the path so it can be run in the machine
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
4.Confirm plugin containment level
$ sudo snap set certbot trust-plugin-with-root=ok
5. Install the DNS plugin
$ sudo snap install certbot-dns-cloudflare
In this example, I used cloudflare, If you are not using cloudflare, please find your equivalent plugin name here: dns plugins
6.Set up the credential
We will need a cloudflare API token with Zone:DNS:Edit
permission for only the domain you need certificates for.
- Access this link of Cloudflare or go to "Profile -> API Token"
- Click "Create API Token" and use "Edit Zone DNS" template
- Narrow down the permission on only specific domain
4. Click "Continue to summary", confirm and grab your token
We will save this credential as a file, in order to pass through the certbot command. In my case, I will save it in ~/.secrets/cloudflare_domain.com.ini
and file content as follow:
# Cloudflare API token used by Certbot
dns_cloudflare_api_token = <paste your api key here>
Grab and use the SSL certificates
Acquire the SSL certificate
I recommend to acquire a single certificate for your root domain (domain.com), and wildcard domain (*.domain.com) for all other sub domain.
Also I recommend to grab the certificate only so we can reuse and configure it whatever we want later.
To acquire a single certificate for both <domain>.com
and *.<domain>.com
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare_domain.com.ini \
--dns-cloudflare-propagation-seconds 60 \
-d "<domain>.com" \
-d "*.<domain>.com"
I set the propagation second to 60 to make sure the DNS record has time to effect.
You will need to enter the email address, and also agree to their Term of Service in the prompt and wait for it to process. The success output would look like this
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for <redacted>.com and *.<redacted>.com
Waiting 60 seconds for DNS changes to propagate
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/<redacted>.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/<redacted>.com/privkey.pem
This certificate expires on 2023-07-29.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
As you can see in the output, we have the key and certificate at /etc/letsencrypt/live/.com/privkey.pem
and /etc/letsencrypt/live/.com/fullchain.pem
Alternative, if you want to generate certificate for single domain, you can run this command:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/cloudflare_domain.com.ini \
--dns-cloudflare-propagation-seconds 60 \
-d "<domain>.com"
Use the SSL certificates
This is how you would configure with nginx, because I signed for domain.com
and *.domain.com
so I can use this pair of certificate for my root domain and all sub-domain.
upstream ghost-backend {
server 127.0.0.1:2368;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cms.example.com;
# SSL
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# logging
access_log /var/log/nginx/cms.example.com.access.log;
error_log /var/log/nginx/cms.example.com.error.log warn;
# reverse proxy
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://ghost-backend;
}
}
# HTTP redirect
server {
listen 80;
listen [::]:80;
server_name cms.example.com;
location / {
return 301 https://cms.example.com$request_uri;
}
}
Just focus on ssl_certificate
, ssl_certificate_key
, ssl_trusted_certificate
that is where the ssl certificates are used.
The same can be done with other web servers, if you are using Apache, HAProxy, etc you can insert the equivalent file as above.
Verify the auto renew process
When we use the dns plugin, they will update DNS record as the requirement without human interference. Certbot also configured the cron job to automatically renew the domain, now we need to make sure it is configured and working, by dry-run it.
$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/<redacted>.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for <redacted>.com and *.<redacted>.com
Waiting 60 seconds for DNS changes to propagate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/<redacted>.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -