If you're following the mini series this is PART2

Encrypt all the things!, it's tempting to leave TLS out when building things on your internal network, especially at home. Self Signed certificate management is a pain and rolling your own certificate authority internally is certainly a project but for home it can be a bit much. Thankfully we can use an external DNS provider, acme.sh and services like ZeroSSL and LetsEncrypt to give us certs that are already valid of most modern browsers, operating systems and devices.

This guide assumes you don't have or want a publicly reachable IP address

Prerequisites

  • This guide uses Ubuntu 24.04 LTS
  • You'll need Git installed, in this case we are going to install to Nginx too.
  • I'm using Bunny CDN, the acme.sh project is compatible with multiple providers.
  • A domain! buy a domain from you preferred provider. The none real example I'll be using for this is 'norefseclan.uk'
  • Your bunny API Key
💡
Make sure your DNS records and name servers are live, your name servers and domain will need to be configured and live on Bunny if you are following this guide in full.

Install acme.sh

acme.sh is an all shell toolset/project that allows us to easily manage the Automated Certificate Management Environment (ACME).

I put my extras in /opt because I'm old and traditional like that.

cd /opt
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
sudo ./acme.sh --install -m my@example.com

Get your Bunny API from the Bunny control panel and set the variable for acme.sh

export BUNNY_API_KEY="your-api-key"

Issue your Certificate

Issue a cert and a wildcard cert for our internal hosts. By default acme.sh uses ZeroSSL if you want to use a different provider you can specify one, in the sample below we specify letsencrypt.

./acme.sh --issue --dns dns_bunny -d norefseclan.uk -d *.norefseclan.uk --server letsencrypt

You can use acme.sh to 'install' your certificates to your Nginx directories and reload Nginx to pick up the new certs. At this point if you're following this series you may not have actually get valid Nginx config up and this will error but we'll fix that in part 3.

acme.sh --install-cert -d norefseclan.uk --key-file /etc/ssl/private/norefseclan_key.pem --fullchain-file /etc/ssl/certs/norefseclan_cert.pem --reloadcmd  "service nginx force-reload"

Configuration

Achme.sh will create a configuration file for your domain based on the input you provided in the previous section. It's important to note that the reload command you used is encoded in BASE64

The config should be in /root/.acme.sh/yourdomain_name/yourdomain.conf and will be similar to below.

Le_Domain='norefseclan.uk'
Le_Alt='*.norefseclan.uk'
Le_Webroot='dns_bunny'
Le_PreHook=''
Le_PostHook=''
Le_RenewHook=''
Le_API='https://acme-v02.api.letsencrypt.org/directory'
Le_Keylength='ec-256'
Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/XXXX'
Le_LinkOrder='https://acme-v02.api.letsencrypt.org/acme/order/XXXXX'
Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/XXXXXX'
Le_CertCreateTime='1741290705'
Le_CertCreateTimeStr='2025-03-06T19:51:45Z'
Le_NextRenewTimeStr='2025-05-04T19:51:45Z'
Le_NextRenewTime='1746388305'
Le_RealCertPath=''
Le_RealCACertPath=''
Le_RealKeyPath='/etc/ssl/private/norefseclan.pem'
Le_ReloadCmd='__ACME_BASE64__START_c2VydmljZSBuZ2lueCBmb3JjZS1yZWxvYWQ=__ACME_BASE64__END_'
Le_RealFullChainPath='/etc/ssl/certs/norefseclan_cert.pem'

Automatic Renewal

To test the renewal you can manually run the command, in this example the --home value is where our config is, if you have run this as a user it will be in /home/username instead.

/opt/acme.sh/acme.sh --cron --home "/root/.acme.sh/" 

You should be told you're not due a renewal yet having just got your certs in an output similar to below

[Sat Mar 15 19:29:06 GMT 2025] ===Starting cron===
[Sat Mar 15 19:29:06 GMT 2025] Renewing: 'norefseclan.uk'
[Sat Mar 15 19:29:06 GMT 2025] Renewing using Le_API=https://acme-v02.api.letsencrypt.org/directory
[Sat Mar 15 19:29:06 GMT 2025] Skipping. Next renewal time is: 2025-05-04T19:51:45Z
[Sat Mar 15 19:29:06 GMT 2025] Add '--force' to force renewal.
[Sat Mar 15 19:29:06 GMT 2025] Skipped norefseclan.uk
[Sat Mar 15 19:29:06 GMT 2025] ===End cron===

You can add this to crontab in order to automatically renew your certs.

0 0 * * * /opt/acme.sh/acme.sh --cron --home "/root/.acme.sh/" > /dev/null

This will run the job everyday and automate your renewals!.

Next step will be to configure our Nginx server to use the certs correctly and act as a reverse proxy for our services.