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-utils package 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.