clean separation instead of one shared default network
Running every container in the default bridge network means giving up name resolution, isolation between projects and the ability to cut containers off from the internet on purpose. A dedicated bridge network per project solves exactly these three problems with a few lines of configuration.
Table of contents
- 1. Why the default bridge falls short
- 2. Docker network drivers at a glance
- 3. Creating and using a custom bridge network
- 4. Built-in DNS and service discovery
- 5. Segmenting with multiple bridge networks
- 6. Internal networks with no internet access
- 7. Subnets, gateways and fixed IP addresses
- 8. Configuring networks in Docker Compose
- 9. Default bridge, custom bridge and host network compared
- 10. Summary
- 11. FAQ
1. Why the default bridge falls short
Every freshly installed Docker host ships with a network called bridge that gets assigned to every container without an explicit choice. At first glance this works: containers get an IP address, can reach the internet and can talk to each other by IP. That is exactly the problem for anyone running more than one or two containers. A bridge network in its default configuration provides no automatic name resolution between containers, which means every connection has to go through an IP address that can change on every restart.
Even more serious is the missing isolation. If project A and project B both run on the same host without their own bridge network, all containers end up in the same default segment and can reach each other, even when that was never intended functionally. A compromised container from project A would then have direct network access to the database of project B. A dedicated bridge network per project or per environment closes this gap, because Docker separates containers in different networks by default unless they explicitly join the same network.
2. Docker network drivers at a glance
Docker ships with several network drivers, and a bridge network is the default case for anything running on a single host. The bridge driver creates a virtual network bridge inside the Linux kernel, to which every container is connected through a virtual Ethernet pair. The host driver skips isolation entirely and shares the host's network namespace directly with the container, which brings performance benefits but makes any port mapping impossible because the container listens directly on the host's ports.
For multi-host scenarios there is the overlay driver, which connects containers across multiple Docker hosts inside one virtual network, usually in the context of Docker Swarm. The macvlan driver assigns containers their own MAC addresses on the physical LAN, so they appear as standalone devices on the network. For most projects on a single server or a single development machine, though, the bridge network remains the right choice because it offers the best balance of isolation, configurability and simplicity.
# List all networks including the default bridge, host and none
docker network ls
# Inspect the driver, subnet and connected containers of a network
docker network inspect bridge
# Show only the driver column for a quick overview
docker network ls --format '{{.Name}}: {{.Driver}}'
3. Creating and using a custom bridge network
Creating a custom bridge network is a one-line command. It is important to choose a descriptive name so that on a host running multiple projects it is immediately clear which network belongs to which application. After creation, the network is assigned to a container at start time via --network, or an already running container can be added afterward with docker network connect without restarting it.
A container can be a member of several networks at the same time, for example a reverse proxy that sits both in the public network and in several internal application networks. This is a common pattern for defining exactly one entry point, while the services behind it stay isolated from each other in separate bridge networks. Anyone who wants to remove a network first has to disconnect or stop all connected containers, otherwise Docker refuses the deletion with a clear error message.
# Create a dedicated bridge network for one project
docker network create shop-network
# Start a container attached to that network directly
docker run -d --name shop-db --network shop-network mysql:8.0
# Attach an already running container to an additional network
docker network connect shop-network shop-cache
# Detach a container from a network without stopping it
docker network disconnect shop-network shop-cache
# Remove an unused network
docker network rm shop-network
4. Built-in DNS and service discovery
The decisive advantage of a custom bridge network over the default bridge is built-in name resolution. As soon as two containers join the same custom network, they can reach each other by container name, with zero manual configuration. Docker runs an embedded DNS server at address 127.0.0.11 inside every container for this purpose, resolving container names and, in Compose, service names as well, to their respective IP addresses.
In practice this means: an application that connects to shop-db:3306 instead of a fixed IP keeps working even after the database container restarts and receives a new IP address. This name resolution is the main reason teams should generally use custom bridge networks instead of the default bridge, even when only two containers are involved. Alias names can additionally be assigned via --network-alias, so a container is reachable under several names at once, for example during a migration from an old to a new service name.
5. Segmenting with multiple bridge networks
With multiple bridge networks, an application can be split into clearly separated zones. A typical pattern for an online shop: a frontend network containing only the web server and reverse proxy, a backend network with application containers, and a database network containing only the database and the application containers, but not the web server. The web server then has no network route to the database at all, even if it were compromised.
This kind of segmentation using separate bridge networks is significantly easier to implement than classic firewall rules, because Docker enforces the separation out of the box without requiring manually maintained iptables rules. What matters: any container that needs to communicate across multiple zones, for example the application container between the backend and database networks, simply gets assigned to both networks. Docker manages the corresponding routes automatically through the respective network bridge in the kernel.
6. Internal networks with no internet access
For particularly sensitive services such as a database or an internal cache, a bridge network can be created with the --internal flag. Docker then sets up no route through the host's external interface, so containers in this network can neither open outbound connections to the internet nor be reached from outside. Even if an attacker managed to run code inside such a container, it would have no way out, which makes data exfiltration significantly harder.
The trade-off: containers in an internal bridge network also cannot fetch package updates or make external API calls, which is usually fine for a database but unsuitable for an application container with external dependencies. The common pattern is therefore a combination: an internal network for database and cache, a normal bridge network for the application layer, connected through an application container that is a member of both networks.
# Create an internal network with no route to the outside world
docker network create --internal db-internal
# Attach the database container only to the internal network
docker run -d --name shop-db --network db-internal mysql:8.0
# Verify: this container has no default route to the internet
docker run --rm --network db-internal alpine \
sh -c "ping -c 1 -W 2 1.1.1.1 || echo 'no route to internet, as expected'"
7. Subnets, gateways and fixed IP addresses
By default Docker automatically picks a free subnet from a private address range when creating a bridge network. In environments with many networks or overlaps with the corporate network, it makes sense to specify subnet and gateway explicitly. This prevents address conflicts and makes the network topology traceable in documentation, because each project gets a fixed, known subnet.
Fixed IP addresses inside a bridge network are unnecessary in most cases, because DNS-based name resolution already solves the underlying problem. There are exceptions though: legacy applications that hardcode IP addresses in a configuration file, or monitoring systems that query by IP instead of by name. For such cases, a container can be assigned a fixed IP from the defined subnet at start time, which stays the same across restarts.
# Create a bridge network with an explicit subnet and gateway
docker network create \
--driver bridge \
--subnet 172.28.0.0/16 \
--gateway 172.28.0.1 \
shop-network
# Start a container with a fixed IP address inside that subnet
docker run -d --name shop-db \
--network shop-network \
--ip 172.28.0.10 \
mysql:8.0
8. Configuring networks in Docker Compose
In Docker Compose, a bridge network is created automatically for every project, named after the project directory. For the segmentation described in the previous section, additional named networks can be defined in the networks section of the Compose file and assigned to services individually. This allows combining several bridge networks within the same Compose project, for example an internal and a public one, without maintaining a separate Compose file for each network.
A service without a networks entry is automatically assigned to the Compose project's default network. Anyone taking segmentation seriously should explicitly assign the right networks to every service, instead of relying on the automatically generated default network, because that behavior is easy to overlook and unintentionally merges all services together.
services:
proxy:
image: nginx:alpine
networks:
- frontend
app:
image: shop-app:latest
networks:
- frontend
- backend
db:
image: mysql:8.0
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
9. Default bridge, custom bridge and host network compared
The choice between the default bridge, a custom bridge network and the host network has direct consequences for isolation, DNS resolution and port management. The following table summarizes the key differences that matter when deciding on the network architecture of a new project.
| Property | Default bridge | Custom bridge network | Host network |
|---|---|---|---|
| DNS between containers | No, only by IP | Yes, by container or service name | Not applicable, no own namespace |
| Isolation between projects | Low, all in the same segment | High, separate networks per project | None, container shares the host stack |
| Publishing ports | Requires -p |
Requires -p |
Directly on host ports |
| Blocking internet access | Not possible network-wide | Yes, with --internal |
Not possible network-wide |
| Recommendation | Only for throwaway containers | Standard for most projects | Only when native performance is required |
In practice this comparison shows why the default bridge is rarely a good choice past the initial testing phase of a project. A bridge network per project, supplemented with internal networks for sensitive services, covers most requirements around name resolution and isolation without needing the complexity of overlay networks or macvlan configurations.
Mironsoft
Docker infrastructure, network architecture and container isolation
Docker networks without properly separated isolation?
We audit existing Docker stacks, set up segmented bridge networks and shield sensitive services from the internet using internal networks.
Network audit
Review existing bridge configuration for isolation gaps
Segmentation
Cleanly separate frontend, backend and database networks
Compose refactoring
Extend existing Compose files with internal networks
10. Summary
A dedicated bridge network per project is the simplest lever for isolating Docker containers from each other while still getting comfortable name resolution. Instead of managing IP addresses, containers address each other by container or service name, while the embedded DNS server at 127.0.0.11 handles the resolution. With multiple bridge networks, an application can be segmented into frontend, backend and database zones, so a compromised web server would not automatically have access to the database.
The --internal flag extends this approach for particularly sensitive services by blocking every route to the internet. Fixed subnets and IP addresses remain the exception for legacy cases, while most modern applications benefit from the automatic name resolution of a bridge network. Anyone who consistently maps these fundamentals in Docker Compose through the networks section gets a traceable, documented network topology instead of a randomly grown default bridge with all containers in one segment.
Custom Bridge Networks for Container Isolation — Key Takeaways
DNS instead of fixed IPs
Only custom bridge networks provide name resolution via container and service names through 127.0.0.11.
Segmentation
Multiple bridge networks separate frontend, backend and database; one container can belong to several networks.
internal flag
--internal blocks every route to the internet, ideal for databases and caches with no external dependencies.
Compose practice
Assign networks to every service explicitly instead of relying on the automatically generated default network.