Bridge, Host, and None Networks

Docker network drivers decide what kind of network environment a container receives. The three single-host drivers you will meet most often are bridge, host, and none.

Use bridge for normal application containers, host when you deliberately want a Linux container to share the host network namespace, and none when a container should have no network except loopback. Choosing the right driver affects service discovery, port publishing, security boundaries, and debugging.

Overview: How Network Drivers Work

When you run a container, Docker creates a container from an image’s read-only layers plus a thin writable layer, then starts a process with Linux isolation features. One of those features is a network namespace: a separate view of interfaces, routes, ports, and firewall behavior. A network driver tells Docker how to attach that namespace, or whether to create a separate namespace at all.

The default driver for ordinary single-host containers is bridge. A bridge network is a private virtual network on the Docker host. Docker creates a Linux bridge device, connects containers to it with virtual Ethernet pairs, assigns container IP addresses, and configures forwarding so containers can usually reach the outside world. On user-defined bridge networks, Docker also provides embedded DNS, so containers can reach each other by container name or Compose service name. This is the right default for web apps, APIs, databases, caches, queues, and most local development stacks.

The built-in bridge network named exactly bridge is older and less friendly than user-defined bridge networks. Containers on the default bridge can communicate by IP, but automatic name-based DNS is not available in the same way. For real projects, create your own bridge network or let docker compose create one for the project.

The host driver is very different. With --network host, the container does not get its own isolated network namespace. On Linux, the process inside the container uses the host’s network namespace directly. If an Nginx process inside the container listens on port 80, it is listening on host port 80. Because there is no separate container IP address, -p port publishing is ignored or unnecessary with host networking. This can reduce network translation overhead and simplify some low-level tooling, but it weakens isolation and increases port-conflict risk. Docker Desktop runs containers inside a Linux VM, so host networking behavior may refer to that VM rather than your macOS or Windows host in some environments.

The none driver gives the container an isolated network namespace with only the loopback interface. The container cannot reach the internet, cannot reach other containers, and cannot be reached through a Docker network. This is useful for jobs that should process local files only, tests that must prove code does not make network calls, or defense-in-depth around untrusted workloads. It is not the same as stopping a process from opening localhost; loopback still exists inside the container.

These drivers are about runtime networking, not image contents. A Dockerfile instruction such as EXPOSE 80 is only documentation and image metadata. It does not publish a port, does not open a firewall, and does not override the selected network driver.

Syntax

The general forms are:

docker network create --driver bridge NETWORK_NAME
docker run --network NETWORK_OR_DRIVER IMAGE COMMAND
docker run --network none IMAGE COMMAND
Option or driver Meaning
--driver bridge Create a user-defined bridge network. This is also the default for docker network create.
--network bridge Attach a container to Docker’s built-in default bridge network.
--network my-net Attach a container to a named network, usually a user-defined bridge network.
--network host Use the host network namespace on Linux. Do not combine it with -p.
--network none Create a container with no external network connectivity.
-p 8080:80 Publish a port for bridge-style networking: host port 8080 forwards to container port 80.
docker network inspect NAME Show the driver, subnet, options, and connected containers for a Docker network.

In Compose, the ordinary default network is a bridge network. You can declare custom networks and choose the driver explicitly:

services:
  web:
    image: nginx:1.27-alpine
    networks:
      - appnet
networks:
  appnet:
    driver: bridge

Examples

Example 1: Use a user-defined bridge network

Create a bridge network, start a web server on it, and use a one-off curl container on the same network to reach the web server by name:

docker network create --driver bridge driver-demo
docker run -d --name driver-web --network driver-demo nginx:1.27-alpine
docker run --rm --network driver-demo curlimages/curl:8.9.1 http://driver-web

Output:

driver-demo
5b5f2e1d9a33
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

The two containers share the driver-demo bridge network, so Docker DNS resolves driver-web to the web container’s current IP address. No port is published to the host. This is private container-to-container traffic on a user-defined bridge.

Example 2: Publish a bridge container to the host

Bridge networks keep container ports private until you publish them:

docker run -d --name bridge-published --network driver-demo -p 8080:80 nginx:1.27-alpine
docker ps --filter name=bridge-published

Output:

9c72f0b6e321
CONTAINER ID   IMAGE               STATUS         PORTS
9c72f0b6e321   nginx:1.27-alpine   Up 4 seconds   0.0.0.0:8080->80/tcp

Now a browser or host-side command can reach http://localhost:8080. The container still listens on port 80 internally; Docker forwards host port 8080 to that container port. This forwarding is a bridge-network feature and is separate from container DNS.

Example 3: Inspect host networking on Linux

