Skip to main content
Expose ports from your Ona environment to share running services with teammates, test webhooks, or preview work without deploying.

How it works

When you open a port, Ona creates a URL with automatic TLS termination. All shared URLs use HTTPS. You can configure whether Ona connects to your service via HTTP (default) or HTTPS.
DeploymentAccess
Ona CloudInternal network - anyone with the URL can access
Enterprise RunnersThrough your runner’s Network Load Balancer, controlled by your network configuration

Prerequisites

Services must:
  • Listen on 0.0.0.0 (not localhost or 127.0.0.1)
  • Use the host network stack if running inside a container
app.listen(3000, '0.0.0.0', () => {
  console.log('Server running on port 3000');
});

Services that only listen on localhost

Some tools hardcode localhost as their bind address with no option to change it. AWS SSM port forwarding (session-manager-plugin) is a common example. Since Ona’s port-sharing proxy connects from outside the loopback interface, these services return “Service Unavailable” (503) when accessed through a shared port URL. Two workarounds are available:

Option A: iptables (no extra packages)

Use kernel-level NAT to redirect incoming traffic to the loopback address. This is already available in the environment and lets you keep the same port number.
# Allow routing to loopback addresses (off by default)
sudo sysctl -w net.ipv4.conf.all.route_localnet=1

# Redirect external traffic on port 6767 to localhost:6767
sudo iptables -t nat -A PREROUTING -p tcp --dport 6767 -j DNAT --to-destination 127.0.0.1:6767

# Open the port in Ona
ona environment port open 6767 --name "my-service"

Option B: socat (userspace relay)

Use socat to relay traffic from 0.0.0.0 on a second port to the localhost-bound service. Requires installing socat (apt-get install -y socat) but does not need root.
# Relay from 0.0.0.0:6768 to localhost:6767
socat TCP-LISTEN:6768,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:6767

# Open the relayed port in Ona (note: different port number)
ona environment port open 6768 --name "my-service"

Host network stack

By default, the Dev Container network is isolated from the VM. For port sharing to work, services must be accessible on the host network. There are several scenarios to consider:

Dev Container network mode

To make your Dev Container itself use the host network stack, configure your devcontainer.json: Single container setup:
{
  "name": "My Project",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:20",
  "runArgs": ["--network=host"]
}
Multi-container setup (Docker Compose): See Multi-container development for complete setup. The key requirement is network_mode: host on all services:
# docker-compose.yml
services:
  app:
    build: .
    network_mode: host
    command: sleep infinity

  db:
    image: postgres:16
    network_mode: host
    environment:
      POSTGRES_PASSWORD: postgres

Containers inside Dev Container (Docker-in-Docker)

When running containers inside your Dev Container using Docker-in-Docker, those containers must also share the host network namespace. Otherwise, ports are only accessible within Docker’s bridge network and Ona cannot forward them. Docker run:
# ✗ Won't work - port only accessible on Docker bridge network
docker run -d -p 8080:8080 myapp

# ✓ Works - port accessible to Ona for forwarding
docker run -d --network host myapp
Docker Compose inside Dev Container:
services:
  database:
    image: postgres:16
    network_mode: host
    environment:
      POSTGRES_PASSWORD: postgres

  redis:
    image: redis:7
    network_mode: host
Without network_mode: host or --network host, services use Docker’s bridge network. Ports mapped with -p or ports: are only accessible within that bridge network, not from your Dev Container or Ona’s port forwarding.

Ona Tasks and Services

When running containerized services with docker run, use --network host or map ports explicitly with -p to make them accessible. See containerized service examples for recommended patterns.

Relationship to devcontainer port properties

The devcontainer.json spec includes forwardPorts and portsAttributes properties. These are standard devcontainer properties that tell the editor which ports to forward from the container and how to configure them (labels, auto-forward behavior). These properties work in Ona across VS Code-based editors, but they operate independently from Ona’s port sharing. They do not create shareable URLs or open ports in the Ona dashboard.
MechanismWhat it doesUse case
forwardPorts / portsAttributesEditor-managed port forwarding, auto-forward notifications, port labelsPer-developer access in VS Code-based editors
ona environment port openOna public URL with TLS, visible in dashboardShareable URLs, browser IDE previews, CI integrations

Open ports

UI

In the environment sidebar, find “Public Ports” and click “Open Port”. Enter the port number, optional name, and protocol.

CLI

ona environment port list
ona environment port open 3000 --name my-app
ona environment port open 3000 --protocol https
ona environment port close 3000
Open ports are accessible to anyone who can reach the URL. On Ona Cloud, this means anyone on the internal network. For Enterprise Runners, access depends on your network configuration.

Opening a port and previewing in the browser

You can open a port and launch the preview URL in a single command using the $BROWSER variable:
$BROWSER "$(ona environment port open 8000 -n my-app)"
To see which ports are currently listening in your environment:
ss -tlnp

Limitations

  • Ports 1024–65535 can be exposed. System ports (1–1023) are not supported.
  • Not available on local environments
  • Subject to fair use policies and bandwidth limits
  • Organization administrators can disable port sharing via organization policies. VS Code Browser and agents are exempt from this restriction.
Network flags like --network=host in build.options are stripped during Dev Container builds. Host network mode is only applied at runtime when the container starts.