Uplink Docs
Getting Started

Getting Started

Uplink lets you share a local port — with the world or just your team — in one command.

uplink login                      # sign in once (an emailed code)
uplink serve 3000 --open          # public:  https://app3000-<device><namespace>.<edge-domain>
uplink serve 3000                 # private: same URL, only you + people you share it with
uplink up                         # serve everything declared in ./uplink.yaml

Public URLs are as easy as ngrok. Private apps are reachable through the same URL but gated: only you and the accounts you share with can open them, after a one-tap email login — no VPN, no client to install. The same uplink login is all you need. Identity is the only thing that’s centralized, 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 app — an intuitive CLI and desktop client for serving local apps. Under it runs OpenTunnels, an open, robust tunneling protocol: a mutually-authenticated QUIC transport with TLS 1.3, per-connection channel binding, and a strict registration/stream wire format.

Install

cargo build --workspace
./tools/install.sh      # installs `uplink` to ~/.cargo/bin

Quick start

uplink login                                   # emailed one-time code
uplink serve 3000 --open                       # publish → prints the public URL
uplink share app3000 teammate@example.com      # (private apps) let a teammate in
uplink status                                  # who you are + what you're serving

A served app is reachable at https://<name>-<device-slug><namespace>.<edge-domain>, where <namespace> is yours (set at login), <device-slug> defaults to a short stable id, and <edge-domain> is owned by the edge you serve through. The default <name> is app<port>; override it with --name.

Serving a formation

For anything richer than a single port — saved access policies, firewall rules, sharing lists, per-service edges, or many services at once — declare it in uplink.yaml and serve it with uplink up:

services:
  blog:
    port: 3000
    access: public               # private (default) | password | public | policy:<name>
  api:
    port: 8080
    access: password
    password: ${API_TOKEN}       # raw bearer; hashed locally before it is sent
uplink up                 # serve everything in ./uplink.yaml (foreground)
uplink up -d              # detach: run in the background and return

Next steps

  • Run any command with no arguments to see its usage line.
  • Add --json to status, tunnels, or edges for machine-readable output.
  • Self-host an edge with no hosted identity using an API key (uplink-edge setup).