Skip to content

Docker Networking

Docker creates isolated network namespaces for containers. Networking controls which containers can communicate with each other and how they’re exposed to the outside world.

DriverDescription
bridgeDefault for single-host containers. Isolated network with NAT.
hostShares the host’s network namespace — no isolation.
noneNo network access.
overlayMulti-host networking for Docker Swarm.
macvlanAssigns a MAC address to the container — appears as physical device.

All containers without a network specified join the default bridge network:

Terminal window
docker run -d nginx # uses default bridge
docker run -d my-app # can reach nginx by IP only (not name)

The default bridge doesn’t support DNS — containers can only reach each other by IP address.

Containers on the same user-defined network can resolve each other by container name:

Terminal window
# Create a network
docker network create my-network
# Run containers on the network
docker run -d --name db --network my-network postgres:16
docker run -d --name api --network my-network my-api-image
# api can reach db by hostname "db"
# e.g., DATABASE_URL=postgresql://db:5432/mydb

Expose container ports to the host:

Terminal window
# Map host port 8080 → container port 80
docker run -p 8080:80 nginx
# Map to a specific host interface
docker run -p 127.0.0.1:8080:80 nginx
# Map all ports declared with EXPOSE
docker run -P nginx
# Check mapped ports
docker port my-container

Compose automatically creates a network for your project and connects all services to it. Services can reach each other by service name:

services:
api:
build: .
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
# 'db' resolves to the db service's IP automatically
depends_on:
- db
db:
image: postgres:16

No manual network configuration needed — this is the recommended approach.

services:
frontend:
networks:
- public
api:
networks:
- public
- private
db:
networks:
- private # db is NOT accessible from frontend
networks:
public:
private:
internal: true # no external access
Terminal window
# List networks
docker network ls
# Inspect a network (see connected containers, IPs)
docker network inspect my-network
# Connect an existing container to a network
docker network connect my-network my-container
# Disconnect
docker network disconnect my-network my-container
# Remove unused networks
docker network prune

Shares the host’s network stack — no isolation, no port mapping needed:

Terminal window
docker run --network host nginx
# nginx now listens on host's port 80 directly

Use cases: performance-sensitive apps where NAT overhead matters, containers that need to scan all host ports.

Terminal window
# Within the same network, use container name
curl http://api:3000/health
# From outside the network, use host port mapping
curl http://localhost:8080/health

In production, expose only the reverse proxy to the outside:

services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- public
api:
build: .
networks:
- public # reachable by nginx
# NO ports: exposed — only nginx can reach it
networks:
public:

Containers use Docker’s embedded DNS server (127.0.0.11) for name resolution. This resolves:

  • Container names on the same user-defined network
  • Service names in Docker Compose
  • Network aliases (--network-alias)