Install Pi-hole on Proxmox VE
Why LXC for Pi-hole?
Pi-hole is a DNS server. It needs almost no resources — 50-100 MB of RAM, negligible CPU, a few GB of disk. Running it in a full virtual machine wastes resources. A Proxmox LXC container gives Pi-hole its own isolated environment with native performance and near-zero overhead. LXC is the ideal fit.
The setup: create a Debian or Ubuntu LXC container, install Docker inside it, run Pi-hole in Docker. This gives you container isolation (from LXC), easy upgrades (from Docker), and minimal resource usage (from not running a full VM kernel).
Prerequisites
- Proxmox VE 8.0+ installed and accessible
- 1 vCPU available
- 512 MB RAM available
- 4 GB disk space available
- SSH access to the Proxmox host
- A static IP address for Pi-hole on your network
Create the LXC Container
Download the Template
From the Proxmox web UI, go to your storage (usually local) > CT Templates > Templates and download debian-12-standard. Or from the CLI:
pveam update
pveam download local debian-12-standard_12.7-1_amd64.tar.zst
Create the Container
pct create 200 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname pihole \
--cores 1 \
--memory 512 \
--swap 256 \
--rootfs local-lvm:4 \
--net0 name=eth0,bridge=vmbr0,ip=192.168.1.53/24,gw=192.168.1.1 \
--features nesting=1,keyctl=1 \
--unprivileged 1 \
--onboot 1 \
--start 1 \
--nameserver 1.1.1.1 \
--password
You will be prompted to set a root password for the container.
Configuration breakdown:
--cores 1— One vCPU is more than enough. Pi-hole barely uses any CPU.--memory 512— 512 MB RAM. Pi-hole typically uses 50-100 MB. The rest is buffer for Docker and the OS.--rootfs local-lvm:4— 4 GB disk. Pi-hole’s database, blocklists, and query logs fit comfortably. Increase to 8 GB if you want extended log retention.--net0 ... ip=192.168.1.53/24,gw=192.168.1.1— Static IP assigned directly in Proxmox. No need to configure networking inside the container. Adjust the IP and gateway to match your network.--features nesting=1,keyctl=1— Required for running Docker inside the LXC container.--unprivileged 1— Security best practice. Unprivileged containers cannot access host devices or escalate privileges.--onboot 1— Start the container automatically when Proxmox boots. Critical for a DNS server — your network depends on it.--nameserver 1.1.1.1— Temporary DNS for the container during setup. After Pi-hole is running, the container can use Pi-hole itself.
Verify the Container
pct enter 200
Check networking:
ip addr show eth0
ping -c 3 1.1.1.1
Install Docker Inside the LXC
Inside the container:
apt update && apt install -y curl ca-certificates gnupg
# Install Docker
curl -fsSL https://get.docker.com | sh
Verify Docker is running:
docker run --rm hello-world
If Docker fails with overlay filesystem errors, the LXC storage backend may not support it. Solutions:
- Use a directory-backed storage for the LXC rootfs (not ZFS or BTRFS)
- Or add
--storage-driver=vfsto Docker’s configuration (slower but works everywhere) - Or use a privileged container:
pct set 200 --unprivileged 0(less secure)
Deploy Pi-hole
Create the Pi-hole directory and Docker Compose file:
mkdir -p /opt/pihole
Create /opt/pihole/docker-compose.yml:
services:
pihole:
container_name: pihole
image: pihole/pihole:2026.02.0
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
- "443:443/tcp"
environment:
TZ: "America/New_York"
FTLCONF_webserver_api_password: "change-me-to-a-strong-password"
FTLCONF_dns_upstreams: "1.1.1.1;1.0.0.1"
FTLCONF_dns_listeningMode: "ALL"
volumes:
- ./etc-pihole:/etc/pihole
cap_add:
- NET_ADMIN
- SYS_TIME
- SYS_NICE
restart: unless-stopped
Debian 12 does not run systemd-resolved, so there is no port 53 conflict. Pi-hole binds to port 53 without issues.
Start Pi-hole:
cd /opt/pihole
docker compose up -d
Verify it is running:
docker compose logs pihole | tail -20
Test DNS resolution:
dig @127.0.0.1 google.com
Access the admin interface at http://192.168.1.53/admin.
Configuration
Proxmox Network Configuration
The static IP was set during container creation. If you need to change it later, edit from the Proxmox host:
pct set 200 --net0 name=eth0,bridge=vmbr0,ip=192.168.1.53/24,gw=192.168.1.1
Or edit through the Proxmox web UI: Container > Network > eth0 > Edit.
The LXC container’s network goes through the Proxmox bridge (vmbr0). Make sure this bridge is connected to your physical network interface — otherwise the container will not be reachable from other devices.
Proxmox Firewall Rules
If you use Proxmox’s built-in firewall, allow DNS and web traffic to the Pi-hole container.
From the Proxmox web UI: Container 200 > Firewall > Add Rule:
| Direction | Action | Protocol | Dest. Port | Comment |
|---|---|---|---|---|
| IN | ACCEPT | TCP | 53 | DNS TCP |
| IN | ACCEPT | UDP | 53 | DNS UDP |
| IN | ACCEPT | TCP | 80 | Pi-hole web UI |
| IN | ACCEPT | TCP | 443 | Pi-hole web UI HTTPS |
Or from the CLI, edit /etc/pve/firewall/200.fw:
[RULES]
IN ACCEPT -p tcp -dport 53
IN ACCEPT -p udp -dport 53
IN ACCEPT -p tcp -dport 80
IN ACCEPT -p tcp -dport 443
If the Proxmox firewall is not enabled (default), these rules are not needed — all traffic passes through.
Point Your Network to Pi-hole
Configure your router to use Pi-hole as the DNS server:
- Log into your router’s admin panel
- Set primary DNS to
192.168.1.53(the LXC container’s IP) - Do not use a different secondary DNS (it would bypass Pi-hole)
- Save and reboot the router
Devices pick up the new DNS server on their next DHCP lease renewal.
Start on Boot Priority
Pi-hole should start as early as possible during Proxmox boot — other VMs and containers may depend on DNS. Set a low startup order number:
From the Proxmox web UI: Container 200 > Options > Start/Shutdown order:
- Start order: 1 (first to start)
- Startup delay: 0
- Shutdown order: 100 (last to stop)
Or from CLI:
pct set 200 --startup order=1,up=0,down=100
This ensures Pi-hole is the first container to start and the last to stop during Proxmox restarts.
Multiple Pi-hole Instances for Redundancy
Proxmox makes it trivial to run multiple Pi-hole instances. DNS is critical infrastructure — if Pi-hole goes down, your entire network loses DNS. Running two instances on separate LXC containers provides fault tolerance.
Create a Second Instance
Clone the first container or create a new one:
pct create 201 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname pihole-secondary \
--cores 1 \
--memory 512 \
--swap 256 \
--rootfs local-lvm:4 \
--net0 name=eth0,bridge=vmbr0,ip=192.168.1.54/24,gw=192.168.1.1 \
--features nesting=1,keyctl=1 \
--unprivileged 1 \
--onboot 1 \
--nameserver 1.1.1.1 \
--password
Install Docker and Pi-hole the same way as the first instance. Set the same upstream DNS and blocklists.
Configure Your Router
Set your router’s DNS:
- Primary DNS:
192.168.1.53(Pi-hole #1) - Secondary DNS:
192.168.1.54(Pi-hole #2)
When both are Pi-hole instances, all queries get filtered regardless of which server the device uses.
Keep Blocklists in Sync
Two Pi-hole instances need the same blocklists, whitelists, and settings. Options:
- Manual sync — Export settings from Pi-hole #1 via Teleporter, import into Pi-hole #2. Simple but manual.
- Orbital Sync — A Docker container that automatically syncs Pi-hole settings between instances:
orbital-sync:
container_name: orbital-sync
image: mattwebbio/orbital-sync:1.10.1
environment:
PRIMARY_HOST_BASE_URL: "http://192.168.1.53"
PRIMARY_HOST_PASSWORD: "your-pihole-password"
SECONDARY_HOST_1_BASE_URL: "http://192.168.1.54"
SECONDARY_HOST_1_PASSWORD: "your-pihole-password"
INTERVAL_MINUTES: 60
restart: unless-stopped
Run Orbital Sync on either Pi-hole instance or on a separate container.
Platform-Specific Tips
- LXC vs VM for Pi-hole. There is no reason to use a VM for Pi-hole. An LXC container starts in seconds, uses native performance, and shares the host kernel. A VM adds 512 MB+ RAM overhead for its own kernel and virtual hardware.
- Resource monitoring. Proxmox shows per-container CPU, RAM, disk, and network usage in the web UI. Pi-hole’s LXC should show <5% CPU and <100 MB RAM under normal operation. If you see more, check if gravity updates are running or if Docker is using excessive resources.
- Snapshot before upgrades. Before updating Pi-hole (inside the container), take a Proxmox snapshot from the host:
Roll back instantly if the upgrade breaks something:pct snapshot 200 pre-upgrade --description "Before Pi-hole upgrade"pct rollback 200 pre-upgrade - Disk space monitoring. The 4 GB rootfs is tight. Monitor usage:
If space runs low, resize from the Proxmox host:pct exec 200 -- df -h /pct resize 200 rootfs +4G - Backups. Use Proxmox’s backup scheduler (Datacenter > Backup) to back up the Pi-hole container. A full container backup at 4 GB compresses to under 500 MB. Schedule daily backups and keep 7 copies.
Troubleshooting
LXC Container Cannot Reach the Internet
Symptom: ping 1.1.1.1 works inside the container but apt update or dig google.com fails.
Fix: DNS is not configured inside the container. Check:
cat /etc/resolv.conf
If empty or pointing to a non-functional server, set it manually:
echo "nameserver 1.1.1.1" > /etc/resolv.conf
Or set it from the Proxmox host:
pct set 200 --nameserver 1.1.1.1
After Pi-hole is running, you can point the container’s DNS to itself (127.0.0.1).
Docker Fails to Start in LXC
Symptom: docker info shows errors about overlay2, storage driver, or cgroup.
Fix: Docker inside LXC requires nesting=1 and keyctl=1 features. Verify:
# From the Proxmox host
pct config 200 | grep features
If not set:
pct stop 200
pct set 200 --features nesting=1,keyctl=1
pct start 200
If overlay2 still fails on ZFS-backed storage, configure Docker to use the vfs or fuse-overlayfs storage driver:
mkdir -p /etc/docker
echo '{"storage-driver": "fuse-overlayfs"}' > /etc/docker/daemon.json
apt install -y fuse-overlayfs
systemctl restart docker
Pi-hole Container Restarts in a Loop
Symptom: docker compose ps shows the Pi-hole container in a restart loop.
Fix: Check logs:
docker compose logs pihole
Common causes:
- Port 53 in use — unlikely in Debian LXC, but check:
ss -tlnp | grep ':53' - Insufficient memory — if the LXC has less than 256 MB, Pi-hole may OOM. Increase from the Proxmox host:
pct set 200 --memory 512 - Volume permission issues — if the
./etc-piholedirectory has wrong permissions:chown -R 999:999 /opt/pihole/etc-pihole
Proxmox Host Loses DNS After Pi-hole LXC Stops
Symptom: If the Pi-hole LXC container stops, the Proxmox host itself loses DNS resolution.
Fix: Do not point the Proxmox host’s DNS to the Pi-hole LXC. The host should use external DNS (e.g., 1.1.1.1). Only point your router and client devices to Pi-hole.
Edit the Proxmox host’s DNS: Node > System > DNS — set to 1.1.1.1 or your preferred public DNS.
High Disk Usage in Small LXC
Symptom: The 4 GB rootfs fills up over time.
Fix: Pi-hole’s FTL database (pihole-FTL.db) stores query logs and grows continuously. Limit retention:
- In the Pi-hole web UI: Settings > Privacy — set to “Anonymous mode” or limit log retention to 24 hours
- Manually clean the database:
docker compose exec pihole pihole flush - Resize the LXC from the Proxmox host if you need more space:
pct resize 200 rootfs +4G
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments