This Docker deployment runs both Pi-Hole and Unbound in a single container.
The base image for the container is the official Pi-Hole container, with an extra build step added to install the Unbound resolver directly into to the container based on instructions provided directly by the Pi-Hole team.
| Image | Tag | Build | Latest |
|---|---|---|---|
| ghcr.io/lizenzfass78851/docker-pihole-unbound | stable | 📌 | |
| ghcr.io/lizenzfass78851/docker-pihole-unbound | beta | ||
| ghcr.io/lizenzfass78851/docker-pihole-unbound | oldstable |
- Matrix Build State
First create a .env file to substitute variables for your deployment.
docker run -d \
--name='pihole' \
-e TZ="Europe/Berlin" \
-e 'TCP_PORT_53'='53' -e 'UDP_PORT_53'='53' -e 'UDP_PORT_67'='67' -e 'TCP_PORT_80'='80' -e 'TCP_PORT_443'='443' \
-e 'TZ'='Europe/Berlin' \
-e 'FTLCONF_webserver_api_password'='******' \
-v "$PWD/pihole/pihole/":'/etc/pihole/':'rw' \
-v "$PWD/pihole/dnsmasq.d/":'/etc/dnsmasq.d/':'rw' \
--cap-add=NET_ADMIN \
--hostname=pihole \
'ghcr.io/lizenzfass78851/docker-pihole-unbound:latest'Vars and descriptions replicated from the official pihole container:
| Docker Environment Var | Description |
|---|---|
TZ: <Timezone> |
Set your timezone to make sure logs rotate at local midnight instead of at UTC midnight. |
FTLCONF_webserver_api_password: <Admin password> |
http://pi.hole/admin password. Run docker logs pihole | grep random to find your random pass. |
FTLCONF_dns_revServers: <enabled>,<ip-address>[/<prefix-len>],<server>[#<port>],<domain> |
Enable Reverse server (former also called "conditional forwarding") feature |
USE_IPV6: <"true"|"false"> |
Set to true if ipv6 is needed for unbound (not required in most use-cases) |
Example .env file in the same directory as your docker-compose.yaml file:
TZ=America/Los_Angeles
FTLCONF_webserver_api_password=QWERTY123456asdfASDF
FTLCONF_dns_revServers=true,192.168.0.0/16,192.168.1.1,local
HOSTNAME=pihole
DOMAIN_NAME=pihole.local
Portainer stacks are a little weird and don't want you to declare your named volumes, so remove this block from the top of the docker-compose.yaml file before copy/pasting into Portainer's stack editor:
volumes:
etc_pihole-unbound:
etc_pihole_dnsmasq-unbound:docker-compose up -dIf using Portainer, just paste the
docker-compose.yamlcontents into the stack config and add your environment variables directly in the UI.
There is also a variant of docker-pihole-unbound that works with separate containers
docker-compose.yml
version: '2'
services:
pihole:
container_name: pihole
# Check https://github.com/pi-hole/docker-pi-hole/releases
# to see if there is a newer version than the one tagged here and use that.
# Using 'latest' as a tag is at your own risk regarding "breaking changes".
image: pihole/pihole:latest
hostname: ${HOSTNAME}
domainname: ${DOMAIN_NAME}
ports:
- 53:53/tcp # DNS
- 53:53/udp # DNS
- 80:80/tcp # HTTP
- 443:443/tcp # HTTPS
environment:
- TZ=${TZ}
- FTLCONF_webserver_api_password=${FTLCONF_webserver_api_password}
- FTLCONF_dns_revServers=${FTLCONF_dns_revServers}
- FTLCONF_dns_upstreams=unbound#5335 # Hardcoded to our Unbound server
- FTLCONF_dns_dnssec=true # Enable DNSSEC
volumes:
- etc_pihole:/etc/pihole:rw
- etc_pihole_dnsmasq:/etc/dnsmasq.d:rw
networks:
- pihole-unbound
restart: unless-stopped
depends_on:
- unbound
unbound:
container_name: unbound
image: alpinelinux/unbound:latest
networks:
- pihole-unbound
restart: unless-stopped
post_start:
- command: |
sh -c "cat > /etc/unbound/unbound.conf << EOF
server:
verbosity: 0
interface: 0.0.0.0
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
do-ip6: no
prefer-ip6: no
harden-glue: yes
harden-dnssec-stripped: yes
use-caps-for-id: no
edns-buffer-size: 1232
prefetch: yes
num-threads: $(nproc 2>/dev/null || echo 1)
private-address: 192.168.0.0/16
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 10.0.0.0/8
private-address: fd00::/8
private-address: fe80::/10
access-control: 10.0.0.0/8 allow
access-control: 127.0.0.0/8 allow
access-control: 172.16.0.0/12 allow
access-control: 192.168.0.0/16 allow
access-control: fd00::/8 allow
access-control: fe80::/10 allow
access-control: ::1/128 allow
EOF
until kill -HUP $(pidof unbound) >/dev/null 2>&1; do
sleep 1
done"
healthcheck:
interval: 30s
timeout: 10s
retries: 3
test: >
CMD nslookup one.one.one.one 127.0.0.1:5335 >/dev/null 2>&1 || \
nslookup dns.google 127.0.0.1:5335 >/dev/null 2>&1 || \
exit 1
networks:
pihole-unbound:
volumes:
etc_pihole:
etc_pihole_dnsmasq:The variant with the docker-compose.yml example there is a 2-container solution, which is also shown on the pihole discourse forum with the type and white connection between the containers (without manual IP's between the containers) declared has also been confirmed.