How to use acme.sh to install a ZeroTrust Certificate to Pi-Hole

Pi-hole v6 allows the option to use a SSL certificate. But because Pi-hole is ideally isolated from receiving Internet traffic, the embedded webserver in Pi-hole cannot perform required DNS validation to confirm ownership of the server for automatic renewal of ZeroTrust (default) certificates using certbot. Acme.sh can also install from other CAs if desired.

Acme.sh provides a built-in option to use DNS API provided from a list of domain name registrars to allow installation and renewal of certificates on local servers.

Prerequisites

Full control of a domain with DNS API access (see list at dnsapi · acmesh-official/acme.sh Wiki · GitHub)

Chosen subdomain (pihole.example.com)

Working syslog (sudo apt-get install --reinstall rsyslog)

This guide uses commands operable on Debian 12 and assumes use of Google Domains. Adjust as needed.

    1. Install acme.sh*

    curl https://get.acme.sh | sh -s email=username@example.com
    Close the Terminal and reopen to reset aliases.

2. Follow the appropriate DNS API access instructions for your domain registrar found at Create new page · acmesh-official/acme.sh Wiki · GitHub

3. For example, for Google Domains:

Visit Google Domains and click "Manage" on the domain. Then, in the Security settings, generate an access token for the ACME DNS API. Save this access token as it is only displayed once.

4. At terminal enter:
export GOOGLEDOMAINS_ACCESS_TOKEN="<-generated-access-token->"

5. To issue a cert, run the following:

acme.sh --issue --dns dns_googledomains -d pihole.example.com -k 4096

6. Acme.sh will generate a certificate and store a fullchain and separate key file at:

home/username/.acme.sh/pihole.example.com_ecc/fullchain.cer
home/username/.acme.sh/pihole.example.com_ecc/pihole.example.com.key

7. Create a dummy certificate at the pihole.toml location /etc/pihole:

sudo nano /etc/pihole/server.pem add any content “123” overwrite and exit

8. Edit your Pi-hole's configuration to prepare for the certificate.

sudo nano /etc/pihole/pihole.toml

Change hosts = [
"[static IP of pihole 192.168.1.20] pihole.example.com"
]
Change domain setting to domain=”pihole.example.com”
Change port setting to port = "80r,[::]:80r,443s,[::]:443s”
Change cert setting to cert = "/etc/pihole/server.pem"

Overwrite and exit

9. Because the output of acme.sh produces separate .cer and .key files, we need to combine the fullchain and key portions into a format pihole expects. Do that by creating and running a script (note your code will not use username and example.com. Replace with the path from your acme.sh output).

sudo nano /cerconcat.sh

#!/bin/sh
cd /
echo -n "" > /tmp/temppem.pem
fullchain="home/username/.acme.sh/pihole.example.com_ecc/fullchain.cer"
key="home/username/.acme.sh/pihole.example.com_ecc/pihole.example.com.key"
temppem="tmp/temppem.pem"
current="etc/pihole/server.pem"
cat "$fullchain" > "$temppem"
cat "$key" >> "$temppem"
if ! cmp -s "$temppem" "$current"; then
sudo cp "$temppem" "$current"
sudo pihole restartdns;
echo "The pihole SSL key was changed"
else
echo "The pihole SSL key was not changed"
fi
sudo rm “$temppem”

Overwrite and exit.

10. Test script and make executable if desired
sudo . /cerconcat.sh (should echo The pihole SSL key was changed on initial run)
sudo chmod +x /cerconcat.sh

11. Acme.sh will create a cronjob to run daily in the midnight hour. You need to create a sudo cronjob (sudo crontab -e) with the following content to automatically refresh the certificate in Pi-hole when it renews:

23 1 * * * /cerconcat.sh 2>&1 | /usr/bin/logger -t pihole_cert

12. Finally, after a day, check syslog to see if cronjob is working:
sudo grep "pihole_cert" /var/log/syslog

1 Like