Sitemap

Docker Networking Explained: Hands-On Learning with Bridge Networks, Network Isolation, and Host Mode

10 min readOct 27, 2026

--

Press enter or click to view image in full size

As I continue building my DevOps skills, I’m learning that containers do not operate in isolation from networking concerns. Even when individual containers run successfully, the overall application still depends on how those containers communicate with one another and how they are exposed to external users.

In Assignment 03, I explored Docker Networking through a practical scenario involving Nginx, BusyBox, and MongoDB. The objective was to understand Docker’s default bridge network, custom bridge networks, communication across multiple networks, and host networking.

Rather than developing an application, this exercise focused on the networking principles behind containerized services: connectivity, service discovery, isolation, and controlled external access.

Here is the workflow, the commands involved, and the key lessons from the assignment.

1. Understanding the network design

A typical application may have a frontend, a backend, and a database. These components need to communicate, but they do not all need to be accessible from the internet.

For this assignment, I explored four networking scenarios:

  1. Default bridge: Run a standalone Nginx container and publish its web port.
  2. Custom bridge: Connect a web container and client container using container-name-based service discovery.
  3. Multiple bridge networks: Separate frontend-to-backend communication from backend-to-database communication.
  4. Host networking: Run Nginx using the host machine’s network stack.

The objective was to understand not only how to establish connectivity, but also how to restrict unnecessary communication.

2. Task One: Deploy Nginx using the default bridge network

Step 1: Inspect Docker networks

I started by listing the networks available in Docker:

echo "Full Name: <YOUR FULL NAME>"
docker network ls

The expected output includes Docker’s built-in networks:

  • bridge
  • host
  • none

The default bridge network is commonly used when a container does not explicitly join another network.

Step 2: Pull the Nginx image

I downloaded the lightweight Nginx Alpine image:

echo "Full Name: <YOUR FULL NAME>"
docker pull nginx:alpine

Using a standard image kept the focus on networking rather than application development.

Step 3: Start the web container

I launched Nginx and mapped port 80 on the VM to port 80 inside the container:

docker run -d \
--name myweb \
-p 80:80 \
nginx:alpine

I then checked the container:

echo "Full Name: <YOUR FULL NAME>"
docker ps

The port mapping should resemble:

0.0.0.0:80->80/tcp

This indicates that Docker has published the container’s port 80 on the host’s port 80. The exact output may differ depending on the host configuration.

Step 4: Verify external access

I opened the VM’s public IP address in a browser:

http://<YOUR-VM-PUBLIC-IP>

The expected result is the Nginx welcome page.

For access to work, port 80 must also be allowed by the relevant cloud security group, network security group, or host firewall. Publishing a Docker port does not automatically override cloud-level network restrictions.

What this task demonstrates: A container can serve a web page externally when the appropriate port is published and the surrounding network rules permit access.

3. Task Two: Connect containers through a custom bridge network

The next task focused on service discovery.

Instead of relying on the default bridge network, I created a custom bridge network and attached two containers to it.

Step 1: Clean up the first task

After capturing the required evidence, I removed the original container:

docker rm -f myweb 2>/dev/null || true

This removes the named container if it exists. It does not remove the Nginx image, which can be reused.

Step 2: Create a custom network

docker network create mynetwork
echo "Full Name: <YOUR FULL NAME>"
docker network ls

The expected result is a network named mynetwork using the bridge driver.

Step 3: Start the web and client containers

I started an Nginx container without publishing a host port:

docker run -d \
--name web \
--network mynetwork \
nginx:alpine

Next, I started a BusyBox client on the same network:

docker run -d \
--name client \
--network mynetwork \
busybox:1.36 \
sleep infinity

Both containers should now be running on mynetwork. Neither requires a published host port for communication with the other.

Step 4: Test service discovery by container name

From the client container, I tested access to Nginx:

echo "Full Name: <YOUR FULL NAME>"
docker exec client wget -qO- http://web

The expected output is the HTML returned by the Nginx welcome page.

This test demonstrates an important Docker feature: containers on the same user-defined bridge network can discover one another by container name.

Rather than manually looking up a container’s IP address, the client can use the name web.

Step 5: Inspect network membership

echo "Full Name: <YOUR FULL NAME>"
docker network inspect mynetwork

The output should show both web and client connected to the custom network.

What this task demonstrates: A custom bridge network supports convenient container-name-based service discovery and internal communication without requiring public port mappings.

4. Task Three: Implement multi-network isolation

This was the most important network-design exercise because it introduced separation between application tiers.

