Default Bridge Network
The default bridge is the network Docker quietly gives you when you start a container without asking for anything special. It gets the job done: containers get private IP addresses, can talk to each other, and can reach the outside world. But there is one awkward limitation that becomes important as soon as containers need to behave like an application rather than isolated experiments: they cannot discover each other by name.
Understanding that limitation makes the next lesson — user-defined bridge networks — feel less like another Docker feature and more like the obvious fix.
What You Get by Default
When Docker Engine starts, it creates a built-in network named bridge. On a typical Linux Docker host, that network is backed by a Linux bridge device called docker0.
If you start a container without specifying --network, Docker automatically connects it to this default bridge network.
For example:
docker container run -d --name web nginx:alpineYou didn’t create a network.
You didn’t connect web to one.
Docker simply says, “You didn’t tell me otherwise, so I’ll put it on bridge.”
You can see the built-in networks with:
docker network lsYou’ll normally see networks such as:
NETWORK ID NAME DRIVER SCOPE
... bridge bridge local
... host host local
... none null localThe interesting one for this lesson is:
bridge bridge localThe first bridge is the network name.
The second bridge is the network driver.
That distinction matters later when you create your own bridge network.
Why Is It Called a “Bridge”?
This is one of those Docker names that sounds abstract until you see what is underneath.
A network bridge is basically a software switch.
Imagine two physical computers connected to the same Ethernet switch:
Computer A ──┐
├── Switch ── Network
Computer B ──┘The switch gives both computers a path to the same network.
Docker does something similar inside the host:
Container A ──┐
├── docker0 ── Host network
Container B ──┘docker0 is the bridge.
It is not a physical piece of hardware. It is a software bridge on the Docker host that connects the containers’ virtual network interfaces to a common network.
So when you hear bridge network, remember:
Bridge = a software switch connecting containers on the same Docker host.
That’s the “bridge” part.
The rest of the story is about what Docker puts around that bridge: IP addresses, routing, isolation, and NAT.
The Mental Model to Remember
If you remember only one diagram from this lesson, remember this one:
flowchart LR
C1["Container A<br/>172.x.x.2"] --- V1["virtual interface"]
C2["Container B<br/>172.x.x.3"] --- V2["virtual interface"]
V1 --- D["docker0<br/>Docker bridge<br/>software switch"]
V2 --- D
D --- G["Host network stack<br/>gateway / routing"]
G --- N["NAT / masquerading"]
N --- I((Internet))
Think of it as:
container → virtual interface → docker0 → host → NAT → Internet
And for two containers on the same default bridge:
container → virtual interface → docker0 → other container
That is the core picture to keep in your head whenever you think about Docker bridge networking.
Tip
docker0 is the bridge. It is not “the network” in the abstract — it is the host-side software bridge that connects interfaces belonging to containers on that default bridge network.
What Happens When a Container Starts?
Let’s slow down and follow one container.
Suppose you run:
docker container run -d --name web nginx:alpineBecause you didn’t specify --network, Docker connects web to the default bridge network.
Conceptually, several things happen:
- Docker gives the container its own network namespace.
- The container gets a virtual network interface.
- Docker connects that interface to
docker0. - Docker assigns the container an IP address from the bridge network’s subnet.
- The bridge becomes the container’s path to other containers on that network and, through NAT, to external networks.
From inside the container, it doesn’t see “docker0” and think about bridges.
It simply sees something like:
eth0
172.x.x.x
default gateway: 172.x.x.1The host is doing the plumbing underneath.
You can inspect the network from Docker’s point of view:
docker network inspect bridgeAmong other details, the output shows the bridge network’s configuration and the containers currently attached to it.
Containers Are Automatically Connected
This is the convenient part of the default bridge.
Run two containers without specifying a network:
docker container run -d --name app nginx:alpine
docker container run -d --name test nginx:alpineBoth are automatically connected to bridge.
You can confirm that:
docker network inspect bridgeYou’ll find both app and test listed as containers attached to the network.
That means they have a network path to each other.
But there is an important distinction:
Having network connectivity does not mean having name-based discovery.
The containers can communicate using their IP addresses, but the default bridge does not provide Docker’s automatic container-name DNS resolution.
That’s the limitation that matters.
The Big Limitation: No Container DNS
Suppose Docker gives the containers these addresses:
app → 172.17.0.2
test → 172.17.0.3From test, this works conceptually:
172.17.0.2:80But this does not automatically work:
app:80Why?
Because the default bridge network does not provide the automatic Docker DNS-based service discovery that user-defined bridge networks provide.
So your application would need to know the IP address of the other container.
And container IP addresses are not good application-level identifiers. Containers can be removed and recreated, and their addresses can change.
That creates an awkward setup:
Application
|
v
"Connect to 172.17.0.2"
|
v
Container AIf Container A is recreated and gets 172.17.0.4, the application now has stale information.
What you actually want is:
Application
|
v
"Connect to app"
|
v
Docker resolves "app"
|
v
Container AThat is exactly the problem user-defined bridge networks solve.
Note
Docker’s old --link feature can provide a form of name-based communication on the default bridge, but it is a legacy feature. Modern Docker networking uses user-defined networks for this instead.
A Small Experiment
Let’s see the limitation instead of just taking it on faith.
Start two containers on the default bridge:
docker container run -d --name server nginx:alpine
docker container run -d --name client alpine:latest sleep 300Now ask Docker for the server’s IP address:
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' serverYou should get an address similar to:
172.17.0.2The exact address is not important.
From the client, try the server by its IP:
docker container exec client wget -qO- http://172.17.0.2You should receive HTML from nginx.
Now try the container name:
docker container exec client wget -qO- http://serverOn the default bridge, Docker’s automatic container-name DNS does not resolve server.
This is the key lesson:
Same default bridge
|
+── Can communicate by IP ✓
|
+── Can resolve container name ✗Clean up when you’re finished:
docker container rm -f client serverWhat About the Internet?
The default bridge is not an isolated network with no outside access.
Containers connected to it can normally make outgoing connections through the Docker host.
Conceptually:
flowchart LR
C["Container<br/>172.x.x.x"] --> B["docker0"]
B --> H["Docker host"]
H --> M["NAT / masquerading"]
M --> I((Internet))
The container has a private address that isn’t directly routable on the host’s external network.
Docker uses masquerading/NAT so that outgoing traffic appears to come from the Docker host.
That is why a container can usually do something like:
docker container run --rm busybox ping -c 1 docker.comwithout you manually configuring a route from the container’s private address to the Internet.
Container-to-Container vs Outside Access
There are two different networking questions, and Docker treats them differently.
Container → Container
If both containers are on the same default bridge:
Container A ──┐
├── docker0 ── Container B
Container B ──┘They can communicate using the containers’ internal IP addresses.
No published port is required for this.
Outside → Container
Now imagine your browser is on your laptop and wants to reach a web server inside a container.
That’s different:
Browser
|
v
Host:8080
|
v
Container:80For this, you normally publish the container port:
docker container run -d \
--name web \
--publish 8080:80 \
nginx:alpineNow traffic arriving at the host’s port 8080 can be forwarded to port 80 in the container.
The important distinction is:
Container-to-container communication on the same bridge does not require publishing ports. Publishing is for making a container port reachable through the host’s network interfaces.
Why the Default Bridge Is Fine for Simple Experiments
The default bridge isn’t broken.
For a quick experiment, it is convenient:
docker container run -d --name web nginx:alpineYou get networking automatically.
You don’t need to create anything first.
You don’t need to choose a subnet.
You don’t need to connect the container manually.
For one container that needs Internet access, this is often all you need.
Even for temporary experiments involving multiple containers, communicating by IP can be enough if you’re just exploring networking itself.
The problem appears when containers become parts of an application.
Imagine:
Web application
|
v
Database
|
v
CacheHard-coding container IP addresses is fragile.
You want stable names:
web → database → cacheand you want Docker to resolve those names as containers join the network.
That’s where the default bridge starts feeling like a rough first draft rather than the network you actually want to build an application on.
The Default Bridge’s Main Limitations
Keep these limitations in mind:
| Limitation | Why it matters |
|---|---|
| No automatic container-name DNS | Containers need IP addresses for direct communication |
| All unspecified containers share the same default bridge | Unrelated containers end up on the same network |
| The default bridge is a legacy-style setup | User-defined bridge networks are the recommended approach |
| Configuration is tied to Docker’s daemon-level default bridge | Less flexible than creating separate user-defined networks |
| Container IPs are not stable application identifiers | Recreating a container can change its IP |
The most important one for us is the first:
Default bridge gives you connectivity, but not convenient container-name discovery.
The Bridge Mental Model, One More Time
When you hear Docker bridge network, don’t immediately think of a command.
Think of this:
Docker Host
┌─────────────────────────────────────────────┐
│ │
│ Container A Container B │
│ ┌──────────┐ ┌──────────┐ │
│ │ eth0 │ │ eth0 │ │
│ │172.x.0.2 │ │172.x.0.3 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └──────────┬───────────┘ │
│ │ │
│ ┌───▼───┐ │
│ │docker0│ ← software bridge │
│ └───┬───┘ │
│ │ │
│ Host network stack │
│ │ │
│ NAT / routing │
└──────────────────┼──────────────────────────┘
│
InternetIf you remember container → docker0 → host → NAT → Internet, you’ve got the basic shape of Docker’s default bridge networking.
And if you remember “same bridge = connectivity, but default bridge ≠ automatic name discovery”, you’ve got the reason we need the next lesson.
What’s Next
The default bridge gives us the basic plumbing, but it makes application networking unnecessarily awkward.
The fix is not to abandon bridge networking.
It is to create our own bridge network.
In the next lesson, we’ll create a user-defined bridge with docker network create, put containers on it, and see the important difference firsthand:
Default bridge
app ──?──> database
IP required
User-defined bridge
app ──"database"──> database
Docker DNSThat’s where bridge networking starts becoming genuinely useful for multi-container applications.