Skip to main content
Two copies of the same application on the same machine, both wanting port 8080 — how can that work? On Maya’s old virtual machines, that would have been impossible. Tidepool avoided collisions by keeping a spreadsheet: someone recorded which service owned which host port — and nobody updated it reliably. So why didn’t the second container fail? Because Maya never asked Nomad to bind the same host port. In her job file she created a named port with a to value of 8080 inside the network block. That to value is the port inside the task (the container), not the host port. She named the port but left the host port unspecified, allowing Nomad to choose it. Separate the two concepts:
  • The to value is the port inside the task — the port the application listens on (for Tidepool’s API this is 8080 and is baked into the image).
  • The host port is what the machine exposes. If you omit it, Nomad assigns a free host port from a default range (20000–30000).
Example: container port (task-facing)
Because no static host port was declared, Nomad picked distinct host ports for each allocation. Inside each container the application still sees 8080, but Nomad maps different host ports to those internal ports. How the mapping works depends on the network mode in the group block — the two common modes are:
  • host mode (the default): the task shares the machine’s network stack. No port translation occurs; two allocations that both request the same host port will collide.
  • bridge mode: the group gets an isolated network namespace with its own IP. Nomad maps a host port it chose into the container port specified by to.
A slide illustrating host vs bridge Docker networking. It shows icons for host (globe), bridge (lock) and ports mapped (plug) with four Docker containers labeled box-1 to box-4 and the note "Bridge · its own namespace, ports mapped."
Bridge mode is what enables host-to-container port mapping and is the recommended choice when you plan to run multiple instances of the same service. Comparison at a glance: If Nomad chooses the host port, how does the application know which port it got? Nomad exposes environment variables for every port label you declare. For a label named HTTP, Nomad provides variables like:
  • NOMAD_PORT_http — the host port number Nomad chose
  • NOMAD_IP_http — the host’s IP address (as seen from the allocation)
  • NOMAD_ADDR_http — the host IP and port combined
Example environment variables Nomad injects into the task:
Use the same port label in your service block so Nomad registers the actual host port under the service name. Do not hard-code numeric host ports in the service stanza — let Nomad wire things together from the label.
Always reference the port by its label (for example HTTP) in service and task code. This keeps the container-facing port and the Nomad-assigned host port synchronized without hard-coded numbers.
A presentation slide titled "One Label, Written Once" showing icons for a network label and an env var alongside the phrase "Never from a config file." Below are Docker whale icons and server illustrations labeled box-1 through box-4.
Nothing else in your infrastructure needs to record static ports. That lets instances move between machines and scale up or down without manual edits. If you need service-to-service identity (mutual TLS, encrypted traffic, etc.), that’s typically handled by a service mesh. Nomad integrates with service meshes using a connect block that injects a sidecar proxy next to each task and routes traffic through it — a larger topic beyond the scope of this article. One common pitfall is pinning every service to a fixed host port. Using a static host port can make firewall rules simpler, but it breaks scaling: when you increase from two to four copies, new allocations may be unable to start because the fixed ports are already in use. That returns you to the spreadsheet problem.
Avoid static host ports unless an external constraint requires them (for example, a legacy load balancer or a partner integration that demands fixed ports). In most cases, allow Nomad to assign host ports and read the assigned port from the environment.
A presentation slide titled "The Static Port Trap" showing icons (traffic light, bar chart, hourglass) with captions about pinned services, counts and pending allocations, and four Docker/server boxes labeled box-1 through box-4. The right side highlights the text "Pending allocations, and the spreadsheet returns."
Summary
  • Use to to declare the container port your application listens on.
  • Prefer bridge mode for multi-instance services so Nomad can map host ports.
  • Read NOMAD_PORT_<label> (and related env vars) from inside the task to discover the host port.
  • Only use static host ports when absolutely necessary.
Links and references

Watch Video

Practice Lab