Skip to main content

Run Pi-hole as Docker Swarm Stack

·487 words·3 mins·

Intro #

Many of you already know Pi-hole as a trusted DNS firewall solution in your home labs. But what if your home lab should just provide containerized services? - I know, running Pi-hole as a container isn’t new. In fact, the developer community already provides official images.

In this post I want to show you why you should run Pi-hole (or even every container) in a docker swarm configuration as a defined stack.

So let’s begin with some worts about the Docker Swarm Mode.

What’s Docker Swarm Mode ? #

Docker Swarm Mode takes simply multiple Docker engines and creates a cluster. On these docker nodes you can then run containers defined in a stack files. These stacks are written in the same format as docker-compose.yml files. After deploying the stack the engine takes care about the deployment on suitable nodes.

I think the best feature is that you can update your stacks and its container services. This makes updating your containers much easier whenever there is a new image version available. Without this feature you needed to stop and restart your containers with docker-compose.

Don’t expect to get a fully featured cluster management for container environments like Kubernetes with Docker Swarm Mode. You still need to take care about key element by yourself. For example how to and how to sync volumes and make them available on all nodes. On the other hand, Kubernetes isn’t always needed and comes not only with mor features - It also requires ab better knowledge about the underlying techniques and faces you with much more challenges.

Pi-hole Stack #

I use traefik on my docker swarm clusters as reverse proxy. Like every reverse proxy traefik handles the request and routes it to to the target service. It terminates the https traffic and manages the certificates. You could also use something else like Nginx Proxy Manager. Just keep in mind, that the listed service labels are required for traefik to perform its dynamic config.

version: '3.8'

# More info at and
    image: pihole/pihole:2022.01.1
      - target: 53
        published: 53
        protocol: tcp
        mode: host
      - target: 53
        published: 53
        protocol: udp
        mode: host
      - target: 67
        published: 67
        protocol: udp
        mode: host
      TZ: 'Europe/Berlin'
      WEBPASSWORD: 'foobar2000'
    # Volumes store your data between container upgrades
      - /nfs-share/pihole/volumes/pihole-data:/etc/pihole/
      - /nfs-share/pihole/volumes/pihole-dnsmasq:/etc/dnsmasq.d/

    # Recommended but not required (DHCP needs NET_ADMIN)
    #  - NET_ADMIN
      - pihole
      - traefik-public
      replicas: 1
        - 'traefik.enable=true'
        - ''
        - 'traefik.http.routers.pihole.rule=Host(``)'
        - 'traefik.http.routers.pihole.tls=true'
        - 'traefik.http.routers.pihole.tls.certresolver=myresolver'
        - ''

    external: true

The special part here is the port config. Normally you would use this syntax to publish ports:

  - '53:53/tcp'
  - '53:53/udp'
  - '67:67/udp'
  - '8080:80/tcp'

But this publishes the ports on the ingress / overlay network and causes pihole to show only the service ip on the connected clients list. So we have to use the long format with the mode set to host. This of cause does only work if there is no other process already using the listed ports.

Additionally you have to set Permit all origins option under Settings -> DNS tab -> Interface settings.

That’s it. Now you’re running Pi-hole as a docker swarm service as DNS Server. You can now start defining your Pi-hole groups and filter the clients.