Loading .env.default +15 −0 Original line number Diff line number Diff line Loading @@ -80,3 +80,18 @@ WATCHTOWER_IMAGE_VERSION= WATCHTOWER_ROLLING_RESTART= WATCHTOWER_SCHEDULE= WORDPRESS_IMAGE_VERSION= PIHOLE_DNS1= PIHOLE_DNS2= PIHOLE_DNSMASQ_LISTENING= PIHOLE_HOSTNAME= PIHOLE_IMAGE_VERSION= PIHOLE_REV_SERVER= PIHOLE_REV_SERVER_CIDR= PIHOLE_REV_SERVER_DOMAIN= PIHOLE_REV_SERVER_TARGET= PIHOLE_V4_ADDRESS= PIHOLE_V6_ADDRESS= PIHOLE_WEBPASSWORD= TRAEFIK_DNS_ENTRYPOINT= docker-compose.yml +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ include: - path: 'nginx/docker-compose.nginx.yml' - path: 'pastebin/docker-compose.pastebin.yml' - path: 'peertube/docker-compose.peertube.yml' - path: 'pihole/docker-compose.pihole.yml' - path: 'portainer/docker-compose.portainer.yml' - path: 'remotely/docker-compose.remotely.yml' - path: 'rocketchat/docker-compose.rocket-chat.yml' Loading pihole/.gitignore 0 → 100644 +3 −0 Original line number Diff line number Diff line etc-pihole/ etc-dnsmasq.d/ logs/ pihole/README.md 0 → 100644 +106 −0 Original line number Diff line number Diff line # Pi-hole [Pi-hole](https://pi-hole.net/) is a network-wide DNS sinkhole that blocks ads and trackers for every device on your network. This service definition deploys Pi-hole behind Traefik so the admin interface is available securely at `https://pihole.${SITE}` while DNS requests continue to be served directly on port 53. ## Volumes - `./etc-pihole` → `/etc/pihole` (gravity database, lists, custom configs) - `./etc-dnsmasq.d` → `/etc/dnsmasq.d` (dnsmasq overrides, DHCP config) - `./logs` → `/var/log/lighttpd` (web UI access/error logs) Back up these folders before upgrading or recreating the container to retain settings, blocklists, and DHCP leases. ## Environment variables | Variable | Default | Description | | --- | --- | --- | | `PIHOLE_IMAGE_VERSION` | `2024.05.0` | Pi-hole Docker image tag | | `PIHOLE_WEBPASSWORD` | `changeme` | Admin UI password; override in `.env` | | `PIHOLE_V4_ADDRESS` | `0.0.0.0` | IP address Pi-hole advertises to clients | | `PIHOLE_V6_ADDRESS` | `::` | IPv6 address Pi-hole advertises | | `PIHOLE_HOSTNAME` | `pihole` | Hostname shown in the UI and DHCP replies | | `PIHOLE_DNS1` | `1.1.1.1` | Primary upstream DNS | | `PIHOLE_DNS2` | `1.0.0.1` | Secondary upstream DNS | | `PIHOLE_DNSMASQ_LISTENING` | `all` | dnsmasq listening mode (`local`, `all`) | | `PIHOLE_REV_SERVER` | `false` | Enable conditional forwarding | | `PIHOLE_REV_SERVER_TARGET` | `192.168.0.1` | Router/DNS to forward PTR queries | | `PIHOLE_REV_SERVER_DOMAIN` | `lan` | Local domain for reverse lookups | | `PIHOLE_REV_SERVER_CIDR` | `192.168.0.0/24` | Subnet for reverse lookups | | `SITE` | `localhost` | Used to build the admin UI host `pihole.${SITE}` | | `TZ` | `Europe/Paris` | Container timezone | | `TRAEFIK_DNS_ENTRYPOINT` | `53` | Port that Traefik exposes for DNS (defined in the Traefik service) | The DNS port exposed to your network is now configured globally via `TRAEFIK_DNS_ENTRYPOINT` and defaults to 53. Update `.env` (copied from `.env.default`) with secure values, especially `PIHOLE_WEBPASSWORD`. ## DNS port requirements Traefik now terminates all DNS traffic for Pi-hole. It binds both TCP and UDP port 53 by default (configurable via `TRAEFIK_DNS_ENTRYPOINT`) and proxies the traffic to the Pi-hole container over the internal `srv` network. Make sure the host resolver (`systemd-resolved`, dnsmasq, etc.) is disabled or moved away from that port before starting Traefik, otherwise Traefik cannot bind to it. 1. Disable the built-in resolver (for example `sudo systemctl disable --now systemd-resolved` on Ubuntu) and restart Docker so the ports are freed. 2. If you must keep another resolver running locally, set `TRAEFIK_DNS_ENTRYPOINT` in `.env` to an alternate port and point every DNS client to that same port on the Traefik host. ## Traefik integration - The compose file registers Pi-hole with Traefik using the shared `srv` network. - The router `pihole` matches `Host(`pihole.${SITE}`)` and explicitly targets the `websecure` entrypoint so TLS is always negotiated. - The DNS routers `pihole-dns` bind to the `dns-tcp` and `dns-udp` entrypoints so Traefik proxies raw DNS queries on port 53 to the container without exposing any Pi-hole ports. - Certificates are handled by Traefik via the globally configured ACME resolver. The admin UI relies on Pi-hole’s own `WEBPASSWORD`. If you want an additional basic-auth prompt, add the standard middleware labels from the `traefik` service (or create a dedicated middleware in `dynamic_conf/`) before exposing the route. ## DNS configuration steps 1. Deploy the service: `SITE=example.com docker-compose up -d pihole` (or run the global helper to start every service). 2. Point your network clients (router DHCP option or manual DNS setting) to the host running Traefik on port `${TRAEFIK_DNS_ENTRYPOINT:-53}`. 3. Access `https://pihole.${SITE}` to finish the web-based setup and verify that queries are being processed. ### Optional DHCP support If you want Pi-hole to serve DHCP, you still need to grant it `NET_ADMIN` and expose UDP/67 directly (Traefik does not proxy DHCP). Create an override such as: ```yml services: pihole: cap_add: - NET_ADMIN ports: - '67:67/udp' ``` This reintroduces a host port mapping, so only enable it if no other DHCP server is active on your LAN and you understand the exposure. ## Maintenance - Update Pi-hole with `docker-compose pull pihole && docker-compose up -d pihole`. - Review logs in `pihole/logs/` or via the web UI if troubleshooting. - Export blocklists or settings regularly from the admin UI in addition to filesystem backups. pihole/docker-compose.pihole.yml 0 → 100644 +45 −0 Original line number Diff line number Diff line services: pihole: image: 'pihole/pihole:${PIHOLE_IMAGE_VERSION:-2025.11.1}' environment: DNS1: '${PIHOLE_DNS1:-1.1.1.1}' DNS2: '${PIHOLE_DNS2:-1.0.0.1}' DNSMASQ_LISTENING: '${PIHOLE_DNSMASQ_LISTENING:-all}' FTLCONF_REPLY_ADDR4: '${PIHOLE_V4_ADDRESS:-0.0.0.0}' FTLCONF_REPLY_ADDR6: '${PIHOLE_V6_ADDRESS:-::}' HOSTNAME: '${PIHOLE_HOSTNAME:-pihole}' REV_SERVER: '${PIHOLE_REV_SERVER:-false}' REV_SERVER_CIDR: '${PIHOLE_REV_SERVER_CIDR:-192.168.0.0/24}' REV_SERVER_DOMAIN: '${PIHOLE_REV_SERVER_DOMAIN:-lan}' REV_SERVER_TARGET: '${PIHOLE_REV_SERVER_TARGET:-192.168.0.1}' TZ: '${TZ:-Europe/Paris}' VIRTUAL_HOST: 'pihole.${SITE:-localhost}' WEBPASSWORD: '${USERS}' healthcheck: test: - 'CMD' - 'dig' - '+time=1' - '+tries=1' - '@127.0.0.1' - 'pi-hole.net' labels: traefik.enable: true traefik.http.routers.pihole.entrypoints: 'websecure' traefik.http.routers.pihole.rule: 'Host(`pihole.${SITE:-localhost}`)' traefik.http.routers.pihole.tls: true traefik.http.services.pihole.loadbalancer.server.port: 80 traefik.tcp.routers.pihole-dns.entrypoints: 'dns-tcp' traefik.tcp.routers.pihole-dns.rule: 'HostSNI(`*`)' traefik.tcp.routers.pihole-dns.service: 'pihole-dns' traefik.tcp.services.pihole-dns.loadbalancer.server.port: 53 traefik.udp.routers.pihole-dns.entrypoints: 'dns-udp' traefik.udp.routers.pihole-dns.service: 'pihole-dns' traefik.udp.services.pihole-dns.loadbalancer.server.port: 53 networks: - 'srv' restart: 'always' volumes: - './etc-pihole:/etc/pihole' - './etc-dnsmasq.d:/etc/dnsmasq.d' - './logs:/var/log/lighttpd' Loading
.env.default +15 −0 Original line number Diff line number Diff line Loading @@ -80,3 +80,18 @@ WATCHTOWER_IMAGE_VERSION= WATCHTOWER_ROLLING_RESTART= WATCHTOWER_SCHEDULE= WORDPRESS_IMAGE_VERSION= PIHOLE_DNS1= PIHOLE_DNS2= PIHOLE_DNSMASQ_LISTENING= PIHOLE_HOSTNAME= PIHOLE_IMAGE_VERSION= PIHOLE_REV_SERVER= PIHOLE_REV_SERVER_CIDR= PIHOLE_REV_SERVER_DOMAIN= PIHOLE_REV_SERVER_TARGET= PIHOLE_V4_ADDRESS= PIHOLE_V6_ADDRESS= PIHOLE_WEBPASSWORD= TRAEFIK_DNS_ENTRYPOINT=
docker-compose.yml +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ include: - path: 'nginx/docker-compose.nginx.yml' - path: 'pastebin/docker-compose.pastebin.yml' - path: 'peertube/docker-compose.peertube.yml' - path: 'pihole/docker-compose.pihole.yml' - path: 'portainer/docker-compose.portainer.yml' - path: 'remotely/docker-compose.remotely.yml' - path: 'rocketchat/docker-compose.rocket-chat.yml' Loading
pihole/.gitignore 0 → 100644 +3 −0 Original line number Diff line number Diff line etc-pihole/ etc-dnsmasq.d/ logs/
pihole/README.md 0 → 100644 +106 −0 Original line number Diff line number Diff line # Pi-hole [Pi-hole](https://pi-hole.net/) is a network-wide DNS sinkhole that blocks ads and trackers for every device on your network. This service definition deploys Pi-hole behind Traefik so the admin interface is available securely at `https://pihole.${SITE}` while DNS requests continue to be served directly on port 53. ## Volumes - `./etc-pihole` → `/etc/pihole` (gravity database, lists, custom configs) - `./etc-dnsmasq.d` → `/etc/dnsmasq.d` (dnsmasq overrides, DHCP config) - `./logs` → `/var/log/lighttpd` (web UI access/error logs) Back up these folders before upgrading or recreating the container to retain settings, blocklists, and DHCP leases. ## Environment variables | Variable | Default | Description | | --- | --- | --- | | `PIHOLE_IMAGE_VERSION` | `2024.05.0` | Pi-hole Docker image tag | | `PIHOLE_WEBPASSWORD` | `changeme` | Admin UI password; override in `.env` | | `PIHOLE_V4_ADDRESS` | `0.0.0.0` | IP address Pi-hole advertises to clients | | `PIHOLE_V6_ADDRESS` | `::` | IPv6 address Pi-hole advertises | | `PIHOLE_HOSTNAME` | `pihole` | Hostname shown in the UI and DHCP replies | | `PIHOLE_DNS1` | `1.1.1.1` | Primary upstream DNS | | `PIHOLE_DNS2` | `1.0.0.1` | Secondary upstream DNS | | `PIHOLE_DNSMASQ_LISTENING` | `all` | dnsmasq listening mode (`local`, `all`) | | `PIHOLE_REV_SERVER` | `false` | Enable conditional forwarding | | `PIHOLE_REV_SERVER_TARGET` | `192.168.0.1` | Router/DNS to forward PTR queries | | `PIHOLE_REV_SERVER_DOMAIN` | `lan` | Local domain for reverse lookups | | `PIHOLE_REV_SERVER_CIDR` | `192.168.0.0/24` | Subnet for reverse lookups | | `SITE` | `localhost` | Used to build the admin UI host `pihole.${SITE}` | | `TZ` | `Europe/Paris` | Container timezone | | `TRAEFIK_DNS_ENTRYPOINT` | `53` | Port that Traefik exposes for DNS (defined in the Traefik service) | The DNS port exposed to your network is now configured globally via `TRAEFIK_DNS_ENTRYPOINT` and defaults to 53. Update `.env` (copied from `.env.default`) with secure values, especially `PIHOLE_WEBPASSWORD`. ## DNS port requirements Traefik now terminates all DNS traffic for Pi-hole. It binds both TCP and UDP port 53 by default (configurable via `TRAEFIK_DNS_ENTRYPOINT`) and proxies the traffic to the Pi-hole container over the internal `srv` network. Make sure the host resolver (`systemd-resolved`, dnsmasq, etc.) is disabled or moved away from that port before starting Traefik, otherwise Traefik cannot bind to it. 1. Disable the built-in resolver (for example `sudo systemctl disable --now systemd-resolved` on Ubuntu) and restart Docker so the ports are freed. 2. If you must keep another resolver running locally, set `TRAEFIK_DNS_ENTRYPOINT` in `.env` to an alternate port and point every DNS client to that same port on the Traefik host. ## Traefik integration - The compose file registers Pi-hole with Traefik using the shared `srv` network. - The router `pihole` matches `Host(`pihole.${SITE}`)` and explicitly targets the `websecure` entrypoint so TLS is always negotiated. - The DNS routers `pihole-dns` bind to the `dns-tcp` and `dns-udp` entrypoints so Traefik proxies raw DNS queries on port 53 to the container without exposing any Pi-hole ports. - Certificates are handled by Traefik via the globally configured ACME resolver. The admin UI relies on Pi-hole’s own `WEBPASSWORD`. If you want an additional basic-auth prompt, add the standard middleware labels from the `traefik` service (or create a dedicated middleware in `dynamic_conf/`) before exposing the route. ## DNS configuration steps 1. Deploy the service: `SITE=example.com docker-compose up -d pihole` (or run the global helper to start every service). 2. Point your network clients (router DHCP option or manual DNS setting) to the host running Traefik on port `${TRAEFIK_DNS_ENTRYPOINT:-53}`. 3. Access `https://pihole.${SITE}` to finish the web-based setup and verify that queries are being processed. ### Optional DHCP support If you want Pi-hole to serve DHCP, you still need to grant it `NET_ADMIN` and expose UDP/67 directly (Traefik does not proxy DHCP). Create an override such as: ```yml services: pihole: cap_add: - NET_ADMIN ports: - '67:67/udp' ``` This reintroduces a host port mapping, so only enable it if no other DHCP server is active on your LAN and you understand the exposure. ## Maintenance - Update Pi-hole with `docker-compose pull pihole && docker-compose up -d pihole`. - Review logs in `pihole/logs/` or via the web UI if troubleshooting. - Export blocklists or settings regularly from the admin UI in addition to filesystem backups.
pihole/docker-compose.pihole.yml 0 → 100644 +45 −0 Original line number Diff line number Diff line services: pihole: image: 'pihole/pihole:${PIHOLE_IMAGE_VERSION:-2025.11.1}' environment: DNS1: '${PIHOLE_DNS1:-1.1.1.1}' DNS2: '${PIHOLE_DNS2:-1.0.0.1}' DNSMASQ_LISTENING: '${PIHOLE_DNSMASQ_LISTENING:-all}' FTLCONF_REPLY_ADDR4: '${PIHOLE_V4_ADDRESS:-0.0.0.0}' FTLCONF_REPLY_ADDR6: '${PIHOLE_V6_ADDRESS:-::}' HOSTNAME: '${PIHOLE_HOSTNAME:-pihole}' REV_SERVER: '${PIHOLE_REV_SERVER:-false}' REV_SERVER_CIDR: '${PIHOLE_REV_SERVER_CIDR:-192.168.0.0/24}' REV_SERVER_DOMAIN: '${PIHOLE_REV_SERVER_DOMAIN:-lan}' REV_SERVER_TARGET: '${PIHOLE_REV_SERVER_TARGET:-192.168.0.1}' TZ: '${TZ:-Europe/Paris}' VIRTUAL_HOST: 'pihole.${SITE:-localhost}' WEBPASSWORD: '${USERS}' healthcheck: test: - 'CMD' - 'dig' - '+time=1' - '+tries=1' - '@127.0.0.1' - 'pi-hole.net' labels: traefik.enable: true traefik.http.routers.pihole.entrypoints: 'websecure' traefik.http.routers.pihole.rule: 'Host(`pihole.${SITE:-localhost}`)' traefik.http.routers.pihole.tls: true traefik.http.services.pihole.loadbalancer.server.port: 80 traefik.tcp.routers.pihole-dns.entrypoints: 'dns-tcp' traefik.tcp.routers.pihole-dns.rule: 'HostSNI(`*`)' traefik.tcp.routers.pihole-dns.service: 'pihole-dns' traefik.tcp.services.pihole-dns.loadbalancer.server.port: 53 traefik.udp.routers.pihole-dns.entrypoints: 'dns-udp' traefik.udp.routers.pihole-dns.service: 'pihole-dns' traefik.udp.services.pihole-dns.loadbalancer.server.port: 53 networks: - 'srv' restart: 'always' volumes: - './etc-pihole:/etc/pihole' - './etc-dnsmasq.d:/etc/dnsmasq.d' - './logs:/var/log/lighttpd'