3 min read

Docker Networking: Bridge vs Macvlan for Segmented Environments

Docker networking is easy to ignore until you start caring about isolation, clean IP addressing, and firewall-controlled access. At that point, the default bridge network often stops being my favorite choice.

This article briefly covers Docker’s default networking behavior and then focuses on macvlan adapters; how it works, why it’s useful, and how it fits into a segmented, security-focused network design.

A humorous three-panel infographic explaining Docker networking: IPvlan is shown as containers sharing a single house/MAC; Macvlan shows containers with their own individual houses/MACs; and Internal is shown as a "secret club" in an underground bunker that is invisible to the outside router.

Docker’s Default Network: Bridge

By default, Docker places containers on a Linux bridge (docker0). Containers receive private IPs (usually 172.17.0.0/16) and traffic is NATed through the host.

Why this works well:

  • No configuration required
  • Containers can communicate easily
  • Host access is simple

Where it falls short:

  • Containers are hidden behind NAT
  • Port mappings become difficult to manage at scale
  • Poor fit for environments that rely on IP-based firewall rules

Where Macvlan Fits In

Macvlan connects containers directly to a physical interface. Each container:

  • Has its own MAC address
  • Receives an IP from your DHCP network service
  • Is reachable without port forwarding

This makes macvlan a good fit when containers need to behave like normal networked systems rather than processes hidden behind the Docker host.


Creating a Macvlan Network

docker network create -d macvlan \
  --subnet=192.168.50.0/24 \
  --gateway=192.168.50.1 \
  -o parent=eth0 \
  macvlan50

Containers attached to this network receive IPs from 192.168.50.0/24.


Using Macvlan in Docker Compose

version: "3.9"

services:
  nginx:
    image: nginx:alpine
    container_name: nginx-macvlan
    restart: unless-stopped
    networks:
      macvlan50:
        ipv4_address: 192.168.50.20

networks:
  macvlan50:
    external: true

No ports are published, the service is reachable directly via its LAN IP.


Macvlan Host Isolation

By design, the Docker host cannot communicate with macvlan containers. This is intentional Linux macvlan behavior and not a Docker bug.

From a security perspective, this creates a clean boundary:

  • Containers cannot directly reach host services
  • Host services are not implicitly exposed to containers

If host access is required, it must be added explicitly with a macvlan interface on the host.


From My Experience: Why I Prefer Macvlan

From my experience, macvlan works best when containers are placed into a dedicated, segmented VLAN.

In my environment:

  • Containers live in their own VLAN
  • The VLAN is tagged on a MikroTik switch
  • Firewall rules and address lists control all inter-network access

Every allowed connection is intentional. Nothing is reachable simply because it runs on the same Docker host. This scales cleanly and keeps firewall policy readable as the number of containers grows.


Mixing Macvlan with Internal Networks

Not every container needs LAN access. A common pattern is:

  • Application container on macvlan
  • Database on an internal Docker bridge
version: "3.9"

services:
  app:
    image: example/app:latest
    container_name: app-macvlan
    networks:
      macvlan50:
        ipv4_address: 192.168.50.30
      backend:
    environment:
      DB_HOST: db

  db:
    image: postgres:16-alpine
    container_name: app-db
    networks:
      backend:

networks:
  macvlan50:
    external: true
  backend:
    driver: bridge
    internal: true

The application is reachable on the LAN; the database is not.


Why I Don’t Put Databases on Macvlan

Databases rarely need direct LAN access. Putting them on macvlan increases exposure without providing real benefit.

Keeping databases on an internal Docker network:

  • Removes them from the physical network
  • Limits access to explicitly connected services
  • Reduces blast radius if something is misconfigured

This mirrors traditional tiered network design and keeps data services where they belong.


Final Thoughts

Docker’s default networking favors convenience. Macvlan favors clarity and control.

When containers have real IP addresses, live in dedicated VLANs, and are governed by explicit firewall rules, Docker fits cleanly into security-focused environments. It requires more planning, but that planning is exactly what enforces good network hygiene.

-- ms
-- ms
Measuring the internet...