How to Configure Docker Networking on RHEL 7
Docker provides a powerful networking model that allows containers to communicate with each other, with the host, and with the outside world in a secure and configurable way. Out of the box, Docker creates a default bridge network and manages its own iptables rules to control traffic flow. Understanding Docker’s network drivers — bridge, host, overlay, and none — allows you to design container architectures appropriate for development, single-host production, and multi-host cluster deployments. This tutorial covers Docker networking in depth on RHEL 7, from the default setup through custom networks, port publishing, and inter-container DNS resolution.
Prerequisites
- Docker CE installed and running on RHEL 7
- Basic familiarity with TCP/IP networking concepts (subnets, ports, routing)
- Root or sudo access
- The
bridge-utilspackage for inspecting bridge interfaces:sudo yum install -y bridge-utils
Step 1: Understand the Default Bridge Network
When Docker is installed, it creates a virtual bridge interface called docker0 on the host. All containers that do not specify a network are connected to this default bridge. You can see it with:
ip addr show docker0
By default, docker0 uses the subnet 172.17.0.0/16. Each container connected to it receives an IP address in this range. Containers on the default bridge can communicate with each other by IP address, but not by container name — name-based DNS resolution is a feature of user-defined networks only.
To see the full configuration of the default bridge:
docker network inspect bridge
Step 2: Create a User-Defined Bridge Network
User-defined bridge networks are isolated from the default bridge and offer automatic DNS resolution between containers by name. This is the recommended approach for all multi-container applications.
Create a custom network:
docker network create
--driver bridge
--subnet 192.168.100.0/24
--gateway 192.168.100.1
myapp_net
List all networks:
docker network ls
Sample output:
NETWORK ID NAME DRIVER SCOPE
a1b2c3d4e5f6 bridge bridge local
f6e5d4c3b2a1 host host local
abcdef123456 myapp_net bridge local
000000000000 none null local
Start containers on the custom network:
docker run -d --name webserver --network myapp_net nginx:1.25-alpine
docker run -d --name appserver --network myapp_net python:3.11-slim sleep 3600
Now appserver can reach webserver by name:
docker exec appserver ping -c 3 webserver
This works because Docker’s embedded DNS server (running at 127.0.0.11 inside containers on user-defined networks) resolves container names to their current IP addresses automatically, even when containers are restarted with new IPs.
Step 3: Connect and Disconnect Containers from Networks
A running container can be connected to additional networks without being restarted:
docker network connect myapp_net existing_container
Disconnect a container from a network:
docker network disconnect myapp_net existing_container
Inspect a network to see which containers are attached and their assigned IPs:
docker network inspect myapp_net
Step 4: Expose Ports and Publish to the Host
Containers are isolated from the host network by default. To make a container service reachable from outside the host, you must publish ports using the -p flag with docker run.
The format is -p host_port:container_port:
# Publish container port 80 to host port 8080
docker run -d -p 8080:80 --name webtest nginx:1.25-alpine
Bind to a specific host IP (useful on multi-homed servers):
# Only expose on the loopback interface
docker run -d -p 127.0.0.1:8080:80 --name webtest_local nginx:1.25-alpine
Publish multiple ports at once:
docker run -d
-p 8080:80
-p 8443:443
--name multi_port_web
nginx:1.25-alpine
Use -P (uppercase) to publish all exposed container ports to random high-numbered host ports:
docker run -d -P --name random_ports nginx:1.25-alpine
docker port random_ports
Step 5: Host Networking
With the --network host option, the container shares the host’s network namespace directly — there is no network isolation, no virtual bridge, and no NAT. The container sees all host network interfaces and its processes bind directly to host ports.
docker run -d
--network host
--name host_nginx
nginx:1.25-alpine
In this mode, Nginx binds to port 80 on all host interfaces directly, without port mapping. Use this mode when you need maximum network performance or when specific kernel networking features are required. However, it eliminates container network isolation, so use it cautiously.
Note: Host networking on Docker for Mac and Docker for Windows behaves differently. On RHEL 7, it works exactly as described.
Step 6: The None Network
Assigning --network none gives the container a network namespace with only the loopback (lo) interface — no external connectivity whatsoever. This is useful for batch processing containers that must not have network access for security reasons.
docker run --rm
--network none
busybox
ip addr
Output will show only the loopback interface with no other interfaces configured.
Step 7: Overlay Networks and Docker Swarm
Overlay networks enable containers on different Docker hosts to communicate as if they are on the same local network. They require Docker Swarm mode to be initialized, as Swarm provides the distributed key-value store (etcd-based) that overlay networks depend on for routing.
Initialize Swarm on the manager node:
docker swarm init --advertise-addr <MANAGER_IP>
Create an overlay network:
docker network create
--driver overlay
--attachable
myswarm_net
Deploy a service on the overlay network:
docker service create
--name web
--network myswarm_net
--replicas 3
-p 80:80
nginx:1.25-alpine
Containers running any of the three replicas on any swarm node can reach each other by service name over the overlay network.
Step 8: iptables Rules Docker Creates
Docker manages its own iptables chains on RHEL 7 to control container traffic. Understanding these chains helps you troubleshoot connectivity issues and integrate Docker with existing firewall rules.
Docker creates several chains in the filter and nat tables:
sudo iptables -L -n --line-numbers
sudo iptables -t nat -L -n --line-numbers
Key chains to know:
- DOCKER: Contains per-container ACCEPT rules for published ports
- DOCKER-USER: A user-managed chain inserted before the DOCKER chain — place custom rules here so they are not overwritten by Docker
- DOCKER-ISOLATION-STAGE-1/2: Enforces network isolation between separate bridge networks
- POSTROUTING in nat table: Provides MASQUERADE (SNAT) rules that allow containers to reach the internet through the host’s IP
To add custom firewall rules that persist across Docker daemon restarts, always add them to the DOCKER-USER chain:
# Allow traffic only from a specific subnet to containers
sudo iptables -I DOCKER-USER -i eth0 ! -s 10.0.0.0/8 -j DROP
Step 9: Remove Unused Networks
Over time, unused custom networks can accumulate. Remove a specific network (only if no containers are connected):
docker network rm myapp_net
Remove all unused networks at once:
docker network prune
Conclusion
You now have a solid understanding of Docker networking on RHEL 7, from the default bridge and user-defined networks with automatic DNS, through host networking, overlay networks for multi-host Swarm deployments, and the iptables rules Docker manages in the background. For most single-host production workloads, user-defined bridge networks with explicit port publishing provide the right balance of isolation, performance, and ease of use. When troubleshooting container connectivity, docker network inspect, docker exec <container> ip addr, and sudo iptables -L -n are your first diagnostic tools.