Docker Networking Explained: Bridge, Host and Custom Networks
Basics4 minInnovialabs editorial team
In short
Containers on the same user-defined network find each other by service name, and the outside world reaches an app only through a published port (-p). Host networking removes isolation and is rarely needed.
How Docker networking works
Every container gets its own network stack: its own IP address, its own ports, its own localhost. Docker connects containers to each other and to the host through network drivers. In everyday work three options matter:
- bridge (default) — a virtual network inside the host. Containers get internal addresses and reach the outside through NAT.
- user-defined bridge network — the same idea, plus built-in DNS by container name and better isolation. This is the standard choice.
- host — the container uses the host's network stack directly, with no isolation and no port publishing.
Other drivers exist (none, overlay, macvlan), but they serve special cases: full isolation, clusters, or attaching a container directly to a physical network.
Publishing ports: reaching a container from outside
By default, a port inside a container is not reachable from the host or the internet. To open it, you publish it:
docker run -d -p 8080:80 nginx
Read it as HOST:CONTAINER: requests to port 8080 on the host go to port 80 in the container.
Details that matter:
-p 8080:80listens on all host interfaces, so the port may be visible from the internet. If the service is for local use only, use-p 127.0.0.1:8080:80.- Docker adds its own firewall rules on the host, and they can bypass tools like
ufw. Do not publish database ports unless you have to. EXPOSEin a Dockerfile is documentation only — it does not open a port.
DNS by service name
On a user-defined network, containers address each other by name, not IP. IP addresses change every time a container is recreated; names do not.
docker network create app-net
docker run -d --name db --network app-net postgres
docker run -d --name api --network app-net my-api
Now api connects to the database at db:5432. On the default bridge network this DNS does not work, which is a common cause of "host not found" errors.
In Docker Compose, a user-defined network is created automatically, and each service name from docker-compose.yml becomes its DNS name:
services:
api:
build: .
ports:
- "8080:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
db:
image: postgres:16
Note that db has no ports section. The database does not need to be reachable from outside — api reaches it over the internal network.
Comparing the modes
| Mode | Isolation | DNS by name | Needs -p | When to use |
|---|---|---|---|---|
| default bridge | yes | no | yes | quick experiments |
| user-defined bridge | yes | yes | yes, for outside access | almost always |
| host | no | — | no | special network performance cases, Linux only |
| none | full | — | — | workloads without network |
Common mistakes
localhostinside a container. For a container,localhostis itself — not the host and not a neighbour container. Reach neighbours by service name.- The app listens on 127.0.0.1. If the server inside the container binds to
127.0.0.1, the published port will not work. Listen on0.0.0.0. - Swapped ports in
-p. The host port is on the left, the container port on the right. - Port already taken on the host. Docker will not start the container if another process uses that host port.
- Containers on different networks. Services from different Compose projects cannot see each other by default. Attach them to a shared external network.
- A database exposed to the world. Publishing
5432or3306on all interfaces is a direct security risk.
How to check connectivity
docker network ls— list networks.docker network inspect app-net— which containers are attached and their addresses.docker exec -it api sh, thenping dbornc -zv db 5432(if the image has these tools) — test reachability from inside.docker port api— which ports are published.
Driver details are in the official Docker documentation.