Container Networking: bridge, host, none, and Custom Networks
Introduction¶
Docker networking confuses people because a lot happens invisibly: a bridge interface, veth pairs, NAT rules, an embedded DNS server. Understanding the modes makes port and connectivity problems obvious.
The modes¶
bridge (default). Each container gets a private IP on the docker0 bridge
(or a user-defined bridge). Outbound traffic is NATed (masqueraded) to the
host's IP. Inbound requires explicit port publishing.
host. The container shares the host's network namespace — no isolation, no
NAT, no port publishing needed (or possible). EXPOSE 8080 means it's on the
host's 8080 directly. Fastest, least isolated. Linux only.
none. No networking at all except loopback. For batch jobs that only touch
the filesystem, or where you attach networking yourself.
container:<name>. Share another container's namespace (how a sidecar shares
localhost with the main container; also how Kubernetes pods work).
Default bridge vs user-defined bridge¶
The legacy default bridge network has no service discovery — containers
reach each other only by IP, and you'd use the deprecated --link. A
user-defined bridge adds an embedded DNS server: containers resolve each
other by name.
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet -p 3000:3000 myapi
# inside "api", the host "db" resolves to db's container IP
Always create a network. Compose does this for you automatically (one network per project, services reachable by service name).
Publishing vs exposing¶
EXPOSE 8080in the Dockerfile is documentation only — it opens nothing.-p 8080:80(orports:in compose) publishes: Docker adds a DNAT rule so the host's0.0.0.0:8080forwards to the container's:80.-p 127.0.0.1:8080:80binds only to loopback — the container port is reachable from the host but not the network. Use this for admin/debug ports.
The firewall reality: -p 8080:80 inserts rules into the DOCKER iptables
chain that bypass your INPUT filtering. A ufw deny 8080 will not block
a published container port. Mitigations: bind to 127.0.0.1, use
DOCKER-USER chain rules, or set "iptables": false and manage it yourself
(advanced).
Inspecting¶
docker network ls
docker network inspect appnet # subnet, gateway, connected containers + IPs
docker inspect -f '{{json .NetworkSettings.Networks}}' api | jq
docker exec api ip addr
docker exec api getent hosts db # test embedded DNS
iptables -t nat -L DOCKER -n # the DNAT rules for published ports
Verification and troubleshooting¶
- Container A can't reach container B by name — they're on the default
bridge (no DNS) or on different networks.
docker network connect appnet B, or put both on the same user-defined network. - Published port not reachable from another machine — the app inside binds
to
127.0.0.1inside the container, not0.0.0.0. It must listen on all interfaces within its namespace. ufw/firewalldrule not blocking a container port — Docker's NAT rules run first. UseDOCKER-USERchain or bind to loopback.- Outbound DNS fails inside the container — the container uses Docker's
resolver (127.0.0.11) which forwards to the host's; if the host's
/etc/resolv.confpoints at127.0.0.53(systemd-resolved) it can break. Set--dnsor fix composedns:. hostmode "port already in use" — no isolation, so the container's port collides with a host service. That's the tradeoff.- Two compose projects can't talk — separate networks by default. Create an external shared network and reference it in both.
- Slow DNS / 5s stalls — musl libc (alpine) doing parallel A/AAAA lookups
against Docker's resolver; a known interaction.
single-requestoptions or a glibc base.
Related tools and reading¶
- On-site: Port Checker, Subnet Calculator.
- Related posts: Docker Compose for local development, Kubernetes Services and Endpoints.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Docker & Kubernetes
StatefulSets Explained
StatefulSets give pods sticky names, sticky storage, and ordered operations — what databases and clustered apps need. Here's how each guarantee works.
October 24, 2026Persistent Volumes and Claims, Explained
PVC is a request, PV is the fulfilled storage, StorageClass is the factory. Most 'Pending PVC' problems are an access-mode or provisioner mismatch.
October 24, 2026Kubernetes Jobs and CronJobs
A Job runs pods until they succeed; a CronJob creates Jobs on a schedule. Here's parallelism, retry limits, the missed-schedule trap, and history cleanup.
October 24, 2026