A lightweight, self-hosted stack combining Pi-hole, Cloudflared (DoH), and WireGuard to give you fast, private, ad-free DNS anywhere — even outside your home network.
Optimized for 2-core CPUs and 4 GB RAM — perfect for Raspberry Pi, small servers, and VMs.
| Component | Purpose |
|---|---|
| Pi-hole | Blocks ads, trackers, and malware at the DNS level |
| Cloudflared (DoH) | Encrypts DNS queries with DNS-over-HTTPS |
| WireGuard (wg-easy) | Secure VPN that routes all traffic through Pi-hole |
| Optional Power Saver Script | Auto-pauses containers when offline and resumes instantly |
- Linux host (Ubuntu/Debian/Other distro not tested)
- Docker & Docker Compose
- Recommended: 2 vCPU + 4 GB RAM
Clone this repository:
git clone https://github.com/yourusername/pihole-doh-wireguard.git
cd pihole-doh-wireguard/Pi-holeStart everything:
sudo docker compose up -d-
Handles encrypted DNS-over-HTTPS queries
-
Forwards to:
https://pleaseusecloudflarezerotrust.cloudflare-gateway.com/dns-queryhttps://1.1.1.1/dns-queryhttps://1.0.0.1/dns-query
-
Listens on port 5054
- Uses Cloudflared as DNS upstream
- Web UI: https://localhost:4443
- Default password:
passwordyoulikeidontcare→ change it after setup!
- Web UI: http://localhost:51821
- Port 51820/udp for VPN connections
- Supports IPv4 and IPv6
docker exec -it pihole pihole -a -pChange your Pi-hole password, and adjust upstream DoH or WireGuard settings as needed.
An optional helper that automatically pauses containers (Pi-hole, WireGuard, Cloudflared) when the internet is down,
and unpauses them instantly when connectivity returns.
Also adjusts CPU power profiles and can suspend the system on battery.
# Move the helper script
sudo cp scripts/power_saver.sh /usr/local/bin/power_saver.sh
sudo chmod +x /usr/local/bin/power_saver.sh
# Copy and enable the service
sudo cp scripts/power-saver.service /etc/systemd/system/
sudo systemctl enable --now power-saver.serviceIf your repo is elsewhere (e.g. /home/pi/pihole-doh-wireguard):
sudo nano /etc/systemd/system/power-saver.serviceChange this line if needed:
ExecStart=/usr/local/bin/power_saver.sh→ to:
ExecStart=/home/pi/pihole-doh-wireguard/scripts/power_saver.shReload systemd:
sudo systemctl daemon-reload
sudo systemctl restart power-saver.serviceView logs:
sudo journalctl -u power-saver.service -fDisable:
sudo systemctl disable --now power-saver.serviceTo include extra containers (like hbbr, hbbs), edit the CONTAINERS=(...) list in
scripts/power_saver.sh — no rewrite needed.
pihole-doh-wireguard/
├── Pi-hole/
│ └── docker-compose.yml
├── scripts/
│ ├── power_saver.sh
│ └── power-saver.service
| └── README.md
└── README.md
| Service | Check |
|---|---|
| Cloudflared | cloudflared version |
| Pi-hole | dig +short @127.0.0.1 google.com |
| WireGuard | wg show |
# Logs
docker logs pihole -f
docker logs cloudflared -f
docker logs wg-easy -f
# Restart all
docker compose restartdocker compose down -v
sudo systemctl disable --now power-saver.service
sudo rm /usr/local/bin/power_saver.sh /etc/systemd/system/power-saver.serviceIf your ISP uses CGNAT or you can’t forward ports for WireGuard,
you can optionally add Tailscale as a backup for remote access.
What it does:
Tailscale creates a secure, peer-to-peer mesh VPN between your devices — like a private LAN that works over the internet.
It automatically handles NAT traversal, encryption, and device discovery, so you can reach your Pi-hole and network from anywhere
without opening ports or needing a static IP.
Think of Tailscale as a fallback connection when direct WireGuard access isn’t possible.
You can safely run both Tailscale and WireGuard together — Tailscale just ensures connectivity,
while your Pi-hole + Cloudflared setup continues to handle DNS and filtering.
- Pi-hole
- Cloudflared
- WG-Easy
- And you — for hosting your own privacy stack