TCP Tunnels

TCP Tunnels

Publish raw TCP services through ephemeral or reserved addresses.


A published TCP tunnel exposes a public hostname and port and relays each accepted connection to a TCP service behind the rstream agent. It is intended for protocols such as SSH that already provide their own encryption and authentication.

rstream does not secure the downstream side of a TCP tunnel. The bytes received on the public port are forwarded as-is. Use a secure application protocol, and use a TLS tunnel when rstream should terminate TLS or pass a TLS session through to the upstream service.

Published TCP tunnels are available on Pro and Enterprise projects. They are enabled by default, and the project must allow public access.

Ephemeral addresses

Use --tcp to publish a local TCP service on an address allocated for the lifetime of the tunnel:

rstream forward 22 --tcp

The command prints the allocated address as a hostname and port. A client connects directly to that address. For SSH, for example:

ssh -p <port> <user>@<tcp-hostname>

The port returns to the ephemeral pool when the tunnel closes. Do not build a persistent client configuration around an ephemeral address.

Reserved addresses

A reserved TCP address belongs to a project independently of a running tunnel. Reserve one from the project TCP page in the dashboard or from the CLI:

rstream project tcp-address reserve

The result contains an address and its public port. Pass the port when opening the tunnel:

rstream forward 22 --tcp --tcp-port <port>

The engine verifies that the port is reserved by the authenticated project before opening the listener. A reservation can be used by only one live tunnel at a time.

List the project addresses with:

rstream project tcp-address list

The dashboard also correlates each reservation with its live tunnel. This association is runtime state: the reservation remains available while the agent is offline.

Stop a tunnel before releasing its address. The dashboard disables release while its live project Watch reports an active binding. The CLI uses the public port:

rstream project tcp-address release <port>

The address leaves the project immediately and enters quarantine before it can be assigned again. Reachable engines remove an active binding immediately. A bounded authorization lease lets a private or temporarily unreachable engine detect a missed release when the next connection arrives. Quarantine prevents a newly assigned project from receiving connections that were still intended for the previous owner.

Project security policy

Published TCP is enabled by default. A project owner or administrator can disable Published TCP tunnels in the project settings when the project must never expose raw TCP services. The project public access policy must be allowed.

auth-required is deliberately incompatible with raw TCP publishing. Token authentication, rstream Auth, and Tunnel mTLS depend on a protocol handshake at the edge; a raw TCP listener has no such handshake. Authentication must therefore be provided by the application protocol itself. forbidden rejects the tunnel like every other published tunnel.

Declarative configuration

YAML uses protocol: tcp. Omit port for an ephemeral address, or set it to the port of an existing reservation:

version: 1
tunnels:
  - name: ssh
    forward: 22
    tunnel:
      publish: true
      protocol: tcp
      port: 10042

The corresponding Docker labels are:

labels:
  rstream.tunnel.ssh.forward: "22"
  rstream.tunnel.ssh.publish: "true"
  rstream.tunnel.ssh.protocol: "tcp"
  rstream.tunnel.ssh.port: "10042"

In Kubernetes, use spec.protocol: tcp and the optional spec.tcpPort field. The operator rejects TCP manifests that request a hostname, a datagram tunnel, a private tunnel, or HTTP and TLS options.

Self-hosted engines

Community Edition can expose ephemeral TCP addresses when published_tcp is enabled on the standalone engine. Reserved addresses require the hosted Control plane and are not available in Community Edition.

The portable dynamic ingress backend binds only ports used by active tunnels. The configured ephemeral range must be open in the host and cloud firewalls, but the engine does not pre-bind the complete range. Container deployments should use host networking so dynamically selected ports are reachable without publishing a complete Docker port range.

Linux operators can instead select the tproxy backend. It redirects the configured range to one transparent listener while preserving the original destination port and source address. This backend requires explicit host policy routing, TPROXY rules, and CAP_NET_ADMIN; the engine does not modify host networking or fall back automatically. In a standalone engine, both backends route only tunnels owned by that engine.

See Self-Hosted Configuration for the engine fields and Self-Hosted Deployment for the network layout.