Using a wildcard domain specification with a Let's Encrypt SSL certificate
March 18, 2018
March 18, 2018
On March 13, 2018, Let’s Encrypt began supporting wildcard certificates. This post goes over how to create a Let’s Encrypt certificate with a wildcard domain specification, and how to transition a Let’s Encrypt certificate from one that doesn’t have a wildcard domain specification to one that does.
It’s worth noting that this post is largely a note to myself. As such, the instructions are tailored to my situation (which involves the DNS for my domains being hosted by Gandi and the servers for my domains being hosted by Linode (referral link)).
Anyway, if you’re transitioning a Let’s Encrypt certificate from one without a wildcard specification to one with a wildcard specification, the first thing you will want to do is get some information about your certificate; you can do this by running the following command:
sudo certbot certificates
This should give you some informative output about the certificates that
you’ve installed with certbot
. The output should look something like
this:
-------------------------------------------------------------------------------
Found the following certs:
Certificate Name: example.org
Domains: example.org,git.example.org,shiny.example.org
Expiry Date: 2018-06-05 22:10:00+00:00 (VALID: 79 days)
Certificate Path: /etc/letsencrypt/live/example.org/fullchain.pem
Private Key Path: /etc/letsencrypt/live/example.org/privkey.pem
-------------------------------------------------------------------------------
Next, you’ll want to use the certonly
command to modify the
certificate. This command has several options that you can use. First,
you’ll want to specify the certificate name with --cert-name
. If
you’re transitioning an old certificate, you’ll want to use this flag to
specify the same name as the certificate name that you just saw after
running the command sudo certbot certificates
. If you’re creating a
new certificate, you can optionally use this flag to specify a name for
the certificate; if you omit it, it will just use the first domain in
the certificate as the name for the certificate.
After the certificate name, you’ll need to specify the domains that the
certificate should be used for, which you can do with the --domains
flag (or -d
for short).
So, for the above certificate, where I previously had example.org
,
git.example.org
, and shiny.example.org
as domains, I now would only
have example.org
and *.example.org
domains. The second one covers
both of the previous subdomains: git.example.org
and
shiny.example.org
. Note, however, that the wildcard *.example.org
does not cover domains like adam.users.example.org
; it only covers
subdomains up to one level. If you wanted a subsubdomain for an
arbitrary user, you’d need to add the domain *.users.example.org
.
You’ll also need to ensure that you’re using a version of certbot
≥
0.22.0. It is only since version 0.22.0 that certbot
is compatible
with version 2 of Let’s Encrypt’s ACME API, and it is only version 2 of
this API that supports wildcard certificates. Moreover, the default API
is still the first version of the API, so you’ll need to explicitly
specify --server https://acme-v02.api.letsencrypt.org/directory
, when
running the command.
Relatedly, the only acceptable challenge for proving you own the domain
when requesting a wildcard certificate is the DNS challenge, so you’ll
also need to specify --preferred-challenges dns
.1
There are several DNS authenticator plugins for certbot
; however,
there is no authenticator plugin for Gandi, so I furthermore need to
specify the --manual
flag in order to do the authentication myself.
Putting this all together, you should run the following command:
sudo certbot certonly --cert-name example.org -d example.org,*.example.org --server https://acme-v02.api.letsencrypt.org/directory --preferred-challenges dns --manual
You may then be asked to enter your email address (I think you’ll be asked if this is the first time using version 2 of the ACME API):
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel):
Go ahead and enter your email address.
Next, you’ll be asked to agree to the terms of service for version 2 of the API:
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel:
And then you’ll be asked whether you want to share your email address with EFF:
-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
-------------------------------------------------------------------------------
(Y)es/(N)o:
If you’re updating an old certificate that had subdomains that you’ve
now dropped in favor of the wildcard specification, you’ll see a warning
about the fact that you’re adding new domains and removing previously
included domains. Review this information, and, if it looks correct,
accept it by typing U
:
-------------------------------------------------------------------------------
You are updating certificate example.org to include new domain(s):
+ *.example.org
You are also removing previously included domain(s):
- git.example.org
- shiny.example.org
Did you intend to make this change?
-------------------------------------------------------------------------------
(U)pdate cert/(C)ancel:
Next, you’ll see a warning about the fact that the IP address of your server will be logged as having publicly requested the certificate for your domain.
Renewing an existing certificate
Performing the following challenges:
dns-01 challenge for example.org
-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o:
Finally, you will see instructions for deploying a DNS TXT record to
verify that you own the domain(s) for the certificate that you’ve just
requested. If the certificate is for multiple domains, you’ll need to
deploy this TXT record for each domain. Minimally, you’ll be asked to
create two TXT records for _acme-challenge.example.org
: one is for the
certification of example.org
, and one is for the certification of
*.example.org
. Furthermore, if you’ve requested a wildcard certificate
for subsubdomains, you’ll also need to deploy the TXT record for,
e.g., _acme-challenge.users.example.org
.
-------------------------------------------------------------------------------
Please deploy a DNS TXT record under the name
_acme-challenge.example.org with the following value:
okzpb6F0pE8klBLVE4456jkwlUnNCC1SObMmhAu4qwe
Before continuing, verify the record is deployed.
-------------------------------------------------------------------------------
Press Enter to Continue
After setting up the TXT record with your DNS provider (Gandi, in my
case), you’ll need to wait for the DNS record to propogate before
hitting Enter
.2 You can verify that the DNS record has propogated
by running the nslookup
command:
nslookup -type=TXT _acme-challenge.example.org
If the DNS record has not yet propogated, you should see this in the returned value:
[...]
Non-authoritative answer:
*** Can't find _acme-challenge.example.org: No answer
[...]
However, if the DNS record has propogated, you should see this in the returned value:
[...]
Non-authoritative answer:
_acme-challenge.example.org text = "okzpb6F0pE8klBLVE4456jkwlUnNCC1SObMmhAu4qwe"
[...]
Again, if you’re creating a certificate that covers multiple domains, you’ll need to do this for each domain, and the value that you need to specify for the TXT record will be different for each domain.
If everything succeeds, you’ll see the following output:
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.org/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.org/privkey.pem
Your cert will expire on 2018-05-18. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- 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
The last thing to do, at least in my case, is to restart my web server.
In my case, that’s nginx
, so I just run:
sudo /etc/init.d/nginx restart
Feel free to comment with any questions! I’m happy to try to help out as best I can. 🤓 However, like I said, this particular post is largely intended as a note to self, and some aspects of this process are dependent on your particular setup; nonetheless, I’m happy to help if I can!
Notes
-
Specifically, you need to use the
dns-01
challenge; at the time of writing this post, thedns-01
challenge is the most recentdns
challenge, anddns
is just an alias for the most recentdns
challenge. ↩ -
Because it can take a while for DNS records to propogate, it might be worth doing all of this from inside of a multiplexer, such as tmux or GNU Screen in order to keep the process alive, should you be disconnected from your server while you’re waiting for the DNS records to propogate. See, for example, “How to keep processes running after ending ssh session?”. ↩