[Question] Why is a a DHCP relay necessary to run a DHCP server in a Docker bridge network?

Hi all,

I recently migrated my bare metal pi-hole setup over to a containerized environment where my pi-hole was sitting behind an NGINX reverse proxy in a bridged network. I quickly realized that my pi-hole's DHCP server wasn't functioning and couldn't issue IP addresses to devices. I was able to follow the instruction here and resolved the issue by deploying a DHCP relay in a separate docker container.

Could someone provide more context on why this was an issue? What exactly is a DHCP relay and why is it needed in this scenario? Why wasn't my original setup sufficient? My original setup had mapped port 53 and 67 from my pi-hole container to my host machine. I thought that this would be enough for the DHCP server to receive and handle DHCP requests. For example, I think my pi-hole was intercepting DHCP requests, but it failed to assign an IP address with an error message stating "no address range available for DHCP request via eth0" container". I'm new to this space (networking) and trying to learn more, so more context is helpful!

version: '3.3'
services:
  nginx:
    image: nginx:1.18.0
    volumes:
      - ./configs/nginx/conf.d/:/etc/nginx/conf.d/
    networks:
      - pihole
    ports:
      - '80:80'
      - '443:443'
  pihole:
    image: pihole/pihole:v5.1.2
    ports:
      - '53:53/tcp'
      - '53:53/udp'
      - '67:67/udp'
    expose:
      - '80/tcp'
      - '443/tcp'
    networks:
      - pihole
    volumes:
      - ./.docker-volumes/pihole/:/etc/pihole/
      - ./.docker-volumes/dnsmasq/:/etc/dnsmasq.d/
    cap_add:
      - NET_ADMIN
    restart: unless-stopped
networks:
  pihole: {}

Did you expose the DHCP server? Edit: Missed the configuration.

What is the full yaml file contents? You've not really declared any kind of network.

As to why a DHCP relay may be needed, DHCP is broadcast based, it only works on a collision domain, a bridge will break that collision domain.

Edit2: The linked instructions are pretty thorough and detailed, and explains bridge network isolation.

Updated my original post with my full docker configuration (before DHCP). The only thing I omitted before was the reverse proxy. DNS worked fine in the containerized environment and I only ran into issues once enabling DHCP.

I followed the instructions and got my DHCP setup working now, but I still don't understand why it works. I'm new to networking so I don't think I fully understand the concepts (e.g. I don't know what a collision domain is). When I set up my docker network, I bound the pi-hole container's DHCP and DNS ports to the host machine. Why would the pi-hole container be able to intercept DHCP requests, but not able to assign an IP address to the client?

Here's a diagram of how I think my original setup was instrumented. Please let me know where the gap in my understanding is and why this setup was insufficient. In the below diagram, the pi-hole container has ports 53/57 exposed and mapped to the host machine. I saw that the container was able to intercept both DHCP and DNS requests, but had difficulties responding to the DHCP requests.

A client that joins a network isn't aware of any network details yet.

With IPv4, DHCP negotiation is initiated by a client via a network broadcast with the intention of discovering available DHCP servers to query for those network details.

A broadcast is received by all nodes in the same collision domain. In layman's terms, you could think of that as all devices directly connected to the same router. Of course, that's a gross simplification, as things like repeaters, extenders, access points and other network equipment may extend this physically, and software like VLANs may extend or restrict it virtually.

Docker is such a software that isolates a container into a separate network by default, effectively introducing another layer 2 network segment (or collision domain) into your network. DHCP broadcasts issued from a client connnected to your router will never make it to Docker's network.

A DHCP relay acts as a DHCP server in one network segment and knows about IP addresses of DHCP servers in other segments. It receives your client's broadcast (limited to same segment nodes) and translates it into a unicast directed at an IP address (subject to routing between segments).

If your router would support acting as a DHCP relay, it would suffice to configure it with the correct IP accordingly.
If your router doesn't support that, you'd have to set up a dedicated separate DHCP relay. Constructing a DHCP relay container is one way to do so.

1 Like

That's not really correct, you haven't set any configuration or values for the user-defined network.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.