You have two containers that need to communicate, but they can't see each other. Or you have a database in one container and an app in another, but latency is high. Or you need containers across multiple servers to talk. If you have faced these scenarios, you know that Docker networking is more than just docker run --network. Choosing the wrong network means poor performance and broken security.
Here at Meteora Web, we've been there. A client's e-commerce with a Vue frontend and Laravel backend: containers couldn't sync sessions because we used the wrong bridge. We fixed it in an afternoon, but the lesson stuck: each network driver has a reason. In this guide, we cover bridge, host, and overlay with concrete examples. No textbook theory — just what you need to make your containers work in production.
This guide is a deep dive from our Pillar on Docker and containerization. If you've never used Docker, start there.
How does the default Docker bridge work and when should you use it?
The bridge is Docker's default network. When you run a container without --network, it attaches to a virtual bridge called docker0. Each container gets a private IP (e.g. 172.17.0.2) and can talk to other containers on the same host only if they're on the same bridge.
Sponsored Protocol
Limitations of the default bridge
The default bridge is isolated: containers cannot resolve each other by name. They must know the IP, which changes on restart. In production, that's a disaster. That's why Docker recommends user-defined bridges.
User-defined bridge: the solution for same-host containers
You create a custom bridge network and launch containers on it. The benefit is automatic DNS resolution: containers see each other by name.
# Create a custom bridge network
docker network create my-bridge
# Launch two containers on the same network
docker run -d --name app --network my-bridge nginx
docker run -d --name db --network my-bridge postgres
# From the 'app' container you can ping 'db' by name
docker exec app ping db
When to use it? Always, for communication between containers on the same server. It's the most secure and performant option for monolithic apps or microservices on a single host.
Common mistake: exposing unnecessary ports
If you use a user-defined bridge, you don't need to expose internal ports on the host. Only expose ports that need external access. We often see developers publishing 5432 (PostgreSQL) on the host when the frontend is on another container. Unnecessary and insecure.
Sponsored Protocol
When should you use the host network instead of the bridge?
The host network removes isolation: the container shares the host's network stack. No virtual IP, no NAT. Ports are exposed directly on the host.
# Run a container with host network
docker run --network host nginx
The advantage is low latency: no address translation, no virtual bridge. Ideal for services that demand high network performance (e.g. reverse proxies, load balancers, real-time apps). The downside is zero isolation: if two containers try to use the same port (e.g. 80), conflict. Also, the container has access to all host network interfaces.
When to choose it?
- When latency is critical and you can't afford the virtualisation layer.
- For containers that need to listen on a large range of dynamic ports.
- If the host has complex network configuration (VPN, multiple interfaces) and you want the container to inherit it.
Warning: Do not use host in multi-tenant environments or where isolation is needed. A malicious (or buggy) container could sniff traffic of other services.
How to configure an overlay network for containers on multiple hosts?
When your containers live on different servers (Docker Swarm cluster or Kubernetes), you need an overlay network. It creates a virtual network that spans across nodes, allowing containers to communicate as if on the same host.
Sponsored Protocol
# On a Docker Swarm manager node
docker network create --driver overlay --attachable my-overlay
# Launch a service across two nodes using the same overlay
docker service create --name frontend --network my-overlay --replicas 2 nginx
docker service create --name backend --network my-overlay --replicas 2 your-app
Containers of these services can talk by service name (e.g. http://backend:8080). Docker handles routing between nodes via a data plane (VXLAN by default).
Requirements
- Docker in Swarm mode (or Kubernetes with compatible CNI).
- Port 4789 (VXLAN) open between nodes.
- Key-value store (Consul, etcd) if using the old standalone overlay.
When to use it?
If you have a cluster of servers and want distributed microservices with transparent communication. It's the equivalent of a VLAN for containers. We used it for a client with two datacenters in Sicily: app and database on different nodes, zero manual routing config.
What are the differences between bridge, host and overlay in terms of security and performance?
Here's a quick comparison based on our experience:
Sponsored Protocol
- Isolation: bridge (high), host (low), overlay (medium – traffic can be encrypted between nodes if IPsec enabled).
- Performance: host (maximum), bridge (slight loss), overlay (more loss due to encapsulation).
- Scalability: bridge only (single host), overlay (multi-host).
- Ease: bridge (simple), host (simple), overlay (needs cluster).
The right choice depends on context. A tip from real projects: always start with a user-defined bridge and switch to others only when you have a measurable reason (latency or multi-host).
How do containers communicate with each other via Docker networking?
Beyond network drivers, you need to understand how containers discover and talk to each other. In a custom bridge, Docker provides built-in DNS based on container name. If you use Docker Compose, services can reach each other by service name (e.g. db from the app service).
# docker-compose.yml
services:
app:
image: nginx
db:
image: postgres
# By default, 'app' can reach 'db' by service name
For inter-host communication, use overlay with Swarm or Kubernetes. Without a cluster, you can use docker run --link (deprecated) or expose ports on the host and configure containers to know external IPs. We don't recommend it — it becomes a maintenance nightmare.
Sponsored Protocol
Real-world example: web app + database across two hosts
# Host 1: database
docker run -d --name postgres --network host -e POSTGRES_PASSWORD=secret postgres
# Host 2: app (connects to Host1's public IP:5432)
docker run -d --name app --network host -e DATABASE_URL=postgres://user:pass@IP_HOST1:5432/db app
Not elegant, but it works. In production, better to use a cluster or a reverse proxy like Traefik.
What to do now
- Identify whether your containers are on one or multiple hosts. On a single host, always create a user-defined bridge and attach containers to it.
- If you have a Docker Swarm cluster, create an overlay network and launch services on it.
- Avoid the default bridge — no DNS, containers suffer.
- Don't use
--link(deprecated). Replace with custom networks. - Review security: on a user-defined bridge, containers only see others on the same network. Keep them separated by role (e.g. frontend network, backend network).
- To dive deeper into the parent pillar, go back to the complete guide on Docker and containerization.