Uplink Docs
Introduction
Documentation

Introduction

Uplink shares a local port — publicly or privately — in one command. Public URLs are as simple as ngrok. Private apps are reachable through the same URL but gated: only you and the people you share with can open them, after a one-tap emailed login. Visitors need no VPN or client install. Keep a private overlay such as Tailscale for trusted device and network access; use Uplink when a selected service needs guarded public HTTPS.

uplink login                 # choose a browser link or emailed code
uplink serve 3000 --open     # public:  prints an HTTPS URL anyone can open
uplink serve 3000            # private: same URL, only you + people you share with
uplink up                    # serve everything declared in ./uplink.yaml

Identity is the only centralized piece, and even that is optional when you self-host. The edges that serve your traffic run anywhere — in the cloud or on your own infrastructure — and hold no shared database.

Uplink is the product: the uplink CLI, the desktop app, the local agent, and the dashboards. OpenTunnels is the protocol underneath: a mutually-authenticated QUIC transport with TLS 1.3, per-connection channel binding, and a strict registration/stream wire format. You use Uplink; OpenTunnels carries the bytes. See Architecture for the protocol.

How it fits together

visitor ──HTTPS──▶ edge ──OpenTunnels stream──▶ connector ──▶ localhost:3000
TermWhat it is
ConnectorYour machine running uplink or the desktop app. It dials out to an edge; the edge never dials into your machine.
Edge deployment (Caddy + uplink-edge)The public server that owns an edge domain, terminates visitor HTTPS (serving HTTP/1.1, HTTP/2, and HTTP/3), accepts connector tunnels, and holds ephemeral in-memory routes. Edges hold no shared database.
Control planeOptional. Issues identity, manages accounts and edges, and backs cross-device dashboards. It is never on the visitor request path.
NamespaceAssigned at login; part of every managed app host, so names never collide across accounts.
App nameThe service label in a URL. uplink serve 3000 defaults to app3000; set it with --name or a services.<name> key in uplink.yaml.

Install

For terminal-only machines, install the latest stable CLI on Linux (x86_64 or arm64) or Apple Silicon macOS:

curl -fsSL https://uplink.computer/install.sh | sh

This installs two binaries: uplink (the CLI) and uplink-agent (the local serving daemon the CLI starts automatically). The installer knobs are environment variables: UPLINK_CHANNEL picks the release channel (stable, the default, or dev), UPLINK_MANIFEST_URL overrides the full manifest URL, and UPLINK_INSTALL_DIR chooses the destination (default /usr/local/bin when writable, else ~/.local/bin). It records standalone ownership at ~/.uplink/cli-install.json (or under UPLINK_STATE_DIR) so the desktop can identify a custom install location later.

On macOS with Uplink.app, use Settings → Command line → Install instead. That command links to the CLI and agent inside the signed app, so the desktop updater keeps all three on exactly one build. The standalone installer detects Uplink.app and refuses to create a competing copy unless explicitly opted in with UPLINK_ALLOW_STANDALONE=1.

If you previously installed both forms, Settings uses that receipt plus legacy standalone locations such as /usr/local/bin and shows the conflicting path. Remove the old uplink and uplink-agent copies before installing the managed command. If the receipt is malformed, Settings reports the receipt path and keeps installation disabled until you reinstall the standalone CLI or remove that stale receipt.

The dev channel is also reachable directly — install with curl -fsSL https://uplink.computer/install-dev.sh | sh, and stay on it with uplink upgrade --dev.

To build the CLI from the uplink source tree on any platform:

cargo build --release -p uplink -p uplink-agent

The operator-side edge binary is uplink-edge. See Self-Hosting to run your own.

First app

uplink login                 # choose a browser link or emailed code
uplink serve 3000 --open     # publishes localhost:3000, prints the public URL
uplink status                # who you are + what you're serving

A served app is reachable at:

https://<name>-<device-slug><namespace>.<edge-domain>

<name> defaults to app<port> (override with --name); the rest comes from your login profile and the edge you serve through. See Serve a Port for the full per-part breakdown.

Share a private app

Private is the defaultuplink serve 3000 (no --open) publishes the same URL, but the edge admits only verified members of the app’s owning account and anyone you invite explicitly. A private app owned by an organization is automatically available to every member of that organization.

uplink status --output=json                       # list available account IDs
uplink serve 3000 --name demo --account acct_acme # share with an organization
uplink share demo contractor@example.com          # invite someone else
uplink unshare demo contractor@example.com        # revoke

Next steps

  • Serve a port — the everyday flow, app URLs, and the additive access model.
  • Formations — declare many services, their access and firewall settings in uplink.yaml.
  • Access Control — private/identity, organization access, invitations, and bearer tokens.
  • CLI Reference — every command and environment variable.

Run any command with no arguments to see its usage line. Add --output=json to status, tunnels, or edges for machine-readable output.

Search across 15 pages.
↑↓ navigate openEsc close