Docker Networking: Connect Containers

Once you move past single-container tests, the next problem is communication. A web application needs to reach its database, a reverse proxy needs to forward traffic to an app server, and none of those internal services should be exposed to the public internet by accident.
Docker networking handles that traffic. The defaults work for quick tests, but production-like setups are easier to manage when you understand networks, drivers, DNS names, and published ports. This guide explains how Docker networking works and walks through practical examples for connecting and isolating containers.
How Docker Networking Works
When the Docker daemon starts, it creates three networks automatically: bridge, host, and none. You can see them with docker network ls:
docker network lsNETWORK ID NAME DRIVER SCOPE
b84a2c1f9d8e bridge bridge local
c1f3a7b2d4e5 host host local
e7d6a8c2b1f4 none null localEach network uses a driver that decides how containers on that network communicate:
bridge- Creates an isolated virtual network on one Docker host.host- Removes network namespace isolation and uses the host network directly.none- Starts the container with only a loopback interface.
The bridge driver is the default and works for most single-host applications. For anything beyond a quick test, create a user-defined bridge network instead of relying on the default bridge network. User-defined networks give containers automatic DNS resolution by name and keep unrelated services separated.
The Default Bridge Network
When you start a container without specifying a network, Docker attaches it to the default bridge network. Containers on this network can reach each other by IP address, but not by container name, which makes configuration brittle.
Start two containers on the default network:
docker run -d --name default_web1 nginx
docker run -d --name default_web2 nginxInspect the default bridge to see both containers and their IP addresses:
docker network inspect bridgeThe output includes a Containers section listing each container with its assigned IP address. Containers on the default bridge can communicate with those addresses, but a name such as default_web2 does not resolve automatically from default_web1. That is the main reason to avoid the default bridge for application stacks.
Creating a User-Defined Bridge Network
User-defined bridge networks solve the name resolution problem and let you group related containers together. Create one with docker network create:
docker network create app_neta1b2c3d4e5f67890123456789abcdef0Now run containers on that network by passing --network:
docker run -d --name net_web --network app_net nginx
docker run -d --name net_client --network app_net alpine sleep 3600From inside net_client, you can reach net_web by container name:
docker exec -it net_client ping -c 2 net_webPING net_web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.098 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.074 msThe embedded Docker DNS server resolves the container name to the correct IP address. If you add or remove containers, the DNS records update automatically, so you do not have to track container IP addresses yourself.
Publishing Ports to the Host
Containers on a bridge network are reachable from other containers on the same network, but not from outside the Docker host unless you publish a port. Use -p host_port:container_port with docker run:
docker run -d --name port_web -p 8080:80 nginxNginx listens on port 80 inside the container, and Docker forwards traffic from port 8080 on the host to it. A browser pointed at http://localhost:8080 reaches the container.
You can publish multiple ports by repeating the flag:
docker run -d --name port_app -p 8081:80 -p 8443:443 nginxBy default, Docker publishes the port on all host interfaces. To bind only to a specific host interface, prefix the host port with the address:
docker run -d --name loopback_web -p 127.0.0.1:8082:80 nginxThis binds the port to the loopback interface only. The container is reachable from the host itself, but not from other machines on the network.
Connecting a Running Container to a Network
A container is not locked to the network it was started on. You can attach a running container to an additional network with docker network connect:
docker network connect app_net default_web1After connecting, default_web1 has an IP address on both its original network and app_net. Containers on either network can reach it through the network they share. This is useful when a service needs to talk to more than one group of containers, for example a shared logger or monitoring agent.
To remove a container from a network, use docker network disconnect:
docker network disconnect app_net default_web1Isolating Containers with Separate Networks
Multiple user-defined networks act as separate network segments. Containers on different networks cannot reach each other unless one of them is explicitly connected to both. This makes it simple to isolate a frontend tier from a database tier.
Create two networks:
docker network create frontend_net
docker network create backend_netStart a database on backend_net, an application container on both networks, and a web server on frontend_net:
docker run -d --name db_net --network backend_net -e POSTGRES_PASSWORD=localpass postgres:16-alpine
docker run -d --name app_net_demo --network backend_net alpine sleep 3600
docker network connect frontend_net app_net_demo
docker run -d --name web_net --network frontend_net -p 8083:80 nginxThe web_net container can reach app_net_demo over frontend_net, and app_net_demo can reach db_net over backend_net. The web_net container cannot reach db_net directly because they do not share a network. If the web container is compromised, it cannot open a connection to the database without going through the application layer.
The host Network Driver
The host driver skips network namespace isolation and attaches the container directly to the host network. The container shares the host network interfaces, so any port it listens on is immediately available on the host:
docker run --rm -d --name host_nginx --network host nginxNginx is now reachable on port 80 of the host with no port publishing. In host mode, -p, --publish, and --publish-all are ignored because there is no separate container network namespace to map from.
Use host networking only when you specifically need it, such as for very high port counts or when the application must bind directly to host interfaces. The trade-off is weaker network isolation and possible port conflicts with services already running on the host.
Host networking is native to Docker Engine on Linux. Docker Desktop supports host networking in version 4.34 and later, but it must be enabled in Docker Desktop settings.
The none Network Driver
The none driver disables external networking for the container. The container gets a loopback interface and nothing else:
docker run --rm --network none alpine ip addrThis is useful for batch jobs that process local files and should not reach the network.
Inspecting Networks
docker network inspect prints the full configuration of a network in JSON:
docker network inspect app_netThe output includes the subnet, gateway, driver options, and a list of every container attached to the network with its IPv4 and IPv6 addresses. When a container cannot reach another container, this is usually the first place to look.
For a quick overview across all bridge networks, use a filter:
docker network ls --filter driver=bridgeYou can also inspect a container to see its network attachments:
docker inspect net_webLook for the NetworkSettings.Networks section in the output.
Removing Networks
Unused networks remain on the host until you remove them. Delete a single network with docker network rm:
docker network create temp_net
docker network rm temp_netThe removal command fails if any containers are still attached. Stop or disconnect those containers first, then retry.
To clean up every user-defined network that is not in use, run:
docker network pruneDocker asks for confirmation and then removes idle user-defined networks. The built-in bridge, host, and none networks are not removed.
Docker Compose Networking
When you run applications with Docker Compose , Compose creates a dedicated default network for each project and attaches every service to it. Services reach each other by service name without extra configuration:
services:
web:
image: nginx
ports:
- "8080:80"
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}Define the password in a local .env file:
POSTGRES_PASSWORD=change-this-passwordFrom the web service, db resolves to the database container IP address. You can also declare multiple named networks under a top-level networks key and attach services selectively, which mirrors the frontend and backend split shown earlier.
.env files or real passwords to version control. Add .env to .gitignore, and use secret management from your platform for production credentials.Quick Reference
For a printable quick reference, see the Docker cheatsheet .
| Command | Description |
|---|---|
docker network ls | List Docker networks |
docker network create app_net | Create a user-defined bridge network |
docker run --network app_net image | Start a container on a network |
docker network connect app_net container | Attach a running container to a network |
docker network disconnect app_net container | Remove a container from a network |
docker network inspect app_net | Show network configuration and attached containers |
docker run -p 8080:80 image | Publish container port 80 on host port 8080 |
docker run -p 127.0.0.1:8080:80 image | Publish a port only on the host loopback interface |
docker run --network host image | Run a container on the host network |
docker run --network none image | Run a container with no external network access |
docker network rm app_net | Remove an unused network |
docker network prune | Remove all unused user-defined networks |
Troubleshooting
Containers cannot reach each other by name
Name-based DNS works on user-defined networks. If you started the containers on the default bridge network, recreate them on a user-defined network, or attach them with docker network connect.
Port is already allocated when publishing
Another process on the host is already using that port. Pick a different host port, or find and stop the conflicting process with lsof -i :PORT
.
Cannot remove a network
The network still has containers attached. List them with docker network inspect NAME, disconnect or stop them, and try again.
Service is unreachable from the host after publishing a port
Check that the service inside the container is listening on 0.0.0.0, not only on 127.0.0.1. A service bound to the container loopback interface is not reachable through the published port.
The -p option does not work with host networking
Published ports are ignored when a container uses --network host. The container is already using the host network directly, so it must listen on the desired host port itself.
FAQ
What is the difference between a bridge and a host network?
A bridge network creates an isolated virtual network for containers and requires port publishing to expose services on the host. A host network attaches the container directly to the host network, with no separate container network namespace and no port publishing.
Do containers on the same user-defined bridge network need published ports to talk to each other?
No. Port publishing controls access from the host or external network. Containers on the same user-defined network reach each other directly on the container port.
Can two containers share the same name on different networks?
No. Container names are unique per Docker daemon, regardless of how many networks they are attached to. Network-scoped aliases, set with --network-alias, can overlap across networks.
Why does ping not work from some containers?
Some minimal images do not include ping. Alpine includes it by default, which makes it useful for quick network tests. Other images may require installing the relevant package, or you can use a temporary troubleshooting image.
Conclusion
Docker networking becomes easier to manage when each application gets its own user-defined network and only public-facing services publish ports. For more Docker basics, see the docker run and docker exec guides.
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page