✦ For everyone, free.

Practical knowledge for real and everyday life

Home

16.2.2.2 Runtime Port Mapping Error

A focused guide to Runtime Port Mapping Error, connecting core concepts with practical Docker and container operations.

A runtime port mapping error covers mistakes and failures in the actual syntax and mechanics of Docker's port publishing flags themselves, as distinct from the application-level listening address or firewall issues covered elsewhere, focusing specifically on how -p, -P, protocol specifiers, and bind addresses are written and on the underlying docker-proxy mechanism that implements the mapping.

Basic syntax and common typos

The -p flag's full syntax supports an optional host IP, a host port, and a container port, and getting the colon-separated structure wrong produces either an outright error or a mapping that silently does not behave as intended:

docker run -p 3000 my-api
Error: invalid containerPort: 3000

A bare port number with no colon is interpreted as a container port specification rather than a full mapping, which is rarely what is actually intended; the correct form explicitly separates host and container ports:

docker run -p 3000:3000 my-api

Specifying a bind address to restrict accessibility

By default, a published port is bound to all of the host's network interfaces, but an explicit IP address can restrict it to a specific interface, commonly used to publish a port only on localhost rather than making it reachable from the host's external network interfaces:

docker run -p 127.0.0.1:3000:3000 my-api
docker run -p 3000:3000 my-api

The first example publishes the port only on the loopback interface, reachable only from processes on the host itself; the second publishes on every interface, making it reachable from the broader network the host is connected to, which is an important distinction for any service that should not be directly exposed beyond the host.

Protocol specification

By default, -p publishes a TCP mapping; a service using UDP needs this specified explicitly, and forgetting to do so results in a port that appears mapped but does not actually carry UDP traffic at all:

docker run -p 53:53/udp my-api
docker run -p 53:53/tcp -p 53:53/udp my-api

A DNS server or similar UDP-based service published without the /udp specifier will accept TCP connections on that port but silently fail to receive any UDP traffic, which can be confusing since the port appears correctly mapped according to docker ps while the actual protocol the application needs is not being forwarded at all.

Publishing a range of ports

A contiguous range of ports can be published in a single flag using a hyphenated range, useful for services that need multiple sequential ports, such as certain passive FTP configurations or applications using a range for dynamic port allocation:

docker run -p 50000-50010:50000-50010 my-api

Each port in the host range maps to the corresponding port in the container range; mismatched range sizes between host and container produce an error rather than a partial, best-effort mapping.

The -P flag versus -p

The capital -P flag publishes every port declared by the image's EXPOSE instructions to randomly assigned, ephemeral host ports, which is a fundamentally different behavior from -p's explicit, deliberate mapping, and conflating the two produces confusion about which host port actually maps to which container port:

docker run -P my-api
docker port my-api
3000/tcp -> 0.0.0.0:32768

Because -P assigns host ports dynamically rather than to a predictable, fixed value, docker port needs to be checked directly after starting the container to discover which host port was actually assigned, which is rarely desirable for a production service expecting to be reached at a known, stable address.

Port conflicts in Compose

In a Compose stack, two services both attempting to publish the same host port produces a clear, immediate error when the stack is brought up, but the more subtle version of this problem occurs when one service's published port silently shadows another's intended mapping due to a copy-paste error in the Compose file:

services:
  api:
    ports:
      - "3000:3000"
  worker:
    ports:
      - "3000:3001"
Error: failed to bind host port for 0.0.0.0:3000: address already in use

Reviewing every service's port mappings together when adding a new one catches this category of conflict before attempting to bring up the stack, rather than relying on the error message alone to identify which two services are actually competing for the same host port.

The docker-proxy process and its role

For each published port, Docker typically runs (depending on configuration and platform) a small userspace proxy process responsible for actually forwarding traffic between the host port and the container's internal address, and in less common cases, this proxy process itself can fail or behave unexpectedly, independent of anything wrong with the container or the application inside it:

ps aux | grep docker-proxy
systemctl restart docker

A published port that stops working without any change to the container itself, particularly after a host-level event like a network interface change, is occasionally attributable to this proxy mechanism specifically, and restarting the Docker daemon, which restarts the proxy processes for all currently published ports, is a reasonable troubleshooting step when more direct causes have been ruled out.

Verifying the actual effective mapping

Regardless of how a port mapping was specified, directly inspecting the container's actual, effective port configuration confirms what is genuinely in effect, rather than relying on what the original command or Compose file appeared to request:

docker port my-api
docker inspect my-api --format '{{json .NetworkSettings.Ports}}'

This is the most reliable way to resolve any ambiguity about exactly which host address and port currently map to which container port, especially useful when troubleshooting a mapping configured through a Compose file with several layers of override files potentially affecting the final result.

Common mistakes

  • Omitting the colon-separated host-port-to-container-port structure, producing an unintended or outright invalid port specification.
  • Forgetting the /udp protocol specifier for a UDP-based service, resulting in a port that appears mapped but does not actually carry the needed traffic.
  • Using -P when a specific, predictable host port was actually needed, then being surprised by a randomly assigned ephemeral port.
  • Not reviewing all of a Compose stack's port mappings together when adding a new service, missing a conflict or an unintended shadowing of an existing mapping.
  • Assuming a port mapping is in effect based on the original command or Compose file alone, without verifying the actual, effective mapping directly through docker port or docker inspect.

Runtime port mapping errors are largely a matter of syntax and specification precision, getting the host-to-container direction, protocol, and bind address exactly right, and directly inspecting the actual effective mapping after the fact is the most reliable way to confirm a port publishing configuration is genuinely working as intended rather than assuming based on the original command alone.