LearnAI ToolsCareerPractice BuildsPlayDevelopmentContact
Lesson 713 min read

Ports and Networks: Connecting Containers

Publish container ports to your computer, avoid port conflicts, and let containers talk to each other by name on a user-defined network.

On this page 10 sections

Introduction

Each container has its own isolated network: its own IP address and its own ports. That isolation is a security feature, but real applications need connections — from your browser to a web app, and from the web app to its database. This lesson covers both directions.

What You Will Learn
  • How -p maps a port on your computer to a port in a container.
  • What “port is already allocated” means and how to fix it.
  • How containers on the same user-defined network find each other by name.
  • How to list, inspect and connect networks.

Publishing Ports

Priya’s Quotes API listens on port 5000 inside its container. The -p HOST:CONTAINER option decides which port on her computer forwards to it — the two numbers do not have to match. Here port 8000 on her computer goes to port 5000 in the container (> /dev/null just hides the container ID that docker run prints, and sleep 2 gives the app a moment to start):

docker run -d --name api -p 8000:5000 quotes-api > /dev/null
sleep 2
curl -s http://localhost:8000/
Output

Click Run to see what this code prints.

docker port shows a container’s published ports. Docker listens on all IPv4 (0.0.0.0) and IPv6 (::) addresses by default:

docker port api
Output

Click Run to see what this code prints.

OptionMeaning
-p 8000:5000Port 8000 on every network interface of your computer → port 5000 in the container
-p 127.0.0.1:8000:5000Only reachable from your own computer, not from the network — safer for databases and admin tools
-p 5000Docker picks a free port on your computer; check which with docker port
EXPOSE 5000 (in a Dockerfile)Documentation only — it does not publish anything by itself

Port Conflicts

Only one program can listen on a given port on your computer. Priya tries to start a second copy of the API on port 8000, which the first copy already uses:

docker run -d --name api2 -p 8000:5000 quotes-api
Output

Click Run to see what this code prints.

Docker created the container (that is the long ID on the first line) but could not start it. The fix is to choose a different host port — the container port stays 5000, because both containers are separate. Priya removes the failed container with docker rm api2 and tries again on port 8001:

docker run -d --name api2 -p 8001:5000 quotes-api > /dev/null
sleep 2
curl -s http://localhost:8001/
Output

Click Run to see what this code prints.

The container field shows a different hostname: this answer came from the second container. Two copies of the same app, side by side, each with its own port on the host.

Mini Challenge · Fix the Command

Port 5432 on your computer is already used by a locally installed PostgreSQL. Which command starts a PostgreSQL container you can still reach from your computer?

Choose one answer

Container-to-Container Networking

Containers often need to talk to each other — an API to its database, a proxy to an app. The clean way is a user-defined network: containers on it can reach each other using their container names as hostnames, and no ports need to be published for that. Priya stops her two APIs (docker rm -f api api2) and creates a network:

docker network create appnet
Output

Click Run to see what this code prints.

docker network ls
Output

Click Run to see what this code prints.

Besides appnet there are three built-in networks: bridge (the default for containers), host (the container shares the host’s network directly, Linux only) and none (no networking). Now Priya runs the API on appnet without publishing any port, and calls it from a second container on the same network using the name api:

docker run -d --name api --network appnet quotes-api > /dev/null
sleep 2
docker run --rm --network appnet alpine wget -qO- http://api:5000/
Output

Click Run to see what this code prints.

Docker runs a small DNS server for each user-defined network, so the name api resolved to the API container’s address. Notice the port: containers talk to each other on the container port (5000) — published host ports are only for traffic coming from outside Docker.

Names Need a User-Defined Network

Without --network, a container joins the default bridge network. Containers there do not get name resolution, so the same request fails:

docker run --rm alpine wget -qO- http://api:5000/
Output

Click Run to see what this code prints.

Always Create a Network

For any group of containers that work together, create a network and put them all on it. Docker Compose (lesson 10) does this for you automatically.

Inspecting and Connecting

docker network inspect shows a network’s settings and the containers attached to it, with their IP addresses. A --format template keeps it short:

docker network inspect appnet --format "{{range .Containers}}{{.Name}} {{.IPv4Address}}{{println}}{{end}}"
Output

Click Run to see what this code prints.

IP addresses can change when containers are recreated, which is why you should always use names. A running container can also join a network later with docker network connect:

docker run -d --name tester alpine sleep 600 > /dev/null
docker network connect appnet tester
docker exec tester wget -qO- http://api:5000/quotes
Output

Click Run to see what this code prints.

Mini Challenge · Put It in Order

Put the steps to let a web app reach its database by name in order.

  1. Configure the app to connect to the host name db on port 5432
  2. docker network create shopnet
  3. docker run -d --name web --network shopnet -p 8080:5000 shop-app
  4. docker run -d --name db --network shopnet -e POSTGRES_PASSWORD=secret postgres:18-alpine
  5. Open http://localhost:8080 to test the app

Common Mistakes

Avoid These Mistakes
  • Using localhost inside a container to reach another container — localhost means the container itself. Use the other container’s name.
  • Using the published host port (8000) between containers instead of the container port (5000).
  • Publishing database ports to the whole network when only other containers need them.
  • Relying on container IP addresses, which change when containers are recreated.

Frequently Asked Questions

With Docker Desktop, use the special name host.docker.internal. On Linux, add --add-host=host.docker.internal:host-gateway to docker run to get the same name.

Yes. A reverse proxy, for example, can be connected to a public-facing network and to an internal network with the apps behind it.

Check your firewall, and check that you did not publish with 127.0.0.1:8000:5000, which only accepts connections from your own computer.

Key Takeaways

  • -p HOST:CONTAINER forwards a port on your computer to a port in the container.
  • Each host port can be used by only one container; change the host side to avoid conflicts.
  • Containers on the same user-defined network reach each other by container name, on the container port.
  • The default bridge network has no name resolution, so always create your own network.
  • docker network ls, inspect and connect manage networks.

Summary

Your containers can now be reached from outside and can talk to each other. But anything they store disappears when they are removed — next you will fix that with volumes.

Next Lesson →

Volumes and Bind Mounts: Keeping Your Data