Skip to content

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:alpine

You 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 ls

You’ll normally see networks such as:

NETWORK ID     NAME      DRIVER    SCOPE
...            bridge    bridge    local
...            host      host      local
...            none      null      local

The interesting one for this lesson is:

bridge    bridge    local

The 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:alpine

Because you didn’t specify --network, Docker connects web to the default bridge network.

Conceptually, several things happen:

  1. Docker gives the container its own network namespace.
  2. The container gets a virtual network interface.
  3. Docker connects that interface to docker0.
  4. Docker assigns the container an IP address from the bridge network’s subnet.
  5. 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.1

The host is doing the plumbing underneath.

You can inspect the network from Docker’s point of view:

docker network inspect bridge

Among 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:alpine

Both are automatically connected to bridge.

You can confirm that:

docker network inspect bridge

You’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.3

From test, this works conceptually:

172.17.0.2:80

But this does not automatically work:

app:80

Why?

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 A

If 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 A

That 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 300

Now ask Docker for the server’s IP address:

docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' server

You should get an address similar to:

172.17.0.2

The exact address is not important.

From the client, try the server by its IP:

docker container exec client wget -qO- http://172.17.0.2

You should receive HTML from nginx.

Now try the container name:

docker container exec client wget -qO- http://server

On 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 server

What 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.com

without 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:80

For this, you normally publish the container port:

docker container run -d \
  --name web \
  --publish 8080:80 \
  nginx:alpine

Now 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:alpine

You 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
Cache

Hard-coding container IP addresses is fragile.

You want stable names:

web → database → cache

and 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:

LimitationWhy it matters
No automatic container-name DNSContainers need IP addresses for direct communication
All unspecified containers share the same default bridgeUnrelated containers end up on the same network
The default bridge is a legacy-style setupUser-defined bridge networks are the recommended approach
Configuration is tied to Docker’s daemon-level default bridgeLess flexible than creating separate user-defined networks
Container IPs are not stable application identifiersRecreating 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                 │
└──────────────────┼──────────────────────────┘
                   │
                Internet

If 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 DNS

That’s where bridge networking starts becoming genuinely useful for multi-container applications.

Last updated on