Docker Macvlan vs Ipvlan: Assign Dedicated LAN IPs
To assign a dedicated local LAN IP address to a Docker container, configure a Macvlan or Ipvlan L2 network driver in docker-compose.yml bound to your host's physical Ethernet interface. This bypasses Docker's default NAT bridge, giving services like Pi-hole, Home Assistant, and Plex their own unique IP and eliminating host port collisions.
- Bypass NAT Port Collisions: Macvlan gives containers independent LAN IPs on your physical home subnet, allowing multiple containers to use Port 53, 80, or 443 simultaneously.
- True Client Visibility: DNS servers (Pi-hole/AdGuard) running on Macvlan see exact client source IP addresses rather than Docker's masked internal gateway IP (
172.17.0.1). - The Kernel Communication Barrier: Linux security forbids direct communication between the Docker host and Macvlan child containers; a macvlan bridge shim interface solves this.
- Macvlan vs Ipvlan L2: Use Macvlan for distinct MAC addresses per container; use Ipvlan L2 when running on Wi-Fi NICs or cloud hypervisors that drop multiple MACs on one switch port.
The Docker NAT Bridge Bottleneck: Why Containers Need Dedicated Subnet IPs
By default, Docker deploys containers onto an internal virtual bridge (bridge or docker0) using private RFC 1918 subnets (typically 172.17.0.0/16). Communication with your physical local area network relies on Network Address Translation (NAT) and host port-forwarding mappings (e.g., -p 8080:80). While convenient for quick testing, this architecture creates severe operational hurdles for network infrastructure containers:
- Port Collisions: Two containers cannot bind to the same host port. You cannot run Pi-hole and AdGuard Home (both requiring Port 53) or multiple web servers (requiring Port 80/443) on the same host without messy port remapping.
- Source IP Masking: When queries hit a container behind Docker's NAT bridge, the source IP address is rewritten to the Docker gateway (
172.17.0.1). In DNS sinkholes like Pi-hole, every single DNS request appears to originate from the Docker host, completely blinding your query logs and per-client blocking rules. - Broadcast/Multicast Failures: Services like Home Assistant, Apple AirPlay, and DLNA rely on mDNS (
UDP 5353) and SSDP discovery broadcasts, which do not cross Docker's Layer-3 NAT bridge boundaries.
The solution is Docker's Macvlan or Ipvlan network drivers. These drivers bind virtual container interfaces directly to your host's physical network adapter (eth0 or eno1), placing containers directly onto your physical LAN subnet with their own dedicated IP addresses.
Configuring Docker Macvlan Networks via Docker Compose
Before launching a Macvlan network, you must inspect your home router's DHCP pool. You must carve out an isolated static IP reservation range outside your router's dynamic DHCP assignment pool to avoid duplicate IP collisions. For example, if your router hands out DHCP leases from 192.168.1.100 to 192.168.1.250, reserve 192.168.1.192/27 (IPs .193 through .222) exclusively for Docker Macvlan containers.
In your docker-compose.yml file, define the Macvlan network driver under the root networks block, binding it to your host's physical NIC (e.g., eth0):
version: "3.8"
services:
pihole:
image: pihole/pihole:latest
container_name: pihole
environment:
TZ: "America/New_York"
volumes:
- ./etc-pihole:/etc/pihole
- ./etc-dnsmasq.d:/etc/dnsmasq.d
networks:
home_lan:
ipv4_address: 192.168.1.201
restart: unless-stopped
networks:
home_lan:
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
ip_range: 192.168.1.192/27
When you execute docker compose up -d, Docker creates a virtual interface with a randomized unique MAC address (e.g., 02:42:c0:a8:01:c9) and assigns 192.168.1.201. The container is immediately reachable across your entire physical home network on standard ports without specifying any ports: mapping lines.
Solving the Macvlan Host-to-Container Communication Lockout
Immediately after deploying a Macvlan container, you will discover a strange networking anomaly: every PC, smartphone, and smart TV on your local network can ping and access the container at 192.168.1.201, except the Docker host machine itself. Pinging the container from the host returns Destination Host Unreachable.
This is an intentional security design of the Linux kernel's Macvlan sub-driver. Traffic transmitted from a Macvlan child interface is routed directly out the physical wire; the kernel driver deliberately isolates parent interfaces from communicating with their own child sub-interfaces over Layer-2 to prevent loop storms.
To enable bidirectional communication between the Docker host and its Macvlan containers (for instance, allowing host backup scripts or metrics collectors to scrape container endpoints), you must build a macvlan bridge shim on the host OS:
# 1. Create a macvlan sub-interface linked to the physical parent
sudo ip link add macvlan-shim link eth0 type macvlan mode bridge
# 2. Assign an unused static IP from your reserved Docker subnet pool
sudo ip addr add 192.168.1.220/32 dev macvlan-shim
# 3. Bring the interface up
sudo ip link set macvlan-shim up
# 4. Route traffic targeting the Docker container range via the shim
sudo ip route add 192.168.1.192/27 dev macvlan-shim
To ensure this bridge shim persists across system reboots, place these commands into your Debian/Ubuntu /etc/network/interfaces file or create an automated systemd startup unit.
When to Choose Ipvlan L2 Over Macvlan (Wi-Fi & Hypervisors)
While Macvlan is the gold standard for wired Linux hosts, it possesses a critical physical limitation: Macvlan requires promiscuous mode on the underlying network interface because it registers multiple unique MAC addresses over a single physical link. Two primary environments will violently choke on Macvlan:
- Wireless Interfaces (Wi-Fi): The IEEE 802.11 standard enforces a 3-address frame format in client station mode (STA). Wireless access points drop frames originating from foreign MAC addresses transmitted over an authenticated client link. Running Macvlan over a Wi-Fi card (
wlan0) almost always fails. - Virtual Machines & Cloud Hypervisors: If your Docker host runs inside a Proxmox VM, ESXi, or Microsoft Hyper-V guest, the virtual switch will drop Macvlan packets by default due to MAC spoofing prevention rules unless you explicitly enable MAC Spoofing / Promiscuous Mode on that VM's virtual NIC.
In these scenarios, use Ipvlan L2. Ipvlan functions nearly identically to Macvlan by assigning unique local IP addresses to containers, but all containers share the exact same physical MAC address as the host. The Linux kernel multiplexes traffic based on destination IP instead of destination MAC. In your Compose file, simply change driver: macvlan to driver: ipvlan with driver_opts: { parent: eth0, ipvlan_mode: l2 }. Switch MAC tables remain clean, Wi-Fi links function seamlessly, and virtual machine hypervisors require zero promiscuous mode overrides.
Docker Network Drivers Architecture & Performance Matrix
| Network Driver | MAC Address Scheme | Subnet Addressing | Port Forwarding Required | Promiscuous Mode | Best For |
|---|---|---|---|---|---|
| Bridge (Default) | Virtual veth pair | Internal 172.17.0.0/16 | Yes (-p host:container) | No | Standard isolated microservices, web apps |
| Host Mode | Shares Host MAC | Identical to Host IP | No (Binds host stack) | No | Extreme throughput (10GbE), VoIP, low latency |
| Macvlan (Bridge) | Unique MAC per container | Direct LAN Subnet IP | No (Direct IP access) | Yes (Requires wire promiscuous) | Pi-hole, AdGuard, Home Assistant, multi-IP services |
| Ipvlan L2 | Shares Host MAC | Direct LAN Subnet IP | No (Direct IP access) | No | Wi-Fi Docker hosts, Proxmox/ESXi VMs without MAC spoofing |
| Ipvlan L3 | Shares Host MAC | Routed L3 Subnet (No ARP) | No (Host acts as L3 router) | No | Complex multi-subnet routed enterprise topologies |
| Overlay Network | Virtual VXLAN | Encapsulated multi-host mesh | Yes (Ingress mesh) | No | Docker Swarm multi-node clusters across physical nodes |
Docker Macvlan / Ipvlan Setup Verification Checklist
- Verify your home router's dynamic DHCP pool and carve out an isolated static subnet range.
- Identify your host's exact physical network interface name via
ip -br link. - Ensure promiscuous mode is enabled on upstream virtual switch if running Docker inside a VM.
- Define the
macvlannetwork driver indocker-compose.ymlwith subnet and gateway. - Deploy containers with explicit static IP assignments under the service
networksblock. - Configure a macvlan bridge shim interface on the host OS if the Docker host requires container access.
Frequently Asked Questions
Why can't my Docker host ping its own Macvlan containers?
This is a fundamental security behavior of the Linux kernel Macvlan driver, which prevents Layer-2 hairpin loops between the parent physical interface and child virtual endpoints. To allow the host to reach its containers, you must configure a macvlan bridge shim interface on the host pointing to that subnet.
Can I run Docker Macvlan over a Wi-Fi connection?
Generally, no. The 802.11 Wi-Fi specification drops multi-MAC traffic from client adapters in standard station mode. If your Docker host connects via Wi-Fi, use the Docker ipvlan driver in L2 mode (ipvlan_mode: l2), which shares the host's single authenticated Wi-Fi MAC address across all containers.
Do I need to expose ports with -p when using Macvlan?
No. When using Macvlan or Ipvlan L2, containers behave like separate physical hardware connected to your switch. All internal container ports (e.g., 53 for DNS, 80 for HTTP, 32400 for Plex) are accessible directly at the container's assigned LAN IP without any port forwarding.
How does Macvlan benefit a Pi-hole or AdGuard Home installation?
Under Docker's default NAT bridge, all client queries appear in Pi-hole logs as originating from the Docker internal gateway (172.17.0.1). Macvlan assigns Pi-hole its own LAN IP, allowing clients to query it directly so individual client hostnames and IP addresses are cleanly tracked and filtered.
Related Wired LAN Setup & Engineering Guides
- Subnet Mask Beginner Guide (CIDR /24, /23 & /16) — Understand IPv4 subnet masks, CIDR notation (/24, /23, /16, /30), binary bitmasking, usable host formulas, and RFC 1918 private IP ranges for home and office.
- NAS Network Setup Guide for Home and Small Office — Configure a Synology, QNAP, or TrueNAS server with DHCP reservations, 2.5GbE/10GbE switching, SMB3 multichannel vs LACP, and WireGuard/Tailscale access.
- Cat5e vs Cat6 vs Cat6a Ethernet Cables Compared — Compare Cat5e, Cat6, and Cat6a Ethernet cables across 1Gbps, 2.5GbE, and 10GBASE-T distances, MHz bandwidth, PoE heat, CMR vs CMP, and solid copper vs CCA.
- Small Business Network Setup Checklist — Build a reliable small business network with our checklist covering Dual-WAN failover, 4-VLAN segmentation, PoE budgets, UPS sizing, and WPA3 WiFi security.