Use when configuring networks and service communication in Docker Compose including bridge networks, overlay networks, service discovery, and inter-service communication.
Configure Docker Compose networking including custom bridge networks, service discovery, network isolation, static IPs, and multi-tier architectures for secure container communication.
/plugin marketplace add TheBushidoCollective/han/plugin install jutsu-cypress@hanThis skill is limited to using the following tools:
Master network configuration and service communication patterns in Docker Compose for building secure, scalable multi-container applications.
Docker Compose automatically creates a default bridge network for all services in a compose file:
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "80:80"
# Can reach backend using service name as hostname
backend:
image: node:18-alpine
command: node server.js
# Accessible at hostname 'backend' from frontend
database:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD: secret
# Accessible at hostname 'database' from backend
In this setup:
http://backend:3000postgres://database:5432Define custom networks for service isolation and segmentation:
version: '3.8'
services:
frontend:
image: nginx:alpine
networks:
- frontend-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
- frontend-network
- backend-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- backend-network
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-network
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge
internal: true
volumes:
db-data:
redis-data:
Network isolation:
Configure multiple hostnames for service discovery:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
public:
aliases:
- website
- www
- web-server
internal:
aliases:
- web-internal
api:
image: node:18-alpine
networks:
public:
aliases:
- api-server
- backend
internal:
aliases:
- api-internal
depends_on:
- database
database:
image: postgres:15-alpine
networks:
internal:
aliases:
- db
- postgres
- primary-db
environment:
POSTGRES_PASSWORD: secret
networks:
public:
driver: bridge
internal:
driver: bridge
internal: true
Services can be reached by any of their aliases:
http://website, http://www, http://web-server all reach web servicepostgresql://db:5432, postgresql://postgres:5432 both reach databaseAssign fixed IP addresses for services requiring stable networking:
version: '3.8'
services:
loadbalancer:
image: nginx:alpine
networks:
app-network:
ipv4_address: 172.28.1.10
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
app-1:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.11
environment:
APP_ID: "1"
app-2:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.12
environment:
APP_ID: "2"
app-3:
image: myapp:latest
networks:
app-network:
ipv4_address: 172.28.1.13
environment:
APP_ID: "3"
database:
image: postgres:15-alpine
networks:
app-network:
ipv4_address: 172.28.1.20
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.1.1
volumes:
pgdata:
Connect to existing Docker networks created outside Compose:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
- shared-network
environment:
DATABASE_URL: postgresql://db:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
shared-network:
external: true
name: company-shared-network
volumes:
pgdata:
Create external network first:
docker network create company-shared-network
docker compose up -d
Use host networking for maximum performance (Linux only):
version: '3.8'
services:
high-performance-app:
image: myapp:latest
network_mode: "host"
environment:
BIND_ADDRESS: "0.0.0.0"
PORT: "8080"
# No port mapping needed - directly uses host's network stack
monitoring:
image: prometheus:latest
network_mode: "host"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.listen-address=0.0.0.0:9090'
volumes:
prometheus-data:
Note: Host networking bypasses Docker network isolation and is typically used for monitoring tools or high-throughput applications.
Configure DNS resolution and service discovery:
version: '3.8'
services:
api:
image: node:18-alpine
networks:
- app-network
dns:
- 8.8.8.8
- 8.8.4.4
dns_search:
- company.local
extra_hosts:
- "legacy-api.company.local:192.168.1.100"
- "auth-service.company.local:192.168.1.101"
environment:
DATABASE_HOST: database.company.local
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- database.company.local
- db.company.local
hostname: primary-database
domainname: company.local
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-company-app
volumes:
pgdata:
While links is deprecated, understanding it helps migrate legacy configurations:
version: '3.8'
services:
# Modern approach - use networks instead
web:
image: nginx:alpine
networks:
- app-network
depends_on:
- api
api:
image: node:18-alpine
networks:
- app-network
depends_on:
- database
environment:
# Use service name as hostname
DATABASE_URL: postgresql://database:5432/app
database:
image: postgres:15-alpine
networks:
- app-network
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
Complex applications with multiple isolated networks:
version: '3.8'
services:
nginx:
image: nginx:alpine
networks:
- public
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- api
frontend:
image: react-app:latest
networks:
- public
- frontend-tier
environment:
API_URL: http://api:3000
api:
image: node-api:latest
networks:
- frontend-tier
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
REDIS_URL: redis://cache:6379
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- cache
- queue
worker:
image: node-worker:latest
networks:
- backend-tier
environment:
DATABASE_URL: postgresql://postgres:5432/app
QUEUE_URL: amqp://rabbitmq:5672
depends_on:
- database
- queue
deploy:
replicas: 3
database:
image: postgres:15-alpine
networks:
- backend-tier
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7-alpine
networks:
- backend-tier
command: redis-server --appendonly yes
volumes:
- redis-data:/data
queue:
image: rabbitmq:3-management-alpine
networks:
- backend-tier
- management
ports:
- "15672:15672" # Management UI
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: secret
volumes:
- rabbitmq-data:/var/lib/rabbitmq
monitoring:
image: prometheus:latest
networks:
- management
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
networks:
public:
driver: bridge
frontend-tier:
driver: bridge
internal: true
backend-tier:
driver: bridge
internal: true
management:
driver: bridge
volumes:
pgdata:
redis-data:
rabbitmq-data:
prometheus-data:
Network segmentation:
Control how services expose ports:
version: '3.8'
services:
# Short syntax - host:container
web:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- public
# Long syntax with protocol specification
api:
image: node:18-alpine
ports:
- target: 3000
published: 3000
protocol: tcp
mode: host
networks:
- app-network
# Random host port
app:
image: myapp:latest
ports:
- "3000" # Docker assigns random host port
networks:
- app-network
# Bind to specific host interface
admin:
image: admin-panel:latest
ports:
- "127.0.0.1:8080:80" # Only accessible from localhost
networks:
- admin-network
# UDP protocol
dns:
image: bind9:latest
ports:
- "53:53/udp"
- "53:53/tcp"
networks:
- dns-network
# Range of ports
streaming:
image: rtmp-server:latest
ports:
- "1935:1935"
- "8080-8089:8080-8089"
networks:
- streaming-network
networks:
public:
app-network:
admin-network:
internal: true
dns-network:
streaming-network:
version: '3.8'
services:
gateway:
image: nginx:alpine
networks:
- frontend
ports:
- "80:80"
volumes:
- ./nginx-gateway.conf:/etc/nginx/nginx.conf:ro
service-a:
image: service-a:latest
networks:
- frontend
- backend
environment:
SERVICE_B_URL: http://service-b:8080
DATABASE_URL: postgresql://db:5432/service_a
service-b:
image: service-b:latest
networks:
- frontend
- backend
environment:
DATABASE_URL: postgresql://db:5432/service_b
database:
image: postgres:15-alpine
networks:
- backend
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
pgdata:
version: '3.8'
services:
publisher:
image: publisher:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
depends_on:
- redis
subscriber-1:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "1"
depends_on:
- redis
subscriber-2:
image: subscriber:latest
networks:
- messaging
environment:
REDIS_URL: redis://redis:6379
SUBSCRIBER_ID: "2"
depends_on:
- redis
redis:
image: redis:7-alpine
networks:
- messaging
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
messaging:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_icc: "true"
volumes:
redis-data:
Enable debugging and monitoring:
version: '3.8'
services:
app:
image: myapp:latest
networks:
app-network:
aliases:
- primary-app
cap_add:
- NET_ADMIN
- NET_RAW
debug:
image: nicolaka/netshoot:latest
networks:
- app-network
command: sleep infinity
cap_add:
- NET_ADMIN
- NET_RAW
stdin_open: true
tty: true
database:
image: postgres:15-alpine
networks:
app-network:
aliases:
- db
environment:
POSTGRES_PASSWORD: secret
networks:
app-network:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.driver.mtu: "1500"
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
Debug commands:
# Enter debug container
docker compose exec debug bash
# Test connectivity
ping app
curl http://app:8080/health
# Check DNS resolution
nslookup app
dig app
# Network scanning
nmap -p- app
# Trace route
traceroute app
# Monitor traffic
tcpdump -i eth0 -n
Enable IPv6 support:
version: '3.8'
services:
web:
image: nginx:alpine
networks:
- ipv6-network
ports:
- "80:80"
api:
image: node:18-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::10
database:
image: postgres:15-alpine
networks:
ipv6-network:
ipv6_address: 2001:db8:1::20
environment:
POSTGRES_PASSWORD: secret
networks:
ipv6-network:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
- subnet: 2001:db8:1::/64
Use docker-compose-networking when you need to:
Use Custom Networks for Isolation: Always create custom networks instead of relying solely on the default network for better security and organization.
Implement Network Segmentation: Separate frontend, backend, and data tiers into different networks to limit attack surface.
Use Internal Networks: Mark backend networks as internal: true to prevent external access to sensitive services like databases.
Prefer Service Names Over IPs: Use Docker's built-in DNS and service names instead of hardcoding IP addresses for maintainability.
Configure Health Checks: Implement health checks to ensure services are ready before routing traffic to them.
Use Network Aliases: Define meaningful aliases for services to support multiple naming conventions and easier migration.
Avoid Host Networking Unless Necessary: Use bridge networks by default; host networking should only be used for specific performance requirements.
Document Network Architecture: Clearly comment your network design and document which services can communicate with each other.
Use Depends_on Wisely: Combine depends_on with health checks to ensure services start in the correct order.
Implement Least Privilege: Only expose ports that absolutely need to be accessible from outside the Docker network.
Use Environment Variables for URLs: Configure service endpoints through environment variables for flexibility across environments.
Test Network Isolation: Regularly verify that services can only communicate through intended network paths.
Configure Appropriate MTU: Set MTU values based on your network infrastructure to avoid fragmentation issues.
Use External Networks for Shared Resources: When multiple Compose projects need to communicate, use external networks rather than duplicating services.
Monitor Network Performance: Use tools like docker stats and dedicated monitoring containers to track network usage and identify bottlenecks.
Exposing All Services Publicly: Don't publish ports for services that should only be accessed internally; use networks instead of port publishing.
Hardcoding IP Addresses: Avoid static IP addresses unless absolutely necessary; rely on service discovery instead.
Using Default Network Only: Not creating custom networks misses opportunities for proper segmentation and isolation.
Ignoring Network Modes: Using the wrong network mode (bridge vs host vs overlay) for your use case can cause connectivity or performance issues.
Missing Network Dependencies: Not properly configuring depends_on can cause services to fail when trying to connect to unavailable services.
Overusing Host Networking: Using network_mode: host unnecessarily breaks container isolation and portability.
Not Using Internal Networks: Failing to mark backend networks as internal leaves databases and sensitive services exposed.
Mixing Network Modes: Trying to publish ports or connect to networks when using network_mode: host causes configuration errors.
Circular Network Dependencies: Creating network dependencies that form a circle prevents containers from starting properly.
Ignoring DNS Configuration: Not configuring DNS properly can cause name resolution failures in containerized applications.
Subnet Conflicts: Using IP ranges that conflict with host or other Docker networks causes routing issues.
Not Testing Network Policies: Assuming network isolation works without testing can leave security vulnerabilities.
Exposing Management Interfaces: Publishing management ports (like RabbitMQ, Redis, PostgreSQL) without authentication or IP restrictions.
Using Links Instead of Networks: The deprecated links feature should be replaced with modern network configuration.
Ignoring Network Driver Options: Not configuring driver options like MTU or IP masquerade can cause subtle connectivity problems in production.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.