Enabling HTTPS for your Pi-hole Web Interface

Not sure why but things seem to be failing when using IPv6.

Background:
0. Pihole running on small IntelNUC connected to router
12. Have self signed cert for my desired domain (pihole.ipv6.example.com)
2. Dont know what is the "CA-file" line supposed to be so just dropped it.

Testing 1 - When connecting to internal ipv4 IP - get red padlock in chrome and can read off the details of the certificate fine (ie it was self signed and for domain pihole.v6.example.com). So pihole box is reading/serving certificate ok on ipv4.

Testing 2 - connection via IPv6 address fails with "ERR CONNECTION REFUSED" so connecting to pihole box no longer works on ipv6 (note before changes with empty external.conf, connection via ipv6 was fine)

Testing 3 - When connecting to box via FQDN (which is AAAA to the IPv6 address of box) then get connection refused (ie same result as Testing 2)

Testing 4 - When I poke a hole through router firewall to port-forward [[some random high port]] to 443 on the pihole box (and set up a temporary pihole.v4.example.com with A record pointing to router) then connection works (of course with red padlock and complaint that the SNI is wrong.)

From the testing above - seems like for some reason lighttpd ssl engine doesn't like IPv6? Any thoughts on how to fix?

For SSL/TLS certs it doesnt matter what transport method (IPv4 or IPv6) is used.
Only thing for certs that matter are subject common name (CN), validity, subject alternative Name (SAN) if any, and if time/date at both ends is correct:

pi@noads:~ $ openssl x509 -in pi.hole.crt -noout -text
[..]
        Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = noads.dehakkelaar.nl
[..]
        Validity
            Not Before: Sep  8 20:18:09 2019 GMT
            Not After : Sep  5 20:18:09 2029 GMT
[..]
            X509v3 Subject Alternative Name:
                DNS:pi.hole
[..]

pi@noads:~ $ timedatectl
      Local time: Sun 2020-05-10 20:24:57 CEST
  Universal time: Sun 2020-05-10 18:24:57 UTC
        RTC time: n/a
       Time zone: Europe/Amsterdam (CEST, +0200)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

Sounds like wrongly configured lighttpd or IPv6.
But as this is not a lighttpd support forum, you have to be lucky if someone can help you out here.
Am not that proficient with IPv6 yet :wink:

Just realized, you cant change domain name from:

pihole.v4.example.com

into:

pihole.ipv6.example.com

without adjusting the certs common name (CN).

Or you could use SAN and have as many domain aliases as you like in the cert:

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

From what I understand elsewhere, I think the common name approach is deprecated and the CA/Browser Forum folks are pushing for the alterative you linked so just using CN will still get the red padlock / warning. Anyway, issue is not the cert; I am fairly certain if I can get to connect via the right SNI it would show as secure.

Let me see if easily available lighttpd place to ask.

Aha, didnt know was depreciated.
Configuring for SNI seems simple enough with lighttpd.
That "ERR CONNECTION REFUSED" error might imply lighttpd not listening on ipv6:

pi@noads:~ $ sudo netstat -nltup | grep 'Proto\|:80 '
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1880/lighttpd
tcp6       0      0 :::80                   :::*                    LISTEN      1880/lighttpd

Or maybe firewall blocking:

pi@noads:~ $ sudo iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

EDIT: ow ps. default Pi-hole install without vhost configured for 443 wont connect either:

pi@noads:~ $ nc -vz $(hostname -I) 443
nc: connect to 10.0.0.2 port 443 (tcp) failed: Connection refused

pi@noads:~ $ curl -Iv https://$(hostname -I)
* Rebuilt URL to: https://10.0.0.2/
*   Trying 10.0.0.2...
* TCP_NODELAY set
* connect to 10.0.0.2 port 443 failed: Connection refused
* Failed to connect to 10.0.0.2 port 443: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 10.0.0.2 port 443: Connection refused

Just checked - listening on 80 for both ipv4/ipv6 but only 443 for ipv4. From the external.conf in the OP there is a redirect from http/https and so I think that is working and pushing me to 443 which results in the connection refused. Basically need to set up listening on ipv6 443 (its an odd default since 80 is switched on and fine but 443 is left out. Yippe for adoption and equal treatment of ipv6)

I've put to lighttpd folks in their respective forum but if anyone here knows would be much obliged.

Can you post output for below ?

sudo netstat -nltup | grep 'Proto\|:80 '

EDIT: darn you right, my netstat doesnt listen to 443 either.
I guess you need to setup a valid vhost for 443 before starts listening.

Here she is:

pi@noads:~ $ less /etc/lighttpd/lighttpd.conf
[..]
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port

pi@noads:~ $ cat /usr/share/lighttpd/use-ipv6.pl
#! /usr/bin/perl -w

use Socket;
use strict;

my $sock;
my $PORT = 80;
$PORT = $ARGV[0] if $ARGV[0] and $ARGV[0] >= 0 and $ARGV[0] <= 65535;

if (socket($sock, AF_INET6, SOCK_STREAM, 0)) {
    print qq/\$SERVER["socket"] == "[::]:$PORT" { }\n/;
}

EDIT: wonder if you can add a port.

Yep. Looks like isolated out the reason - c.f. netstat reporting on listening 80 and 443:

80:

tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 12375/lighttpd
tcp6 0 0 :::80 :::* LISTEN 12375/lighttpd

443:

tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 12375/lighttpd

Can you connect now with curl or nc ?

Hmm above says only listening 443 for IPv4 and not IPv6.

EDIT: can try change port in below file for fun :wink:

/usr/share/lighttpd/use-ipv6.pl

Plus:

sudo service lighttpd restart

not dice on ths - tried changing 80 to 443 and after restart of lighttpd service the netstat still the same. Perhaps reading another config file.

Anyway - gotta get going on work now; look at this in evening.

Looks like the lighttpd guys came through. Need to have additional section below in external.conf. Tested and it makes IPv6 work.

Thanks to gstrauss (redmine.lighttpd.net) for solving this.

@wally3k - perhaps add this to the block with the change suggested as this should applicable to all

$SERVER["socket"] == "[::]:443" {
ssl.engine = "enable"
ssl.pemfile = "/home/username/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"
}

1 Like

Yeah you beat me to it.
Was bout to post below through trial error :wink:

pi@noads:~ $ sudo netstat -nltup | grep 'Proto\|lighttpd'
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      5977/lighttpd
tcp6       0      0 :::80                   :::*                    LISTEN      5977/lighttpd

pi@noads:~ $ sudo mkdir /etc/lighttpd/certs
pi@noads:~ $

pi@noads:~ $ cat pi.hole.crt pi.hole.key | sudo tee /etc/lighttpd/certs/pi.hole.pem
[..]

pi@noads:~ $ sudo chmod 600 /etc/lighttpd/certs/pi.hole.pem
pi@noads:~ $

pi@noads:~ $ sudo nano /etc/lighttpd/external.conf
$HTTP["host"] == "noads.dehakkelaar.nl" {
  # 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/pihole.example.com/combined.pem"
#    ssl.ca-file =  "/etc/letsencrypt/live/pihole.example.com/fullchain.pem"
    ssl.pemfile = "/etc/lighttpd/certs/pi.hole.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"
  }
  $SERVER["socket"] == "[::]:443" {
    ssl.engine = "enable"
#    ssl.pemfile = "/etc/letsencrypt/live/pihole.example.com/combined.pem"
#    ssl.ca-file =  "/etc/letsencrypt/live/pihole.example.com/fullchain.pem"
    ssl.pemfile = "/etc/lighttpd/certs/pi.hole.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")
    }
  }
}

pi@noads:~ $ sudo service lighttpd restart
pi@noads:~ $

pi@noads:~ $ sudo netstat -nltup | grep 'Proto\|lighttpd'
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN
tcp6       0      0 :::80                   :::*                    LISTEN
tcp6       0      0 :::443                  :::*                    LISTEN

