Enabling HTTPS for your Pi-hole Web Interface

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

The block page is the 404 page, so you will only get it when visiting a page which does not exist.

Like many others, I use my own certificate from my own Windows CA....

I tried this but I can only connect to the Pi-Hole thru HTTPS using the IP; I cannot access it using the hostname or the FQDN.

When I try, Chrome gives me:

ERR_SSL_UNRECOGNIZED_NAME_ALERT

The certificate is correct and I am accessing the correct hostname and FQDN

How do I fix this?

The hostname/FQDN needs to be presented in the pem cert as a Subject CN (Common name) or as a SAN (Subject alternative name):

pi@noads:~ $ openssl x509 -in pi.hole.pem -noout -text
[..]
        Issuer: C = US, ST = MN, L = Minneapolis, OU = Domain Control Validated, CN = some.cert.signer.ca
[..]
        Subject: C = US, ST = MN, L = Minneapolis, OU = Domain Control Validated, CN = noads.dehakkelaar.nl
[..]
            X509v3 Subject Alternative Name:
                DNS:pi.hole
[..]

C=US ST=WY L=Sheridan

I just blindly entered through those settings using openssl defaults.
They dont matter anyway :wink:

EDIT:
http://apetec.com/support/GenerateSAN-CSR.htm

Been staring at this for bout half an hour trying to find cryptic hidden message :wink:

No offense but this isnt the first or the last certificate Ive made.

I just checked it anyways and it is correct: Its in the CN and the SAN.

Also like I mentioned, If I go to the IP, it works correctly.

And you get the right cert presented ? (substitute <IP_ADDRESS_OR_DOMAIN_HERE>)

echo | openssl s_client -connect <IP_ADDRESS_OR_DOMAIN_HERE>:443 2>/dev/null | openssl x509 -text -noout

If I use = for wildcard, I get thus far:

WhY danSC===er U STLSi

For the CSR. Country is US, State is WY, Locality is Sheridan

Yeah but whats the cryptic part ?

:wink:

I don't understand what you mean?

That makes two :smiley:
I dont understand relevance of below posting:

Thats why I was looking for cryptic hidden message :wink:

@riahc3 , forgot to mention, you could run below one too to see cert details presented like CN & SAN:

curl -Iv https://<DOMAIN>

Sometimes results differ from using openssl when inspecting a socket depending on how the web server is configured.

1 Like