Skip to main content

Bridge Network

The default Docker network driver that creates an isolated virtual network on the host, connecting containers via a Linux bridge device. User-defined bridge networks add automatic DNS resolution by container name.

Bridge Network — The Default Way Docker Containers Communicate

What Is a Bridge Network in Simple Terms?

A bridge network is Docker's default way of connecting containers to each other and to the outside world. When you run docker run nginx without specifying a network, Docker automatically connects that container to the bridge network. The container gets a private IP address, and Docker sets up routing rules on the host so the container can reach the internet and you can publish ports to access it.

The name comes from the Linux networking concept — Docker creates a virtual network bridge device called docker0 on the host, and every container on the bridge network connects to it like a switch.

◈ DIAGRAM
+------------------------------------------+
| Linux Host |
| |
| docker0 bridge (172.17.0.1) |
| | | | |
| v v v |
| +--------+ +--------+ +--------+ |
| |nginx | |api | |db | |
| |.0.2 | |.0.3 | |.0.4 | |
| +--------+ +--------+ +--------+ |
| |
| iptables NAT rules: |
| containers -> internet (masquerade) |
| -p 8080:80 -> DNAT to container IP |
+------------------------------------------+

Default Bridge vs User-Defined Bridge

There are two types of bridge network and they behave very differently:

Bash
+------------------------------------------+
| Default Bridge (docker0) |
| |
| Created automatically by Docker |
| All containers join this by default |
| |
| NO DNS — containers can only reach |
| each other by IP address |
| IP addresses change on restart |
| NOT suitable for multi-container apps |
+------------------------------------------+
+------------------------------------------+
| User-Defined Bridge |
| |
| Created with: docker network create |
| Containers join with --network flag |
| |
| HAS DNS — containers resolve each |
| other by container name |
| Name-based addressing is stable |
| CORRECT choice for real applications |
+------------------------------------------+

How Linux Bridge Networking Works

Bash
# When Docker creates a bridge network, it creates a Linux bridge device
ip link show
# docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
# br-a84f9c2b: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
# ^ user-defined bridge network
# Each container gets a veth pair (virtual ethernet cable)
# One end inside the container (eth0)
# Other end on the host connected to the bridge
ip link show | grep veth
# veth3a2b1c0@if4: <- connected to container eth0
# iptables handles routing
sudo iptables -t nat -L POSTROUTING
# MASQUERADE all -- 172.17.0.0/16 -> internet (outbound NAT)
# MASQUERADE all -- 172.18.0.0/16 -> internet (user-defined network)

Working With Bridge Networks

Bash
# Default bridge — containers join automatically
docker run -d --name web nginx
docker run -d --name api node:20-alpine sleep 3600
# Cannot reach by name on default bridge
docker exec api ping web
# ping: bad address 'web' — NO DNS on default bridge
# Must use IP — but IP changes on restart
docker inspect web --format '{{.NetworkSettings.IPAddress}}'
# 172.17.0.2
docker exec api ping 172.17.0.2
# works, but fragile
# Create a user-defined bridge
docker network create payment-network
# Run containers on user-defined bridge
docker run -d --name payment-api \
--network payment-network \
registry.razorpay.in/payment-api:v3.1.0
docker run -d --name postgres \
--network payment-network \
postgres:15 -e POSTGRES_PASSWORD=secret
# Now DNS works — containers find each other by name
docker exec payment-api ping postgres
# PING postgres (172.18.0.3) — success
# List all networks
docker network ls
# NETWORK ID NAME DRIVER
# a84f9c2b1d bridge bridge <- default
# b72c8a9f4e payment-network bridge <- user-defined
# Inspect a network
docker network inspect payment-network
# Shows subnet, gateway, connected containers and their IPs
# Connect an existing container to another network
docker network connect monitoring-network payment-api
# payment-api is now on both payment-network and monitoring-network
# Remove a network (all containers must be disconnected first)
docker network rm payment-network
# Remove all unused networks
docker network prune

Bridge Networks in Docker Compose

Docker Compose automatically creates a user-defined bridge network for each project:

YAML
# docker-compose.yml
version: "3.8"
services:
api:
image: payment-api:latest
postgres:
image: postgres:15
# Compose creates: projectname_default bridge network
# api can reach postgres by name: postgres
# postgres can reach api by name: api
# No extra network config needed for basic use
Bash
# See the auto-created network
docker network ls | grep projectname
# projectname_default bridge local

Troubleshooting Bridge Network Issues

Problem Cause Fix
Container name not resolving On default bridge (no DNS) Create user-defined network
Cannot reach internet from container iptables FORWARD rules missing Restart Docker: systemctl restart docker
Port binding fails Another process using host port Check `ss -tulpn
Two containers cannot communicate On different networks docker network connect network-name container
IP address keeps changing Using default bridge by name Use user-defined bridge — names are stable
Tip

Always create a user-defined bridge network for any multi-container application. The one-line command docker network create app-network takes 2 seconds and gives you DNS, better isolation, and stable container name resolution. The default bridge network is only suitable for running a single standalone container.

Remember

The default bridge network docker0 has no DNS — containers can only find each other by IP address which changes on every restart. User-defined bridge networks automatically provide DNS resolution by container name. This single difference is the most important thing to understand about Docker networking.

Common Mistake

Trying to use container names in application config when containers are on the default bridge network. DB_HOST=postgres in your environment variables will fail with name not resolved on the default bridge. Either create a user-defined network or use Docker Compose which creates one automatically.

Security

Containers on the same bridge network can communicate with each other on any port without restriction. If you need to restrict which containers can talk to which, use Docker Network Policies or move services that should not communicate onto separate networks.

Frequently Asked Questions

Why does Docker recommend user-defined bridge networks over the default one?

Containers on the default bridge network can only reach each other by IP address — there's no built-in DNS resolution by container name, so linking services requires either hardcoded IPs (which change on restart) or the deprecated `--link` flag. A user-defined bridge network runs an embedded DNS server that resolves container names to their current IP automatically, which is why `docker-compose` creates a dedicated bridge network per project by default rather than using the default one.

What's a common networking mistake with bridge networks in production-like setups?

Assuming containers on a bridge network are as isolated from the host as they are from each other. Published ports (`-p 8080:80`) punch through the bridge's iptables rules to the host's network interface, and by default that binds to all host interfaces (`0.0.0.0`), not just localhost — exposing the container to anything that can reach the host's network, not just other local processes. Binding to `127.0.0.1:8080:80` instead is the fix when the port should only be reachable locally.