pihole: fix gravity writes, declare the blocklists

FTL could not write gravity.db, reporting "attempt to write a readonly
database". The database file was writable; the directory was not. sqlite
creates a sibling gravity.db-journal for every write transaction, so FTL
needs to CREATE files in /var/lib/pihole, and the tmpfiles rule left it
root-owned. The error names the database rather than the directory, which
sends you looking at the file and the filesystem, neither of which is at
fault.

Own the directory as 1000 instead -- the pihole user FTL drops to after
the entrypoint's root phase. Podman is rootful here with no userns
remapping, so the number is the same inside and out; on the host it
collides with darman, harmlessly.

The blocklists are now declared in this module and seeded by a oneshot,
because /var/lib/pihole is not declarative and a reflash took gravity
with it. INSERT OR IGNORE keyed on the URL is idempotent so it can run on
every boot, while the expensive rebuild only runs when gravity is empty.
Adding a list to the Nix attribute needs a manual `pihole -g` -- that is
deliberate, since the rebuild downloads every list and is slow on a Pi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 21:52:01 +02:00
co-authored by Claude Opus 4.8
parent 4fb4297e12
commit 6bf0eeab04
2 changed files with 74 additions and 8 deletions
+11 -6
View File
@@ -210,14 +210,19 @@ another way in.
sudo nix-store --verify --check-contents # add --repair to fix
```
A card that has corrupted one path will corrupt more. Replace it and reflash.
- **A reflash wipes `/var/lib/pihole`**, which is NOT declarative. The
`FTLCONF_*` env vars rebuild the DNS/DHCP config, but the gravity database
goes with it — so adlists and blocking are gone and resolution silently
keeps working with nothing blocked (`Blocked DNS queries: 0` in the logs is
the tell). Re-add the adlists, then:
- **A reflash wipes `/var/lib/pihole`**, taking the gravity database with it.
The blocklists themselves are declared in `services/network/pihole.nix`, and
the `pihole-adlists` unit re-seeds them on boot and rebuilds gravity when it
finds it empty — so this heals itself, but the first boot after a reflash
spends several minutes downloading lists. Query history and dynamic DHCP
leases are genuinely lost (static leases are declarative). Check with:
```
sudo podman exec pihole pihole -g
systemctl status pihole-adlists
sudo podman exec pihole pihole-FTL sqlite3 /etc/pihole/gravity.db \
"SELECT address,enabled FROM adlist; SELECT COUNT(*) FROM gravity;"
```
`Blocked DNS queries: 0` in the pihole logs means gravity is empty — DNS
resolves fine, nothing is filtered.
- mercury's own `resolv.conf` is deliberately public resolvers, not its own
pihole (`resolveLocalQueries = false`, see `CLAUDE.md`) — so `.sol` names do
not resolve *on mercury itself*. That is expected, not a fault.