PORTAL v2

CLI Reference

The portal CLI exposes local services through Portal relay servers. The relay provides transport and routing. The tunnel process decides whether a connection is handled as the default HTTPS stream, routed HTTP, raw TCP, or UDP.

Install

macOS / Linux

curl -fsSL https://github.com/gosuda/portal-tunnel/releases/latest/download/install.sh | bash

Windows PowerShell

$ProgressPreference = 'SilentlyContinue'
irm https://github.com/gosuda/portal-tunnel/releases/latest/download/install.ps1 | iex

From A Relay

If your relay publishes its own installer:

curl -sSL https://portal.example.com/install.sh | bash

The installer writes the portal binary only. It does not write a config file.

Command Overview

CommandPurpose
portal exposeExpose one local service or one routed HTTP bundle
portal listPrint relay URLs resolved for this invocation
portal agentRun a durable local multi-tunnel agent
portal updateReplace the CLI with the latest release
portal versionPrint the current version

portal expose

Expose a local service:

portal expose [flags] <target>

Or run routed HTTP mode:

portal expose [flags] --http-route PATH=UPSTREAM [--http-route PATH=UPSTREAM]

Target Formats

FormatExampleResolves to
Bare port3000127.0.0.1:3000
Host and portlocalhost:8080localhost:8080
URL hosthttp://127.0.0.1:3000127.0.0.1:3000

URL inputs are accepted for address parsing. Paths, queries, and fragments are not supported.

Mode Selection

ModeExampleNotes
Default HTTPS streamportal expose 3000Relay routes by SNI; tunnel process terminates tenant TLS
Routed HTTPportal expose --http-route /api=3001 --http-route /=5173Tunnel process runs the HTTP reverse proxy
Dedicated raw TCPportal expose localhost:25565 --tcpRelay allocates a public TCP port
UDP relayportal expose 8080 --udp --udp-addr 19132Relay allocates a public UDP port

Flags

FlagTypeDefaultDescription
--relaysstringregistryAdditional relay API URLs, comma-separated
--discoverybooltrueInclude registry relays and relay discovery expansion
--max-active-relaysint3Maximum auto-selected relays to keep connected; explicit relays are always included
--multi-hopstringOrdered multi-hop relay API URLs, comma-separated
--multi-hop-depthint0Automatically select one multi-hop route with this hop count; 0 or 1 disables multi-hop
--ban-mitmbooltrueBan relay when the MITM self-probe detects TLS termination
--identity-pathstringidentity.jsonIdentity JSON file path; created automatically when missing
--identity-jsonstringIdentity JSON payload; overrides --identity-path contents and is persisted there when both are set
--namestringautoPublic hostname prefix, one DNS label
--descriptionstringService description metadata
--tagsstringService tags metadata, comma-separated
--thumbnailstringService thumbnail URL metadata
--ownerstringService owner metadata
--hideboolfalseHide service from relay listing screens
--http-routestringHTTP route mapping in PATH=UPSTREAM form; repeatable
--tcpboolfalseRequest a dedicated raw TCP port on the relay
--udpboolfalseEnable public UDP relay in addition to the default stream path
--udp-addrstringLocal UDP target; defaults to the primary target when --udp is enabled
--metrics-addrstringOptional host:port for Prometheus /metrics

Constraints

  • <target> cannot be combined with --http-route.
  • --http-route cannot be combined with --udp.
  • Explicit --multi-hop cannot be combined with automatic --multi-hop-depth.
  • Multi-hop currently supports only the default SNI TLS stream transport.
  • --tcp and --udp require matching transport support on the relay.

Examples

Expose a local web app:

portal expose 3000

Use a custom name and relay:

portal expose localhost:8080 
  --name myapp 
  --relays https://portal.example.com 
  --discovery=false 
  --description "My web application" 
  --tags webapp,demo

Run routed HTTP mode:

portal expose --name myapp 
  --http-route /api=http://127.0.0.1:3001 
  --http-route /=http://127.0.0.1:5173

Route matching is longest-prefix-first. /api matches /api/* and strips the /api prefix before proxying to the upstream.

Expose a Minecraft server:

portal expose localhost:25565 --name minecraft --tcp

Enable UDP alongside the default stream target:

portal expose localhost:8080 --udp --udp-addr localhost:19132 --name game

Use an explicit multi-hop route:

portal expose 3000 --multi-hop https://entry.example.com,https://exit.example.com

Ask Portal to select one three-hop route:

portal expose 3000 --multi-hop-depth 3

Keep MITM probe failures warning-only:

portal expose 3000 --ban-mitm=false

portal list

Print relay URLs resolved for the current invocation:

portal list [flags]
FlagTypeDefaultDescription
--relaysstringregistryAdditional relay URLs
--default-relaysbooltrueInclude public registry relays

portal list does not run the runtime relay discovery expansion loop. It only resolves the registry seed list plus explicit relay URLs.

portal agent

Run a durable local agent that owns multiple tunnels from one config file:

portal agent run
portal agent dashboard
portal agent stop
portal agent restart
CommandDescription
portal agent runInstall or update and start the managed agent service
portal agent run --config config.toml --foregroundRun the agent in the current terminal
portal agent dashboardOpen the local TUI for tunnels, relays, multi-hop routes, and settings
portal agent stopGracefully stop the agent and disable or stop the OS service
portal agent restartStop the current agent if present, install or update the service, and start it again

The local control API binds only to loopback and uses a token in the agent state directory. See Portal Agent for the workflow and Configuration Reference for the config.toml format.

Agent flags:

CommandFlagDefaultDescription
portal agent run--configplatform defaultAgent TOML config path
portal agent run--foregroundfalseRun in the current process without installing the OS service
portal agent run--servicefalseInternal service entrypoint used by the installed OS service
portal agent dashboard--configplatform defaultConfig path used for display and state-dir discovery
portal agent dashboard--state-dirconfig/defaultAgent state directory to attach to
portal agent stop--configplatform defaultConfig path used to resolve state dir and service name
portal agent stop--state-dirconfig/defaultAgent state directory to stop
portal agent restart--configplatform defaultConfig path used to reinstall and restart the service

portal update

Update the CLI binary:

portal update

The updater resolves the latest GitHub release, compares it with the installed version, downloads the matching asset, verifies its SHA256 checksum, and replaces the current executable.

portal version

portal version

Prints the installed version string and exits.

Behavior Notes

  • portal expose and portal list check for new releases in the background.
  • portal expose loads or creates a signing identity at identity.json or --identity-path.
  • Multiple relay URLs are registered independently. A failed relay does not stop healthy relays from serving.
  • With discovery enabled, the tunnel consumes relay /discovery results and reconciles its relay pool.
  • MITM enforcement is enabled by default for the default stream path.
  • When the local stream target is unreachable, the tunnel returns an HTTP 503 page to browser-style clients.
  • Routed HTTP mode is HTTP-only and runs inside the tunnel process.
  • --tcp requires relay TCP port transport, a valid MIN_PORT/MAX_PORT range, and TCP port transport enabled in the admin panel.
  • --udp requires relay UDP transport, a valid MIN_PORT/MAX_PORT range, UDP enabled in the admin panel, and SNI_PORT/udp reachable for the QUIC backhaul.
  • Bare portal [flags] is not accepted; use portal expose explicitly.
  • Runtime APP_*, RELAYS, and DEFAULT_RELAYS environment variable fallbacks are not used.

Next Steps