Generate wildcard certificate with Let’s Encrypt

SSL certificate is something that you need all the time, you want to encrypt your traffic even if it’s inside your LAN. You also want to know that you can trust the certificate. And with self-signed certificate you will run in to issues with Apple devices and other devices will throw errors. Lucky for us we can use Let’s Encrypt to get a valid certificate!

That’s something that you can achieve with a CA. But let’s face it who have a CA in a home lab or smaller infrastructure? So, it’s an easy way to get it. We can use Let’s Encrypt and generate a wildcard certificate and then use that, in this guide we are going to use acme shell script in Ubuntu 24.04. Good thing with acme shell script is that you won’t need to open any ports.

Introduction

Validated on

This how-to have been tested and known to work, but not limited to the following versions

  • Ubuntu 24.04
  • Ubuntu 22.04

Prerequisite

  • Sudo or root access to your Ubuntu Server
  • SSH access to your Ubuntu Server
  • SSH software
    • macOS, you can use Terminal
    • Linux, you can use Terminal
    • Windows, I do recommend you to use PuTTY
  • Your own domain
  • API account for your domain with the following permissions
    • addSubdomain
    • addZoneRecord
    • getDomains
    • getSubdomains
    • getZoneRecords
    • removeSubdomain

Good to know

  • No need to open any ports in your firewall
  • In this guide I’ll use Loopia as an example as it’s my domain provider, so make sure to change it to the domain provider you’re using if you’re not using Loopia.
  • During this guide you need to replace some of the text with your unique name etc
    • YOUR@MAIL.COM = Replace it with your own mail
    • APIUSERNAME@DOMAINPROVIDER = Username for your user that have API access to your domain
    • YOURPASSWORD = Password for your user that have API access to your domain
    • YOURDOMAIN.com = Replace it with your domain
  • Nano commands
    • To save a file after you have made changes press CTRL+X and then Y
    • Go to the end of the file press CTRL+W and then CTRL+V
    • Search for text in the file, press CTRL+W and then write what you want to search for then press enter

Recommendation

  • If you haven’t secured SSH on your Ubuntu Server I do recommend you to read my guide about it

Install acme shell script

First thing to do is to make sure that we have all needed components installed and Ubuntu up to date.

  • Update Ubuntu

    sudo apt update && sudo apt upgrade -y
    
  • Now we need to install a few components that are needed for everything to work

    sudo apt install socat -y
    

  • Now when that’s done, we need to reboot

    sudo reboot
    
  • We need to change user to root

    sudo su -
    

  • It’s time to install acme

    curl https://get.acme.sh | sh -s email=YOUR@MAIL.COM
    

  • Now you need to disconnect from your SSH instance and then connect again

  • Once again let’s change to the root user

    sudo su -
    

  • One good thing with Let’s Encrypt is that we can auto update our certificate before it expires, so let’s make sure that’s activated.

    acme.sh --upgrade --auto-upgrade
    

Generate wildcard certificate

  • First, we need to add our domain providers API URL to acme, example below I’m using Loopia.

    export LOOPIA_Api="https://api.loopia.se/RPCSERV"
    

  • We also need to add our API user and password for that user

    export LOOPIA_User="APIUSERNAME@DOMAINPROVIDER"
    export LOOPIA_Password="YOURPASSWORD"
    

  • It’s time to generate the wildcard certificate, this can take some time to do. Remember to replace dns_loopia if you’re using any other domain provider then Loopia.

    acme.sh --issue --dns dns_loopia -d *.YOURDOMAIN.com
    

  • Now we need to install the certificate and depending on what web server you’re using you can do it in some different ways, I use to create a folder named SSL in the web server root folder so first let’s do that.

    sudo mkdir /etc/nginx/ssl
    
    sudo mkdir /etc/apache2/ssl
    
    sudo mkdir /etc/lighttpd/ssl
    
  • To install the certificates to the newly created folder we need to execute some commands and once again depending on what web server you’re using the command is different

    acme.sh --install-cert -d *.YOURDOMAIN.com \
    --key-file       /etc/nginx/ssl/privkey.pem  \
    --fullchain-file /etc/nginx/ssl/fullchain.pem
    
    acme.sh --install-cert -d *.YOURDOMAIN.com \
    --key-file       /etc/apache2/ssl/privkey.key \
    --fullchain-file /etc/apache2/ssl/fullchain.pem \
    
    acme.sh --install-cert -d *.YOURDOMAIN.com \
    --key-file       /etc/lighttpd/ssl/privkey.pem  \
    --fullchain-file /etc/lighttpd/ssl/fullchain.pem
    

  • Now we need to generate a strong Diffie-Hellman group, this can take some time to finish

    sudo curl https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/nginx/ssl/dhparam.pem
    
    sudo curl https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/apache2/ssl/dhparam.pem
    
    sudo curl https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/lighttpd/ssl/dhparam.pem
    

Create Snippet (optional)

(I’ll later add how to do this with Lighttpd)
Our life’s will get much easier when we are going to create server blocks in NGINX and APACHE2 if we create snippets for SSL. So, let’s do that

  • First, we need to create a snippet where we can add the location of our SSL certificates

    sudo nano /etc/nginx/snippets/ssl-cert.conf
    
    sudo mkdir /etc/apache2/snippets
    sudo nano /etc/apache2/snippets/ssl-cert.conf
    
  • Add the following to the file

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    
    SSLCertificateFile /etc/apache2/ssl/fullchain.pem
    SSLCertificateKeyFile /etc/apache2/ssl/privkey.key
    SSLOpenSSLConfCmd DHParameters /etc/apache2/ssl/dhparam.pem
    
  • Now we are going to create a snippet with SSL parameters

    sudo nano /etc/nginx/snippets/ssl-param.conf
    
    sudo nano /etc/apache2/snippets/ssl-param.conf
    
  • Add the following to the file

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1440m;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
    add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options nosniff always;
    
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
    SSLHonorCipherOrder     off
    SSLSessionTickets       off
    
    SSLUseStapling On
    SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
    

Conclusion

Now everything is finished, I did not walk you through how to configure NGINX, APACHE2 etc as that’s something that I’ll do in the other guides as it depends on what service you will run and so etc. I do hope you find this guide useful.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.