The assignment specified two networks:

frontend-network

  • Connects frontend and backend.
  • Supports frontend-to-backend communication.

backend-network

  • Connects backend and db.
  • Supports backend-to-database communication.

The backend is the only container connected to both networks. This arrangement allows the frontend and database to remain on separate networks.

Step 1: Remove the previous task’s containers and network

docker rm -f web client 2>/dev/null || true
docker network rm mynetwork 2>/dev/null || true

I would run cleanup commands only after capturing the required evidence and confirming that the named resources belong to this exercise.

Step 2: Create both networks

docker network create frontend-network
docker network create backend-network
echo "Full Name: <YOUR FULL NAME>"
docker network ls

Both networks should appear in the network listing.

Step 3: Start MongoDB on the backend network

docker run -d \
--name db \
--network backend-network \
mongo:7.0

Notice that no -p option is used.

MongoDB’s port 27017 is not published on the VM. The database is intended to be accessible through its Docker network, rather than directly through a public host port.

Step 4: Start the backend and connect it to both networks

docker run -d \
--name backend \
--network backend-network \
nginx:alpine

Then connect the backend to the frontend network:

docker network connect frontend-network backend

The backend now belongs to both backend-network and frontend-network.

Get Tope Adedavids’s stories in your inbox

Join Medium for free to get updates from this writer.

An important detail is that this container is running Nginx as a networking demonstration, not as a fully implemented backend application. Docker membership alone does not make Nginx act as an application-layer gateway between the two networks.

Step 5: Start the frontend

docker run -d \
--name frontend \
--network frontend-network \
-p 80:80 \
nginx:alpine

Then inspect the running containers:

echo "Full Name: <YOUR FULL NAME>"
docker ps

The expected configuration is:

  • frontend has port 80 published.
  • backend has no published host port.
  • db has no published host port.

This reflects the intended exposure model: the frontend is accessible externally, while the backend and database remain internal.

Step 6: Verify the network memberships

Inspect the frontend network:

echo "Full Name: <YOUR FULL NAME>"
docker network inspect frontend-network

Expected members: frontend and backend.

Inspect the backend network:

echo "Full Name: <YOUR FULL NAME>"
docker network inspect backend-network

Expected members: backend and db.

These inspections are important because they provide evidence of the actual network configuration, not merely that the containers are running.

Step 7: Test frontend-to-backend communication

echo "Full Name: <YOUR FULL NAME>"
docker exec frontend wget -qO- http://backend

The expected output is the Nginx welcome page HTML.

This communication works because frontend and backend share frontend-network. Docker's embedded DNS resolves the container name backend on that network.

Step 8: Test backend-to-database connectivity

The assignment uses Netcat to test whether the backend can connect to MongoDB’s port.

First, install the required testing utility inside the backend container:

docker exec backend apk add --no-cache netcat-openbsd

Then run:

echo "Full Name: <YOUR FULL NAME>"
docker exec backend nc -zv -w 5 db 27017

The expected result is a successful TCP connection to db on port 27017, provided MongoDB has finished starting and is listening on that port.

If the first test fails, wait for MongoDB to finish initializing and try again.

This test verifies network-level connectivity. It does not prove that database authentication, application queries, or the database’s full functionality work.

Step 9: Test frontend-to-database isolation

Next, I used Netcat in the frontend container to test whether it could reach MongoDB:

docker exec frontend apk add --no-cache netcat-openbsd

Then:

echo "Full Name: <YOUR FULL NAME>"
docker exec frontend sh -c \
'nc -zv -w 5 db 27017 && echo "Unexpected success" || echo "Expected result: frontend cannot reach db"'

The intended result is:

Expected result: frontend cannot reach db

Because the frontend is not connected to backend-network, it cannot resolve the database's container name through that network. Consequently, the connection should fail.

This is the central lesson of the task: the frontend can reach the backend, and the backend can reach the database, but that does not automatically give the frontend direct access to the database.

The separation reduces unnecessary communication paths and helps enforce a least-privilege network design.

Step 10: Verify public access to the frontend

I opened the VM’s public IP in the browser:

http://<YOUR-VM-PUBLIC-IP>

The expected result is the Nginx welcome page from the frontend container.

The backend and database remain without published host ports. Their network membership and lack of port publishing provide the intended internal-only configuration, subject to the host’s other network and security settings.

5. Task Four: Explore Docker host networking

The final task compared bridge networking with host network mode.

Step 1: Clean up the multi-network containers

After capturing the required evidence, I removed the named containers and networks:

