Sign inSign up

fernandodelucca/docker-net-dhcp

By fernandodelucca

Updated about 7 hours ago

Containers on your real LAN via DHCP: IPv4+IPv6, macvlan/ipvlan/bridge, VLAN, APIPA failsafe

Image
Plugin
Networking
Security
Monitoring & observability
0

9.9K

fernandodelucca/docker-net-dhcp repository overview

docker-net-dhcp

Linux Docker managed plugin that connects containers to your existing LAN and lets your real DHCP server (router, Dnsmasq, Kea, ISC, UniFi, …) hand out their addresses — IPv4 and IPv6. Containers appear on the network as first-class LAN clients, with their own MAC, DHCP lease, hostname registration and router visibility. The DHCP client is Go-native (no udhcpc, no CGO), and all privileged network setup is done by the plugin — workload containers need zero capabilities.

Supported tags

TagChannelMeaning
latest, stablestablestable code from the main branch (latest is what untagged installs resolve to)
vX.Y.Zreleaseimmutable versioned launches
releasereleasealways the newest version
devdevcode in progress (still test-gated before publishing)
<sha8>immutable pin for any published build

Multi-arch: linux/amd64, linux/arm64.

What it does

  • Three network modesbridge, macvlan (bridge/private), ipvlan (l2/l3), with automatic 802.1Q VLAN sub-interfaces (-o vlan=N).
  • Full DHCPv4 lifecycle — acquire, renew (unicast), rebind, release; the lease obtained at endpoint creation is the one the container keeps.
  • APIPA fail-safe — if DHCP does not answer in time, the container still starts on a deterministic 169.254.0.0/16 address and the plugin keeps soliciting; the real lease is swapped in the moment a server responds.
  • IPv6 — SLAAC with continuous address observation and RDNSS DNS, plus optional stateful DHCPv6 (-o dhcpv6=true).
  • Permanent IPv6 identity — SLAAC interface IDs are pinned to modified EUI-64 of the endpoint MAC and privacy/temporary addresses are disabled inside every container. With a fixed MAC, the ULA/GUA is a pure function of (prefix, MAC): stable across restart, recreate and reboot — safe for firewall rules and DNS.
  • DNS and hostname propagation — DHCP/RDNSS nameservers are written to the container resolv.conf; the container hostname is sent as DHCP option 12 so routers register the lease by name.
  • Stable MAC → stable IP — Docker's endpoint MAC drives every DHCP request; when no MAC is given, a deterministic one is generated. Use a fixed --mac-address plus a server-side reservation for a fixed IP.
  • State and restore — per-endpoint persistent state; after a plugin or daemon restart, endpoints re-attach and renewals resume.
  • Observability/healthz with per-endpoint lease/phase detail, Prometheus /metrics, structured JSON logs, and rich docker network inspect endpoint info.

Requirements

  • Linux host with Docker managed-plugin support (plugins run under runc; keep default-runtime: runc — workloads may still opt into other runtimes).
  • A DHCPv4 server reachable from the chosen parent interface.
  • The state directory created on the host before enabling the plugin.
  • The capabilities declared by the plugin manifest, granted at install (--grant-all-permissions).

Install

sudo mkdir -p /var/lib/docker-net-dhcp

docker plugin install fernandodelucca/docker-net-dhcp:latest \
  --alias docker-net-dhcp \
  --grant-all-permissions

docker plugin ls   # docker-net-dhcp  ENABLED true

Upgrade without losing endpoints (leases are restored by the new process):

docker plugin disable docker-net-dhcp
docker plugin upgrade docker-net-dhcp --grant-all-permissions
docker plugin enable  docker-net-dhcp

Quick start

Containers directly on the LAN via macvlan, addresses from your DHCP server (Mode A — resilient default; note the tag in the driver name):

docker network create \
  --driver docker-net-dhcp:latest --ipam-driver null \
  -o bridge=eth0 -o mode=macvlan \
  lan

docker run -d --network lan --hostname web-01 \
  --mac-address 02:42:ac:11:00:05 nginx

docker exec <id> ip addr show eth0   # inet 192.168.1.x/24 from your server

Dual-stack (IPv4 + SLAAC IPv6) on a tagged VLAN — pass both --ipv6 (Docker) and -o ipv6=true (plugin):

