Jens Willmer

Tutorials, projects, dissertations and more..

Docker Networking Pitfalls

Docker networking is powerful but can be confusing, especially when dealing with communication between the host machine and Docker containers. Many developers assume that network behavior inside a Docker network works the same as on the host, leading to unexpected issues. In this post, we’ll explore common pitfalls when running services with Docker Compose and how to handle them correctly.


The Basics: Host vs. Docker Network

Docker Compose creates an isolated network for services to communicate. Each container gets a unique DNS name corresponding to its service name in docker-compose.yml. However, the way networking works inside Docker is different from how it works on the host machine.

Host Perspective (External Access)

When accessing a service from the host machine (outside Docker), you must use localhost and the mapped port:

curl http://localhost:8080  # Accessing a container-bound service via a mapped port

You cannot use Docker-internal DNS names (such as service_name) or host.docker.internal from the host machine.

Docker Container Perspective (Internal Communication)

Containers within the same Docker network can refer to each other by service name:

curl http://app-store:5000  # Works inside Docker

But if a container needs to communicate with a service running on the host machine, it must use host.docker.internal:

curl http://host.docker.internal:3000  # Works inside Docker to reach host

Common Pitfalls and How to Solve Them


Pitfall 1: Trying to Access a Container Using Service Names from the Host

❌ Incorrect:

curl http://app-store:5000  # Won't work from the host machine

The app-store service name is only resolvable inside Docker’s internal network.

✅ Correct:

curl http://localhost:5000  # Use localhost + mapped port from the host

This works if the port is correctly mapped in docker-compose.yml:

docker-compose.yml:
services:
  app-store:
    ports:
      - "5000:5000"

Pitfall 2: Using localhost Inside a Container to Reach Another Container

❌ Incorrect:

curl http://localhost:5000  # Won't work inside a container

Inside a container, localhost refers to itself, not other services in the Docker network.

✅ Correct:

curl http://app-store:5000  # Use the service name inside Docker

Pitfall 3: A Container Trying to Access a Host Service Without host.docker.internal

❌ Incorrect:

curl http://localhost:3306  # Won't work inside Docker

Since localhost inside a container refers to the container itself, this won’t connect to a host service.

✅ Correct:

curl http://host.docker.internal:3306  # Correct way inside Docker

Pitfall 4: Web Applications Generating Incorrect URLs

Web applications often generate links for users dynamically based on their environment. If the application is running inside a Docker container, it may generate links using internal Docker service names, which are not accessible to users.

❌ Incorrect:

<a href="http://web-service:8080">Click here</a>  <!-- Won't work for the user -->

✅ Correct:

Ensure the application differentiates between:

  • Internal URLs (used by services within Docker, such as web-service:8080)
  • External URLs (used by users, such as localhost:8080 or a domain name)

Understanding host.docker.internal Availability

host.docker.internal is a special hostname that resolves to the host machine’s IP address from within a Docker container. However, its availability depends on the operating system:

Platform Availability Notes
Windows ✅ Available Works out of the box
Mac (Intel & M1/M2) ✅ Available Built-in since Docker Desktop 18.03
Linux ❌ Not Available Requires manual setup via extra_hosts
WSL 2 ✅ Available Works with Docker Desktop
iOS ❌ Not Available No official support

For Linux users, a workaround is required:

docker-compose.yml:
services:
  my-service:
    extra_hosts:
      - "host.docker.internal:host-gateway"

This maps host.docker.internal to the host gateway.


Visualizing the Networking Model

Source Destination Works? Solution
Host → Container localhost:port Use mapped port in docker-compose.yml
Host → Container service_name Won’t resolve
Container → Container service_name Works within the same Docker network
Container → Host localhost Refers to itself
Container → Host host.docker.internal:port Works correctly
Web App → User Link service_name:port Won’t work for users
Web App → User Link localhost:port Use proper externally accessible URLs

Key Takeaways

Overview of the communication flow
  • Use localhost:port to access Docker services from the host.
  • Use service names for inter-container communication inside Docker.
  • Use host.docker.internal for Docker-to-host communication (if supported).
  • Linux requires manual configuration for host.docker.internal.
  • Mapped ports are crucial for external access.
  • Ensure web applications generate URLs users can actually reach.

By keeping these rules in mind, you can avoid common networking pitfalls when using Docker Compose. Share this guide with your colleagues to clarify how Docker networking works and improve debugging efficiency!