Host networking is mostly useful on Linux. This self-contained example asks a container to show the network interfaces it sees while using the host network namespace:

docker run --rm --network host alpine:3.20 ip addr show

Output:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default

On native Linux, this output reflects the host network namespace rather than a private container bridge endpoint. A server process started with host networking binds host ports directly. Notice that there is no -p flag, because there is no separate container network endpoint to publish.

Example 4: Run a container with no network

The none driver is useful when a container should not make network calls:

docker run --rm --network none alpine:3.20 ip addr show

Output:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    inet 127.0.0.1/8 scope host lo

The container has a loopback device, but no Ethernet interface connected to a Docker bridge. A command that tries to download packages, call an API, or reach another container will fail unless it only uses local files or loopback services started inside the same container.

How It Works Step by Step

  1. The Docker CLI sends the requested image, command, and network mode to the Docker daemon.
  2. The daemon prepares the container filesystem from image layers and creates the runtime configuration.
  3. For bridge, Docker creates a container network namespace, attaches it to a bridge through a virtual Ethernet pair, assigns an IP address, and registers DNS names on user-defined networks.
  4. If you used -p with bridge networking, Docker configures host-port forwarding to the container’s IP and port.
  5. For host on Linux, Docker starts the process in the host network namespace. There is no separate container IP address and no Docker port mapping layer.
  6. For none, Docker creates a network namespace but does not connect it to any external network. Only loopback is present.
  7. When the container is removed, Docker removes its network endpoint. User-defined networks remain until you remove them or Compose removes the project.

Common Mistakes

Using host networking to fix a DNS problem

This is usually the wrong fix:

docker run -d --name api --network host myapi:1.0

If the real problem is that the API cannot find Redis, put both containers on the same bridge network and use the service name:

docker network create api-net
docker run -d --name redis --network api-net redis:7.2-alpine
docker run -d --name api --network api-net myapi:1.0

Host networking removes much of the network isolation and creates host port conflicts. It does not provide Docker DNS for another container the way a user-defined bridge network does.

Combining host networking with port publishing

This command is conceptually wrong:

docker run -d --name host-web --network host -p 8080:80 nginx:1.27-alpine

With host networking, the process binds host ports directly. Use bridge networking with -p, or use host networking without -p only when you truly want direct host namespace access.

Expecting none to allow internet access

This will not be able to fetch from the network:

docker run --rm --network none alpine:3.20 wget -O - https://example.com

The fix is not a DNS flag; the container has no external interface. Use a bridge network when the workload needs outbound access, or keep none for deliberately offline jobs.

Expecting EXPOSE to publish a bridge port

A Dockerfile can document a port:

FROM nginx:1.27-alpine
EXPOSE 80

But EXPOSE does not publish anything. Start the container with -p 8080:80 or use Compose ports: when host access is required.

Best Practices

  • Use user-defined bridge networks for normal single-host applications and local development.
  • Use Compose service names or container names for discovery on bridge networks; avoid hard-coded container IP addresses.
  • Publish only the ports that users or host-side tools need. Container-to-container traffic on the same bridge does not require -p.
  • Treat host as a specialized Linux mode for performance-sensitive, diagnostic, or host-integrated workloads, not as a default.
  • Do not combine --network host with -p; the port mapping layer is not what host networking uses.
  • Use none for intentionally offline jobs, local file processing, or tests that must fail if code tries to use the network.
  • Remember Docker Desktop’s host networking details may differ from native Linux because containers run inside a Linux VM.
  • Use pinned image tags such as nginx:1.27-alpine and alpine:3.20 for reproducible examples and deployments.
  • Inspect behavior with docker network inspect, docker ps, and simple test containers such as curlimages/curl:8.9.1.

Practice Exercises

  1. Create a user-defined bridge network named shop-net. Run Nginx as shop-web on that network, then use a one-off curl container to request http://shop-web. Expected end state: curl prints the Nginx welcome page.
  2. Run an Alpine container with --network none and inspect its network interfaces. Hint: compare the output with the same command on a normal bridge network.
  3. Decide whether bridge, host, or none fits this scenario: a batch job reads mounted files, transforms them, and must never call an external API. Explain your choice.

Summary

  • bridge is Docker’s standard single-host networking model and the best default for most containers.
  • User-defined bridge networks provide automatic DNS by container or service name.
  • Bridge containers need -p HOST_PORT:CONTAINER_PORT when the host must reach a container port.
  • host networking shares the host network namespace on Linux, so ports bind directly and -p is unnecessary.
  • none creates an isolated network namespace with loopback only and no external connectivity.
  • EXPOSE is metadata, not port publishing.
  • The safest default is a user-defined bridge network with only required ports published.