Wildcard HTTPS on Linux + Let's Encrypt + Nginx
Introduction
In this step-by-step guide, you'll learn how to set up HTTPS on a Linux server for both the root domain and its subdomains. You'll also learn how to use an auto-renewing wildcard certificate from Let's Encrypt and set up the Nginx website configuration files accordingly.
Head to my article What are HTTPS, TLS certificates, and Let's Encrypt? if you want an introduction, including what Certbot is and the difference between regular certificates and wildcard certificates.
Regular certificates vs. wildcard certificates
In this guide, we'll obtain a regular certificate to secure the flsilva.com
root domain and a wildcard certificate to secure *.flsilva.com
. That's more cumbersome, with a few extra steps required. Still, we'll do that with a single certificate issuing command, giving the impression that we only obtain one certificate.
My system setup
The following is my system setup at the time of this writing:
Debian: 11Linux Kernel: 5.10.0-11-amd64Nginx: 1.18.0Certbot: 1.12.0dnsimple.com (as provided on the publish date)
This guide should also work on Ubuntu.
Do not type the $
sign you see in the command examples in this article.
That's just an indicator that you should run the command that follows it in your command
line tool.
About the Nginx plugin for Certbot
There's an Nginx plugin for Certbot to automatically change your Nginx website configuration files, adding TLS certification configuration. But we cannot use it alongside a DNS plugin for Certbot that makes auto-renewing certificates possible.
In this guide, we'll go with the latter and manually change Nginx's website configuration files.
In case you're curious, this is how you install the Nginx plugin for Certbot:
$ sudo apt install python3-certbot-nginx
You pass a --nginx
option to the certbot
command to use it. But again, we won't do that in this guide, so you don't need to run the command above.
Prerequisites
Before starting, make sure you have met all the following requirements:
- A Linux server you can access via SSH and the ability to run
sudo
. If you don't, head to my guide on How to set up a Linux VPS. - Nginx installed on it. If you don't, head to my guide on How to install Nginx on Linux.
- Nginx listening to port 80 and serving your website over HTTP. If you don't, head to my guide on How to set up a website on Nginx + Linux.
- Access to your DNS provider and the ability to create an access token and a wildcard (
*
) DNS record (we'll see how to do that). Also, your DNS provider must have a Certbot plugin. This page lists supported DNS plugins. I can't say if that's a comprehensive list, but many popular providers are listed there. Go check out if yours is.
All good? So let's do this! 😎
Step 1. Updating your Linux distro
It's always a good practice to start with everything up to date. So, first, let's update our Linux distro:
$ sudo apt-get update$ sudo apt-get upgrade --show-upgraded
Step 2. Install Certbot
Run the following command to install Certbot:
$ sudo apt install certbot
Step 3. Check the Certbot installation
Now run the following command to make sure it worked:
$ certbot --version
You should see something like certbot 1.12.0
.
Step 4. Make sure you don't have any certificates on your server
Now, let's run the following command to make sure you don't have any certificates on your server:
$ sudo certbot certificates
You should see the following output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -No certificates found.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Great, that's expected. We'll rerun it after trying to obtain our certificate to ensure it's worked.
Step 5. Install the Certbot plugin for your DNS provider
This plugin is necessary for wildcard certificates, as it needs to resolve challenges directly with your DNS provider (DNSimple, in my case) and to auto-renew our certificates.
I'm using DNSimple as my DNS provider. If you're using a different provider, you need to find out if it's supported and what's its plugin name so you can install it. This page lists supported DNS plugins. I can't say if that's a comprehensive list, but many popular providers are listed there. Go check out if yours is.
I'll run the following to install the DNSimple plugin for Certbot:
$ sudo apt install python3-certbot-dns-dnsimple
Step 6. Checking Certbot installed plugins
To make sure the plugin installation worked and learn a new command, let's run the following to see all Certbot plugins installed:
$ certbot plugins
You should see an output listing the dns-dnsimple
plugin (or the one you installed).
Step 7. Create an access token for your DNS provider
This step is only necessary because we're installing a wildcard certificate.
You'll have to find out exactly how to create an access token on your DNS provider, but it should be simple and similar to what I did.
The following is how I did it on DNSimple:
- I browsed to
dnsimple.com
and signed in. - In the
Dashboard
screen, I hitUser Settings
at the top right corner of the screen. - In the
User Settings
screen, I could see aUser access tokens
section and hit anAdd
button at the bottom of it. - I'm asked to type a name for this token in the
New access token
screen. To ensure security, I named the tokencertbot-wildcard-certification-access
and only granted it to Certbot. If I need to grant access to another service, I create a new token with an appropriate name. That makes it easy to revoke access to any unnecessary services. - Finally, I hit the
Generate token
button. - I get a
Token certbot-wildcard-certification-access generated! See details below...
feedback message. - It shows me the key in the
User access tokens
section and warns me:
Keep a copy of this token, we won't show it again.
Yes, sir.
Keep a copy of your token. We'll use it next.
Step 8. Put your access token in a secure file on your server
Connect to your server and run the following:
$ nano ~/certbot-wildcard-dnsimple-credentials.ini
That will create and open such a file. Now, add the following to it:
dns_dnsimple_token = you_access_token_here
Make sure to replace you_access_token_here
with your access token.
Also, if you're using a DNS provider other than DNSimple, replace only the dnsimple
bit above with the name of your DNS provider as used when you installed its plugin.
Save the changes and close it by hitting Control-X, then Y, and then Enter.
To keep your token secure, you should limit access to it by other users. To do so, you can use the chmod
command to give read and write permissions only to your user.
$ chmod 600 ~/certbot-wildcard-dnsimple-credentials.ini
Step 9. Create a wildcard DNS record on your DNS provider
This step is only necessary because we're installing a wildcard certificate.
You'll have to find out exactly how to add a wildcard DNS record on your DNS provider, but in the end, it should be the same simple thing: you create a new A
DNS record, typing *
in the name field, and your web server's IP address in the IP address
field.
The following is how I did it on DNSimple:
- I browsed to
dnsimple.com
and signed in. - I chose my domain (
flsilva.com
) in the' Dashboard' screen. - In the
Domain
screen, I hitDNS
in the left menu. - In the
Domain DNS
screen, I could see aDNS records
section with a list of records I had set up, and I hit aManage
button at its bottom. - At the top of the
Domain DNS records
screen, I hit theAdd record
dropdown menu and chose itsA
option. - I typed
*
in thename
field of theAdd A record
screen, making it look like*.flsilva.com
, and my web server's IP address in theIP Address
field. - Finally, I hit the
Add record
button.
After adding it, you should see a record like *.flsilva.com
in your list of DNS records (replacing flsilva.com
with your domain).
Now is the boring part. DNS changes may take up to 48 hours to propagate. However, in most cases, it will propagate within a few hours, and the process also depends on your domain registrar, which may differ from your DNS provider.
We need to wait for propagation before proceeding. In the next step, Certbot will connect Let's Encrypt with your DNS provider to confirm your domain ownership and validate that your wildcard DNS record works appropriately.
The good news is that we can test it! We don't have to just wait for it.
Let's do that.
Step 10. Check if your wildcard DNS record is working
To test if a wildcard DNS record is working, we can use the host
command passing some random, non-existing subdomain name, for example:
$ host xyz.flsilva.com
You can run it on your local machine.
If it's working, you should see a message like the following:
xyz.flsilva.com has address <your_server_ip_address_here>
In this case, you can move to the next step!
Otherwise, you'd get a message like the following:
Host xyz.flsilva.com not found: 3(NXDOMAIN)
Your wildcard DNS record may have yet to propagate, or there could be another issue. I suggest waiting a few hours before attempting to troubleshoot any problems.
Step 11. Run the certbot
command to obtain your certificate
Finally! Let's run the certbot
command that will generate and download our certificate to /etc/letsencrypt/
dir:
$ sudo certbot certonly \ --dns-dnsimple \ --dns-dnsimple-credentials ~/certbot-wildcard-dnsimple-credentials.ini \ --agree-tos \ -m your_email@example.com \ -d flsilva.com \ -d *.flsilva.com
Don't forget to:
- Replace
--dns-dnsimple
and--dns-dnsimple-credentials
with your DNS provider's plugin name. - Replace
~/certbot-wildcard-dnsimple-credentials.ini
with the path to your credentials if you named it something else. - Replace
your_email@example.com
with your email. - Replace
flsilva.com
with your domain name in both places.
You can see that we pass two -d
(domain) arguments. A wildcard (*
) certificate will only secure subdomains. It cannot secure the root domain (flsilva.com
in this case). So we are asking for two certificates, a wildcard one for any subdomains and a single-name one for the root flsilva.com
domain.
It's important to know that Let's Encrypt certificates expire every 90 days, so it's necessary to renew them before that. Fortunately, running the Certbot command above sets up a cron job that runs twice daily and automatically renews our certificates 30 days before expiration. Neat!
When you run it, Certbot will ask you if you want to share your email with EFF to get emails about some matters. That's up to you to decide.
After answering that, you should get an output like the following:
Saving debug log to /var/log/letsencrypt/letsencrypt.logPlugins selected: Authenticator dns-dnsimple, Installer NoneRequesting a certificate for flsilva.com and *.flsilva.comPerforming the following challenges:dns-01 challenge for flsilva.comdns-01 challenge for flsilva.comWaiting 30 seconds for DNS changes to propagateWaiting for verification...Cleaning up challengesIMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/flsilva.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/flsilva.com/privkey.pem Your certificate will expire on <expiration_date>. 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" - 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
Congratulations, your certificate has been generated and downloaded successfully! 🥳
As the output states, your certificate files are saved at /etc/letsencrypt/live/flsilva.com/
, replacing flsilva.com
with your domain.
Step 12. Check your certificate
Now, let's rerun the following command to make sure Certbot generated and downloaded your certificate to your server:
$ sudo certbot certificates
You should get the following output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Found the following certs: Certificate Name: flsilva.com Serial Number: <serial_number_here> Key Type: RSA Domains: flsilva.com *.flsilva.com Expiry Date: <expiration_date_here> (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/flsilva.com/fullchain.pem Private Key Path: /etc/letsencrypt/live/flsilva.com/privkey.pem
Fantastic, your certificate is definitely on your server!
You can confirm it is a wildcard certificate when it says Domains: flsilva.com *.flsilva.com
.
You can also cd
into /etc/letsencrypt/live/flsilva.com/
to see your certificate files, replacing flsilva.com
with your domain.
Step 13. Check auto-renewing
Let's check if we have auto-renew set up by running the following command:
$ sudo certbot renew --dry-run
You should get the following output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Processing /etc/letsencrypt/renewal/flsilva.com.conf- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Cert not due for renewal, but simulating renewal for dry runPlugins selected: Authenticator dns-dnsimple, Installer NoneAccount registered.Simulating renewal of an existing certificate for flsilva.com and *.flsilva.comPerforming the following challenges:dns-01 challenge for flsilva.comdns-01 challenge for flsilva.comWaiting 30 seconds for DNS changes to propagateWaiting for verification...Cleaning up challenges- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -new certificate deployed without reload, fullchain is/etc/letsencrypt/live/flsilva.com/fullchain.pem- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/flsilva.com/fullchain.pem (success)- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
That means everything is okay!
If there are any issues, you should get an output like the following:
Saving debug log to /var/log/letsencrypt/letsencrypt.log- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -No simulated renewals were attempted.- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certbot creates a certbot
cron job file at the following path:
/etc/cron.d/certbot
That's the file responsible for trying to auto-renew your certificate twice daily. It's a text file, so you can open it to take a look.
Step 14. Update the Nginx website configuration file for your root domain
The last step is to set up our Nginx website configuration files. Since we couldn't use the Certbot plugin for Nginx, we must do that manually.
Below is all the content of my configuration file for flsilva.com
:
server { listen 80; listen [::]:80; server_name flsilva.com www.flsilva.com; return 301 https://flsilva.com$request_uri;}server { listen 443 ssl; server_name www.flsilva.com; # RSA certificate ssl_certificate /etc/letsencrypt/live/flsilva.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/flsilva.com/privkey.pem; return 301 https://flsilva.com$request_uri;}server { listen 443 ssl; server_name flsilva.com; # RSA certificate ssl_certificate /etc/letsencrypt/live/flsilva.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/flsilva.com/privkey.pem; rewrite "/services/delivery/" /services/ permanent; rewrite "/services/consulting-coaching/" /services/ permanent; rewrite "/opensource/" /open-source/ permanent; root /var/www/flsilva.com/public; error_log /var/log/nginx/flsilva.com.error.log; access_log /var/log/nginx/flsilva.com.access.log; location ~* \.(jpg|jpeg|gif|webp|css|png|js|json|ico|eot|svg|ttf|otf|woff|woff2)$ { expires max; } location ~* \.(html)$ { expires epoch; } location / { index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/flsilva.com; }}
The first server {
block handles HTTP-only requests, redirecting them to HTTPS. It works for both http://flsilva.com
and http://www.flsilva.com
, redirecting them to https://flsilva.com
.
The second server {
block handles HTTPS requests to https://www.flsilva.com
only, redirecting it to https://flsilva.com
.
The third server {
block handles HTTPS requests to https://flsilva.com
. That's the one we set up Nginx to serve the website, so we don't redirect from it.
Inside this third block, we only make the following two changes to it compared to an HTTP-based one:
We use listen 443 ssl;
instead of listen 80;
and listen [::]:80;
.
And we add the following lines so Nginx can find and use our certificates:
# RSA certificatessl_certificate /etc/letsencrypt/live/flsilva.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/flsilva.com/privkey.pem;
Don't forget to replace flsilva.com
with your domain.
Step 15. Update the Nginx website configuration file for your subdomains
Below is all the content of my configuration file for a subdomain, in this case, vostokframework.flsilva.com
:
server { listen 80; listen [::]:80; server_name vostokframework.flsilva.com; return 301 https://vostokframework.flsilva.com$request_uri;}server { listen 443 ssl; server_name vostokframework.flsilva.com; # RSA certificate ssl_certificate /etc/letsencrypt/live/flsilva.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/flsilva.com/privkey.pem; root /var/www/vostokframework.flsilva.com/public; error_log /var/log/nginx/vostokframework.flsilva.com.error.log; access_log /var/log/nginx/vostokframework.flsilva.com.access.log; location / { index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/vostokframework.flsilva.com/public; }}
The first server {
block is like the first block from the flsilva.com
config file above, except we don't need to worry about the www
part. It handles HTTP-only requests, redirecting them from http://vostokframework.flsilva.com
to the HTTPS version, https://vostokframework.flsilva.com
.
The second server {
block is like the third block from the flsilva.com
config file above. It handles HTTPS requests to https://vostokframework.flsilva.com
. That's the one we set up Nginx to serve the website, so we don't redirect from it.
Inside this second block, we only make the following two changes to it compared to an HTTP-based one (the same changes as the flsilva.com
config file above):
We use listen 443 ssl;
instead of listen 80;
and listen [::]:80;
.
And we add the following lines so Nginx can use our certificate:
# RSA certificatessl_certificate /etc/letsencrypt/live/flsilva.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/flsilva.com/privkey.pem;
Don't forget to replace flsilva.com
and vostokframework.flsilva.com
with your domain.
Checking for any common errors is advisable after changing your Nginx configuration files. To do this, execute the following command:
$ sudo nginx -t
You should get the following output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful
Otherwise, you should see some errors.
You must do that for every subdomain you want to serve under HTTPS. That's what I did since I only have a few subdomains. Other ways to accomplish that include setting up a dynamic configuration that can work for many subdomains.
Step 16. Reload your Nginx instance to make your changes take effect
To do that, run the following command:
$ sudo systemctl reload nginx
Step 17. Test your website!
You can now test your website by opening it in your browser! If you followed the instructions on changing your Nginx website configuration files, you could type your domain and subdomain names without typing https://
for your server to use it. Additionally, even if you type http://
(without the s
), you will still be redirected to your website's https://
version. 👌
Conclusion
And that's it for this guide. I hope you enjoyed it!
Thank you for reading, and let me know if you have any issues or suggestions in the comments below.
I incorporated generative AI tools into my workflow, and I love them. But I use them carefully to brainstorm, research information faster, and express myself clearly. It's not copy/paste in any way.
Related posts
What are HTTPS, TLS certificates, and Let's Encrypt?
How to set up a Linux VPS
How to install Nginx on Linux
How to set up a website on Linux + Nginx
How to password-protect content on Linux + Nginx
Interesting links
Wildcard HTTPS on Linux + Let's Encrypt + Nginx by Flavio Silva is licensed under a Creative Commons Attribution 4.0 International License.