Pi-Hole & Let’s Encrypt

Last modified date

Comments: 3

Update April 2024

I have a new article with instructions for installing on Ubuntu LTS 22.04 and all the things that have changed since writing this guide.

Original Instructions

The next server in my lab to sort out with a Let’s Encrypt (LE) trusted SSL is Pi-Hole. Pi-Hole does a good job of ad-blocking without needing to mess with anything on device endpoints (browser plugins etc). Version 5.0 which was released this week adds some new features, one of which I appreciate is the ability to add static DNS entries via GUI (it saves messing with text files).

Pi-Hole uses Lighttpd as the web server, so we need to provide the SSL files for that to use. Again I’m going to use the acme.sh utility with the DNS-01 challenge method for getting the certificate to avoid having to expose anything to the Internet.

For reference, my Pi-Hole server runs on a Ubuntu 16.04 LTS VM.

As we’ll need to move the certificate files around, I installed acme.sh as root so when the renewal script runs, it can access everything it needs. The authors of acme.sh don’t recommend running the script via sudo – see here.

Step One

Switch into sudo, install acme.sh and to create a sub-folder in the lighttpd folder to move the certificates to. acme.sh has also moved to using ZeroSSL by default for new installations, so we need the last command to use LE.

sudo -i
curl https://get.acme.sh | sh
mkdir -p /etc/lighttpd/certs/pihole.mylab.domain/
acme.sh --set-default-ca  --server  letsencrypt

Note: stay in sudo for now

Step Two

Generate a large DH file to improve security (see here for a full explanation!)

cd /etc/lighttpd/certs/pihole.mylab.domain
openssl dhparam -out dhparam.pem -dsaparam 4096

Step Three

Obtain the certificate using acme.sh from LE with the DNS-01 challenge, so we need to provide the relevant Cloudflare IDs via the export command.

export CF_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
export CF_Account_ID="xxxxxxxxxxxxx"
export CF_Zone_ID="xxxxxxxxxxxxx"

./acme.sh --issue --dns dns_cf -d pihole.mylab.domain

If successful, the four SSL certificate files should be in /root/.acme.sh/pihole.mylab.domain/

Step Four

Enable SSL in lighttpd and configure it to use the new certificate

nano /etc/lighttpd/external.conf 

Edit the configuration with the appropriate settings for your domain:

$HTTP["host"] == "pihole.mylab.domain" {
# Ensure the Pi-hole Block Page knows that this is not a blocked domain
setenv.add-environment = ("fqdn" => "true")
# Enable the SSL engine with a LE cert, only for this specific host
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/certs/pihole.mylab.domain/ssl.pem"
ssl.ca-file = "/etc/lighttpd/certs/pihole.mylab.domain/ca.cer"
ssl.dh-file = "/etc/lighttpd/certs/pihole.mylab.domain/dhparam.pem"
ssl.honor-cipher-order = "enable"
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
ssl.use-compression = "disable"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
# Redirect HTTP to HTTPS
$HTTP["scheme"] == "http" {
$HTTP["host"] =~ ".*" { 
url.redirect = (".*" => "https://%0$0")
}
}
}

Step Five

Create the script which acme.sh will run as the post installation hook to move the files into the lighttpd folder. This script is based one on from Cyberciti.biz

nano /root/.acme.sh/pihole/hook.sh
#!/bin/bash
dom="pihole.mylab.domain"                   #your Pihole FQDN 
dest="/etc/lighttpd/certs/pihole.mylab.domain"    #lighttpd ssl folder created in step one
croot="/root/.acme.sh/${dom}"             #acme.sh root path for your domain
 
### NO edit below ###
sslfile="${dest}/ssl.pem"                  #lighttpd .pem file path
certfile="${croot}/${dom}.cer"             #lighttpd certficate file path        
keyfile="${croot}/${dom}.key"              #lighttpd key file path 
 
echo "Copying certificate"
/bin/cat "${certfile}" "${keyfile}" > "${sslfile}"
echo "Settings permissions"
chown root:root /etc/lighttpd/certs/pihole.mylab.domain/ssl.pem
chmod 400 /etc/lighttpd/certs/pihole.mylab.domain/ssl.pem
echo "Restarting lighttpd service"
/bin/systemctl restart lighttpd

Save / close the script, then make it executable:

chmod +x /root/.acme.sh/pihole/hook.sh

Step Six

Use acme.sh to install the certificate and run the hook.sh script we created to copy the file

acme.sh --installcert -d pihole.mylab.domain \
--capath /etc/lighttpd/certs/pihole.mylab.domain/ca.cer \
--reloadcmd '/root/.acme.sh/pihole/hook.sh'

Certificate Renewal

acme.sh will automatically a cron job to check & renew the certificate when required. You can check this is setup:

crontab -l

Chris

3 Responses

  1. Hi,
    I tried to use this for my pihole site but step 3 does not result in four SSL certificate files in /root/.acme.sh/pihole.mylab.domain/. Instead the certificates are located in /root/.acme.sh/pihole.mylab.domain_ecc/. Executing the command ./acme.sh –issue –dns dns_cf -d pihole.mylab.domain didnt work. Instead I used acme.sh –issue –dns dns_cf -d pihole.mylab.domain which did execute. I modified the rest of the install to cater for the certs being located in the pihole.mylab.domain_ecc and the final step resulted in certs being copied to pihole.mylab.domain folder but I still get vert errors in the browser. Can you help?

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment

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