Running a Temporary DHCP Server in Docker

Sometimes you need a DHCP server for only a short lab window. dnsmasq in Docker is a simple option because the container is disposable and the configuration is easy to inspect.

These examples assume Docker on Linux, because the container needs direct access to the target Layer 2 segment. Replace ens192 with your real interface name.

Important: run this only on a Layer 2 segment where this should be the active DHCP server. If another DHCP server is already active on the same segment, clients can receive leases from the wrong server.

There are two useful modes:

  1. Isolated DHCP only - the safer option. The lab segment uses a separate subnet, the host gets a secondary IP on the target interface, and DHCP does not advertise a default gateway or DNS server.
  2. DHCP with gateway and DNS - clients receive normal network parameters and can reach other networks through the advertised router.

1. Find the Target Interface

The following commands require the iproute2 package.

If you want to use the interface with the current default route:

ip route show default

To list all interfaces:

ip link show

2. Create the Dockerfile

Create Dockerfile:

FROM alpine:3.23.3

RUN apk add --no-cache dnsmasq

EXPOSE 67/udp 53/udp

ENTRYPOINT ["dnsmasq", "-k", "--log-facility=-"]

This keeps dnsmasq in the foreground and sends logs to stdout, so docker compose logs works as expected.

3. Create the Compose File

Create docker-compose.yml:

services:
  dnsmasq:
    build: .
    container_name: temp-dhcp
    restart: unless-stopped
    network_mode: host
    cap_add:
      - NET_ADMIN
      - NET_RAW
    volumes:
      - ./dnsmasq.conf:/etc/dnsmasq.conf:ro

network_mode: host is the important part. DHCP uses broadcast traffic, so host networking makes the container behave like a local DHCP service on the target interface.

Option 1: Isolated DHCP Only

Use this when the connected devices should not interact with the current network. The host only gets a temporary secondary IP so you can manage or test devices in the isolated subnet.

Add a temporary IP address to the host:

sudo ip addr add 10.255.255.1/24 dev ens192

Create dnsmasq.conf:

interface=ens192
bind-interfaces

log-dhcp
dhcp-authoritative
port=0

dhcp-range=10.255.255.10,10.255.255.254,255.255.255.0,1h
dhcp-option=option:router
dhcp-option=option:dns-server

What matters here:

  • interface=ens192 binds DHCP to the target interface.
  • port=0 disables the DNS service in dnsmasq.
  • dhcp-range=... defines the lease pool and lease time.
  • dhcp-option=option:router suppresses the default router option.
  • dhcp-option=option:dns-server suppresses the default DNS server option.

Clients will receive only an address and mask from 10.255.255.0/24. They can talk to the host address 10.255.255.1 and to each other on that isolated segment, but they will not receive a default gateway or DNS server.

Option 2: DHCP with Gateway and DNS

Use this when clients should receive full connectivity settings. This must be the only DHCP server on the Layer 2 segment, or clients can receive leases from the wrong server.

Example where an existing router provides connectivity:

interface=ens192
bind-interfaces

log-dhcp
dhcp-authoritative
port=0

dhcp-range=192.168.50.100,192.168.50.150,255.255.255.0,1h
dhcp-option=option:router,192.168.50.1
dhcp-option=option:dns-server,8.8.8.8

In this mode, dnsmasq still does not run DNS itself. It only tells clients which DNS servers to use.

If the Docker host should act as the router for an isolated subnet, advertise the host IP as the gateway and enable IP forwarding and NAT on the host. Example:

sudo ip addr add 10.255.255.1/24 dev ens192
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 10.255.255.0/24 -o eth0 -j MASQUERADE

Then use this DHCP configuration:

interface=ens192
bind-interfaces

log-dhcp
dhcp-authoritative
port=0

dhcp-range=10.255.255.10,10.255.255.254,255.255.255.0,1h
dhcp-option=option:router,10.255.255.1
dhcp-option=option:dns-server,1.1.1.1,8.8.8.8

Replace eth0 in the NAT command with the host interface that has upstream connectivity.

4. Start the DHCP Server

Run:

docker compose up -d --build
docker compose logs -f dnsmasq

For Option 1 and the NAT variant of Option 2, the lease range is:

10.255.255.10 - 10.255.255.254

For the existing-router variant of Option 2, adjust the range, router, and DNS servers to match that network.

5. Stop and Clean Up

When the temporary DHCP window is over:

docker compose down

If you added the secondary IP manually, remove it:

sudo ip addr del 10.255.255.1/24 dev ens192

If you added the NAT rule, remove it too:

sudo iptables -t nat -D POSTROUTING -s 10.255.255.0/24 -o eth0 -j MASQUERADE

Notes

  • Make sure no other DHCP server is active on the same Layer 2 segment.
  • Replace ens192 and eth0 with your real interface names.
  • Adjust the subnet, range, lease time, router, and DNS servers to fit your environment.
  • If you enabled IP forwarding only for this test, disable it again after the test if the host should not route traffic.