Pi-hole

From NixOS Wiki
Jump to: navigation, search

Pi-hole is software that blocks ads and trackers across your entire network.

It provides a mature, trusted, integrated service that includes a web interface, DHCP server, and DNS server.

Presumptions

  • NixOS 25.11 xantusia (or newer)
  • Classic channels configuration
  • Personal home network
  • IPv4
  • Homelab skills
  • Patient users while you tinker and stabilize

Please extrapolate for other NixOS versions, configurations, flakes, et cetera.

Basic Setup

  1. Create /etc/nixos/pi-hole.nix and add the following. Replace homelab.me and the IPs with your own DNS domain and network addresses. If you don’t have a DNS domain, you can create your own. No fee or registration is required. It’s private to your network.

    #
    # pi-hole.nix
    #
    # Notes
    # - Pi-hole doesn't have a mechanism to manage Groups, Clients, or
    #   Domains. Use the web gui.
    #   - https://docs.pi-hole.net/group_management/example/
    #
    {lib, ...}: {
      #
      # Networking
      #
      # Essential infrastructure
      # - List your most essential network resources here
      networking = {
        hosts = {
          "192.168.33.1" = ["gateway.homelab.me" "gateway"];
          "192.168.33.2" = ["pi-hole.homelab.me" "pi-hole"];
          "192.168.33.15" = ["nas.homelab.me" "nas"];
        };
      };
    
      #
      # Services
      #
      services = {
        # I'm not actually using the dnsmasq service. Pi-hole provides
        # it's own dnsmasq. I'm using Nix' ability to manage the
        # dnsmasq-style configuration file that Pi-hole utilizes.
        dnsmasq = {
          enable = false;
          settings = {
            address = [
              "/feelinsonice-hrd.appspot.com/ # Block Snapchat"
              "/feelinsonice.appspot.com/ # Block Snapchat"
              "/snapchat.com/ # Block Snapchat"
            ];
            dhcp-name-match = [
              "set:hostname-ignore,wpad"
              "set:hostname-ignore,localhost"
            ];
            # Set DHCP option 6 to the DNS server you nodes should use.
            dhcp-option = [
              "vendor:MSFT,2,1i"
              "6,192.168.33.2"
            ];
            domain = [
              "homelab.me,192.168.33.0/24,local"
            ];
          };
        };
    
        pihole-ftl = {
          enable = true;
          lists = [
            {
              url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
              type = "block";
              enabled = true;
              description = "Steven Black's HOSTS";
            }
          ];
          openFirewallDNS = true;
          openFirewallDHCP = true;
          openFirewallWebserver = true;
          queryLogDeleter.enable = true;
          settings = {
            dhcp = {
              active = false; # <-- SET TO TRUE ONLY WHEN YOU'RE READY!
              end = "192.168.33.254";
              hosts = [
                "00:00:5e:00:53:01,192.168.33.22,jane-laptop"
                "00:00:5e:00:53:ab,bill-desktop"
                "00:00:5e:00:53:ff,office-printer"
              ];
              ipv6 = false;
              leaseTime = "24h";
              start = "192.168.33.61";
              rapidCommit = true;
              resolver = {
                resolveIPv6 = false;
              };
              router = "192.168.33.1";
            };
            # misc.readOnly = false;
            dns = {
              cnameRecords = [
                "color-printer,office-printer"
                "color-printer.homelab.me,office-printer.homelab.me"
              ];
              domain = "homelab.me";
              domainNeeded = true;
              expandHosts = true;
              interface = "eth0";
              hosts = [
                "192.168.33.1   gateway"
                "192.168.33.2   pi-hole"
                "192.168.33.15  nas"
              ];
              upstreams = ["1.1.1.1" "1.1.1.2"];
            };
            # Let's not use Pi-hole time service. My home router provides clock.
            ntp = {
              ipv4.active = false;
              ipv6.active = false;
              sync.active = false;
            };
            webserver = {
              api = {
                # To manage the web login:
                # 1) Temporarily set misc.readOnly to false in
                #    configuration.nix and switch to it.
                # 2) Manually set a password:
                #    Pi-hole web console > Settings > All settings >
                #    Webserver and API > webserver.api.password > Value: ******
                # 3) Read the generated hash:
                #    sudo pihole-FTL --config webserver.api.pwhash
                pwhash = "$BALLOON-SHA256...";
              };
              session = {
                timeout = 43200; # 12h
              };
            };
          };
          useDnsmasqConfig = true;
        };
    
        pihole-web = {
          enable = true;
          ports = [80];
        };
    
        resolved = {
          extraConfig = ''
            DNSStubListener=no
            MulticastDNS=off
          '';
        };
      };
    
      #
      # System
      #
      system.activationScripts = {
        print-pi-hole = {
          text = builtins.trace "building the pi-hole configuration..." "";
        };
      };
    
      #
      # Systemd
      #
      # The following silences a benign FTL.log warning:
      # WARNING API: Failed to read /etc/pihole/versions (key: internal_error)
      systemd.tmpfiles.rules = [
        # Type Path Mode User Group Age Argument
        "f /etc/pihole/versions 0644 pihole pihole - -"
      ];
    }
    
  2. Update your configuration.nix to import ./pi-hole.nix

      imports =
        [
          ./hardware-configuration.nix
          ./pi-hole.nix
        ]
    
  3. nixos-switch rebuild --upgrade

    Note

    • This command presumes that you are using classic NixOS channels and not an experimental flakes configuration.
    • This command will freshen all installed packages and configuration settings.
  4. Browse to your new Pi-Hole service to review it and learn more.

    Example: http://192.168.33.2

    Avoid making settings in the GUI. Most are managed via configuration.nix, except for Group Management: Groups, Clients, and Domains. You can also temporarily disable ad/tracking blocking in the web GUI.

Commentary

I’ve been running Pi-hole for at least three years. It’s a gem of a service that markedly improves your web browsing experience.

It was my last non-NixOS homelab service. I’m pleased that 25.11 xantusia now supports it. Please consider donating to NixOS and Pi-hole. They provide value to the public and would appreciate you reciprocating.

https://nixos.org/donate/

https://pi-hole.net/donate/

I’ve had almost no problems or negative feedback, with one notable exception. When family was applying for jobs online, I had to temporarily disable ad/tracker blocking via Pi-hole > DNS Control > Disable Blocking. I was irked to learn that mainstream companies utilize ads/trackers when submitting a resume. I’m not talking about sites like LinkedIn, which works fine. I’m talking about the employers themselves.

I host my NixOS Pi-hole in a lightweight LXC. I use two of them and a service called Keepalived to reduce the risk of an outage.