Backstory

I’ve had and posted about working with Raspberry Pi’s before and recently bought the new Raspberry Pi 5. I picked mine up from CanaKit, and it’s almost complete silent! Woohoo! So I’m going to run this one running all the time and have it act like a server basically.

This post is about setting this up and tying it into Grafana Cloud for monitoring.

Assumptions

A couple basic ones:

  1. You’ve already put your Raspberry Pi, it’s connected to your network, you’re ready to rock.
  2. You’ve setup your Pi to have a static IP on your network. Most routers allow you to do this
  3. You’ve setup the grafana-agent on your Pi. Follow the docs in the instructions and it’ll give you a one-liner that’ll setup the apt repo.

Setting up the pihole and grafana monitoring

Get Docker, or whatever you want to use to run your containers up and running. As of the writing on this document, the package name is docker.io.

$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Package names may change, but I’m just using Docker with docker-compose to get this up and running quickly:

sudo apt install docker.io docker-compose

(Optional) Personally, I like using the docker command from an unprivieged user to limit the need to run it as root. To do this, you’ll need to change your na

sudo usermod -aG docker pi # substitute pi with your user
newgrp docker pi # substitute pi with your user

docker-compose.yml

For the configuration, I do a couple non-default things:

  1. I allow the Apple Private Relays to work and not be blocked. FTLCONF_BLOCK_ICLOUD_PR is how you pass that to the FTL config with pihole. Removing that line will block the relays.
  2. I use the Cloudflare malware blocking name servers instead of Google name servers.
  3. I use Farenheit for temperatures because I’m American.
  4. I use a dark theme for the pihole interface. Don’t most people prefer dark at this point?

This is what your docker-compose.yml could look like:

version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    # For DHCP it is recommended to remove these ports and instead add: network_mode: "host"
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80/tcp"
    environment:
      PIHOLE_DNS_: '1.1.1.2;1.0.0.2;2606:4700:4700::1112;2606:4700:4700::1002' # Cloudflare
      DNSSEC: 'true'
      TEMPERATUREUNIT: 'f'
      QUERY_LOGGING: 'false'
      WEBTHEME: 'default-dark'
      TZ: 'America/Chicago'
      WEBPASSWORD: 'Amaz1ngP4sswordF0rB1og' # This password is used in PIHOLE_PASSWORD, too
      FTLCONF_BLOCK_ICLOUD_PR: 'false'
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    # cap_add:
    #  - NET_ADMIN # Required if you are using Pi-hole as your DHCP server, else not needed
    restart: unless-stopped
  # See: https://github.com/eko/pihole-exporter
  pihole_exporter:
    container_name: 'pihole-exporter'
    image: 'ekofr/pihole-exporter:latest'
    # Agent is running in VM, so moved this config to ports
    # expose:
    #  - 9617
    ports:
      - "127.0.0.1:9617:9617/tcp" # So agent on VM can poll this service on localhost
    environment:
      PIHOLE_HOSTNAME: '192.168.1.123'  # UPDATE with the static IP of your Pi
      PIHOLE_PORT: 80
      PIHOLE_PASSWORD: 'Amaz1ngP4sswordF0rB1og' # Same as the password used on the pihold
      INTERVAL: 30s
      PORT: 9617
    restart: always

It’s in the file as comments, you need to copy the password for the pihole for the pihole_exporter service to be able to login to the pihole to get stats.

Now, bring it up!

docker-compose up -d

Validate the services are up and running and haven’t prematurely exited:

$ docker ps -a
CONTAINER ID   IMAGE                          COMMAND               CREATED         STATUS                   PORTS                                                                                                             NAMES
88f378db2b37   pihole/pihole:latest           "/s6-init"            4 minutes ago   Up 4 minutes (healthy)   0.0.0.0:53->53/tcp, :::53->53/tcp, 0.0.0.0:80->80/tcp, 0.0.0.0:53->53/udp, :::80->80/tcp, :::53->53/udp, 67/udp   pihole
9ae16022d83f   ekofr/pihole-exporter:latest   "./pihole-exporter"   4 minutes ago   Up 4 minutes             127.0.0.1:9617->9617/tcp

Test out your configuration by using tools like dig to query against the IP of you Pi from other machines on your network to make sure things are resolving:

$ dig @192.168.1.123 google.com

; <<>> DiG 9.10.6 <<>> @192.168.1.123 google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50127
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;google.com.			IN	A

;; ANSWER SECTION:
google.com.		75	IN	A	142.250.115.138
google.com.		75	IN	A	142.250.115.101
google.com.		75	IN	A	142.250.115.113
google.com.		75	IN	A	142.250.115.102
google.com.		75	IN	A	142.250.115.100
google.com.		75	IN	A	142.250.115.139

;; Query time: 82 msec
;; SERVER: 192.168.1.123#53(192.168.1.123)
;; WHEN: Sun Jan 21 11:01:46 CST 2024
;; MSG SIZE  rcvd: 135

Update your router

Now that you’ve verified your that your pihole is responding to DNS requests from another machine on your network, you can update your router to use the pihole! If you need at least two name servers, see the notes in the Google Fiber section on how to add another interface to your Pi.

