Enabling HTTPS for your Pi-hole Web Interface

I get that, but according to the tutorial this problem should not occur:

But this isn't working as it should, as you can see it is conflicting with blocked HTTPS enabled domains.
What am I doing wrong?

You will still get HTTPS errors when they are blocked, because you do not have a valid cert for that blocked domain.

I just got this working after around an hour of playing around with it.

I'm running lighttpd/1.4.35 and PiHole v4.0 (latest) and here's how I got it to work.\

I'm using acme.sh to do my Let's Encrypt certificate stuff automatically through Cloudflare DNS.

add "mod_alias" to /etc/lighttpd/lighttpd.conf so it looks like

server.modules = (
        "mod_access",
        "mod_accesslog",
        "mod_auth",
        "mod_expire",
        "mod_compress",
        "mod_redirect",
        "mod_setenv",
        "mod_rewrite",
        "mod_alias"

)

I speculate that I will have to change this file every time I update PiHole now.

Then add external.conf as stated above

$HTTP["host"] == "url.FQDN.com" {
  # 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 = "/home/pi/.acme.sh/url.FQDN.com/combined.pem"
    ssl.ca-file =  "/home/pi/.acme.sh/url.FQDN.com/fullchain.cer"
    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")
    }
  }
}

Finally, I was doing port forwarding from port 80 on this Raspberry Pi to a random port exposed to the world and I didn't remember to change it from port 80 to 443 to get SSL to work correctly. So remember kids, change your port forwarding settings.

2 Likes

Hi ! Thanks for this FAQ.

Could you kindly integrate an info?
Which owner, group and permission must I set for the following file ?

/etc/lighttpd/external.conf

Thanks in advance

I had to modify the chaining

You use privkey + cert

I must use privkey + fullchain

This is because I'm using haproxy

I have a similar question. I followed the guide and it should only be enabled for my pi-hole fqdn. However, I first tested it just giving the IP address and also with the IP address I get the cert error, so I'm expecting, also any other domain will get the cert shown? Shouldn't it be only bound to the specific FQDN with the guide shown here?

Yes, that is exactly what I meant!
I don't know if @starbuck's message is the solution?

I now tried a bit around and it seems, that this is the expected behavior. As HTTPS get‘s enabled, there is a response on port 443, however the response is, that there is no response (port 443 „offline“) for all other sites. However, it looks not such fine, but there is no other solution like that and it won’t expire. Only alternative solution would be to issue certs for all blocked sites via an internal CA, but then it need to be spread out to all systems and it’s no good practice. I just wonder, why the IP is available, but maybe it’s because of missing any domain name.

1 Like

Thanks for the guide. I wanted my pihole admin interface to be reachable from both pihole.domain.local and pihole. The setting $HTTP["host"] == "pihole.domain.local" doesn't allow multiple hostnames though.

My solution (after a bit of googling) was to replace that line with:

$HTTP["host"] =~ "pihole($|\.domain\.local)" {

This will use regex instead of an absolute setting (the regex just accepts pihole OR pihole.domain.local).

Note: this might be obvious, but make sure your cert has a SAN (Subject Alternate Name) containing the shortname as well as the FQDN. Otherwise the cert won't be trusted/valid for the shortname.

Hope this helps anyone else looking to access their admin UI via the shortname or the FQDN.

1 Like

My question is can I use "Let's Encrypt" to secure Pi-hole if I do NOT have any of these:
* a website
* FQDN (Fully Qualified Domain Name)
* a web server
* hosting provider
* VPS

So far, I just have a simple Raspberry Pi (with Pi-hole installed) attached to the home router and it block ads successfully.

I have no idea if I can make use of "Let's Encrypt" to make Pi-hole more secure if I do not have any of the items in the list above.

Do I actually need "Let's Encrypt" to secure Pi-hole if I do not have any of the items in the list above?

Please advise.

Thanks a million.

You at least need a domain to get the Let's Encrypt certificate for, and you need to be able to port-forward your Pi-hole's web interface so that it can be accessed by that domain.

A post was split to a new topic: Lighttpd errors while enabling HTTPS

Using a private CA for a private network, and issuing the pihole certificate under that CA has more some advantages. E.g., the browser won't need to check with an OSCP responder, which is helpful if the network is down.

Here is my blog post about running a private CA..

Here is a gist with only the bash code for that system.

Just wanted to add—since most of us are running Pi-hole on Linux distributions [that] provide automated renewal when you use the [Certbot] packages installed through their system package manager, appending the following to /etc/letsencrypt/renewal/{your.domain}.conf should suffice:

renew_hook = cat $RENEWED_LINEAGE/privkey.pem \
                 $RENEWED_LINEAGE/cert.pem > \
                 $RENEWED_LINEAGE/combined.pem;\
                 systemctl try-reload-or-restart lighttpd

Hope others find this helpful, as the renew_hook configuration (note the _ instead of -) doesn't seem to be well-documented (at least in the official Certbot documentation).

Notes:

  • I think (but am not sure) that .conf files support \ line continuations; I wrote it out like this (instead of all on one line) for readability.
  • I think that reload-or-try-restart (as suggested by @aks) has been renamed try-reload-or-restart in recent versions of systemctl—if you are unsure which you should use, try man systemctl to see the list of available commands (or just use reload-or-restart).

I would prefer to avoid this and have only FQDN in the certificate.
So my question is how to configure a redirect shortname --> FQDN to avoid certificate error?

Since most of us run these internal without a FQDN, here's how to generate a self-signed cert, to create the combined.pem and proceed with the process avoiding letsencrypt.

mkdir ssl ; cd ssl
openssl req \
       -newkey rsa:2048 -nodes -keyout domain.key \
       -x509 -days 365 -out domain.crt
# fill out the interactive prompt for country, org, CN, etc
cat domain.key domain.crt > combined.pem
cp -R ../ssl /etc/lightttpd

external.conf modified to use SSL regardless of HOST header -- e.g. if you visit
https://192.168.0.200 it will work

cat /etc/lighttpd/external.conf
# 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/ssl/combined.pem"
	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")
	}
}
3 Likes

