🛠️ DevOps Tutorials Docker Network Modes Explained: bridge, host, and none

Docker Network Modes Explained: bridge, host, and none

Understand Docker's bridge, host, and none network modes with practical examples — when to use each, how containers communicate, and how to create custom networks.

Docker's default networking behaviour surprises developers who expect containers to behave like normal processes. Understanding the three built-in network modes — bridge, host, and none — prevents a class of bugs where services cannot reach each other or cannot bind to expected ports.


The default: bridge mode

When you run a container without specifying a network, Docker attaches it to the default bridge network (docker0). Each container gets an IP on the 172.17.0.0/16 subnet and can reach other containers on the same bridge by IP, but not by name.

docker run -d --name app1 nginx
docker run -d --name app2 nginx

# Inspect the IPs
docker inspect app1 | grep IPAddress
docker inspect app2 | grep IPAddress

The default bridge has a limitation: containers cannot resolve each other by name. That is why you should use custom networks for any multi-container setup.


Custom bridge networks

Custom networks enable DNS resolution between containers — this is the main reason to use them:

docker network create mynet

docker run -d --name api   --network mynet myimage
docker run -d --name cache --network mynet redis:7-alpine

Inside api, you can now reach Redis as cache:6379 instead of looking up an IP. Docker's embedded DNS server handles the name resolution automatically.

List networks:

docker network ls

Inspect a network (shows connected containers and their IPs):

docker network inspect mynet

Connect a running container to an additional network:

docker network connect mynet another-container

Host mode

Host mode removes the network namespace entirely. The container shares the host's network stack — it sees the host's IP, binds directly to host ports, and there is no NAT:

docker run --network host nginx

Nginx now binds to port 80 on the host directly. There is no -p flag needed — and in fact -p is ignored in host mode because there is no port mapping to do.

When to use host mode:

  • Performance-critical networking (avoids the overhead of NAT and veth pairs)
  • Applications that need to detect the host's IP or network interfaces
  • Tools that need raw access to host network traffic (monitoring, packet capture)

When not to use host mode:

  • Any situation where you run multiple containers that bind to the same port — they will conflict on the host
  • Environments where you need network isolation between containers and the host

Host mode is Linux-only. On Docker Desktop (macOS / Windows), --network host is silently ignored — the container runs in a VM and does not share the host's actual network stack.


None mode

none disables networking entirely. The container has only a loopback interface:

docker run --network none alpine ip addr

Output:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536
    inet 127.0.0.1/8 scope host lo

Use none for compute jobs that must be air-gapped from the network, or for security-sensitive processing where you want to guarantee no data can leave the container over the network.


Port mapping and how it works

Port mapping (-p) translates between the host's network and the container's bridge network:

docker run -p 8080:80 nginx

Traffic arriving at host port 8080 is NAT'd to container port 80. The host port is optional — omit it to let Docker assign one:

docker run -p 80 nginx                 # Docker picks an available host port
docker port <container_id>             # See what port was assigned

Bind to a specific host interface to restrict exposure:

docker run -p 127.0.0.1:8080:80 nginx  # Only localhost can reach it
docker run -p 0.0.0.0:8080:80 nginx    # All interfaces (default)

The 127.0.0.1: prefix is important on production servers — binding to all interfaces (0.0.0.0) exposes the container directly to the public internet, bypassing any firewall rules on the host.


Container-to-container communication patterns

Scenario Solution
Same host, same app Custom bridge network with DNS names
Same host, different apps Named network, connect each app's containers to it
App talks to service on host Use host.docker.internal (Linux: needs --add-host=host.docker.internal:host-gateway)
Cross-host communication Docker overlay network (Swarm) or an external service mesh

On Linux, accessing the host from inside a container:

docker run --add-host=host.docker.internal:host-gateway alpine curl http://host.docker.internal:3000

Networks in Docker Compose

Compose creates a custom bridge network automatically and attaches all services to it. Services resolve each other by their service name:

services:
  api:
    image: myapp
  db:
    image: postgres:16-alpine
  cache:
    image: redis:7-alpine

api reaches Postgres as db:5432 and Redis as cache:6379 with no extra network configuration.

To isolate groups of services on separate networks:

networks:
  frontend:
  backend:

services:
  nginx:
    networks: [frontend, backend]
  api:
    networks: [backend]
  db:
    networks: [backend]

nginx can talk to both api and reach the internet. db is only reachable from backend — not from anything on frontend. This is the right isolation model for production Compose deployments.


Debugging network issues

Check which network a container is on:

docker inspect <container> --format '{{json .NetworkSettings.Networks}}' | jq .

Test connectivity from inside a container:

docker exec -it api ping db
docker exec -it api curl http://db:5432

See what ports are published on a running container:

docker port <container>

For broader host-level port auditing, the Audit Open Ports tutorial covers ss, netstat, and nmap approaches. For a complete multi-container setup with networking already configured, see Docker Compose.