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.
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:
| Driver | Use Case | Isolation |
|---|---|---|
bridge | Default. Containers on the same bridge communicate freely. | Internal to host |
host | Container shares the host’s network stack. | None |
macvlan | Container gets its own MAC and IP on the physical LAN. | Per-container |
none | No 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
netdataorsnmp-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).
4. The Reverse Proxy Pattern (Recommended)
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
proxynetwork - Only Traefik exposes ports
80and443to 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
| Scenario | Recommendation |
|---|---|
| Web services behind a domain | Reverse proxy on a shared network |
| DNS / DHCP / network services | Host mode |
| Media servers needing LAN broadcast | Macvlan or host mode |
| Internal databases | Bridge (stack-internal only) |
| Isolated batch jobs | Bridge 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.