Custom Networks and Container Isolation
Why separate networks
Section titled “Why separate networks”Putting every container on the same network means all of them can reach each other — frontend and database, or one microservice and another microservice that should have no reason to know about it. Network segmentation is a zero-cost security control: containers on different networks cannot reach each other unless explicitly connected to both.
Creating a separate network per tier of your application:
- Limits communication to only what is necessary.
- Reduces the blast radius if a container is compromised.
- Makes the architecture explicit and self-documenting.
Creating separate networks
Section titled “Creating separate networks”docker network create uses the bridge driver by default, so you can omit --driver bridge for brevity. Create two networks for a frontend and a backend:
docker network create frontend-netdocker network create backend-netRunning containers on different networks
Section titled “Running containers on different networks”docker run -d --name frontend --network frontend-net nginx:alpinedocker run -d --name database --network backend-net -e POSTGRES_PASSWORD=example postgres:alpinefrontend and database are on different networks, so they cannot reach each other by default.
A typical three-tier application takes this further with three networks:
| Network | Containers attached | Can reach |
|---|---|---|
frontend-net | nginx-proxy, web-app | Each other only |
backend-net | web-app, api-server | Each other only |
data-net | api-server, postgres | Each other only |
web-app is connected to both frontend-net and backend-net, so it bridges the two tiers. postgres is on data-net only — the nginx proxy cannot reach the database directly, even if compromised.
Verifying containers cannot communicate
Section titled “Verifying containers cannot communicate”docker exec frontend ping -c 2 database || echo "Cannot reach database"The ping fails as expected, because frontend is on frontend-net and database is on backend-net.
Connecting a container to an additional network
Section titled “Connecting a container to an additional network”A running container can be attached to another network without restarting it:
docker network connect backend-net frontendfrontend now has interfaces on both frontend-net and backend-net, and can resolve and reach database by name:
docker exec frontend ping -c 2 databaseDisconnecting and removing networks
Section titled “Disconnecting and removing networks”# Detach frontend from backend-net againdocker network disconnect backend-net frontend
# Filter docker network ls to just bridge networksdocker network ls --filter driver=bridge
# Inspect a network's driver, subnet, gateway, and attached containersdocker network inspect frontend-netA network cannot be removed while containers are attached to it — stop and remove the containers first, then remove the network:
docker network rm frontend-netCleanup
Section titled “Cleanup”docker stop frontend databasedocker rm frontend databasedocker network rm frontend-net backend-netHands-on: isolation between networks
Section titled “Hands-on: isolation between networks”# Create two isolated networks
docker network create frontend-net
docker network create backend-net
# Run containers on separate networks
docker run -d --name frontend --network frontend-net nginx:alpine
docker run -d --name database --network backend-net -e POSTGRES_PASSWORD=example postgres:alpine
# frontend cannot reach database (different networks)
docker exec frontend ping -c 2 database || echo "Cannot reach database"
# Connect frontend to backend-net so it can reach the database
docker network connect backend-net frontend
# Now frontend can reach database
docker exec frontend ping -c 2 database
# Inspect a network
docker network inspect frontend-net
# Disconnect
docker network disconnect backend-net frontend
# Cleanup
docker stop frontend database && docker rm frontend database
docker network rm frontend-net backend-netTrade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
| Put everything on one network | Fast to set up, no network topology to think about | Every container can see and reach every other one, needlessly widening the attack surface |
| Separate networks per tier (frontend/backend/data) | Limits communication to what is necessary, reduces the impact of a compromised container | Have to manage several networks and connect/disconnect containers yourself |
Common mistakes
Section titled “Common mistakes”- Putting unrelated containers on the same network (or leaving them on the default bridge), so a database becomes reachable from any container running on the same machine.
- Forgetting that
docker network connectonly adds a network — you still have todocker network disconnectit yourself; a container does not drop it automatically when it stops. - Reusing the same network across every environment (dev/staging/prod), so containers from different environments end up mixed together unintentionally.
💡 Real-world example
Docker Compose automatically creates a separate user-defined network per project (named after the project directory, e.g.
myapp_default), so services in one project cannot collide with or see containers from another project on the same dev machine — the standard pattern for multi-project local development.