Skip to content

Instantly share code, notes, and snippets.

@lukeify
Last active December 27, 2023 21:24
Show Gist options
  • Save lukeify/96e73218b4de79891a46a89fdc2c2045 to your computer and use it in GitHub Desktop.
Save lukeify/96e73218b4de79891a46a89fdc2c2045 to your computer and use it in GitHub Desktop.
Running PiHole on a UDM

Preamble

I have been looking to free up one of my rPi's from PiHole duty for a while now, and I was pleasantly surprised to see it is indeed possible to run a containerized instance of PiHole on a UDM, thanks to the excellent work of boostchicken, who created several utility scripts to expedite the process. This quick gist documents my setup steps as of January 2023, and also just generally improves the formatting of the order of operations. You probably want to start here.

Step zero for me was figuring out SSH access for UniFiOS. This (to my knowledge) isn't able to be enabled from UniFiOS at https://192.168.1.1—you'll need to visit the UniFi Portal at unifi.ui.com, navigate to your network, then SettingsSystemNetwork Device Authentication and enable Device SSH Authentication. Enabling SSH in your local console controls won't cut it.

Screenshot 2023-01-03 at 3 25 17 PM

It's also worth noting UniFiOS as of 1.12.33 depends on the insecure ssh-rsa key negotiation protocol, so ~/.ssh/config should be amended like so:

ssh udm
    PubkeyAcceptedAlgorithms +ssh-rsa
    HostkeyAlgorithms +ssh-rsa

Steps

  1. SSH in, and grab a copy of the boot script:

    curl -fsL "https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/HEAD/on-boot-script/remote_install.sh" | /bin/sh

    This will install CNI plugins for the ARM64 architecture onto your UDM—this is necessary as we'll be running PiHole via podman. Once complete, you'll have a directory at /mnt/data/on_boot.d to place files which will be executed on boot of your UDM. This ensures pihole is both restarted on-boot, and even across firmware updates.

  2. Copy the 05-install-cni-plugins.sh file to this new directory, and execute it. If you've run the remote installer, you'll already have this file in your directory, and can skip right to executing it.

    cd /mnt/data/on_boot.d
    curl -J https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/cni-plugins/05-install-cni-plugins.sh
    chmod +x 05-install-cni-plugins.sh
    /mnt/data/on_boot.d/05-install-cni-plugins.sh
  3. Create a new VLAN in your UDM here. I didn't think the example configuration was that intuitive so I chose my own settings:

    Setting Value
    Network Name PiHole
    Auto-Scale Network false
    Gateway IP/Subnet 192.168.2.1/26
    VLAN ID 2
    Network Type Standard
    Content Filtering None
    Multicast DNS true
    DHCP Mode None

    192.168.1.x is my primary network, so incrementing the third component of the IP seemed like a sensible choice, and I don't need the space a /24 subnet provides—and again, a VLAN ID of 2, aligning it with the Gateway IP, seemed reasonable.

    Very important: DHCP mode must be set to None.

    Screenshot 2023-01-03 at 3 50 48 PM
  4. Amend 20-dns.conflist, to match your settings:

    • Replace name with the name of your network above.
    • For plugins.0.mac, ensure the xx:xx:xx component of the MAC address is replaced, i.e. 00:00:00. There is no real reason for it to be random or otherwise randomly generated, and setting it explicitly to such a value makes it easy to identify (however, the choice to use Iridium's MAC namespace here is somewhat questionable in my opinion, though).
    • Replace plugins.0.master with the identifier of your VLAN you've created, prefixed with "br". In my case, "br2".
    • Replace plugins.0.ipam.addresses.0.address with the CIDR-notated address of the address of your PiHole instance. This differs from the gateway address of your VLAN. Given that I chose a gateway address of 192.168.2.1, using 192.168.2.2 for my PiHole instance seemed sensible—this will also become your DNS resolver once operational.

    Following these changes, my 20-dns.conflist was as such:

    {
      "cniVersion": "0.4.0",
      "name": "PiHole",
      "plugins": [
        {
          "type": "macvlan",
          "mode": "bridge",
          "master": "br2",
          "mac": "00:1c:b4:00:00:00",
          "ipam": {
            "type": "static",
            "addresses": [
              {
                "address": "192.168.2.2/26",
                "gateway": "192.168.2.1"
              }
            ],
            "routes": [{ "dst": "0.0.0.0/0" }]
          }
        }
      ]
    }

    This step, represented in bash:

    cd /mnt/data/podman/cni
    curl -J https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/cni-plugins/20-dns.conflist
    nano 20-dns.conflist # amend file here as described above.
    chmod +x 20-dns.conflist
    cp 20-dns.conflist /etc/cni/net.d/dns.conflist

    Finally, if everything has worked as expected, when you run podman network inspect PiHole, you'll see your configuration you entered above.

  5. Modify the arguments within 10-dns.sh to match your configuration, and execute it. Amend the arguments as so:

    • Modify VLAN to match the identifier of your VLAN (for me, 2).
    • Modify IPV4_IP to match the IP address of your PiHole instance (192.168.2.2).
    • Modify IPV4_GW to match the CIDR-notated IP of the network (192.168.2.1/26).
    • Modify CONTAINER to match the name of the docker container you're about to run.
    cd /mnt/data/on_boot.d
    curl -J https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/main/dns-common/on_boot.d/10-dns.sh
    nano 10-dns.sh # amend file here as described above.
    chmod +x 10-dns.sh
    /mnt/data/on_boot.d/10-dns.sh

    You may see this error appear on execution, this is normal and fine.

  6. Create the following directories. These will be mounted as persistent volumes for our pihole container.

    mkdir -p /mnt/data/etc-pihole
    mkdir -p /mnt/data/pihole/etc-dnsmasq.d
  7. Finally, time to create our pihole container instance. The following entries must match:

    • As mentioned above, --name should equal the container name defined in 10-dns.sh.
    • --network should equal the name you defined in 20-dns.conflist.
    • -e FTLCONF_REPLY_ADDR4 must match the IP address you're defining for your PiHole instance.

    Some other notes:

    podman run -d \
      --network PiHole \
      --restart always \
      --name pihole \
      --cap-add=NET_ADMIN \
      -v "/mnt/data/etc-pihole/:/etc/pihole/" \
      -v "/mnt/data/pihole/etc-dnsmasq.d/:/etc/dnsmasq.d/" \
      --dns=127.0.0.1 \
      --dns=1.1.1.1 \
      --hostname pi.hole \
      -e TZ="Pacific/Auckland" \
      -e VIRTUAL_HOST="pi.hole" \
      -e PROXY_LOCATION="pi.hole" \
      -e FTLCONF_REPLY_ADDR4="192.168.2.2" \
      -e FTLCONF_BLOCK_ICLOUD_PR="false" \
      -e FTLCONF_PRIVACY_LEVEL="0" \
      -e IPv6="False" \
      pihole/pihole:latest

    Check your container works with podman container ls.

  8. Provision your PiHole instance by setting a password: podman exec -it pihole pihole -a -p PW.

  9. Configure your WAN such that it's primary DNS Server is set to the IP address of your PiHole instance, in my case 192.168.2.2.

    Screenshot 2023-01-03 at 5 48 30 PM
  10. Likewise configure your LAN's DHCP Server to be enabled, and pointing to the same IP address.

    Screenshot 2023-01-03 at 5 49 02 PM
  11. Enjoy the PiHole!

    Screenshot 2023-01-03 at 6 09 50 PM
@lukeify
Copy link
Author

lukeify commented Dec 27, 2023

Superseded by PiHole on UniFi OS 3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment