How to use Unbound with Docker?

Hello,

I´m trying to use PiHole and Unbound for the first time. I use Ubuntu Server with Docker and Docker-Compose.

I usually cannot start Unbound unless I disable system-resolved but when I do that I have no internet connection so it's either no Unbound or no internet connection.

docker-compose up -d
WARNING: Some networks were defined but are not used by any service: pihole_network
Creating network "unbound_dns" with the default driver
Creating unbound ... 
Creating unbound ... error

ERROR: for unbound  Cannot start service unbound: driver failed programming external connectivity on endpoint unbound (2158f7a9d67344c51301d616f3e1102b582736f87330ccc30ce1b8fbdc18081d): Bind for 0.0.0.0:53 failed: port is already allocated

ERROR: for unbound  Cannot start service unbound: driver failed programming external connectivity on endpoint unbound (2158f7a9d67344c51301d616f3e1102b582736f87330ccc30ce1b8fbdc18081d): Bind for 0.0.0.0:53 failed: port is already allocated
nslookup example.com 192.168.1.82
;; communications error to 192.168.1.82#53: timed out
;; communications error to 192.168.1.82#53: timed out
;; communications error to 192.168.1.82#53: timed out
;; no servers could be reached

https://tricorder.pi-hole.net/5QlfqFD5/

I used this guide for PiHole:
https://github.com/pi-hole/docker-pi-hole/

Unboundś docker-compose.yml:

version: "3"

services:
  unbound:
    container_name: unbound
    image: "mvance/unbound:latest"
    expose:
      - "53"
    networks:
      - dns
    ports:
      - "53:53/tcp"
      - "53:53/udp"
    volumes:
      - "/data/unbound/my_conf/forward-records.conf:/opt/unbound/etc/unbound/forward-records.conf"
      - "/data/unbound/my_conf/a-records.conf:/opt/unbound/etc/unbound/a-records.conf"
    restart: unless-stopped

networks:
  dns:
  pihole_network:
    external: true

PiHoleś docker-compose.yml:

version: "3"

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      # DNS Ports
      - "53:53/tcp"
      - "53:53/udp"
      # Default HTTP Port
      - "80:80/tcp"
      # Default HTTPs Port. FTL will generate a self-signed certificate
      - "443:443/tcp"
      # Uncomment the line below if you are using Pi-hole as your DHCP server
      #- "67:67/udp"
      # Uncomment the line below if you are using Pi-hole as your NTP server
      #- "123:123/udp"
    environment:
      # Set the appropriate timezone for your location (https://en.wikipedia.org/wiki/List_of_tz_database_t>
      TZ: 'Europe/Oslo'
      # Set a password to access the web interface. Not setting one will result in a random password being >
      FTLCONF_webserver_api_password: 'temptemp'
      # If using Docker's default `bridge` network setting the dns listening mode should be set to 'all'
      FTLCONF_dns_listeningMode: 'all'
    # Volumes store your data between container upgrades
    volumes:
      # For persisting Pi-hole's databases and common configuration file
      - './etc-pihole:/etc/pihole'
      # Uncomment the below if you have custom dnsmasq config files that you want to persist. Not needed fo>
      #- './etc-dnsmasq.d:/etc/dnsmasq.d'
    cap_add:
      # See https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
      # Required if you are using Pi-hole as your DHCP server, else not needed
      - NET_ADMIN
      # Required if you are using Pi-hole as your NTP client to be able to set the host's system time
      - SYS_TIME
      # Optional, if Pi-hole should get some more processing time
      - SYS_NICE
    restart: unless-stopped

networks:
  pihole_network:
    external: true

Can anyone point me in the right direction? I've been trying for 4 hours now and I have no idea what Iḿ actually doing.

Thank you,
Simon

Edit:
Probably also good to know:
DNSStubListener is set to no.

Tried disabling systemd-resolved too and removing the symlink to /etc/resolv.conf and creating a new /etc/resolv.conf too but it didn´t solve it.

Iḿ willing to reinstall Ubuntu if needed.

Your issue is with unbound's container, not with Pi-hole.

You have to move unbound to another port, or not publish its port 53 at all.

Port 53 is required by Pi-hole, as your clients will need to send their DNS requests to Pi-hole. unbound will only be used by Pi-hole.

In addition, you could consider to combine your Pi-hole and unbound compose files into one, perhaps also containing your actual pihole_network definition.

You should also be aware that mvance/unbound image is not configuring unbound as a recursive resolver:

By default, this image forwards queries Cloudflare DNS server over TLS. In other words, it does not act as a recursive server.

If you'd want a recursive resolver, you probably need to find a different unbound image.

Okay, thanks for your reply.

Iĺl use another port, thank you very much for pointing that out.

And I thought 2 different Docker Compose files was the way to go so I haven´t even tried putting the two programs into one .yml file. Iĺl try that as well.

And as far as I know the mvance/unbound is the only available Docker image for Unbound so Iĺl have to use that and make a custom configuration file, I think.

Iḿ going to try again, thanks so far!

Error: error sending query: Could not send or receive, because of network error.

So the Docker container is unhealthy and stuff like dig times out and says no serves could be reached.

I don’t know, I’m out of my depth. Set or even disabled the firewall, both programs use the same Docker network. I think the configuration file for Unbound is okay too. Also used the standard one.

I always recommend that services running together should be on the same compose.yaml. I used to run all services on a single file, but you can split it if it doesn't depend on something else.

Unbound is upstream of Pihole when configured, as in, only Pihole needs to communicate with Unbound. In bridge networking mode, that means you do not need to, nor should you, bind ports from the Unbound container to the host machine. The problem is this:

    ports:
      - "53:53/tcp"
      - "53:53/udp"

You're binding port 53 on the host to port 53 in the container. You already configured that for Pihole's container, and you set Unbound as that originally. Again, no ports need to be bound for Unbound to work in this context.

If using docker network inspect pihole_network indicates that the network is not in bridge mode, then you're using macvlan or host mode. Host mode makes most of the security benefits of containerization useless, and it can cause problems, such as two services originally wanting to use the same port.

The likely solution you need is to just remove the port binding in Unbound's container.

Thanks. I had already changed the ports but I hadn’t tried removing them entirely.

The network is bridge. Removing the ports from the docker-compose.yml did not fix the issue unfortunately. Still no internet connection, time outs when testing, an unhealthy Docker container and still the same error message when inspecting the docker container.

Please share your current docker compose file.

Okay so the health of the Docker container has nothing to do with the ports listed in the Docker-Compose file, thatś all about the ports used in the Unbound configuration file.

Current docker-compose.yml:

services:
  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
    volumes:
      - ./unbound/db:/var/lib/unbound               
      - type: bind
        read_only: true
        source: ./my_conf/unbound.conf
        target: /opt/unbound/etc/unbound/unbound.conf
    networks:
      - pihole_network

networks:
  pihole_network:
    external: true

In the Unbound configuration file I keep messing around with:

interface: 127.0.0.1@53
port: 8053

Didn't you combine your compose files yet?

That compose file only has unbound.
What about Pi-hole?

Well I can do that but it's not the most fun job in the world without a GUI, haha.

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
 #   networks:
 #     - pihole_network
    ports:
      # DNS Ports
      - "53:53/tcp"
      - "53:53/udp"
      # Default HTTP Port
      - "80:80/tcp"
      # Default HTTPs Port. FTL will generate a self-signed certificate
      - "443:443/tcp"
      # Uncomment the line below if you are using Pi-hole as your DHCP server
      #- "67:67/udp"
      # Uncomment the line below if you are using Pi-hole as your NTP server
      #- "123:123/udp"
    environment:
      TZ: 'Europe/Oslo'
      FTLCONF_webserver_api_password: 'temptemp'
      # If using Docker's default `bridge` network setting the dns listening mode should be set to 'all'
      FTLCONF_dns_listeningMode: 'all'
    volumes:
      # For persisting Pi-hole's databases and common configuration file
      - './etc-pihole:/etc/pihole'
    restart: unless-stopped

  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
#    ports:
#      - "8053:53/tcp"   # For DNS queries over TCP
#      - "8053:53/udp"   # For DNS queries over UDP
    volumes:
      - ./unbound/db:/var/lib/unbound                  # Database for caching
#      - ./unbound/conf:/opt/unbound/etc/unbound       # Configuration files
      - type: bind
        read_only: true
        source: ./my_conf/unbound.conf
        target: /opt/unbound/etc/unbound/unbound.conf
#    networks:
#      - pihole_network

#networks:
#  pihole_network:
#    external: true

That shows you've dropped your pihole_network now, which would prompt Docker to use its default bridge.

You didn't set FTLCONF_dns_upstreams for your Pi-hole container.
How did you configure Pi-hole to use unbound as its only upstream ?

1 Like

Yeah, figured I'd test with the most basic setup.

And via the web interface:

127.0.0.1 is the loopback address, pointing back to a machine itself.
In case of a dockered Pi-hole, that's the Pi-hole container itself, where nothing is listening on port 8053.

You need to point Pi-hole to your unbound container's IP address, which can be unbound's Docker internal IP.
If you are using that, Pi-hole can talk to your unbound container on port 53, where your unbound is listening, without requiring exposure of a remapped port.

You should consider pointing FTLCONF_dns_upstreams in your Pi-hole container's environment section to your unbound container. You can do so by using that container's name, e.g.

FTLCONF_dns_upstreams: 'unbound'

Verify that you didn't configure your unbound installation within the container to listen on different ports, as your previous post may suggest you tried to accomplish:

You want to revert those settings and/or start with a freshly created default unbound container.

Alternatively, as it would seem you are not familiar with Docker at all, you could switch to bare metal installations, which would remove some complexity from your setup.

Okay, thank you, that makes sense.

I'm now testing with FTLCONF_dns_upstreams: 'unbound'.
I have also tested with the IP address of the Docker container.

And I keep changing the interface address en port. From 0.0.0.0 to 127.0.0.1 to the Docker's IP addresses.

I'll stick to port 53 in Unbound's configuration file for now.

And I'm not very familiar with Docker yet, no. But if I don't work with it I'll never be. And I can't be the only person in the world who'd like to combine PiHole and Unbound and who uses Docker so this might benefit other people in the future as well. I've already learned a lot.

I really appreciate your time and patience, by the way, Bucking_Horn. I might be just a n00b who is trying to use a setup no one else uses but your answers have already taught me a lot.

Yep, @Bucking_Horn is very timely and helpful. To give you a bit of context, I'll show you some things.


services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
 #   networks:
 #     - pihole_network
    ports:
      # DNS Ports
      - "53:53/tcp"
      - "53:53/udp"
      # Default HTTP Port
      - "80:80/tcp"
      # Default HTTPs Port. FTL will generate a self-signed certificate
      - "443:443/tcp"
      # Uncomment the line below if you are using Pi-hole as your DHCP server
      #- "67:67/udp"
      # Uncomment the line below if you are using Pi-hole as your NTP server
      #- "123:123/udp"
    environment:
      TZ: 'Europe/Oslo'
      FTLCONF_webserver_api_password: 'temptemp'
      # If using Docker's default `bridge` network setting the dns listening mode should be set to 'all'
      FTLCONF_dns_listeningMode: 'all'
    volumes:
      # For persisting Pi-hole's databases and common configuration file
      - './etc-pihole:/etc/pihole'
    restart: unless-stopped

  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
