Why self-host Pi-hole on a VPS
Pi-hole is a filtering DNS resolver: it intercepts your devices' requests and refuses to resolve advertising, telemetry and tracking domains based on block lists. Hosted on a VPS rather than on a Raspberry at home, it follows you everywhere: your phone on 4G, your laptop at the café, or a remote server can use it as DNS and benefit from the filtering. The VPS provides what local hardware cannot: a stable public IP accessible from anywhere and permanent availability. The trade-off is security — a DNS resolver open on the Internet is a target. That's the whole point of this deployment: to expose Pi-hole in a controlled way, never as an open public DNS.
Concrete benefits of Pi-hole on a VPS
- Ad filtering and anti-tracking for all your devices, wherever they are, with no software to install.
- Encrypted DNS possible (DNS-over-HTTPS / DNS-over-TLS) upstream via a resolver such as cloudflared.
- Detailed dashboard: see in real time which domains your devices are contacting.
- Customizable block lists and allow/deny rules per client for differentiated policies.
- Faster resolution thanks to the local DNS cache, shared across all your devices.
- Reusable as DNS for your other VPSs and containers, with centralized logging.
Technical prerequisites
Pi-hole is extremely lightweight: 1 vCPU, 512 MB to 1 GB of RAM and a few gigabytes of disk are enough. You need Docker and Docker Compose. The critical point is not power but network and security: Pi-hole listens on port 53 (DNS, TCP and UDP) and exposes a web admin interface. Never open port 53 to the whole Internet — an open DNS resolver will be abused for amplification attacks. So plan for either a VPN (WireGuard) to access the DNS privately, or a firewall restriction to authorized IPs only. A pihole.yourdomain.com subdomain is useful for the interface over HTTPS.
Deploy Pi-hole step by step
Prepare the Docker stack
On the VPS, create /opt/pihole and a docker-compose.yml based on the pihole/pihole:latest image. Set the WEBPASSWORD variable, the TZ time zone, and mount volumes for /etc/pihole and /etc/dnsmasq.d to persist the configuration.
Lock down DNS access first of all
Do not publish port 53 to 0.0.0.0. The safest approach: first deploy WireGuard on the VPS and make Pi-hole listen only on the VPN interface. Failing that, restrict port 53 by firewall (ufw) to trusted IPs only. An open resolver is unacceptable.
Start Pi-hole
Start with docker compose up -d. Check that the service responds internally: docker compose exec pihole dig @127.0.0.1 doubleclick.net must return a blocked response (0.0.0.0).
Secure the admin interface
Expose the web interface (internal port 80) only behind an HTTPS reverse proxy, never in the clear. With Caddy: pihole.yourdomain.com { reverse_proxy pihole:80 }. The admin remains accessible at /admin with the password you set.
Enable an encrypted upstream DNS
Add a cloudflared container as a DoH resolver and configure Pi-hole to use it as upstream (127.0.0.1#5053). Your outbound requests are then encrypted between the VPS and the public resolver.
Configure your devices
Point your devices' DNS (or the WireGuard config) to the VPS's IP. On mobile, use the VPN profile to route DNS through Pi-hole even on the go. Check the filtering in the real-time dashboard.
Combine Pi-hole with WireGuard on the same VPS: make Pi-hole listen exclusively on the wg0 interface and distribute it as DNS in the WireGuard peers' configuration. You get a private, encrypted, filtering DNS accessible from anywhere, without ever exposing port 53 to the Internet — it's the only truly safe way to have a “roaming” Pi-hole. Then add themed block lists (for example anti-telemetry or regional anti-tracker lists) rather than a single giant list, to keep the false-positive rate low.