- Shell 100%
| config/pihole | ||
| .gitignore | ||
| bootstrap.sh | ||
| docker-compose.yml | ||
| README.md | ||
BCS_PiHole_Project
Standalone Pi-hole DNS sinkhole with an AdGuard DNS-over-HTTPS (DoH) proxy sidecar.
This is a clean, deployable extraction of the Pi-hole + dnsproxy setup originally built for the Sawgrass Security Dashboard.
What it does
- Pi-hole (
pihole/pihole:latest) provides network-wide ad blocking, tracker blocking, and local DNS resolution. - dnsproxy (
adguard/dnsproxy:latest) runs on127.0.0.1:5335and forwards all upstream queries to Cloudflare via encrypted DNS-over-HTTPS. - Pi-hole forwards its upstream queries to the local dnsproxy, falling back to plaintext Cloudflare malware-filtered resolvers (
1.1.1.2/1.0.0.2) if the proxy is unavailable.
Ports
| Port | Protocol | Purpose |
|---|---|---|
| 53 | TCP + UDP | DNS service for clients |
| 8080 | TCP | Pi-hole web admin interface |
| 5335 | TCP | Internal DoH proxy (localhost only) |
Requirements
- Linux host with Docker and Docker Compose v2
hostnetworking enabled (Pi-hole must bind directly to the host interface)- Firewall/UFW configured to allow inbound TCP/UDP 53 and TCP 8080 from trusted sources
- A static host IP recommended (
SERVERIPin.env)
Configuration
- Copy the example environment file and edit it:
cp .env.example .env
nano .env
- Set at least these variables in
.env:
| Variable | Description |
|---|---|
PIHOLE_PASSWORD |
Password for the Pi-hole web admin |
SERVERIP |
IP address of the host interface clients use for DNS |
PUID |
User ID for container file ownership (default 1000) |
PGID |
Group ID for container file ownership (default 1000) |
TZ |
Timezone (default America/New_York) |
Host preparation
This project is designed for a dedicated Pi-hole host using network_mode: host. On such a host, systemd-resolved binds port 53 and will prevent Pi-hole from starting.
Run the provided host-prep script as root before the first deploy:
sudo ./bootstrap.sh
Or manually stop and disable systemd-resolved and point /etc/resolv.conf to 127.0.0.1.
⚠️ Only do this on a host where this Pi-hole instance is intended to be the DNS resolver. Rewriting
/etc/resolv.confcan break DNS on shared or desktop systems.
Deploy
cd /home/secbeard/.openclaw/workspace/projects/BCS_PiHole_Project
docker compose up -d
Verify the containers are running:
docker compose ps
docker logs bcs-pihole
docker logs bcs-pihole-dnsproxy
If Pi-hole fails to start with a port 53 "Address in use" error, the host may already have another DNS resolver or a Sawgrass setup.sh DNS watchdog running. Stop or disable the conflicting service before deploying.
Pi-hole v6 runs as non-root UID 1000, so this compose file adds cap_add: [NET_BIND_SERVICE, NET_ADMIN, NET_RAW, SYS_NICE, SYS_TIME] so the container can bind privileged port 53 and manage DNS sockets. Without these capabilities, port binding will fail.
Web admin port
The web admin port is set to 8080. In Pi-hole v6 the legacy WEBPORT environment variable is no longer honored; the compose file uses FTLCONF_webserver_port so FTL overrides webserver.port in pihole.toml at runtime.
First use
- Open the Pi-hole admin panel at
http://<SERVERIP>:8080/admin - Log in with the password set in
.env(PIHOLE_PASSWORD) - Point client devices to
<SERVERIP>for DNS
Networking notes
- Both services use
network_mode: hostso Pi-hole can listen on the host's real interfaces and dnsproxy can bind127.0.0.1:5335from the host network namespace. DNSMASQ_LISTENING: localtells Pi-hole to listen on all local interfaces.- The web admin port is set to
8080viaFTLCONF_webserver_portbecause Pi-hole v6 does not honor the legacyWEBPORTvariable.
Firewall / security
Ensure the host firewall allows the following from trusted client networks:
# UFW example
sudo ufw allow 53/tcp comment 'Pi-hole DNS TCP'
sudo ufw allow 53/udp comment 'Pi-hole DNS UDP'
sudo ufw allow from <TRUSTED_SUBNET> to any port 8080 proto tcp comment 'Pi-hole web admin'
The dnsproxy DoH sidecar listens only on 127.0.0.1:5335, so it is not externally reachable.
Updating
docker compose pull
docker compose up -d
Stopping
docker compose down # stop containers, keep volumes
docker compose down -v # stop and delete volumes (resets Pi-hole data!)