I’ve been running Pi-hole in a container on my TrueNAS Scale box for a while and had unfortunately experienced a number of upgrades that required deploying the container from scratch. This was due to incompatibilities in the Helm chart settings, which broke in-place upgrades and required reconfiguration. This probably happened 3-4 times over the last two years. Being a bit of a tinkerer, I decided to grab a Raspberry Pi, throw Pi-hle on it, and just plug it in and be done. The process to do that is pretty simple; I was able to get the configuration from the TrueNAS container imported into Pi-hole on the Pi, and presto — done.
While I know that it’s running on my internal network and the odds of needing to care about TLS connections to the administrative web service are probably pretty small, I set out to get TLS enabled on it anyways for a few simple reasons. First, it’s something new to tinker with and figure out. Second, I’m a security guy so encryption probably matters. Third, LetsEncrypt is free so it’s no cost. And probably most importantly, I dislike seeing Chrome give me a “Not Secure” warning every time I go to the web page. It just stirs up a certain level of disappointment within me.
So in this post I’ve detailed the way that I put it all together to use LetsEncrypt for SSL certificates to enable TLS connections to the Pi-hole administrative web site.
Obtain LetsEncrypt certificates
Before making any other changes, we want to install the acme.sh
client that will obtain the LetsEncrypt certificates. This can be done by cloning the git repository and installing it:
$ sudo su -
# cd /root
# git clone https://github.com/Neilpang/acme.sh.git
# cd acme.sh
# ./acme.sh --install
# exit
There are a few choices for hostname verification, I prefer to use CloudFlare and DNS. We can use the environment that the installation setup, grab the CloudFlare API key, and then configure acme.sh
. In this example we’ll use the hostname “pihole.hostname.com” as our FQDN.
If you don’t have a ZeroSSL account, you will need to create that first which is something new in the later version of acme.sh
, apparently. First time I’ve heard of or run into this.
# sudo su -
# ./acme.sh --register-account -m [email protected] --server zerossl
Once this is complete, save your CloudFlare API key and email address to the account.conf
file and get the certificate:
# echo "SAVED_CF_Key='[API key from CloudFlare]'" >>/root/.acme.sh/account.conf
# echo "SAVED_CF_Email='[CloudFlare login email address]'" >>/root/.acme.sh/account.conf
# cd /root/.acme.sh
# ./acme.sh --issue --dns dns_cf -d pihole.hostname.com --server zerossl
Once this is complete, your certificates will be saved in the /root/.acme.sh/pihole.hostname.com_ecc/
directory. At this point, we have to configure lighttpd which is the web server that Pi-hole uses for its administrative interface.
Enable SSL in lighttpd
The first step is to create the directory to store the SSL certificate:
# mkdir -p /etc/lighttpd/ssl/pihole.hostname.com
Make sure that SSL support for lighttpd is installed:
# apt-get install lighttpd-mod-openssl
Create symlinks to make your certificate and key file available for lighttpd without exposing the /root/.acme.sh/
directory. The key file by default is mode 0600 and owned by the root user and group. We need to make a slight change so lighttpd, running as the www-data user, can read it:
# cd /etc/lighttpd/ssl/pihole.hostname.com
# ln -s /root/.acme.sh/pihole.hostname.com_ecc/fullchain.cer .
# ln -s /root/.acme.sh/pihole.hostname.com_ecc/pihole.hostname.com.key .
# chmod 640 /root/.acme.sh/pihole.hostname.com_ecc/pihole.hostname.com.key
# chown root:www-data /root/.acme.sh/pihole.hostname.com_ecc/pihole.hostname.com.key
Configure lighttpd to enable TLS
Next, create the /etc/lighttpd/conf-enabled/10-ssl.conf
file with the following contents:
server.modules += ( "mod_openssl" )
setenv.add-environment = ("fqdn" => "true")
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/pihole.hostname.com/fullchain.cer"
ssl.privkey = "/etc/lighttpd/ssl/pihole.hostname.com/pihole.hostname.com.key"
ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.3", "Options" => "-ServerPreference")
}
# Redirect HTTP to HTTPS
$HTTP["scheme"] == "http" {
$HTTP["host"] =~ ".*" {
url.redirect = (".*" => "https://%0$0")
}
}
At this point you need to restart lighttpd:
# systemctl restart lighttpd
Optional convenient redirect
You can also create a convenient redirect from https://pihole.hostname.com/ to https://pihole.hostname.com/admin/ by creating /var/www/html/index.html
with the contents:
<!DOCTYPE HTML>
<meta charset="UTF-8">
<meta https-equiv="refresh" content="1; url=https://pihole.hostname.com/admin/">
<script>
window.location.href = "https://pihole.hostname.com/admin/"
</script>
<title>Page Redirection</title>
<!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->
If you are not redirected automatically, follow the <a href='https://pihole.hostname.com/admin/'>link to admin</a>
There are a number of different ways to get Pi-hle running under SSL on a Raspberry Pi; this worked for me and hopefully it will work for you as well.