21.9. Networks
Table of Contents
Why Docker Networks Matter
When you run several containers, they need a way to talk to each other securely and predictably. Docker networks provide that communication layer.
Without understanding networks, you will often see confusing errors like "connection refused" or "host not found" when containers try to talk to databases, caches, or other services.
In this chapter you will learn how Docker networking works in practice, and how to connect your backend services in a clean way.
Docker Networking Basics
Docker creates and manages its own virtual networks on your host machine. Containers attach to these networks. Inside a network, containers can talk to each other using container names, similar to using hostnames.
You can see existing networks with:
docker network lsExample output:
| NETWORK ID | NAME | DRIVER | SCOPE |
|---|---|---|---|
| 123abc... | bridge | bridge | local |
| 456def... | host | host | local |
| 789ghi... | none | null | local |
The important parts for now:
- NAME is what you will refer to.
- DRIVER defines the network type and behavior.
Default Network Drivers
Docker includes several built-in network drivers. The main ones you will use:
| Driver | Description | Typical Use Case |
|---|---|---|
| bridge | Private network on the host, NAT to the outside world | Default for single host apps |
| host | Container shares the host network stack | Performance or special network needs |
| none | No network at all | Security isolation, one-off tasks |
| overlay | Multi-host networking (with Swarm) | Distributed apps across multiple Docker hosts |
For most backend development on a single server, bridge networks are what you need.
Bridge Networks in Practice
A bridge network is a private virtual network on the host. Containers on the same bridge network:
- Can reach each other by container name.
- Are isolated from other networks by default.
- Use NAT to access the outside internet.
Docker automatically creates a default bridge network named bridge, but best practice is to create your own user-defined bridge networks.
Important rule:
Use user-defined bridge networks, not the default bridge, when you want containers to discover each other by name and communicate reliably.
Create a user-defined bridge network:
docker network create myapp-networkRun containers on that network:
docker run -d --name api --network myapp-network myapi-image
docker run -d --name db --network myapp-network postgres:16
Inside the api container, you can connect to the database using the hostname db, for example:
Host: db
Port: 5432No IP addresses are needed. Docker runs a small DNS server that resolves container names inside the network.
host and none Networks
Although bridge networks cover most use cases, it is useful to know about host and none.
host Network
With the host driver on Linux, the container shares the host’s network stack.
Example:
docker run --network host myapi-imageEffects:
- No port mapping is needed, the container listens directly on host ports.
localhost:8000on the host is the same aslocalhost:8000in the container.- Less isolation, can be useful for:
- High performance networking.
- Using services that bind only to
127.0.0.1. - Debugging network behavior.
On macOS and Windows, --network host behaves differently due to the extra VM layer, so do not rely on it for production there.
none Network
With the none driver, the container has no network access at all:
docker run --network none myimageUseful when you want:
- Complete network isolation for security.
- To run tools that do not need any network.
Creating and Managing Networks
You already saw docker network create. Here is a small set of common commands.
Creating a Network
docker network create myapp-networkSpecify the driver explicitly (optional for bridge):
docker network create --driver bridge myapp-networkListing Networks
docker network lsFilter by name:
docker network ls --filter name=myappInspecting a Network
To see details and attached containers:
docker network inspect myapp-networkKey pieces in the output:
Driver:bridge,host, etc.IPAM: IP ranges.Containers: list of containers attached and their IP addresses.
Example snippet:
"Containers": {
"c123...": {
"Name": "api",
"IPv4Address": "172.20.0.2/16"
},
"c456...": {
"Name": "db",
"IPv4Address": "172.20.0.3/16"
}
}Removing a Network
docker network rm myapp-networkThe network must be unused. If containers are still attached, you will get an error. Stop or disconnect containers first.
Connecting Containers to Networks
You can attach a container to a network when starting it, or later.
Connect at Container Creation
docker run -d --name api --network myapp-network myapi-image
If you do not specify --network, Docker uses the default bridge network.
Connect After Container Creation
Attach an existing container:
docker network connect myapp-network api
Now the container api can talk to other containers on myapp-network.
Disconnect a container:
docker network disconnect myapp-network apiThe container keeps running, but loses access to that network.
Multiple Networks per Container
A single container can belong to multiple networks. This is useful to separate concerns, for example:
- One frontend network between reverse proxy and app.
- One backend network between app and database.
Example:
# Create networks
docker network create frontend-net
docker network create backend-net
# Run database only on backend-net
docker run -d --name db --network backend-net postgres:16
# Run app on backend-net first
docker run -d --name api --network backend-net myapi-image
# Attach app also to frontend-net
docker network connect frontend-net api
# Run reverse proxy only on frontend-net
docker run -d --name nginx --network frontend-net nginx:alpineNetwork visibility:
| Container | Networks | Can Reach |
|---|---|---|
| db | backend-net | api |
| api | backend-net, frontend-net | db, nginx |
| nginx | frontend-net | api |
nginx cannot directly reach db, which is good for security. Only the api container can talk to the database.
Exposing Ports vs Container Networking
A common confusion is the difference between:
- Ports exposed to the host with
-p HOST:CONTAINER. - Ports used between containers on the same Docker network.
Inside a user-defined bridge network:
- Containers communicate using the container’s internal port.
- Port publishing to the host is not required for containers to reach each other.
Example:
docker network create myapp-network
# PostgreSQL listens on 5432 inside the container
docker run -d --name db --network myapp-network postgres:16
# API listens on port 8000 inside the container
docker run -d --name api --network myapp-network myapi-image
Inside api:
- The database is at
db:5432.
The host machine cannot reach either of them yet.
To allow your browser to access the API:
docker run -d --name api \
--network myapp-network \
-p 8000:8000 \
myapi-imageNow:
- From host:
http://localhost:8000 - From another container on
myapp-network:http://api:8000
Key rule:
Use -p HOST:CONTAINER only when you need host or external access.
For container-to-container communication on a user-defined bridge, you do not need to publish ports.
Example: FastAPI + PostgreSQL Network Setup
A realistic backend scenario:
- A FastAPI app container.
- A PostgreSQL database container.
- A shared user-defined bridge network.
Step 1: Create Network
docker network create backend-netStep 2: Start PostgreSQL
docker run -d \
--name db \
--network backend-net \
-e POSTGRES_USER=appuser \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=appdb \
postgres:16
No -p is used, so the database is not exposed to the host or internet.
Step 3: Start FastAPI
docker run -d \
--name api \
--network backend-net \
-p 8000:8000 \
-e DATABASE_URL="postgresql://appuser:secret@db:5432/appdb" \
my-fastapi-imageImportant parts:
- The
DATABASE_URLusesdbas the hostname. - Port
8000is published to the host for browser access. - The database is only reachable from containers on
backend-net.
Result:
| From | How to reach API | How to reach DB |
|---|---|---|
| Host machine | localhost:8000 | Not accessible directly |
api container | http://db:5432 | Using db hostname |
Other containers on backend-net | http://api:8000 | db:5432 |
Networks and Docker Compose (Preview)
Another chapter covers Docker Compose in detail, but you will often see networks defined there.
A minimal example:
version: "3.9"
services:
api:
build: .
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
networks:
default:
driver: bridge
By default, Compose creates a user-defined bridge network (e.g. projectname_default). Services can reach each other by service name:
apiconnects to DB atdb:5432.
You rarely need to think about docker network create explicitly when using Compose, but the concepts are the same.
Troubleshooting Network Issues
Common networking problems and how to reason about them.
"Connection refused"
Possible causes:
- Target service is not running or crashed.
- Service is listening on a different port.
- You used host
localhostinstead of the container name inside a network.
Check:
- Container status:
docker ps
docker logs <container>- Port configuration in the app and Docker run/compose.
- Hostname in configuration:
- From container to container: use container name or service name.
- From host to container: use
localhost:EXPOSED_PORT.
"Name or service not known" / DNS errors
Docker cannot resolve that hostname inside the network.
Typical mistake:
- Using
localhostas DB host inside the container environment.
Correct:
- Use the container name that runs the database, such as
db.
Example of wrong vs right connection strings inside a container:
| Wrong | Right |
|---|---|
postgresql://user:pass@localhost:5432 | postgresql://user:pass@db:5432 |
Summary
- Docker networks let containers communicate in an isolated and predictable way.
- User-defined bridge networks are the standard choice for single-host backend applications.
- Containers on the same bridge network can reach each other by container name, without publishing ports.
- Publish ports with
-p HOST:CONTAINERonly when the host or external clients must access the service. - A container can join multiple networks, which lets you separate frontend and backend communication.
- Use hostnames like
db,api,redisbetween containers, notlocalhost.
These concepts are the foundation for running complete backend stacks in Docker, especially FastAPI + PostgreSQL + Redis setups.
Views: 7
KAHIBARO