Finite is a NixOS configuration that ships Pi-hole + Unbound as a tiny fortress for your network. Drop it onto a Raspberry Pi and you get ad-blocking, DNS privacy, and self-hosting satisfaction with almost no effort.
Why
-
Your DNS stays local. Normally, every website you visit triggers a DNS request that goes to a company’s server like Google’s or your ISP’s giving them a complete log of what you browse. With Finite, your Raspberry Pi handles those lookups locally. No external logging, no silent profiling. Whether you’re a small business or an individual who values privacy, you keep control of your own data.
-
Ads and trackers are blocked at the source Pi-hole filters out ad and tracking domains before they even reach your browser, so all your devices benefit automatically.
-
It’s fully declarative. All settings live in clean configuration files. Change one line, rebuild, and your setup updates instantly and predictably no manual tweaks to remember.
What
-
Clone, tweak, build, boot. Grab the repo, set a few variables, build the SD image, and start your Pi. That’s all it takes to get a private DNS and ad blocker running.
-
Clean, organized configuration. Passwords, network settings, and services are separated and easy to adjust. No fragile scripts or hidden system files.
-
Powered by Nix flakes. Everything is versioned and reproducible. You can safely experiment, roll back changes, or extend the system without breaking it perfect for curious tinkerers.
Adjust defaults in ./settings.nix:
| variables | Example Value | Description |
|---|---|---|
STATE_VERSION |
"25.11" |
NixOS release version to maintain compatibility with Nix modules. |
SYSTEM |
"aarch64-linux" |
Target architecture for the Raspberry Pi (ARMv8 64-bit). |
USERNAME |
"pi-hole" |
Default system user created during image build. |
USER_PASSWORD |
"hackme" |
Default password for the system user (must be changed after first login). |
SSH_PORT |
1234 |
Port number for incoming SSH connections. |
SSH_PUBLIC_KEY |
"ssh-rsa AAAA..." |
Authorized SSH public key for passwordless login. |
TIMEZONE |
"Europe/Lisbon" |
System timezone configuration. |
ROUTER_IP |
"192.168.50.1" |
IP address of the network’s router/gateway for DNS and routing configuration. |
STATIC_IP |
"192.168.50.2" |
Fixed IP assigned to the Raspberry Pi host. |
TIMESYNCD_SERVERS |
[ "162.159.200.1" "162.159.200.123" ] |
NTP servers used for initial time synchronization to prevent Unbound TLS errors. |
UNBOUND_SUBNETS |
[ "127.0.0.1/32 allow" "192.168.1.0/24 allow" "192.168.50.0/24 allow" ] |
CIDR blocks with access control rules for Unbound (which clients can query the DNS server). |
UNBOUND_PORT |
"5335" |
Listening port for the Unbound DNS resolver. |
make build_image
# or
nix build .#nixosConfigurations.finite.config.system.build.sdImage
- Find target disk:
# linux
lsblk -f
# macOS
diskutil list
- Write image:
# linux
sudo dd if=./result/sd-image/your_image_name.img of=/dev/your_disk_name bs=4M status=progress conv=fsync
sync
# macOS
diskutil unmountDisk /dev/your_disk_name
sudo dd if=./result/sd-image/your_image_name.img of=/dev/your_disk_name bs=4M status=progress conv=fsync
ssh -p 1234 pi-hole@192.168.1.253
Change the very-trustworthy default password "hackme":
passwd
Set your Pi-hole Web UI password before someone else does:
sudo podman exec -it pi-hole pihole setpassword your_new_password
Update database:
sudo podman exec pi-hole pihole -g
Open the Pi-hole dashboard from your PC at your configured IP address STATIC_IP/admin, for example:
http://192.168.50.2/admin
Enjoy watching ads vanish faster than your faith in online privacy.
So you’ve got your shiny little fortress running. Now make your router bow to it.
In your router admin panel, find LAN → DNS Server and set it to your Pi’s static IP:
DNS 1 Server: 192.168.50.2
DNS 2 Server: leave blank
That’s it. Your whole network now swears allegiance to Pi-hole.
Some ISP routers think you don’t deserve custom DNS. Fine. Outsmart them.
-
Option A: Let Pi-hole run DHCP
must be noted that it is not tested and probably needs additional tweaking. I recommend option B if you don't know what you are doing. Future support for DHCP might be added later.
- Turn off DHCP on your router.
- In Pi-hole’s web UI → Settings → DHCP → enable it.
- Now Pi-hole hands out IPs and DNS like a benevolent dictator.
-
Option B: Use a real router
- Plug your own router into the ISP box.
- Let your router manage DHCP and DNS.
- Keep the ISP router just to reach the internet.
- Double NAT? Maybe. Freedom? Definitely.
Run this from any client:
nslookup github.com 192.168.50.2
If it answers, Pi-hole reigns supreme.
Then open the Pi-hole dashboard → Query Log → watch the ads die in real time.
nixos-rebuild switch --flake path:.#finite --target-host pi-hole@raspbery_pi_api --sudo --ask-sudo-passwordbuilds locally and copies the closure to the Pi since it can be too weak for Nix builds.
For curated and well-maintained DNS blacklists, start here: hagezi/dns-blocklists
Tested on Raspberry Pi 3 B+. Reports for other models are welcome. Expected to work on:
- Pi 2 v1.2 and later
- Pi 3
- Pi 4
- Pi 5 → ARMv8
For other versions, adjust the SYSTEM variable in ./settings.nix to match your architecture, and share your results if it works.
- Automatic backups for pi-hole stats (skipped, do not log activity)
- Add luks encryption (skipped, replace with no logging)
- Remote deployment from host
MIT © 2025 Nikita Miloserdov See LICENSE