pi@noads:~ $ curl -Ivk https://[::1]
* Rebuilt URL to: https://[::1]/
*   Trying ::1...
* TCP_NODELAY set
* Connected to ::1 (::1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=noads.dehakkelaar.nl
*  start date: Sep  8 20:18:09 2019 GMT
*  expire date: Sep  5 20:18:09 2029 GMT
*  issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=noads.dehakkelaar.nl
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
> HEAD / HTTP/1.1
> Host: [::1]
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-type: text/html; charset=UTF-8
Content-type: text/html; charset=UTF-8
< Date: Mon, 11 May 2020 03:13:38 GMT
Date: Mon, 11 May 2020 03:13:38 GMT
< Server: lighttpd/1.4.45
Server: lighttpd/1.4.45

<
* Curl_http_done: called premature == 0
* Connection #0 to host ::1 left intact

EDIT: added -k argument for curl for self signed certs.

2 Likes

double thumbs up for the learning through doing (for me, learning through googling hahahha)

slightly OT but perhaps something you can look into if you have a moment; does the conf file syntax support an "OR" operator coz right now it is a bit messy to have two blocks of code exactly the same if it possible to instead do:

$SERVER["socket"] == ":443" ((OR)) "[::]:443"

1 Like

Yeah same.
This one helped:

And I tried $SERVER["socket"] combos but to no avail.

Yeh thats a shame coz I have a few different hostnames in the cert and the kludgey way is to repeat the code block four times (2 for ipv4/ipv6 and 2 for internal/external hostnames) and would be much neater to have a simple
$HTTP["host"] == "pihole.ipv4.internal" OR "pihole.ipv6.internal" OR "pihole.ipv4.external.com" OR "pihole.ipv6.external.com"

Anyway; kludgey works and no need perfection for a oneoff thing.

Thanks for all the help

1 Like

14 posts were split to a new topic: Limit port 80 to https

Alternatively you can set a redirect from 80 to 443
$HTTP["scheme"] == "http" { url.redirect = ("" => "https://${url.authority}${url.path}${qsa}") }

I'm running Pi-hole 5.1.2 (Web Interface 5.1.1/FTL 5.2). I just followed the steps in this documentation.

The site is available via HTTPS and everything seems to be working fine, but whenever I run 'sudo systemctl status lighthttpd.service' or 'journalctl -xe' after restarting lighttpd, I see the following message:

lighttpd[9003]: 2020-11-11 12:13:49: (configfile.c.59) Warning: please add "mod_openssl" to server.modules list in lighttpd.conf. A future release of lighttpd 1.4.x *will not* automatically load mod_openssl and lighttpd *will not* use SSL/TLS where your lighttpd.conf contains ssl.* directives

I tried adding "mod_openssl" to a server.modules directive in external.conf and restarted lighttpd, but it failed to start:

server.modules = (
    "mod_openssl"
)

The output of journalctl -xe wasn't very helpful. I thought maybe adding server.modules to external.conf might completely override what was specified in lighttpd.conf, so I added the full list of modules found in lighttpd.conf + mod_openssl to external.conf and that also failed:

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

This is the output when I try to start lighttpd.service:

Nov 11 12:29:33 pihole systemd[1]: lighttpd.service: Service RestartSec=100ms expired, scheduling restart.
Nov 11 12:29:33 pihole systemd[1]: lighttpd.service: Scheduled restart job, restart counter is at 5.
Nov 11 12:29:33 pihole systemd[1]: Stopped Lighttpd Daemon.
Nov 11 12:29:33 pihole systemd[1]: lighttpd.service: Start request repeated too quickly.
Nov 11 12:29:33 pihole systemd[1]: lighttpd.service: Failed with result 'exit-code'.
Nov 11 12:29:33 pihole systemd[1]: Failed to start Lighttpd Daemon.

Evidently this message is benign right now but whenever lighttpd 1.4 is released, this will become an issue for anyone that enabled HTTPS. Any thoughts?

EDITED - I'm also seeing this message in the log after a successful start:

Nov 11 12:34:08 pihole lighttpd[10314]: 2020-11-11 12:34:08: (server.c.1493) WARNING: unknown config-key: alias.url (ignored)