Pi-hole
- Source: https://github.com/pi-hole/pi-hole
- License: EUPL-1.2
- UI:
https://pihole.<domain> - Credentials: web UI password is
EXIST_PASSWORD(rendered intoPIHOLE_PASSWORD)
Network-wide DNS ad blocker and optional DHCP server. Blocks ads, trackers, and malicious domains for all devices on the network by acting as the primary DNS resolver.
Ports
| Service | Port |
|---|---|
| DNS | 53 (TCP + UDP) — published on the host |
| Web UI | 80 (container-internal), reached only through Caddy at https://pihole.<domain> |
| Web UI direct (optional) | host 42480→80, 42443→443 — uncomment in the compose template to bypass Caddy |
| DHCP (optional) | 67 — uncomment in the compose template |
| NTP (optional) | 123 — uncomment in the compose template |
Setup
- Enable it in
.env.shared:EXIST_IS_HOSTING_PIHOLE=true - Render and start, from the repo root:
./existential.sh && docker compose up -d
- Point your router's DNS to the host running Pi-hole
Pi-hole then resolves the whole of EXIST_DOMAIN locally via a single wildcard record, which
removes the stack's dependency on public DNS. It is an upgrade, not a requirement — see
How It Works.
Upstream resolution and blocklists
Anything not covered by the wildcard record or a blocklist is forwarded upstream. Out of the
box that's Google DNS (8.8.8.8, 8.8.4.4) — the image's own default, no config needed. Override
it with FTLCONF_dns_upstreams in docker-compose.exist.yml if you'd rather use another
resolver (e.g. Cloudflare's 1.1.1.1).
The container ships its own cron, so blocklists (gravity) update weekly, Sunday 04:15
(container time — see PIHOLE_TZ) with no setup required; the query log flushes daily at
midnight. Trigger an update manually with docker exec pihole pihole -g, or manage blocklists
at https://pihole.<domain>/admin/lists.
Debugging
docker compose logs pihole
# Check DNS resolution
docker exec pihole nslookup example.com