Example Grafana Agent Config

This configuration is used so I can collect metrics from the Pi for a Linux dashboard as well as the pihole.

integrations:
  prometheus_remote_write:
  - basic_auth:
      password: YOUR-GRAFANA-CLOUD-TOKEN
      username: YOUR-GRAFANA-CLOUD-ID
    url: https://YOUR-GRAFANA-CLOUD-ENDPOINT/api/prom/push
  agent:
    enabled: true
    relabel_configs:
    - action: replace
      source_labels:
      - agent_hostname
      target_label: instance
    - action: replace
      target_label: job
      replacement: "integrations/agent-check"
    metric_relabel_configs:
    - action: keep
      regex: (prometheus_target_sync_length_seconds_sum|prometheus_target_scrapes_.*|prometheus_target_interval.*|prometheus_sd_discovered_targets|agent_build.*|agent_wal_samples_appended_total|process_start_time_seconds)
      source_labels:
      - __name__
  # Add here any snippet that belongs to the `integrations` section.
  # For a correct indentation, paste snippets copied from Grafana Cloud at the beginning of the line.
  node_exporter:
    enabled: true
    metric_relabel_configs:
    # drop extensive scrape statistics
    - action: drop
      regex: node_scrape_collector_.+
      source_labels: [__name__]
    relabel_configs:
    - replacement: 'pi5'
      target_label: instance
    - replacement: integrations/raspberrypi-node
      target_label: job
logs:
  configs:
  - clients:
    - basic_auth:
        password: YOUR-GRAFANA-CLOUD-TOKEN
        username: YOUR-GRAFANA-CLOUD-ID
      url: https://YOUR-GRAFANA-CLOUD-ENDPOINT/loki/api/v1/push
    name: integrations
    positions:
      filename: /tmp/positions.yaml
    scrape_configs:
      # Add here any snippet that belongs to the `logs.configs.scrape_configs` section.
      # For a correct indentation, paste snippets copied from Grafana Cloud at the beginning of the line.
metrics:
  configs:
  - name: integrations
    remote_write:
    - basic_auth:
        password: YOUR-GRAFANA-CLOUD-TOKEN
        username: YOUR-GRAFANA-CLOUD-ID
    url: https://YOUR-GRAFANA-CLOUD-ENDPOINT/api/prom/push
    scrape_configs:
      # Add here any snippet that belongs to the `metrics.configs.scrape_configs` section.
      # For a correct indentation, paste snippets copied from Grafana Cloud at the beginning of the line.
      - job_name: 'pihole'
        static_configs:
          - targets: ['localhost:9617']
  global:
    scrape_interval: 60s
  wal_directory: /tmp/grafana-agent-wal

Google Fiber

Add Another Interface to your Pi

With the DNS setup as of January 2024, you can specify up to three IPv4 DNS servers, the minimum number of name servers you can set is two. You could run two piholes on two different machines… or you could just add another interface to your pi.

Find an IP that is not used. I use arp to check to see what IPs are used and will run ping against an IP I think is free, then run arp again to see if it shows up in the list.

When you have an IP selected, create a file in /etc/network/interfaces.d. If you have a fresh OS install, that directory is likely empty. I created a file called /etc/network/interfaces.d/eth01 and put the following in (sub out with the appropriate values for your network):

auto eth0:1
iface eth0:1 inet static
        address 192.168.1.124
        netmask 255.255.255.0
        network 192.168.1.0
        gateway 192.168.1.1
        metric 10

THen bring up the interface:

$ ifup eth0:1

You can’t set/override IPv6 name servers

This is flat frustrating. Most reputable routers allow this to be set out of the box.

You will get the Google IPv6 name servers and you can’t override it. I personally prefer to use Cloudflare name servers, specifically the a 1.1.1.2 ones, which blocks malware. You will see some people prefer Cloudflare to reduce the amount of data Google can collect about you and your browsing habits.

I’ve contacted Google Fiber about this and asked them to do this. At this time, I’m not replacing the Google router or running the Raspberry Pi as a DHCP server. I might do this later. I will say, Google Fiber does provide great equipment by default if you do ever consider their services. With previous providers, my first step was to replace the stock modem and wireless router with my own.

Getting around this

  1. You can set devices to only use the pihole and remove the other name servers (not ideal)
  2. Run your own DHCP server, which means your own equipment. There’s not an option to turn off DHCP with Google Fiber.

Surprises

Apple Private Relay

I didn’t expect for this to get blocked. I just hadn’t really thought about it, I could see for some folks this being an issue. Luckily with some research and digging through the FTL project, being able to set FTLCONF_BLOCK_ICLOUD_PR to false in my docker-compose.yml to resolve that issue to allow iPhones and other Apple devices to use private relay.

Some folks are worried about data going through Apple, I’m okay with it. When it comes to privacy, I do trust Cloudflare and Apple more than the other options available.

If you don’t disable the iCloud block, you’ll see popups that the private relay isn’t available on things like iPhones if you have that feature enabled.

Samsung TVs

I didn’t realize how much data my TV sends back to Samsung! It’s the top ad domain by specific domain.