Forwarding and securing ports in DevContainers

Port forwarding is what lets you open localhost:3000 on the host and reach a service inside the container — but the defaults can also auto-forward ports you didn’t intend, and in Codespaces a misconfigured port can become publicly reachable. This page forwards exactly the ports you want, labels them, and locks down visibility. It extends the Understanding the DevContainer Specification cluster.

Prerequisites

  • A devcontainer.json and a service that listens on a known port
  • VS Code Dev Containers extension or the devcontainer CLI

How-To Steps

  1. Declare the ports you want forwarded explicitly rather than relying on auto-detection:

    {
      "image": "mcr.microsoft.com/devcontainers/javascript-node:20@sha256:7c3e...",
      "forwardPorts": [3000, 5432],
      "remoteUser": "vscode"
    }
    
  2. Annotate each port with a label and an auto-forward behaviour via portsAttributes:

    {
      "portsAttributes": {
        "3000": { "label": "web", "onAutoForward": "notify" },
        "5432": { "label": "postgres", "onAutoForward": "silent" }
      }
    }
    
  3. Suppress unwanted auto-forwarding so stray listeners don’t get exposed:

    { "otherPortsAttributes": { "onAutoForward": "ignore" } }
    
  4. Keep services bound correctly. For host access bind 0.0.0.0; for container-internal-only services keep them on 127.0.0.1 and do not list them in forwardPorts. Verify what’s reachable:

    devcontainer exec --workspace-folder . ss -ltnp        # see listening sockets
    curl -fsS http://localhost:3000/health                  # forwarded port works from host
    
  5. In Codespaces, confirm visibility is private (the default). Public visibility makes a port reachable by anyone with the URL — only set it deliberately.

Common Pitfalls

SymptomRoot CauseRemediation
Unexpected ports forwardedAuto-forward detected a listenerSet otherPortsAttributes.onAutoForward to ignore
Forwarded port refuses connectionService bound to 127.0.0.1Bind 0.0.0.0 for host-reachable services
Codespaces port publicly reachableVisibility set to publicReset port visibility to private
Port label missing/confusingNo portsAttributes entryAdd a label per forwarded port

Conclusion

The invariant: forward only the ports you name, label them, and default everything else to ignore. Combine explicit forwardPorts with correct bind addresses and private Codespaces visibility, and you expose exactly the surface you intend — nothing more.

FAQ

What’s the difference between forwardPorts and appPort? forwardPorts maps container ports to the host through the IDE’s forwarding and is the modern, spec-aligned approach. appPort publishes via Docker directly and bypasses the IDE’s visibility controls — prefer forwardPorts.

Why is a port auto-forwarded even though I didn’t list it? The IDE detects new listening sockets and forwards them by default. Set otherPortsAttributes.onAutoForward to ignore to disable that behaviour for unlisted ports.