docker rm -f frontend backend db 2>/dev/null || true
docker network rm frontend-network backend-network 2>/dev/null || true

Step 2: Start Nginx in host network mode

Before running this command, port 80 on the VM must be available.

docker run -d \
--name fastapp \
--network host \
nginx:alpine

Unlike the bridge examples, this command does not use -p 80:80.

In host mode, the container shares the host’s network stack. Nginx listens on the host’s port 80 directly, so a separate Docker port mapping is not required.

Step 3: Verify the network mode

echo "Full Name: <YOUR FULL NAME>"
docker ps
echo "Full Name: <YOUR FULL NAME>"
docker inspect fastapp | grep '"NetworkMode"'

The inspection output should include:

"NetworkMode": "host",

If the container fails to start, check whether another service is already listening on port 80.

Step 4: Verify browser access

I would then open:

http://<YOUR-VM-PUBLIC-IP>

The expected result is the Nginx welcome page, provided the container is running and the relevant network rules permit access.

Step 5: Stop and remove the container

After capturing the required evidence:

echo "Full Name: <YOUR FULL NAME>"
docker stop fastapp
docker rm fastapp

This completes the host-networking exercise and removes the named container created for it.

6. Bridge networking versus host networking

The assignment illustrates several important differences.

FeatureBridge networkingHost networkingNetwork isolationContainer uses a separate Docker networkContainer shares the host network stackPort publishingTypically uses -p for external accessNo Docker port mapping is neededContainer-name discoveryAvailable on user-defined bridge networksNot provided by host mode in the same wayPort conflictsHost port conflicts can occur when publishing portsApplications compete directly for host portsTypical useIsolated services and application tiersSpecific workloads that need host networking behavior

The default bridge network is useful for simple standalone containers, while custom bridge networks provide better service discovery and more deliberate communication boundaries.

Host networking removes the normal network separation between the container and the host. That can be useful in particular scenarios, but it requires careful consideration of port conflicts and security.

7. Troubleshooting considerations

During a practical networking exercise, a failed connection does not always mean the network design is wrong. The issue could be caused by startup timing, a missing utility, an incorrect network attachment, or an unavailable host port.

Here are the first checks I would perform.

Check container status:

docker ps -a

Inspect container logs:

docker logs backend
docker logs db

Inspect network membership:

docker network inspect frontend-network
docker network inspect backend-network

Check published ports:

docker port frontend

For the database test, confirm that MongoDB has finished starting. For the host-network test, check whether port 80 is already occupied. For the service-discovery test, verify that the relevant containers share the intended user-defined bridge network.

The assignment also requires screenshots to include the learner’s full name in terminal evidence. Browser screenshots showing the standard Nginx page should have the name added as a caption in the submission document, as instructed.

8. What I learned

This assignment helped me understand that Docker networking is not simply about allowing containers to communicate. It is also about controlling where communication is permitted.

The most important lessons were:

  • Default bridge: publish a port when external access is required.
  • Custom bridge: use container names for service discovery between connected containers.
  • Multiple bridge networks: separate application tiers and restrict unnecessary communication.
  • Host networking: understand that the container shares the host network stack and does not need Docker port mapping.
  • Network validation: use docker network inspect, docker ps, and connectivity tests to verify configuration rather than relying on assumptions.

I also learned the difference between network-level connectivity and application-level functionality. A successful TCP connection to MongoDB’s port does not prove that an application can authenticate or execute a database query.

Conclusion

Working through Docker Networking strengthened my understanding of how containerized services can be connected, isolated, and exposed.

The multi-network scenario was particularly valuable because it demonstrated a practical security principle: the frontend does not need direct access to the database when the intended design only requires frontend-to-backend and backend-to-database communication.

The next step is to apply these principles in more complete application stacks, where network boundaries work alongside application authentication, secrets management, monitoring, and deployment automation.

I’m continuing to build my DevOps foundation through hands-on assignments, focusing on understanding not just how to run containers, but how to design and verify the systems around them.

#Docker #DockerNetworking #DevOps #Containerization #Linux #CloudEngineering #CloudNative #CyberSecurity #DevOpsLearning #LearningByDoing

P.S. This post is part of the DevOps Micro Internship (DMI) with Agentic AI — Cohort 3 — by Pravin Mishra. My graded progress is public: https://dmi.pravinmishra.com/s/accelage.html · Start your DevOps journey: https://dmi.pravinmishra.com/?utm_source=student&utm_medium=ps-blog&utm_campaign=cohort3

--

--