So i actually prefer my admin panel to only be available if i come in on only a given fqdn, and then forces https. Otherwise it will just serve the block page. The main issue i had was if i went directly to the ip address, the admin panel wouldn't force https. People (or bad web pages calls) could get the webpage to show up if redirecting to an add then ended in /admin/ without https. So I created an external.conf that will only allow access to my sites admin panel through the hostname, always it will always present the block page (http) or fail (https).

This is what my external.conf looks like

###Deny the admin panel for invalid hostnames, except content required by the block page
$HTTP["url"] =~ "^/admin/(.*)?" {
    url.access-deny = ("")
    $HTTP["url"] =~ "^/admin/img/(.*)" {
        url.access-deny = ("disable")
    }
    $HTTP["url"] =~ ".ttf$" {
        # Allow Block Page access to local fonts
        setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
        url.access-deny = ("disable")
    }

}

# Block section for a single hostname profile
$HTTP["host"] == "hostname.example.com" {
  # 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 = "Cert/Privatekey.pem"
    # I am using a self signed CA 
    #ssl.ca-file = "fullchain.cer"
    ssl.honor-cipher-order = "enable"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
  }

##Allow the admin page for the correct fqdn
  $HTTP["url"] !~ "^/admin/\.(.*)" {
     $HTTP["url"] !~ "(~|\.inc|\.md|\.yml|\.ini)$" {
       url.access-allow  = ("")
       setenv.add-response-header = (
           "X-Pi-hole" => "The Pi-hole Web interface is working!",
           "X-Frame-Options" => "DENY"
       )
     }
  }


  # Redirect HTTP to HTTPS
  $HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
      url.redirect = (".*" => "https://%0$0")
    }
  }
}

root@DietPi:/var/www/html# /usr/bin/certbot -q renew
Attempting to renew cert (xxxx.dyndns.berlin) from /etc/letsencrypt/renewal/xxxx.dyndns.berlin.conf produced an unexpected error: Failed authorization procedure. xxx.dyndns.berlin (http-01): urn:ietf:params:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://xxx.dyndns.berlin/.well-known/acme-challenge/wSMzKwYkNs8cvVtFNsahT70kE-uewWPoRa-Tysb86-8 [xxx.xxx.246.237]: "<!DOCTYPE html>\n<!-- Pi-hole: A black hole for Internet advertisements\n*  (c) 2017 Pi-hole, LLC (https://pi-hole.net)\n*  Network". Skipping.
All renewal attempts failed. The following certs could not be renewed:
  /etc/letsencrypt/live/xxx.dyndns.berlin/fullchain.pem (failure)

I now this has worked before, but I don't now why here it comes a message from pihole. Can someone explain me this?

This does not appear to be a Pi-Hole message.

I don't think so.

Normally there should be come the debian default webpage. But since I have installed pihole
and you try to access the default page there come an answer from pihole which denid me the access.

And so I think pihole is also preventing certbot to create the file in .well-known/acme-challenge.
Hopefilly I have drscribed the problem right. Maybe I have to change webroot ?

Micha