How to Put Docker Containers on the Right VLAN Using macvlan
Most Docker setups ignore VLANs entirely. Every container runs on the host's default bridge network, accessible only through port mappings. That is practical for most workloads, but it breaks down when you need a container to appear as a real device on a specific network segment — with its own IP address, reachable from other devices on that VLAN without any port translation. The macvlan driver solves this, but the setup involves enough non-obvious steps that it is worth walking through carefully before you start.
What macvlan Actually Does
A macvlan network assigns each container its own MAC address and IP address. To other devices on the network, the container looks like a standalone physical machine. This is useful for applications that rely on broadcast traffic, need to be accessible at a predictable IP, or need to live on a VLAN that is separate from the Docker host's primary network.
Before going further, three constraints matter. First, by default the Docker host itself cannot communicate with containers on a macvlan network — if your container is reachable from other devices but not from the host, that is expected behavior, not a bug. Second, if your switch has MAC address limits or you are trying to run this over Wi-Fi, you will likely hit problems. Third, the VLANs must be properly segmented at the firewall level. The Docker host only handles the container side.
Configuring the VLAN Sub-Interface
The first change happens on the Docker host, not in Docker itself. You need to create a VLAN sub-interface in your netplan configuration (on Ubuntu Server) tied to the specific VLAN ID you want. The sub-interface does not need its own IP — it serves only as the parent interface that Docker's macvlan network will attach to.
After updating the netplan config and applying it, you should see the new sub-interface appear when you run ip link.
Creating the macvlan Docker Network
With the sub-interface in place, you create a Docker network using the macvlan driver. You specify the subnet for that VLAN, the gateway, and the parent interface (the sub-interface you just created). Assign the network a clear name — you will reference it from Docker Compose later.
When the network is created, it appears in Portainer or your Docker management tool alongside your other networks.
Running Containers with Static IPs
In your Docker Compose file, two changes are required. First, declare the macvlan network as an external network (since you already created it outside of Compose). Second, in the container's network configuration, specify the exact IP address you want it to use on that VLAN.
The critical point: make sure the IP you assign is not in your DHCP server's assignment range. The cleanest way to handle this is to carve out a reserved range in your DHCP configuration — a block of IPs that your router will never hand out — and use those for your macvlan containers.
What to Watch Out For
This setup is best for a small number of containers that genuinely need to be on a specific VLAN. If you have many containers that all need to live on the same VLAN, you are better off running a separate Docker host directly on that VLAN and using standard port mappings. One IP per container adds up.
If anything does not work, the issue is almost always upstream — a switch port that is not configured as a trunk, a VLAN that is not allowed on that trunk, or a firewall blocking the traffic before it reaches the container. The Docker-side configuration is straightforward. The network-side configuration is where problems hide.
Takeaway
macvlan networking gives you a clean way to place specific Docker containers onto dedicated VLANs without any NAT or port translation complexity. The tradeoff is a more involved setup and one IP address consumed per container. For home lab environments running a handful of services that need to live on specific network segments — a wake-on-LAN tool, a local DNS server, an IoT-facing proxy — it is the right tool.