docker network create \
  --driver docker-net-dhcp:latest --ipam-driver null --ipv6 \
  -o bridge=eth0 -o mode=macvlan -o vlan=50 \
  -o ipv6=true -o require_mac=true \
  lan-v6

Compose:

services:
  web:
    image: nginx
    hostname: web
    networks:
      lan:
        mac_address: "02:42:ac:11:00:05"   # fixes the DHCP reservation AND the IPv6 identity

networks:
  lan:
    driver: docker-net-dhcp:latest
    driver_opts:
      bridge: eth0
      mode: macvlan
      require_mac: "true"
    ipam:
      driver: "null"        # Mode A — DHCP handles addressing

Network options (-o key=value)

OptionDefaultMeaning
bridgerequiredExisting Linux bridge or parent NIC
modebridgebridge, macvlan or ipvlan
macvlan_modebridgebridge or private
ipvlan_model2l2 or l3
vlan00–4094; creates parent.N for macvlan/ipvlan
mtu00 inherits the parent MTU
ipv6falseenables IPv6, SLAAC observation and RDNSS
dhcpv6falseadds stateful DHCPv6; requires ipv6=true
lease_timeout10ssynchronous DHCP budget for Mode B
ignore_conflictsfalseallow several networks on one bridge+VLAN
skip_routesfalsedo not copy host bridge static routes
require_macfalsefail endpoint creation without a Docker-supplied MAC

Runtime settings

Change with docker plugin set while the plugin is disabled:

VariableDefaultMeaning
DOCKER_NETWORK_DHCP_LOG_LEVELinfodebug, info, warn, error
DOCKER_NETWORK_DHCP_PROBE_TIMEOUT15sMode A DHCPv4 wait at endpoint creation (1–25s)
DOCKER_NETWORK_DHCP_PROBE_CONCURRENCYautoparallel DHCP probes (NumCPU, clamped 2–16)
DOCKER_NETWORK_DHCP_RESTORE_CONCURRENCYautorestore workers, same clamp
DOCKER_NETWORK_DHCP_V6_PROBE_NEGATIVE_TTL10mper-network "no DHCPv6 server" memory; 0 disables
DOCKER_NETWORK_DHCP_RECONCILE_APIPAenabledfalse blocks new APIPA reconciliation prepares

Mode B — bundled IPAM (experimental)

Opt-in synchronous allocation: docker inspect shows the DHCP address in the IPAM block, and docker run fails fast when the server is unavailable (no APIPA). Use the plugin as both driver and IPAM driver, with the subnet declared:

docker network create \
  --driver docker-net-dhcp:latest --ipam-driver docker-net-dhcp:latest \
  --subnet 192.168.1.0/24 \
  -o bridge=eth0 -o mode=macvlan -o require_mac=true \
  lan-b

Health check

PLUGIN_ID=$(docker plugin inspect docker-net-dhcp --format '{{.ID}}')
curl -s --unix-socket /run/docker/plugins/${PLUGIN_ID}/net-dhcp.sock \
     http://localhost/healthz | jq .

Per-endpoint lease, DHCP phase (acquiring/bound/renewing/…), IPv6 addresses with GUA/ULA classification, and remaining lease time. Prometheus metrics on /metrics at the same socket.

Uninstall

docker plugin disable docker-net-dhcp
docker plugin rm docker-net-dhcp
sudo rm -rf /var/lib/docker-net-dhcp

Notes and limits

  • Linux only; there is no Windows runtime.
  • macvlan: the host cannot reach its own macvlan containers through the same NIC (kernel limitation) — give the host its own macvlan child if needed.
  • ipvlan shares the parent MAC on the wire; the plugin sends DHCP option 61 (client-id) so servers can still reserve per endpoint.
  • With ipv6=true and no DHCPv6 server, containers get ULA/GUA via SLAAC, but libnetwork cannot show them in docker inspect (GlobalIPv6Address); the authoritative view is /healthz or ip -6 addr inside the container.

Tag summary

Content type

Image

Digest

sha256:f61814b73

Size

12.3 MB

Last updated

about 7 hours ago

docker pull fernandodelucca/docker-net-dhcp:dev