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
- The Docker CLI sends the requested image, command, and network mode to the Docker daemon.
- The daemon prepares the container filesystem from image layers and creates the runtime configuration.
- 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. - If you used
-pwith bridge networking, Docker configures host-port forwarding to the container’s IP and port. - For
hoston Linux, Docker starts the process in the host network namespace. There is no separate container IP address and no Docker port mapping layer. - For
none, Docker creates a network namespace but does not connect it to any external network. Only loopback is present. - 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
hostas a specialized Linux mode for performance-sensitive, diagnostic, or host-integrated workloads, not as a default. - Do not combine
--network hostwith-p; the port mapping layer is not what host networking uses. - Use
nonefor 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-alpineandalpine:3.20for reproducible examples and deployments. - Inspect behavior with
docker network inspect,docker ps, and simple test containers such ascurlimages/curl:8.9.1.
Practice Exercises
- Create a user-defined bridge network named
shop-net. Run Nginx asshop-webon that network, then use a one-off curl container to requesthttp://shop-web. Expected end state: curl prints the Nginx welcome page. - Run an Alpine container with
--network noneand inspect its network interfaces. Hint: compare the output with the same command on a normal bridge network. - Decide whether
bridge,host, ornonefits this scenario: a batch job reads mounted files, transforms them, and must never call an external API. Explain your choice.
Summary
bridgeis 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_PORTwhen the host must reach a container port. hostnetworking shares the host network namespace on Linux, so ports bind directly and-pis unnecessary.nonecreates an isolated network namespace with loopback only and no external connectivity.EXPOSEis metadata, not port publishing.- The safest default is a user-defined bridge network with only required ports published.
