Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pi.hole only works intermittently. #247

Open
daisukedaisn opened this issue Aug 10, 2022 · 3 comments
Open

pi.hole only works intermittently. #247

daisukedaisn opened this issue Aug 10, 2022 · 3 comments

Comments

@daisukedaisn
Copy link

Sometimes I can reach the pihole dashboard with http://pi.hole/admin and most times NOT. The static IP address always works. If I add more block lists, it breaks. Restarting does not fix it.

@Paraphraser
Copy link
Contributor

Please see This Project is Dormant.

If you really are still using this repo then you should probably consider migrating to SensorsIot/IOTstack.

If you are already using SensorsIot and filed this case here on gcgarner by mistake, that's OK. I just wanted to make sure you understood this repo isn't being maintained.


Whatever is causing the problem you report probably isn't going to be fixed just by switching to SensorsIot because the service definition for PiHole hasn't changed.

When I look at your URL:

http://pi.hole/admin

I want to ask a few questions. Before I get to my questions, I'd like to set the scene by working through the URL I use on my own instance of PiHole:

http://pihole:8089/admin/

In my case, all my computers know that an unqualified name like "pihole" should be treated as being in "mydomain.com". In Linux terms, that's:

$ grep "search_domains" /etc/resolvconf.conf
search_domains=mydomain.com

So, the URL that actually gets resolved is:

http://pihole.mydomain.com:8089/admin/

When that fully-qualified domain name gets resolved to an IP address, it's the same as:

http://192.168.132.60:8089/admin/

The other thing to note is the "8089" in each of my URLs. That comes from the PiHole service definition:

$ grep "8089" ~/IOTstack/.templates/pihole/service.yml 
    - "8089:80/tcp"

Now my questions:

  1. How does "pi.hole" resolve to an IP address on your system?
  2. Have you mapped the PiHole container so it responds on port 80?

If your active service definition (the one in docker-compose.yml) is still expecting port 8089 then I don't understand why you get a response when you use the IP address in your URL.

If you've re-mapped PiHole to port 80 (nothing wrong with that) then it's whatever process is resolving "pi.hole" to the IP address that is broken. That's what we'll have to drill into.

Last point. If your answer to Q1 involves NGINX or anything similar, you really would be better off re-asking this question on SensorsIot and/or joining the Discord channel (link on the main SensorsIot page). I've never seen the need for reverse proxies, so I don't understand or have any experience with them, so I simply can't provide any useful advice.

@daisukedaisn
Copy link
Author

daisukedaisn commented Aug 18, 2022 via email

@Paraphraser
Copy link
Contributor

OK. I can hear your frustration. I have no idea what the problem is but I will try to help.

I've been using PiHole for more than 5 years. For the first two years it was running as a dedicated image on a Raspberry Pi 3B+. In late 2019 I started using IOTstack so I've been running PiHole as a container since then.

In all that time: zero trouble. Not at all flaky. It just works.

Screen Shot 2022-08-18 at 15 03 57

Last 24 hours. Lots of blocking activity! Definitely doing its job.

My experience doesn't necessarily generalise to your environment. I also have a data-communications background and sometimes things that are obvious to me aren't at all obvious to other people. However, my experience should at least give you comfort that PiHole can work reliably.

It might help if I paint a bit of a picture of how everything comes together. That might give you a better chance of figuring out the best place to ask further questions:

  1. Pi-hole as a concept starts on github.com/pi-hole. It's spread across a number of repositories.

  2. The repository we (IOTstack) are most interested in is pi-hole/docker-pi-hole.

  3. When that repo is "built", the result is a series of images pushed to DockerHub.

  4. Someone installing IOTstack and choosing PiHole as a container winds up with this service definition in their docker-compose.yml. In line 3 you'll see:

    image: pihole/pihole:latest
    

    and that latest suffix connects back to the DockerHub image with the latest tag which, in turn, connects back to the GitHub repository.

    The image: directive (rather than a build: directive) also tells us that IOTstack is using the DockerHub image "as is" without any local modifications.

  5. The very first time you start the PiHole container, docker-compose looks at the left-hand-sides of the volumes: directives:

    volumes:
      - ./volumes/pihole/etc-pihole:/etc/pihole
      - ./volumes/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
    

    and does the equivalent of:

    $ sudo mkdir -p ~/IOTstack/volumes/pihole/etc-pihole ~/IOTstack/volumes/volumes/pihole/etc-dnsmasq.d
    

    Then it starts the container. Everything else is left up to the processes running inside the container, including populating the right-hand-side folders /etc/pihole and /etc/dnsmasq.d. Together, those two folders comprise what is called the "persistent store". What is in those folders is the only stuff that persists across a termination and re-creation of a container. Everything else disappears.

    Some of what is kept in the persistent store is governed by the environment variables:

    environment:
      - TZ=Etc/UTC
      - WEBPASSWORD=%randomAdminPassword%
      - INTERFACE=eth0
    

    Some environment variables (like the password) only have any effect on first launch. Others have an effect on every launch.

    The container listens on the internal (right hand side) ports:

    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "8089:80/tcp"
    

    while Docker listens on the external (left hand side) ports and forwards traffic between the two using network address translation. That last line is why we need to use port 8089.