#    ports:
#      - "8053:53/tcp"   # For DNS queries over TCP
#      - "8053:53/udp"   # For DNS queries over UDP
    volumes:
      - ./unbound/db:/var/lib/unbound                  # Database for caching
#      - ./unbound/conf:/opt/unbound/etc/unbound       # Configuration files
      - type: bind
        read_only: true
        source: ./my_conf/unbound.conf
        target: /opt/unbound/etc/unbound/unbound.conf
#    networks:
#      - pihole_network

#networks:
#  pihole_network:
#    external: true
  • Listing the networks: with pihole_network means the container will utilize your configured external pihole_network network. external: true means that the network was created outside of compose.yaml, whether it is on the host machine or as a Docker network. Removing the external and leaving the configured name will have Docker create a custom bridge network with automated settings to not conflict with other networks. Bridge networking means containers communicate with other containers in the same network.

  • When you list ports, the format is host_port:container_port. So what you did have with your Unbound container ports was port 8053 on your computer binding to port 53 in the container. There are no port conflicts between containers since each container is isolated from others, unless you use host networking.

  • It's the same for volumes. host_volume:container_volume. It can be a file to file or directory to directory. In your current configuration, you have a shorthand and an explicit syntax, both doing the same thing. You have no additional needs within the explicit syntax, so shorthand is fine and easier to read.

  • As you probably have figured, environmental variables manually list certain settings away from the default settings of the container image. Sometimes these variables are changeable in a GUI, like Pi-hole's image allows with the web interface. Unbound does not have a GUI by default, so using a config file or setting environmental variables changes things to work for you.

What you probably want to do is change your unbound.conf to the following:

interface: 0.0.0.0@53

That means Unbound is listening on all network interfaces (within the container) on port 53 for DNS requests. The port setting is unnecessary in this context since @53 is already pointing to port 53.

Then you'll want to uncomment, as in remove the #, network settings in your compose.yaml. I highly recommend you create a static IP for your Unbound container so that you won't have to constantly change the IP in Pi-hole's upstream DNS settings, and then specify it in your compose.yaml. So in the end, I'd recommend you change your unbound.conf as before and use this new, concise compose.yaml:

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    networks:
      - pihole_net
    ports:
      # DNS Ports
      - "53:53/tcp"
      - "53:53/udp"
      # Default HTTP Port
      - "80:80/tcp"
      # Default HTTPs Port. FTL will generate a self-signed certificate
      - "443:443/tcp"
    environment:
      TZ: 'Europe/Oslo'
      FTLCONF_webserver_api_password: 'temptemp'
      # If using Docker's default `bridge` network setting the dns listening mode should be set to 'all'
      FTLCONF_dns_listeningMode: 'all'
      FTLCONF_dns_upstreams="172.33.0.5#53"
    volumes:
      # For persisting Pi-hole's databases and common configuration file
      - './etc-pihole:/etc/pihole'
    restart: unless-stopped

  unbound:
    image: mvance/unbound:latest
    container_name: unbound
    restart: unless-stopped
    volumes:
      - ./unbound/db:/var/lib/unbound                  # Database for caching
      - ./my_conf/unbound.conf:/opt/unbound/etc/unbound/unbound.conf       # Configuration files
    networks:
      pihole_net:
        ipv4_address: 172.33.0.5

networks:
  pihole_net:
    ipam:
      config:
        - subnet: 172.33.0.0/16

5 posts were split to a new topic: Can docker compose files be used with Portainer?

Thank you!

I commented out the network settings to have Docker create a default network. Figured I’d keep it simple and only try to make changes after I’d get Unbound working.

But I’ll give giving out static addresses a shot, thanks. Hopefully this turns out to be the solution..!

How did you decide on giving Unbound 172.33.0.5 and having the DNS upstream server in PiHole set to 172.33.0.0?

1 Like

Whoopsies. Minor oversight, you're right to call me out. It should be 172.33.0.5, and I corrected it.