Docker 5 min read

Docker Networking for the Homelab: Bridge, Macvlan, and Reverse Proxy

A practical guide to Docker networking modes for self-hosted services — covering bridge networks, macvlan, host mode, and reverse proxy integration with Traefik.

dockernetworkingtraefikreverse-proxyhomelablinux

If you self-host services with Docker Compose, networking is where most configurations get tangled. Containers need to talk to each other, to the internet, and to your local network — but the default Docker bridge doesn’t always make that straightforward.

This guide covers the four Docker networking modes you’ll actually use in a homelab, when to pick each one, and how to integrate everything behind a reverse proxy.

The Four Networking Modes

Docker provides four built-in networking drivers relevant to homelab setups:

DriverUse CaseIsolation
bridgeDefault. Containers on the same bridge communicate freely.Internal to host
hostContainer shares the host’s network stack.None
macvlanContainer gets its own MAC and IP on the physical LAN.Per-container
noneNo network. For isolated offline workloads.Complete

1. Bridge Networks (Default)

Every Compose stack gets its own bridge network by default. Containers inside that stack resolve each other by service name:

# docker-compose.yml
services:
  app:
    image: nginx
    networks:
      - frontend
  db:
    image: postgres:16
    networks:
      - backend

networks:
  frontend:
  backend:

This works well for single-stack isolation, but creates a problem: two separate stacks on different bridges can’t communicate directly. That’s where an external network shared by multiple stacks helps.

Shared External Network Pattern

# stack-a/docker-compose.yml
services:
  service-a:
    image: my-app
    networks:
      - shared-net

networks:
  shared-net:
    external: true
    name: shared-net

Create the shared network once:

docker network create shared-net

Now any stack that attaches to shared-net can reach service-a by its container or service name. This is the foundation of the reverse proxy pattern.

2. Host Mode

Host mode binds the container directly to the host’s network stack — no port mapping, no NAT. Performance is identical to a native process:

services:
  adguard:
    image: adguard/adguardhome
    network_mode: host
    restart: unless-stopped

When to use it:

  • DNS servers (AdGuard Home, Pi-hole) that need port 53
  • Services that need to see the true client IP without proxy protocol
  • Network tools like netdata or snmp-exporter

When to avoid it:

  • Any service behind a reverse proxy (you lose port-level routing)
  • Multi-instance services (can’t run two containers on the same port)

3. Macvlan

Macvlan gives each container its own IP and MAC address on your physical LAN, making it appear as a separate device to your router:

services:
  nginx-proxy:
    image: nginx
    networks:
      macvlan-net:
        ipv4_address: 192.168.1.100

networks:
  macvlan-net:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: 192.168.1.0/24
          gateway: 192.168.1.1
          ip_range: 192.168.1.100/28

Pros:

  • Container gets direct LAN access, ideal for services that expose ports
  • No port conflicts between containers on different IPs

Cons:

  • ⚠️ The host cannot reach macvlan containers from itself (by default). This is a kernel limitation. Workarounds exist (macvlan on a sub-interface), but they’re fiddly.
  • Each container consumes a LAN IP — fine in a homelab, wasteful at scale.
  • DHCP reservations needed per container if you want persistent IPs.

Best for: Services that need to broadcast on the local network (DLNA, mDNS, Home Assistant with local integrations).

For most homelabs, the cleanest architecture is a single reverse proxy (Traefik or Nginx Proxy Manager) on a shared network, with all web services attached to that same network:

# traefik/docker-compose.yml
services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: unless-stopped
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
    ports:
      - 80:80
      - 443:443
    networks:
      - proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./acme.json:/acme.json
      - ./traefik.yml:/traefik.yml

networks:
  proxy:
    name: proxy
    external: false  # First stack creates it
# whoami/docker-compose.yml (example backend)
services:
  whoami:
    image: traefik/whoami
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`whoami.example.com`)
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.tls.certresolver=letsencrypt

networks:
  default:
    external: true
    name: proxy

Why this pattern works

  • Every service connects to the proxy network
  • Only Traefik exposes ports 80 and 443 to the world
  • Traffic flows: Internet → Host:443 → Traefik → Backend container
  • TLS termination happens in one place
  • Adding a new service is just labels and attaching to the network

Choosing the Right Approach

ScenarioRecommendation
Web services behind a domainReverse proxy on a shared network
DNS / DHCP / network servicesHost mode
Media servers needing LAN broadcastMacvlan or host mode
Internal databasesBridge (stack-internal only)
Isolated batch jobsBridge or none

Common Pitfalls

Port conflicts — Two containers can’t bind the same host port. Use a reverse proxy so no web service needs to expose raw ports.

DNS resolution — On bridge networks, containers resolve each other by service name, not container name. Use the Compose service name.

Restart loops with network dependencies — Use depends_on sparingly. Design services to retry connections instead of relying on startup order.

Unused networks accumulate — Clean up periodically:

docker network prune

Summary

  • Default bridge networks are fine for isolated stacks
  • Use macvlan only when containers need to appear as standalone LAN devices
  • Use host mode only for network-critical services (DNS, monitoring agents)
  • Build everything else behind a reverse proxy on a shared network

This architecture keeps your homelab manageable, secure, and extensible. Once the networking is right, adding new services takes minutes instead of debugging sessions.


Have questions about a specific Docker networking scenario? Get in touch — we’re happy to help.