Restricting lighttpd to serve only on pi.hole

Unfortunately, the pi-hole web interface is accessable from the outside if the pi gets forwarded from the internet. I would like to edit the config that lighttpd only serves the admin page if the source host name ist pi.hole. But since I shall not override the default lighttpd config, I am not able to do so.

What can I do?

As an alternative: I would also be happy if I could run lighttpd on another port and just use apache for my internet stuff. But again, I cannot do any changes to the lighttpd config file.

Cheers

This is a high security risk and should be avoided by all means! Note that an attacker can easily present any host name he wants to the HTTP server when connecting to your IP. So, even if you would set such a rule, it could be bypassed quite easily.

lighttpd (really, PHP) already checks to see if it should serve the web interface. See here.

Well it seems that it does not work. I can easily access the admin interface from my mobile data (smartphone) for example.

I know it is a security risk, but I have no other option. Another port, which does not get forwarded, would be an option but I dont know how.

If you are accessing the site from an authorized host, then that is expected.

Make your rule in /etc/lighttpd/external.conf. That will be applied right after the Pi-hole settings.

Can you give me an example rule? Because overriding the conf in external does not work (you cannot override already set variables).

Also, the internet address is not an authorized host.

Also, after looking in the php code: the array with the authorized hosts will always contain the hostname from where the request is coming from. Why?

You're right. Make lighttpd/pihole serve to private addresses only. VPNs will work as well.

Add to the /etc/lighttpd/external.conf

$HTTP["remoteip"] != "10.0.0.0/8" { url.access-deny = ("") }
$HTTP["remoteip"] != "172.16.0.0/12" { url.access-deny = ("") }
$HTTP["remoteip"] != "192.168.0.0/16" { url.access-deny = ("") }

The whole wide internet will get a 403 forbidden message : )

1 Like

It appears that some sources say that $_SERVER["SERVER_NAME"] comes from the server's config, while others say it might come from the Host header if not properly configured. We will look into this.

When needing to block stuff like this that I can't block with my router I like to use iptables because it's kinda the systems first line of defence. To accomplish what you're after you'd do this:

iptables -A INPUT -i eth0 -p tcp ! -s 192.168.1.0/24 --dport 80 -j REJECT --reject-with tcp-reset

Change 192.168.0.0/24 to suit your subnet. Rejecting with a TCP reset is same thing that happens when you try to connect to a port on a machine that is closed (the server is acknowledging its there but saying that there's nothing available on that port).

Personally I don't see why you even want the admin interface being served on port 80 because that's where ad traffic is redirected to. So I do this in lighttpd.conf:

$SERVER["socket"] == ":81" {
    #im using arch-linux so your path to admin pages is probably different
    server.document-root= "/srv/http/pihole/admin"
}

I also don't see why you need lighttpd to answer requests for ads when ads can just have their connections rejected in same manner as above (which is what happens for https ads anyway). I also happen to be serving stuff from lighttpd on port 80 that I do want accessible from internet so my iptables rule is actually the opposite to the one above:

iptables -A INPUT -i eth0 -p tcp -s 192.168.1.0/24 --dport 80 -j REJECT --reject-with tcp-reset

This lets external traffic in while stopping ad related traffic from getting to lighttpd.