# docker-pi-hole: the official container image for a network-wide DNS sinkhole

> The pi-hole project's own Docker packaging, built around FTL and dnsmasq, with a compose file that reveals most of the decisions you have to make on day one.

**pi-hole/docker-pi-hole** — The official Pi-hole Docker image from pi-hole.net

- Repository: https://github.com/pi-hole/docker-pi-hole
- Website: https://pi-hole.net
- Stars: 11,665 · Forks: 1,245
- Language: Shell
- License: NOASSERTION
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/pi-hole-docker-pi-hole

## What this repository wraps and what it delegates

docker-pi-hole is the container packaging maintained by the Pi-hole project itself, not a community image. The GitHub description says so in one line: the official Pi-hole Docker image from pi-hole.net. The language is Shell and the tree is small, with `src/`, `test/`, `examples/`, `build.sh`, a `CHANGELOG.md`, and a `LICENSE`.

The division of labor is worth spelling out because it explains what you will and will not find here. The actual DNS engine lives in pi-hole/FTL, the web interface lives in pi-hole/web, and the blocklists are maintained by the project and updated inside the container. This repository builds an image that contains those pieces and gets the wiring right: which ports to expose, which Linux capabilities the process needs, which configuration is injected through environment variables, and how data survives a container replacement.

The release notes make the boundary visible. The 2026.09.0 tag, published 2026-09-19, lists nothing under changes specific to Docker and states plainly that it is tagging to include FTL v6.7.1. That tag exists because of security fixes shipped in FTL: remote code execution and arbitrary file read through `webserver.advancedOpts`, remote code execution through exec-capable options in `misc.dnsmasq_lines`, and configuration validators that can be bypassed through the Teleporter import combined with document-root relocation. So the practical takeaway is that upgrading this image is how you get FTL security patches, and the release notes are where you confirm a given tag carries them.

## Reading the compose file as the real documentation

The quick start asks you to copy a compose file and edit it, which means the configuration decisions and the container declaration arrive together. The service block looks like this:

```yml
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
```

DNS on port 53 is exposed on both protocols because modern resolvers use DNS over TCP for large answers and zone transfers, and a UDP-only mapping silently breaks those. Port 80 serves the admin interface, and port 443 is included with a comment explaining that FTL generates a self-signed certificate for it. Two further ports are present but commented out: 67 for DHCP and 123 for NTP. Both are there because the container can serve those roles if you ask it to, and both are commented out because they conflict with whatever else on your network already owns them.

The environment block is where the important choice sits:

```yml
environment:
  TZ: 'Europe/London'
  FTLCONF_webserver_api_password: 'correct horse battery staple'
  FTLCONF_dns_listeningMode: 'ALL'
```

Every FTL setting is reachable as an environment variable prefixed with `FTLCONF_`, which means configuration is versioned in the same file as the service rather than in a separate YAML inside a volume. The password line carries a warning that leaving it unset results in a random password being assigned, and the listening mode line carries the one piece of advice that is genuinely non-optional: if you use Docker's default `bridge` network setting, this must be `ALL`.

That last point is the most common failure in this project, and the reason is architectural rather than a bug. Docker's bridge network gives the container its own network namespace, so a process bound to the container's own loopback interface is unreachable from the host or the LAN. Setting `ALL` makes FTL bind every interface, which is what allows clients on your network to reach it. On a macvlan or host network arrangement the default may already be correct, so the setting depends on your network mode rather than on Pi-hole itself.

## Capabilities instead of privileged mode

The compose file uses `cap_add` rather than `privileged`, and the README goes out of its way to make that point. A note near the top reports that users have had issues with the `--privileged` flag on 2022.04 and above, and the advice is not to use that mode, instead being explicit about the capabilities actually needed.

The list is three entries, each with a reason attached:

```yml
cap_add:
  - NET_ADMIN
  - SYS_TIME
  - SYS_NICE
```

`NET_ADMIN` is required only if Pi-hole is acting as your DHCP server. `SYS_TIME` is required if it is acting as an NTP client, so the host's clock can be set from outside. `SYS_NICE` is optional and grants additional processing time. That is a much smaller grant than privileged mode, which hands the container the full Linux capability set and largely removes the isolation that containers exist for.

The broader point about capability grants applies to any container serving DNS, not only to this image. A process that can write firewall rules or set the clock should not hold capabilities it does not need for the job. The compose file models that by keeping the privileged-looking approach out and letting you add capabilities conditionally, which is why the DHCP capability comment tells you to drop it if you are not running DHCP.

## Persistence, migration from v5, and list updates

Two volumes-related decisions matter more than the rest. The first is the database and configuration mount:

```yml
volumes:
  - './etc-pihole:/etc/pihole'
```

Without this, every container re-creation throws away your blocklists, settings, and query history, because the image carries defaults only. The README notes that volumes are recommended for persisting data across container re-creations when updating images, and that a second mount for custom dnsmasq configuration files is available but commented out.