I'll make a few observations:

  1. If you think PiHole itself is misbehaving in your environment, you're not going to get much help on SensorsIot/IOTstack. You really need to take it up with the PiHole folks by first searching the open issues to see if someone else has reported the same problem (in which case you can add a "me too" kind of comment), otherwise you can open your own issue to describe the problem you're having.

    I did a search for "The Big Blocklist Collection" and "Fireblog" without getting any hits so I don't think there's an open issue.

  2. Making sure you have the latest version of PiHole is a matter of trying to pull an updated image:

    $ cd ~/IOTstack
    $ docker-compose pull pihole
    $ docker-compose up -d pihole
    

    The "pull" command will either pull down a new image or it won't. If a newer image gets pulled then the "up" will instantiate a new container and discard the old container, otherwise the "up" will do nothing.

  3. If you suspect that the underlying problem might be corruption in the persistent store, you can always get a factory-fresh "clean slate" like this:

    $ cd ~/IOTstack
    $ docker-compose rm --force --stop -v pihole
    $ sudo rm -rf ./volumes/pihole
    $ docker-compose up -d pihole
    

    Getting a clean slate is good practice for any container. If a problem persists across a clean slate, it tells you the problem is probably in the image. If the problem disappears on a clean slate, it tells you that it was probably something in your particular persistent store. Either way, you have a better idea of where to start looking.

  4. For what it's worth, I had never heard of The Big Blocklist so I've never tried to use it. I just accept whatever lists PiHole comes with by default.

    The material point, though, is that if PiHole works fine on a "clean slate" but misbehaves once you try to install The Big Blocklist, then complaining to the PiHole folks is likely to get to told to go complain to The Big Blocklist folks.


I still get ads on my phone. I have to install ad blockers on all the browsers anyway.

OK. Let's just consider your phone. I'll make some assumptions:

  1. Your phone is at home.
  2. It has just been turned on.
  3. It has just connected to your home network via WiFi.

The question is, how does the phone know where to get DNS?

Unless your phone has a static configuration (and only you will know that), the first thing it does when it connects to WiFi is issue a DHCP request.

In the average home network, your router is also your DHCP server so it will respond with a "lease" which includes an IP address for the phone to use plus one or two IP addresses of the DNS servers the phone should use.

In many cases, the IP address of the DNS server in that lease will be the IP address of the router itself.

On the WAN side, your ISP plays the same game and hands your router an IP address to use for its WAN interface, plus a couple of IP addresses of the ISP's own DNS servers.

So, unless you have changed this arrangement, your phone will send DNS queries to your router and your router will relay those queries to your ISP's DNS servers. Nothing will go through PiHole.

It is also reasonably common to change the DNS servers your router hands out in leases to be different to the ones your ISP wants you to use. It's typical to see 8.8.8.8, 8.8.4.4 (both Google) and 1.1.1.1 (Cloudflare).

In that situation, your phone will bypass your router's resolver and send its DNS queries direct to whatever DNS servers you've programmed into the router to be handed out in leases (8.8.8.8 etc). But still not from PiHole.

