CloudOpsGuide
docker

Docker Networking Explained: Bridges, DNS, and Published Ports

Intermediate
10 minutes
October 2026
CloudOpsGuide Team

Docker Networking Explained: Bridges, DNS, and Published Ports

Docker networking is the part everyone glosses over until a container can't reach the database. Here's the model that matters, straight from how the Docker Engine actually implements it.

Table of Contents

The default bridge — and its big limitation

When Docker starts, it creates a built-in bridge network. Every container launched without --network lands there, gets an IP, a gateway, DNS, and outbound access via NAT masquerading — so containers reach the internet out of the box.

The catch: on the default bridge, containers can only reach each other by IP address — no name resolution. Those IPs change on restart. This alone is why real apps go on user-defined networks.

User-defined networks: where DNS lives

docker network create -d bridge my-net
docker run -d --network=my-net --name api myapi
docker run -it --network=my-net busybox ping api   # name resolution works

On a user-defined network, Docker's embedded DNS resolves container names and network aliases. This is also exactly what Compose does: it creates a per-project network so services resolve each other by service name.

The network drivers

  • bridge — the default; private NAT'd network on one host.
  • host — removes network isolation; the container shares the host's interfaces. Fast, no port mapping, but no isolation.
  • none — fully isolated. Loopback only. Useful for batch jobs that shouldn't talk to anything.
  • overlay — spans multiple Docker daemons (Swarm); encrypted VXLAN tunnels between hosts.
  • ipvlan/macvlan — containers get real addresses on your physical LAN. Powerful for legacy network integration, tricky for routing.

Publishing ports: the only door in

All ports on a bridge-networked container are reachable from the host and sibling containers by default — but nothing reaches them from outside until you publish:

docker run -d -p 8080:80 nginx          # host:8080 → container:80
docker run -d -p 127.0.0.1:8080:80 nginx # bind to localhost only

Binding to 127.0.0.1 is the habit to build: only publish to all interfaces (0.0.0.0) what genuinely needs to be public. An exposed database port you forgot about is a classic breach path.

Multi-homed containers and internal networks

A container can join multiple networks — like a host with multiple NICs. The production pattern: a frontend network for the proxy plus an --internal backend network that has no external route at all:

docker network create frontend
docker network create --internal backend

# proxy sees both worlds; db sees only backend
docker run -d --network backend --name db postgres:17
docker run -d --network backend --network frontend --name proxy nginx
docker network connect backend api-container

With --internal, the database can never be reached from the internet even if you mis-publish a port — isolation enforced by the network, not by discipline.

Subnets and IP management

Docker allocates subnets from built-in pools (172.17–31.0.0/x, 192.168.0.0/16). Override with --subnet, or reconfigure default-address-pools in /etc/docker/daemon.json — worth doing if your corporate VPN already uses 172.17.x and routes collide.

Debugging checklist

docker network ls
docker network inspect my-net            # who's attached, what subnet
docker exec api ping -c1 db              # name resolution + reachability
docker exec api getent hosts db          # DNS answer specifically
docker port web                          # published port mappings

"Can't connect" is almost always one of: containers on different networks, hitting the container name on the default bridge (no DNS), or testing localhost from inside a container — which is the container itself, not your host.

Related Articles


Last Updated: October 2026 Author: CloudOpsGuide Team Difficulty: Intermediate Estimated Reading Time: 10 minutes