Intro
Docker bridge networking is the default networking mode for containers on a single host. In production, small misconfigurations can lead to IP conflicts, broken service discovery, or connectivity failures. This guide provides a practical operations checklist to help you manage bridge networks safely and reliably. You will learn how to inventory your environment, make scoped configuration changes, verify connectivity, recover from common failures, and run repeatable operational checks.
A clear bridge networking operations process reduces rework by separating research, implementation, and review. The first useful pilot should be narrow, measurable, and easy to inspect locally before deployment. The steps here are designed for developers, DevOps consultants, and technical startup teams who need a dependable bridge network setup without relying on overlay networks or external tooling.
Throughout this guide, you will find concrete commands with expected output and configuration examples. All examples use the default docker0 bridge and a custom bridge network called app-bridge. These are constructed for illustration and should be adapted to your environment.
Version and Environment Inventory
Before making changes, record the versions and topology. This baseline helps identify compatibility issues and simplifies rollback. Assign a single owner, such as the platform engineer on call, to maintain this inventory and update it after any network change. Review the inventory quarterly or after major Docker upgrades.
Docker Version
Run:
docker version --format '{{.Server.Version}}'
Expected output (example):
24.0.7
Note the client and server versions separately if they differ. Use docker version for full details. Inconsistent client and server versions can cause API mismatches and unexpected behavior, especially when using newer network options. For example, a client from Docker 27 talking to a server on Docker 20 may fail to set some bridge options silently.
Daemon Configuration
Check the effective daemon settings, especially for bridge networking:
docker info --format '{{json .Plugins.Network}}'
Expected output (example):
["bridge","host","ipvlan","macvlan","null","overlay"]
Look for bridge in the list. If it is missing, the daemon is not built with bridge support, which is extremely rare but would break all bridge networking. Next, inspect the default bridge configuration:
docker network inspect bridge
This returns a JSON array with details like Subnet, Gateway, and Options. For example:
[
{
"Name": "bridge",
"Id": "a1b2c3d4...",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
}
}
]
Key fields to record:
Subnet: The default bridge usually uses 172.17.0.0/16. If your organization uses that range internally, you should change the daemon default or avoid the default bridge.Options.com.docker.network.bridge.enable_icc: Inter-container communication is enabled by default on the default bridge, but this is not secure for production. Custom bridges give you finer control.Options.com.docker.network.bridge.enable_ip_masquerade: This allows containers to reach external networks via NAT. Keep it enabled unless you have specific routing needs.
Host Kernel and iptables
Bridge networking relies on iptables for NAT and filtering. Verify kernel version and iptables version:
uname -r
iptables --version
Ensure the br_netfilter module is loaded. This module allows iptables to see bridged traffic, which is essential for inter-container communication policies and port publishing.
lsmod | grep br_netfilter
If missing, load it and make it persistent:
sudo modprobe br_netfilter
# Add the following lines to /etc/modules-load.d/br_netfilter.conf:
# br_netfilter
Also verify the sysctl settings:
sudo sysctl net.bridge.bridge-nf-call-iptables
Expected:
net.bridge.bridge-nf-call-iptables = 1
If it is 0, enable it:
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
# Make it permanent in /etc/sysctl.conf or /etc/sysctl.d/99-bridge.conf
Topology Diagram
Create a simple diagram showing the Docker host, the docker0 bridge, custom bridges, and connected containers. Note IP subnets, exposed ports, and any host firewall rules. Store this diagram in version control or documentation. Include the following details:
- Host IP addresses and interfaces.
- Each bridge name, subnet, and gateway.
- Container names, static or dynamic IPs, and published ports.
- Any firewall rules affecting bridge traffic.
Use a tool like draw.io, Lucidchart, or even a text file with Mermaid syntax. Update the diagram whenever a network changes.
Prerequisites
Confirm the following before any network changes:
- Docker daemon is running:
docker inforeturns without error. - User has permissions to create networks and run containers (typically in the
dockergroup or with sudo). - No conflicting subnets on the host network. For example, if the host LAN is 10.10.0.0/24, do not use that range for a bridge.
- Default bridge is not used for production containers (best practice). Run
docker network inspect bridgeand ensure theContainerssection is empty. If any production containers are attached, migrate them to a custom bridge using the steps in the next section.
Safe Configuration Path
Instead of modifying the default docker0 bridge, create a custom bridge network with explicit IPAM settings. This limits blast radius, allows better isolation, and eases management. Decide who owns network configuration: in a small team, this is often the DevOps engineer; in larger teams, a platform engineering group owns the network templates. Revisit the configuration quarterly or when the Docker environment is upgraded.
Create a Custom Bridge Network
Choose a non-overlapping subnet from your private range. In this example, use 10.10.0.0/24 with gateway 10.10.0.1. The --subnet and --gateway flags are mandatory if you want deterministic IP assignment.
docker network create \
--driver bridge \
--subnet 10.10.0.0/24 \
--gateway 10.10.0.1 \
--opt com.docker.network.bridge.name=br-app \
app-bridge
Expected output:
<network-id>
The --opt com.docker.network.bridge.name=br-app names the Linux bridge interface on the host, which makes it easier to identify in ip addr or brctl show. If you omit this, Docker uses a random interface name like br-4e5f6a7b8c9d. Verify creation:
docker network ls | grep app-bridge
Expected output:
<network-id> app-bridge bridge local
Inspect the new network:
docker network inspect app-bridge
Confirm the subnet and gateway match your intended values.
Attach Containers
When running containers, attach them to the custom network. For example, run a web server and a client:
docker run -d --name web --network app-bridge nginx:alpine
docker run -dit --name client --network app-bridge alpine sh
Check that both containers have IPs in the 10.10.0.0/24 range:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web
Expected output (example):
10.10.0.2
Configure IP Assignment
By default, containers get dynamic IPs from the subnet. For stateful services that need a stable address, assign static IPs using --ip. This requires that the subnet is explicitly defined when creating the network and that the IP is outside any dynamic allocation pool if you have configured one.
docker run -d --name db --network app-bridge --ip 10.10.0.10 postgres:16
Be cautious to avoid IP conflicts. Before assigning a static IP, inspect the network to see which IPs are already in use:
docker network inspect app-bridge --format '{{range .Containers}}{{.IPv4Address}}{{"\n"}}{{end}}'
Expected output (example):
10.10.0.2/24
10.10.0.3/24
Then choose an unused IP. Also check that the network IPAM pool is large enough. For a /24 subnet, you have 253 usable addresses; if you expect more containers, use a larger subnet like /22.
Enable Inter-Container Communication
By default, containers on the same custom bridge network can communicate with each other on all ports. If you need isolation, set --opt com.docker.network.bridge.enable_icc=false when creating the network. This tells Docker to add iptables rules that block traffic between containers on the same bridge unless they are explicitly linked or ports are published.
Example:
docker network create \
--driver bridge \
--subnet 10.10.10.0/24 \
--opt com.docker.network.bridge.enable_icc=false \
isolated-bridge
Then use --link (deprecated but still works) or more commonly use published ports and service discovery. With icc=false, each container can still communicate with the outside world but not with each other directly. To allow specific traffic, you can use --publish on one container and have others access it via the host IP and published port, or use a separate network with icc=true for services that need to talk.
Adjust MTU if Needed
For overlay networks, VPNs, or jumbo frame environments, you might need a lower MTU to avoid fragmentation. Use --opt com.docker.network.driver.mtu=1400.
docker network create \
--driver bridge \
--subnet 10.10.20.0/24 \
--opt com.docker.network.driver.mtu=1400 \
low-mtu-bridge
After creating, verify by running ip link show br-<network-id> on the host and check the MTU value.
Document Changes
Keep a log of network names, subnets, gateways, and attached services. Use a configuration file or Infrastructure as Code tool like Terraform or Ansible. For example, a simple YAML manifest for your networks:
networks:
- name: app-bridge
subnet: 10.10.0.0/24
gateway: 10.10.0.1
options:
bridge_name: br-app
icc: true
mtu: 1500
owner: DevOps Team
review_frequency: quarterly
Commit this file to version control and require a pull request for changes.
Verification and Diagnostics
After configuring, run checks to confirm connectivity, name resolution, and network isolation. Perform these checks immediately after any network change and as part of your routine monitoring.
Basic Connectivity
From the client container, ping the web container by name. Docker's embedded DNS allows name resolution on custom networks but not on the default bridge.
docker exec client ping -c 4 web
Expected output (trimmed):
PING web (10.10.0.2): 56 data bytes
64 bytes from 10.10.0.2: seq=0 ttl=64 time=0.120 ms
...
--- web ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
If ping fails, check:
- Container status:
docker ps -ato see if both are running. - Network assignment:
docker inspect -f '{{.NetworkSettings.Networks}}' clientshould showapp-bridge. - IP address:
docker exec client ip addrto confirm it has an IP in the subnet.
DNS Resolution
Test reverse lookup inside the container:
docker exec client nslookup 10.10.0.2
Expected output includes the container name web:
Server: 127.0.0.11
Address: 127.0.0.11#53
2.0.10.10.in-addr.arpa name = web.
If the lookup fails, ensure the container is on a custom network, not the default bridge, and that the embedded DNS server at 127.0.0.11 is reachable.
Port Exposure
If you published a port, test from the host. For example, run web with -p 8080:80:
docker run -d --name web --network app-bridge -p 8080:80 nginx:alpine
curl http://localhost:8080
Expected output: the nginx default page HTML, starting with <!DOCTYPE html>.
Check port mapping with:
docker port web
Expected:
80/tcp -> 0.0.0.0:8080
If you cannot reach the service, verify the host firewall allows inbound traffic on 8080, and check iptables NAT rules with sudo iptables -t nat -L -n | grep 8080.
Inspect Network Details
View the network with docker network inspect app-bridge. Check the Containers section for IP and MAC addresses. Example snippet:
"Containers": {
"<container-id>": {
"Name": "web",
"IPv4Address": "10.10.0.2/24",
"MacAddress": "02:42:0a:0a:00:02"
}
}
Verify that the IPs are within your subnet and that MAC addresses are unique.
iptables Rules
Check that iptables has rules for the custom bridge. Run:
sudo iptables -L -n -v | grep br-app
You should see rules for forwarding and masquerading. For example:
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- br-app br-app anywhere anywhere
If you have icc=false, you will see DROP rules between containers. If no rules appear, check if the bridge interface name is correct and if the network was created with the expected options.
Network Isolation Test
If you enabled icc=false, test that containers cannot ping each other (unless explicitly allowed). For example, from client, ping db:
docker exec client ping -c 2 db
Expected: no response or timeout.
If the ping succeeds, isolation is not working. Check the network options: docker network inspect isolated-bridge | grep -o 'com.docker.network.bridge.enable_icc": "[^"]*' should show false. Also verify iptables rules for the bridge.
Failure Modes and Recovery
Bridge networks can fail due to IP conflicts, DNS issues, firewall misconfigurations, or daemon restarts. Here are common failure modes and how to recover. Appoint an on-call engineer to handle network incidents, with a primary and secondary contact. Document each incident and review monthly to identify recurring issues.
IP Address Conflict
Symptom: Containers lose connectivity or cannot start with static IP. Docker may report an error like failed to allocate IP address if the IP is already in use outside Docker.
Check: docker network inspect app-bridge and look for duplicate IPs or --ip outside subnet. Also check the host's ARP table: ip neigh | grep 10.10.0.10. If an external device has the same IP, you have a conflict.
Recovery: Disconnect and reconnect the container with a correct IP, or remove and recreate the network after stopping all attached containers.
docker network disconnect app-bridge <container-id>
docker network connect --ip 10.10.0.12 app-bridge <container-id>
If the IP is taken by an external device, either change the external device's IP or choose a different static IP for the container.
DNS Resolution Failure
Symptom: Containers cannot resolve names, but IP connectivity works.
Check: Ensure the network is not the default bridge (default bridge does not provide DNS). Verify /etc/resolv.conf inside the container:
docker exec web cat /etc/resolv.conf
Expected:
nameserver 127.0.0.11
options ndots:0
The 127.0.0.11 is Docker's embedded DNS server. If it is missing or different, the container may not be on a user-defined network.
Recovery: Attach the container to a custom bridge if it was on the default bridge; restart the container if DNS settings are stale. If the issue persists, check if the Docker daemon's DNS configuration is broken: docker info | grep -A3 'DNS'.
Connectivity Lost After Daemon Restart
Docker restores user-defined networks on daemon restart. If not, ensure network configuration files exist in /var/lib/docker/network/files.
ls /var/lib/docker/network/files/
Each network should have a file named like <network-id>.local. If missing, the network may not be recoverable.
Recovery: Manually recreate the network with the same parameters, then reconnect containers. Use a script or IaC to ensure reproducible creation.
docker network create --driver bridge --subnet 10.10.0.0/24 --gateway 10.10.0.1 --opt com.docker.network.bridge.name=br-app app-bridge
# reconnect each container
docker network connect app-bridge web
docker network connect app-bridge client
Check that containers retain their IPs if they were static, or get new IPs if dynamic, and update DNS accordingly.
Firewall Over-Blocking
If a host firewall blocks inter-container traffic, adjust iptables or firewalld. Example: allow all traffic on the br-app interface:
sudo iptables -I FORWARD -i br-app -j ACCEPT
sudo iptables -I FORWARD -o br-app -j ACCEPT
But be careful: this disables any isolation on that bridge. A more targeted rule allows only specific ports between containers.
For firewalld, add the bridge interface to the trusted zone:
sudo firewall-cmd --permanent --zone=trusted --change-interface=br-app
sudo firewall-cmd --reload
Rollback Strategy
Before making changes, snapshot the network configuration using docker network inspect and save to a file. To rollback, stop containers, remove the custom network, and restore the previous state.
# Save current network configs
docker network inspect app-bridge > app-bridge-before.json
# On rollback, disconnect containers
for c in $(docker network inspect app-bridge -f '{{range .Containers}}{{.Name}} {{end}}'); do
docker network disconnect app-bridge $c
done
# Remove the network
docker network rm app-bridge
# Recreate from snapshot (manually or via script)
# Use the parameters from the saved JSON to recreate the network
Automate snapshots before every change and store them in a versioned backup.
Common Pitfalls and Mistakes
Even experienced operators make mistakes with Docker bridge networking. Here are common pitfalls, why they happen, and how to avoid or recover from them.
Using the Default Bridge for Production
Why it happens: It is the easiest option; docker run without --network attaches to the default bridge.
Why it is a problem: The default bridge does not provide automatic DNS resolution between containers; you must use legacy --link. It also does not allow easy isolation or custom subnets. Changes to the default bridge require daemon restart and affect all containers.
How to avoid: Create a custom bridge for each application or environment. Enforce this through a policy or by using a wrapper script that always specifies --network.
Recovery: Stop the container, create a custom bridge, and re-run the container with --network custom-bridge. If the container needs to be reachable by others, use the container name as hostname.
IP Address Exhaustion
Why it happens: Using a small subnet like /28 or /29, or assigning many static IPs without cleanup.
Why it is a problem: New containers cannot get IPs, causing failures.
How to avoid: Monitor IP usage. Use docker network inspect to count used IPs. For dynamic pools, set an appropriate subnet size based on expected container count. If you use static IPs, maintain an IPAM spreadsheet or database. Review monthly.
Recovery: Expand the subnet by recreating the network with a larger subnet (requires stopping all containers and reconnecting). Alternatively, free up unused IPs by removing dead containers.
Forgetting to Set enable_icc=false for Multi-Tenant Networks
Why it happens: The default is true, and operators may not think about isolation.
Why it is a problem: Any container on the same bridge can access any other container on any port, bypassing application-level security.
How to avoid: Set --opt com.docker.network.bridge.enable_icc=false for networks that host untrusted or multi-tenant workloads. Then explicitly allow needed communication via published ports or more granular iptables rules.
Recovery: You cannot change icc on an existing network; you must recreate the network with the option and reconnect containers.
Ignoring Host Firewall Interactions
Why it happens: Assuming Docker manages all firewall rules and the host firewall (ufw, firewalld, iptables) won't interfere.
Why it is a problem: Host firewall rules may block bridge traffic, especially if they have a default deny policy on the FORWARD chain. Docker inserts its own rules, but order matters and other tools can disrupt them.
How to avoid: Understand your host's firewall configuration. Ensure Docker's rules are not overridden. For ufw, set DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw if needed, and use ufw allow for published ports.
Recovery: Temporarily disable the host firewall to test, then add appropriate rules. For iptables, insert ACCEPT rules for the bridge interface, but be cautious not to open too broadly.
Static IP Conflicts with Dynamic Range
Why it happens: When creating a network, Docker's default IPAM allocator reserves the entire subnet for dynamic allocation, so even static IPs may be within that range. If you later manually assign an IP outside the subnet, it fails. But more subtle: if you assign a static IP that falls within the dynamic pool, Docker's IPAM does not know about it and may assign the same IP to another container.
Why it is a problem: IP conflicts cause intermittent connectivity or container start failures.
How to avoid: Reserve a sub-range for static IPs by using --ip-range when creating the network. For example, use subnet 10.10.0.0/24 and ip-range 10.10.0.128/25, leaving 10.10.0.1-127 for static assignment.
docker network create \
--driver bridge \
--subnet 10.10.0.0/24 \
--ip-range 10.10.0.128/25 \
--gateway 10.10.0.1 \
app-bridge-static
Then dynamic containers get IPs >= 10.10.0.128, and you can safely assign static IPs < 10.10.0.128.
Recovery: Recreate the network with a proper --ip-range, or manually track static IPs to avoid the dynamic pool.
Operations Checklist
Use this checklist for routine operations and periodic reviews. It covers the key areas from this guide. Assign a single owner (e.g., the on-call DevOps engineer) to perform daily checks and a platform lead to perform monthly audits. Revisit the checklist itself quarterly.
Daily/Weekly Checks
| Check | Command | Expected Result |
|---|---|---|
| Containers running | docker ps | All desired containers up; no unexpected restarts |
| Network list | docker network ls | Expected custom bridges present; no orphan networks |
| Ping between key services | docker exec <container> ping -c 1 <other> | 0% packet loss |
| DNS resolution | docker exec <container> nslookup <name> | Container IP returned |
| Host port mapping | curl localhost:<host-port> | Service responds with expected content |
| IP address usage | docker network inspect <network> -f '{{range .Containers}}{{.IPv4Address}}{{"\n"}}{{end}}' | No IPs outside subnet; no duplicates |
Example of ping and DNS checks:
docker exec client ping -c 1 web
docker exec client nslookup web
Expected:
1 packets transmitted, 1 packets received, 0% packet loss
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: web
Address 1: 10.10.0.2
Monthly/Quarterly Audits
- Review IPAM allocations for exhaustion: check
docker network inspect <network>and count used IPs. Compare against the subnet size to ensure at least 20% free space. - Verify no production containers are attached to the default bridge network:
docker network inspect bridgeshould show no containers. If any are found, migrate them following the steps above. - Update documentation and diagrams to reflect current state.
- Test failure recovery: simulate container crash (
docker kill <container>and see if restart policy works), and test network recreation in a staging environment. - Clean unused networks:
docker network prune(careful: removes all unused networks). Do a dry run first withdocker network ls -f dangling=true.
Change Management
- Always test new network configurations on a staging host first. Create a mirror of the production bridge network and validate all connectivity and DNS checks.
- Use version-controlled configuration files for network creation. Apply changes via CI/CD pipeline where possible.
- Schedule maintenance windows for network changes. For critical networks, choose low-traffic periods and notify stakeholders at least 48 hours in advance.
- Have a rollback plan ready. Snapshot configurations before changes and rehearse the rollback procedure at least once per quarter.
Conclusion
Docker bridge networking is a foundational technology that requires careful operational attention. By following this checklist, you can reduce downtime and configuration drift. Start with a thorough inventory of your environment, then create custom bridge networks with explicit subnets and options. Verify connectivity and DNS before deploying to production, and be prepared to recover from common failures using the steps outlined.
Your next steps:
- Run the inventory commands and document your current state in a shared wiki or repository.
- Create a new custom bridge network for a test application and validate connectivity and isolation.
- Integrate the daily checks into your monitoring system (e.g., cron jobs, Nagios, or Prometheus exporters).
- Share this checklist with your team and assign an owner for each recurring task.
Remember, a clear bridge networking operations process reduces rework by separating research, implementation, and review. The first useful pilot should be narrow and easy to inspect locally. Use this guide as a living document and adapt it to your organization's standards.