rune port-forward
rune port-forward [flags] <service-or-instance> [LOCAL:]REMOTE [more ports...]rune port-forward opens a local TCP listener and forwards every accepted connection over the API server’s gRPC stream into a port on a running service instance. It’s the Rune-native replacement for ssh root@host -L ... + docker inspect-the-bridge-IP — same shape as kubectl port-forward, with an optional detached mode for daily-use forwards.
Examples
Section titled “Examples”Foreground
Section titled “Foreground”# localhost:27017 → mongo:27017 in the default namespacerune port-forward mongo 27017
# Map a different local port (avoids collision with a local mongod)rune port-forward mongo 27018:27017 -n shared
# Multiple ports at oncerune port-forward flo 9002 9001 -n shared
# Expose the forward to the LAN (default is 127.0.0.1)rune port-forward --bind 0.0.0.0 mongo 27017
# Pin to a specific instance for a scaled servicerune port-forward --instance mongo-1 mongo 27017Detached
Section titled “Detached”For daily-use forwards (Compass against the dev Mongo, browser at the flo dashboard) the -d flag hands the forward off to a small per-user daemon so it survives terminal closes and laptop sleep.
# Background a forward — prints the assigned ID and pidrune port-forward -d mongo 27017# ✓ Forward fwd-a3f29ab1 started: 127.0.0.1:27017 -> shared/mongo (pid 88421)
# What's running?rune port-forward list
# Recent activity for a forwardrune port-forward logs fwd-a3f29ab1
# Tear one downrune port-forward stop fwd-a3f29ab1
# Tear them all downrune port-forward stop --allPort specs
Section titled “Port specs”Each positional arg after the target is one of:
| Form | Meaning |
|---|---|
N | local N ↔ remote N |
LOCAL:REMOTE | local LOCAL ↔ remote REMOTE |
Local 0 and remote 0 are rejected. Multiple specs may be given.
| Flag | Default | Notes |
|---|---|---|
-n, --namespace | context | Target namespace. |
--bind <addr> | 127.0.0.1 | Local bind address. Use 0.0.0.0 to expose to the LAN. |
--instance <id> | first running | Pin to a specific instance for scale>1 services. |
-d, --detach | false | Hand the forward off to the local daemon (see below). |
Targeting
Section titled “Targeting”The positional <service-or-instance> is resolved the same way as rune exec and rune logs:
- A bare service name (e.g.
mongo) selects the first Running instance of that service in the namespace. - An instance ID (e.g.
mongo-0) targets that exact instance. - Explicit prefixes
service/mongoorinstance/mongo-0skip the auto-detect and force a kind.
For scaled services (scale > 1), --instance pins the forward to a specific instance ID so reconnects always land on the same container.
Behavior
Section titled “Behavior”- The CLI binds every local listener up-front. Bind errors (port already in use, EACCES on a privileged port) surface before any “Forwarding…” output.
- All accepted local connections share the same server-side gRPC stream — multiplexed by an internal
conn_id. This keeps the wire layer cheap even when a browser opens many parallel connections to the forwarded port. SIGINT/SIGTERMcleanly drains in-flight bytes and exits 0.- If the bound instance restarts, the foreground command exits with a clear error and a non-zero status; re-run to reconnect. The detached daemon does this automatically with exponential backoff.
Detached mode
Section titled “Detached mode”-d spawns (or reuses) a small daemon — one per user — that owns the local listener and the gRPC stream. State lives at ~/.rune/forwards/:
~/.rune/forwards/├── daemon.pid├── daemon.sock # unix socket (mode 0700)├── daemon.log # daemon stdout/stderr└── fwd-<id>.json # one file per active forwardThe daemon:
- Multiplexes any number of forwards over a single process.
- Reconnects to runed automatically with exponential backoff (1s → 60s, up to 10 attempts) when the stream errors — local listeners stay bound during reconnect so clients don’t see a
ECONNREFUSEDburst. - Exits on its own 60 seconds after all forwards are stopped.
- Re-creates persisted forwards on startup (after a panic /
kill -9); a forward whose dial fails entersfailedstatus, visible inlist.
rune port-forward list columns:
| Column | Meaning |
|---|---|
ID | fwd-XXXXXXXX identifier (random per-forward). |
LOCAL | Bind address of the first listener. (+N) when there are more. |
TARGET | <namespace>/<service-or-instance>. |
STATUS | active, reconnecting, failed, unauthenticated. |
AGE | Time since the forward was created. |
Daemon limitations (v1)
Section titled “Daemon limitations (v1)”- Unix only. macOS and Linux are supported. Windows users get foreground only.
- Per-user. One daemon per user-home; not shared across machines or users on the same box.
- No auto-start on boot. After a reboot, re-run
rune port-forward -d. (launchd / systemd-user integration is a future ticket.)
Permissions
Section titled “Permissions”Gated by the port-forward verb on the services resource — narrower than services.exec since port-forward can only reach already-listening ports, never a shell.
It is deliberately not part of the built-in readwrite policy. Grant it explicitly:
apiVersion: rune.io/v1kind: Policymetadata: name: dev-debugrules: - resource: services verbs: [get, list, logs, port-forward] namespace: sharedThen attach the policy to the operator’s user via rune admin policy attach.
See also
Section titled “See also”rune exec— full interactive shell (much wider blast radius)rune logs— stream container logs- Logs & exec — debug workflow guide
- Service
expose:— for persistent, multi-user exposure (different problem)