There are three ways of forcing your phone to use PiHole for DNS:

  1. Option 1 is to change your router so the DNS server IP address it hands out in leases is the IP address of the Raspberry Pi running PiHole. This is a one-size-fits-all solution which sends everything in your network to PiHole. There are some other consequences from doing this:

    • The Raspberry Pi running PiHole can't have a dynamic IP address. It has to be a fixed address, either as a static configuration in the Rasbperry Pi itself or a static assignment in your DHCP server ("this MAC address always gets this IP address").
    • The Raspberry Pi running PiHole should not use itself for DNS. Opinions vary on this but I think it's poor practice and I don't do it. If you have another DNS server inside your network, that's where the Pi running PiHole should obtain DNS. If you don't, the Pi running PiHole should go straight to 8.8.8.8 etc.
  2. Option 2 is to turn off DHCP in your router and run a more-capable DHCP server in another Raspberry Pi. A more-capable server lets you set up leasing structures where you can send some devices (eg your phone) to PiHole for DNS, while other devices (those that don't need ad-blocking services) are sent elsewhere.

  3. Option 3 is to use your phone's controlls to override the DNS servers coming in from the lease so that the phone always goes to PiHole.

I used #3 for many years. These days I use #2. I've never used #1 because of the what-if scenario where the Pi stops working for some reason - everything is kaput. I'd rather have some devices still working!

Now I'm going to assume you've picked an approach and you are sure your phone is using the IP address of the Pi running PiHole for DNS.

You should test that. First, login to the PiHole admin page (more on this below), then the Query Log tab. Next, do something (anything) on your phone which causes it to issue a DNS query (like browse to a page). Refresh the query log. If you see the expected queries in the log, you'll know PiHole is getting those queries from your phone.

Second, you should test blocking. Go to the Blacklist tab and add a nonsense domain like "freddy.noidea.org". Try to resolve that domain in your browser. Don't worry if you still get a response implying that the block hasn't worked. Look at PiHole's Query Log tab and make sure it shows up as "blocked".

Once you've proved to yourself that your phone is using PiHole and at least one query coming from your phone has been shown to have been blocked, reboot your phone. That's to clear its DNS cache.

Then, see if it is blocking ads as you would expect.


In Group Management » Adlists, I see:

Screen Shot 2022-08-18 at 15 21 37

If I do a clean-slate install, I only see the first one. That should also tell you how little "management" I do on PiHole which, in turn, tells you how little trouble it causes me!

I should probably weed out a few of those.


http://pi.hole/admin

http://pihole:8089/admin/

I think you should ignore URLs like that, at least for the moment. You'd be better off with IP addresses. For example, if the Raspberry Pi running PiHole is 192.168.1.10 then:

http://192.168.1.10:8089/admin

Why? Well, let's consider http://pi.hole/admin. The name pi.hole appears to be known to the PiHole container. When you query that:

$ docker exec pihole dig @127.0.0.1 pi.hole +short
0.0.0.0

That's a different response to something that doesn't actually exist:

$ docker exec pihole dig @127.0.0.1 pi.holier.than.thou +short
$

A response of "0.0.0.0" is actually the "blocked" pattern. In TCP/IP, the address 0.0.0.0 means "this host" (or, more precisely, "any interface on this host"). So, when you use a browser to try to resolve that:

$ curl -I http://pi.hole:8089
HTTP/1.1 302 Found
Location: /admin
Content-type: text/html; charset=UTF-8
Date: Thu, 18 Aug 2022 05:43:20 GMT
Server: lighttpd/1.4.59

it works because the host where I'm running the command is the Pi running PiHole so 0.0.0.0 goes somewhere. But if I try to do that from, say, a phone then the phone is not running anything on port 8089 so the query goes nowhere.

This idea of "an IP address that goes nowhere" is where the "hole" in Pi-Hole comes from - as in being sent into a black hole. Of course, we've just seen that sometimes the combination of 0.0.0.0:port can still produce a response but it will never leave your device, won't go off-net and definitely won't deliver ads to you.

Also notice how I've used pi.hole:8089. If I repeat it without a port number:

$ curl -I http://pi.hole
curl: (7) Failed to connect to pi.hole port 80: Connection refused

This is actually closer to the "like a black hole". The name resolved but nothing is responding on port 80. Just like an ad-server would do if it was taken off the air.

Basically, whatever the pi.hole name is supposedly for (and I can't find it documented), it's not particularly useful, irrespective of whether you provide a port number or not.

Now let's consider the pihole:8089. For "pihole" to work, it has to be resolvable. That means you need either:

  1. An entry in /etc/hosts on the machine where you are trying to use http://pihole:8089/admin/

    I emphasise - not the Pi running PiHole - I am talking about the client! This is usually do-able on a desktop machine but is somewhere between difficult and impossible on something like an iPhone.

  2. A DNS entry that can map pihole to a fully-qualified domain name. In my case, "pihole" is a DNS alias to a host named iot-hub, which is the Pi running PiHole. So I can do:

    $ hostname -I
    192.168.132.62 172.17.0.1 172.30.0.1 
    
    $ getent hosts pihole
    192.168.132.60 iot-hub.mydomain.com pihole.mydomain.com
    
    $ curl -Iv http://pihole:8089/admin
    *   Trying 192.168.132.60:8089...
    * Connected to pihole (192.168.132.60) port 8089 (#0)
    > HEAD /admin HTTP/1.1
    > Host: pihole:8089
    > User-Agent: curl/7.74.0
    > Accept: */*
    > 
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 301 Moved Permanently
    HTTP/1.1 301 Moved Permanently
    < Location: /admin/
    Location: /admin/
    < Date: Thu, 18 Aug 2022 07:20:29 GMT
    Date: Thu, 18 Aug 2022 07:20:29 GMT
    < Server: lighttpd/1.4.59
    Server: lighttpd/1.4.59
    < 
    * Connection #0 to host pihole left intact
    

    In words:

    1. This machine is 192.168.132.62 (the 172.x.x.x addresses are for Docker's internal networks).
    2. The local resolver knows that "pihole" maps to "iot-hub", and that the IP address of iot-hub is 192.168.132.60, so that's where the curl command is going to wind up.
    3. The result of the curl. The first line of output confirms 192.168.132.60:8089.

The point is that unless pihole is resolvable and resolves to what you expect, it doesn't get you very far. By "what you expect" I mean that you always have to be wary of a name like "pihole" winding up pointing to something outside your home network.

Hope something in all of this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants