Uplink Docs
CLI Reference
Documentation

CLI Reference

Run any command with no arguments to see its usage line, or uplink help <command> (subcommands too: uplink help edge add) for its full help. The global --output human|json|jsonl option (-o) controls rendering consistently across the command tree. Human output is the default, JSON is one complete document, and JSON Lines is intended for streams such as followed logs. Progress and prompts stay on stderr, so machine-readable stdout is safe to pipe. Malformed invocations (unknown flags, missing values) exit with code 2; runtime failures exit 1.

uplink status --output=json
uplink logs api --follow --output=jsonl

Session

uplink login                                            # choose a browser link or emailed code
uplink login --email me@example.com [--code ABC12345]
uplink login --token <jwt> [--refresh <refresh-token>]  # headless identity token (CI)
uplink login --device-token <token>                     # host-bound, serve-only session
uplink login --auth <url> --control <url>               # point at a self-hosted stack
uplink logout

With no credential flags, login asks whether to use a one-time browser link or an emailed code. For browser login it opens the system browser when possible and always prints a clickable, copyable fallback URL. login then writes the local profile — account, namespace, device slug, token (and refresh token when present), and the managed edge registry. The secret-bearing flags each take a -file variant that reads from a path (or - for stdin, keeping it off ps): --token-file, --refresh-file, and --device-token-file; --device-token also reads UPLINK_DEVICE_TOKEN. login --output=json prints the resulting identity in the same shape as status --output=json — useful in CI after login --token. logout clears the session and any unpublished local apps but keeps the device identity key.

Serving

uplink serve <port> [--name <name>] [--account <id>] [--public] [--auth <token> | --auth-file <path>] [--share <email>]... [--edges <id[,id...]>] [-d|--detach]
uplink init
uplink up [-f <path>]
uplink reload [-f <path>]
uplink restart
uplink down [-f <path>]
uplink stop <name>
uplink stop --all
uplink managed list
uplink managed attach <url> <port>
uplink managed detach <url>

serve is the quick foreground path for one app; -d/--detach keeps it serving in the background instead. Machine output requires detached mode and prints the served app in the same shape as up --output=json for scripting. init writes a commented starter uplink.yaml in the current directory and refuses to overwrite an existing one. Access is additive — gated to verified members of the owning account by default; --account chooses that personal or organization account, --auth adds a token (--auth-file <path|-> reads it from a file/stdin), --share invites someone by email, and --public (--open is an alias) opens it to everyone (exclusive with the rest). uplink status --output=json lists the accounts available to the current login. up serves the formation in uplink.yaml in the background and returns; reload re-reads it, down clears and stops it — with no arguments it stops everything (including detached UI tunnels), while down -f <path> stops only the services declared by that config file, leaving other tunnels running. stop removes one or all served apps. restart stops the background agent and starts it again from the on-disk binary, re-serving the saved formation — run it after uplink upgrade, since an in-place upgrade leaves the old agent running until it is restarted. On managed edges, formations can also assign verified account custom domains with custom_domain:. Standalone aliases are configured in an edge-side policy instead.

managed controls this device’s participation in a console-owned load-balanced endpoint. list shows the tunnels in the selected account; attach joins one local port to a tunnel’s backend pool; detach drains and removes this device’s attachment. The public URL and ingress policy are changed in the console, not by these commands.

Status & sharing

uplink status
uplink share <app> <email>
uplink unshare <app> <email>
uplink logs <app> [--follow]

status shows identity, available accounts, and served apps. share/unshare add or remove an invited email on a private app — re-serve the app for the change to take effect. Organization-wide access comes from making the organization the app’s owning account. logs prints the app’s local event log (written on this device by the serving side, not fetched from the edge). JSON output is one array; --output=jsonl emits one object per entry, and --follow keeps streaming human or JSONL entries until Ctrl-C.

Traffic capture

There is no capture command in the CLI. Request capture is enabled per service: declaratively with the inspect: off | metadata | full field in uplink.yaml, or interactively per tunnel in the desktop app / uplink ui inspector. A plain uplink serve never enables capture. Captures land in the device-local inspector store the desktop app and web UI browse. See Observability.

Edges & tunnels

uplink edge add <domain> --api-key <uek-key> [--identity-provider <origin>] [--challenge-provider <origin>]
uplink edge add <domain> --connector-auth identity --identity-provider <origin>
uplink edge list                 # alias: uplink edges
uplink edge refresh <domain>     # re-discover saved provider capabilities
uplink edge remove <domain>      # alias: uplink edge rm
uplink tunnels
uplink edges

edge manages local self-hosted edges and lists managed edges adopted at login. In API-key mode, --api-key-file <path|-> can replace --api-key. edge add also accepts a host:port positional; the host becomes the edge’s domain and the whole value its dial address. Otherwise the edge is dialed at <domain>:4100 unless --address overrides the dial authority. edge refresh updates the saved visitor-identity capability after a provider changes its discovery document. The edge runtime discovers the provider independently at startup. edges (an alias for edge list) works without a control plane — it shows your self-hosted edges and, when you’re signed in, the managed edges too. Only tunnels needs a configured control plane: it queries it for live tunnels across your devices.

Devices

uplink device list                     # alias: uplink devices
uplink device nickname <name>          # rename this device (alias: device rename)
uplink device nickname <name> --id <device-id>

A device’s nickname is a friendly label the dashboard and analytics views show for its device_id — it does not change any public URL (those carry the device slug). nickname defaults to renaming the current device; pass --id to rename another of the account’s devices. Both query the control plane.

UI

uplink ui [--port <n>] [--tunnel [--tunnel-name <name>] [--auth <token> | --auth-file <path|->] [-d|--detach]]
uplink api [--socket <path>]

ui serves the embedded desktop UI over HTTP. It always binds 127.0.0.1 (default port 4800); remote access goes through --tunnel, which publishes the UI as an edge-gated Uplink tunnel — see Desktop App & Web UI. api serves the same command contract as a local HTTP control API over an owner-only unix socket (default ~/.uplink/api.sock), for scripts and products that manage tunnels programmatically — see Local API.

Agent

uplink agent status     # alias: uplink agent doctor

Diagnoses the local uplink-agent serving daemon without starting it. For release tooling and support diagnostics, uplink --build-info and uplink-agent --build-info emit the same JSON cohort identity: release version, source build identity, distribution owner, and agent protocol version.

For a broader read-only health report and shell integration:

uplink doctor
uplink doctor --output=json
uplink completions bash

doctor checks local state, installed binaries, and the resident agent in one report. It always emits the complete report and exits 1 if any check fails. completions prints a generated script for Bash, Zsh, Fish, Elvish, or PowerShell; source or install that output using the conventions of your shell.

uplink service install [--user <name>] [--state-dir <path>] [--dry-run] [--force]
uplink service uninstall [--dry-run]
uplink service status

service runs the connector (uplink-agent) under the system service manager — systemd on Linux, launchd on macOS (a system-domain LaunchDaemon) — so a headless box serves its tunnels from boot with nobody logged in. Without it, the agent dies with the session and never comes back after a reboot. install needs root (sudo) and an existing session for the target user (--user defaults to the invoking user; --state-dir to that user’s ~/.uplink); on a headless box log in first with uplink login --device-token-file <path>. --dry-run prints the service definition and commands without touching the system; --force overwrites an existing definition. Declare what it serves with uplink up as usual.

One supervisor per machine. On a machine running the desktop app, the app already supervises the shared agent, and install refuses — the two would fight over the single per-user agent. The service is for headless, CLI-only hosts; on a workstation use the app’s start-at-login setting instead (--force overrides, if you are sure).

Upgrade

uplink upgrade [--dev] [--check] [--yes] [--install-dir <path>] [--manifest-url <url>]

upgrade checks the release manifest for a newer build and replaces the binary in place on Linux (x86_64 or arm64) and Apple Silicon macOS. --check only reports whether an update is available (no install); --yes (-y) skips the confirmation prompt; --install-dir targets a binary location other than the running one; --dev upgrades from the dev release channel instead of stable; --manifest-url overrides the release manifest URL. After an upgrade, uplink restart cycles a still-running agent onto the new binary (upgrade attempts this itself). On a machine with the system service installed, an upgrade of a CLI living outside /usr/local/bin leaves the service on the old build — re-run sudo uplink service install --force to move it over (upgrade prints a reminder when this applies). The CLI installed from Uplink.app is desktop-managed: update it through Uplink → Settings → Updates so modifying the CLI cannot invalidate the signed app bundle.

Run on the edge host, not the connector:

uplink-edge key new [--label <text>] [--file <path>]   # mint a connector API key
uplink-edge key list --file <path>
uplink-edge key revoke --file <path> --id <key-id>
uplink-edge key rotate --file <path> [--label <text>] [--overlap-seconds <n>]
uplink-edge container setup  # initializer used by the self-hosted Compose bundle
uplink-edge doctor [--domain <host>] [--public-ip <ip> | --no-public-ip-detect] [--identity-provider <url>]
uplink-edge doctor --env-reference                    # exhaustive edge environment reference
uplink-edge local --domain <name> --tunnel-cert <path> --tunnel-key <path> [--api-key <key>] [--print-env]
uplink-edge --public-listen <addr> --tunnel-listen <addr> --account <id>  # plaintext origin behind a TLS proxy
uplink-edge completions zsh

key new prints a raw uek_… key once and, with --file, writes a structured JSON key file holding only the key’s SHA-256 hash plus metadata — the edge reads that file via UPLINK_EDGE_API_KEYS_FILE and re-reads it on every connector registration, so revoke and rotate take effect without a restart (rotate --overlap-seconds keeps the old keys valid during a cutover). container setup is the initializer for a self-hosted edge with local API-key or identity-provider connector admission and an optional challenge provider. It collects the facts, waits for DNS, obtains the TLS certificate, and writes restricted Docker volume state; it does not require a management plane. Operators normally invoke it as docker compose run --rm setup and use the operator Compose service for key and doctor commands. The bare uplink-edge public listener is plaintext and must remain on loopback or a private network behind a correctly authenticated TLS proxy. The serving forms require UPLINK_EDGE_PUBLIC_DOMAIN and the tunnel identity (UPLINK_TUNNEL_CERT/UPLINK_TUNNEL_KEY, or --tunnel-cert/--tunnel-key paths for local). Identity-backed connector admission or visitor SSO uses UPLINK_IDENTITY_PROVIDER_URL. Bot protection uses UPLINK_CHALLENGE_PROVIDER_URL plus UPLINK_CHALLENGE_PROVIDER_TOKEN. See Self-Hosting. uplink-edge doctor always emits its complete report and exits 1 when a check fails, so its JSON output can be used directly as a deployment health gate.

Common environment variables

VariableUsed byPurpose
UPLINK_STATE_DIRallCLI state directory (default ~/.uplink)
UPLINK_DEVICE_TOKENloginhost-bound, serve-only account credential
UPLINK_AUTH_URLloginlogin / JWKS issuer base URL
UPLINK_CONTROL_URLlogin / uplink-edgecontrol-plane base URL saved into a connector profile or used for managed-edge reporting; leave unset on a standalone edge
UPLINK_EDGEserve / updefault edge domain
UPLINK_EDGE_ADDRESSserve / updial address for an env-configured self-hosted edge
UPLINK_EDGE_API_KEYserve / upraw self-hosted edge API key
UPLINK_TUNNEL_TRUST_CERTserve / upDER certificate trusted for a self-hosted tunnel endpoint
UPLINK_TUNNEL_SERVER_NAMEserve / upexpected tunnel certificate server name
UPLINK_EDGE_PUBLIC_DOMAINuplink-edgethe public domain the edge owns (required to serve)
UPLINK_TUNNEL_CERT / UPLINK_TUNNEL_KEYuplink-edgethe edge’s tunnel identity cert/key (required to serve)
UPLINK_IDENTITY_PROVIDER_URLuplink-edgediscovery authority for connector identity and/or visitor SSO
UPLINK_EDGE_API_KEYS_FILEuplink-edgepath to the JSON key file from uplink-edge key new --file (enables key mode; reloaded on every registration)
UPLINK_EDGE_API_KEYSuplink-edgeinline JSON key file — tests and emergency one-off runs only
UPLINK_EDGE_ALIAS_POLICY_FILEuplink-edgestandalone YAML map from custom hostnames to canonical generated hosts
UPLINK_EDGE_TRUSTED_PROXY_HOPSuplink-edgenumber of authenticated reverse-proxy hops; setup uses 1 for Caddy
UPLINK_EDGE_TRUSTED_PROXY_TOKENuplink-edgesecret a fronting proxy stamps so forwarded client IPs can be trusted
UPLINK_EDGE_OPERATOR_TOKENuplink-edgetoken for detailed operator diagnostics; unset disables that surface
OTEL_EXPORTER_OTLP_ENDPOINTuplink-edgeoperator-owned OTLP collector endpoint; unset disables export

This table covers the variables most often set by connector and standalone-edge operators. uplink-edge doctor --env-reference prints the exhaustive edge list, including defaults and managed-fleet variables, directly from the edge’s canonical environment registry.

Search across 15 pages.
↑↓ navigate openEsc close