Add LetsEncrypt SSL certificate to Pi-hole

Pi-hole is a wonderful self-hosted advertisement and tracker blocking DNS server.  It was original designed for use, as the name describes, on a Raspberry Pi but also compatible with most common Linux distributions. We’ve used a Pi-hole for some time across our office and home internet connections.

This guide has now been superseded by this one:

SSL Pi-hole Install Guide

As with most of our guides, we’ll be using CentOS in this instance.

We’ll assume you’ve got Pi-hole installed and working. Also, the domain you wish to use should already be pointing to the IP for the server.

First, connect to SSH and install certbot.  This is provided with EPEL, but this repo is added during the install process for Pi-Hole.

[root@server ~] yum install certbot

Pi-hole uses Lighttpd as it’s webserver, which doesn’t have a certbot module, so we’ll need to add the certificate manually.  First we need to make some directories.

[root@server ~] cd /var/www/html/
[root@server ~] mkdir .well-known; cd .well-known; mkdir acme-challenge; cd acme-challenge

Now we can start the certbot process.

[root@server ~] certbot certonly --manual

You’ll be asked to agree to various conditions and then be provided with a key and told where to put it.

Use nano to make the file of the name provided by certbot:

Highlight the key and press CTRL+C

[root@server ~] nano ...random string given....

CTRL+v to paste
CTRL+o to save
CTRL+x to exit

Now complete the certbot process.

You’ll be notified once your certificate has been generated.  Lighttpd needs the certificate and key in a single file so:

[root@server ~] cd /etc/letsencrypt/live/your-hostname
[root@server ~] cat privkey.pem cert.pem > combined.pem

Now set the ownership of the files to allow lighttpd to read them:

[root@server ~] chown lighttpd -R /etc/letsencrypt/live

We now need to alter the lighttpd config to use the certificate.  The config may be overwritten during a Pi-hole update, so to avoid this we’ll create an external config file.

[root@server ~] nano /etc/lighttpd/external.conf

Add the following, replacing the 3 relevant lines with your own hostname:

$HTTP["host"] == "" {
  # 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/letsencrypt/live/" =  "/etc/letsencrypt/live/"
    ssl.honor-cipher-order = "enable"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"       
  # Redirect HTTP to HTTPS
  $HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
      url.redirect = (".*" => "https://%0$0")

CTRL +o to save
CTRL +x to exit

Now restart lighttpd to make the certificate live:

[root@server ~] service lighttpd restart

You should now see a nice secure padlock symbol when you visit your pi-hole admin interface.

Thanks to the following sources:


4 Comments. Leave new

  • Thanks for the guide! I noticed a couple of small typos in your guide though…

    mkdir .well-known; cd .well-know; mkdir acme-challenge; cd acme-challenge
    should be:
    mkdir .well-known; cd .well-known; mkdir acme-challenge; cd acme-challenge


    ssl.pemfile = “” = “”
    Should be:
    ssl.pemfile = “/etc/letsencrypt/live/” = “/etc/letsencrypt/live/”


    • Thanks for that Dave, well spotted.

      Interestingly, the ‘’ part was actually being erroneously added by our cache plugin – but I’ll confess to the typo in the .well-known!

  • One issue is that certbot auto-renew won’t work on lighttpd since the updated files need to be merged. To fix that, update /etc/cron.d/certbot. Comment out the old job and add the following:

    # run the 2nd of every month at 3:44am. Adjust as needed
    44 3 2 * * root certbot renew –post-hook “cat /etc/letsencrypt/live//cert.pem /etc/letsencrypt/live//privkey.pem > /etc/letsencrypt/live//combined.pem; systemctl restart lighttpd”

  • How do I install a local certificate manually which has no domain name. During the setup process of certbot I am asked to enter a domain name. The server has no domain and only a local ip in my network. What should I enter?


Leave a Reply

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

Fill out this field
Fill out this field
Please enter a valid email address.