The commented dnsmasq mount is new and it catches people upgrading. The comment explains the two cases: it is not needed for most people starting fresh with Pi-hole v6, but if you are upgrading from v5 and previously used that directory, keep it enabled for the first v6 container start so the migration can complete, then remove it. That is a one-time instruction buried in a YAML comment, and it is the kind of detail that causes a broken blocklist if missed.

The second thing the container handles for you is list updates. `cron` is baked into the image and pulls the newest blocklists and flushes logs once a week in the small hours of Sunday morning. So there is no external cron to wire up, and no reason to reach for a sidecar container just to refresh lists.

## Date-based tags and what the release history looks like

The versioning scheme needs reading twice, because it is deliberate. The README explains that the date-based tags, including incremented patch versions, do not relate to any semantic version number. A date is used only to differentiate a new image from the old one, nothing more. That rules out treating `2026.09.0` as a semantic version to compare against anything.

Four tags are documented. `latest` always points at the newest release. A date tag such as `2026.09.0` identifies one specific build. `nightly` is built whenever the `development` branch changes and also by a scheduled nightly job, and the README describes those images as the most experimental, liable to change frequently. Full tag listings live on Docker Hub, and the GitHub release notes tell you which versions of Pi-hole Core, Web, and FTL a given image contains, which is the thing to check before upgrading.

The recent release history shows both the strengths and the friction of this arrangement. The 2026.07.1 tag restored the `--no-cache` flag for apk. The 2026.07.2 tag, published 2026-07-07, shipped a single missing commit moving a logrotate file to `/etc/logrotate.d/pihole`, described as the Docker equivalent of a fix for a security advisory in pi-hole itself. Both are tiny changes to plumbing around the real application. Expect date tags to move for reasons that have nothing to do with ad blocking, which is exactly why pinning one matters. The repository is not archived and the last push was on 2026-09-20.

## Where to look after the README runs out

The README links five documentation pages on docs.pi-hole.net, and the split between them and the repository tells you where a given question belongs. Running DHCP from a container is its own page, because the port conflict with an existing DHCP server is the most common way this setup fails. Configuration, Tips and Tricks, Docker tags and versioning, and Upgrading, Persistence, and Customizations each cover one axis of the compose file.

The examples directory holds two files that hint at a use case the README does not spell out: a `Caddyfile` and a `docker-compose-caddy-proxy.yml`. Together they point toward putting a reverse proxy with real certificates in front of the admin interface, rather than relying on the self-signed one FTL generates on port 443. That is a sensible move for anything reachable beyond your LAN.

Issue routing is also documented, and the split is sensible. The README asks you to report on the GitHub project when you suspect something is Docker-specific, and to take Pi-hole or general Docker questions to the user forums instead. One warning is worth repeating because it affects upgrades rather than setup: if you use Watchtower, the note at the top of the README redirects you to a Watchtower section in the documentation, which exists because automatic image replacement and a stateful DNS server interact badly when the replacement is not planned.

## Conclusion

This repository is a packaging project, and it is a good one: the compose file in the README is effectively the documentation, since it forces you to decide about listening mode, capabilities, timeouts, and persistence in the same place you declare the container. Its job ends where the actual blocking begins, which lives in pi-hole/FTL and pi-hole/web, and the release notes say so in as many words when a tag exists only to carry a new FTL build. The two things to settle before deploying are the `FTLCONF_dns_listeningMode` value, which must be `ALL` on a Docker bridge network, and whether you want the DHCP and NTP ports at all. Pin a date-based tag such as `2026.09.0` rather than `latest`, keep the `./etc-pihole` volume, and treat `nightly` as a testing channel.

## FAQ

### Is Pi-hole still relevant in 2026?

The project is shipping. Version 2026.09.0 was published on 2026-09-19 to carry FTL v6.7.1 and its security fixes, and the last push to this repository was on 2026-09-20. Blocking has also moved toward DNS encrypted resolvers on both ends, so the practical question is whether every client on your network is configured to use your resolver at all, rather than whether the software still works.

### Are pi holes illegal?

The repository documents nothing about legality, and it is worth separating that from what the software does. Pi-hole is a DNS server you run on your own hardware, filtering queries from clients that choose to send them to it. Blocking a request at your own resolver is a local configuration choice; anything that affects clients you do not own is a different situation, and the README does not speak to it.

### Should I use the latest tag or a pinned date tag?

Pin a date tag such as `2026.09.0` if you care about knowing which FTL, Web, and Core versions you are running, since the release notes list those per tag. The `latest` tag always tracks the newest release, and `nightly` is described in the README as the most experimental images, built from the development branch. Date tags are not semantic versions, so compare them through the release notes rather than by version arithmetic.

## Sources

- [Issues](https://github.com/pi-hole/docker-pi-hole/issues)
- [pi-hole/docker-pi-hole on GitHub](https://github.com/pi-hole/docker-pi-hole)
- [Project website](https://pi-hole.net)
- [README](https://github.com/pi-hole/docker-pi-hole/blob/master/README.md)
- [Releases](https://github.com/pi-hole/docker-pi-hole/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pi-hole-docker-pi-hole
