Architecture
How it works
The connector runs on your machine and dials out to an edge — the edge never dials in. An edge deployment owns a public domain and terminates visitor HTTPS, serving HTTP/1.1, HTTP/2, and HTTP/3 to browsers. The guided standalone deployment uses Caddy for that TLS front and keeps the Rust edge’s plaintext HTTP listener on loopback. The control plane issues identity and receives liveness/metering when configured, but is not on the visitor request path.
visitor ──▶ edge route ──▶ OpenTunnels stream ──▶ connector ──▶ localhost service
At registration the connector declares its services — each with a compiled access policy and route controls — plus any device ports attached to control-plane-owned load-balanced endpoints. The edge verifies the connector’s identity (or API-key authorization), pins each ordinary route host to the declared app/account/device namespace, and evaluates route policy before proxying. A load-balanced attachment is accepted only when its durable endpoint belongs to the connector’s verified account.
OpenTunnels protocol
OpenTunnels runs over QUIC with TLS 1.3. The connector dials the edge, and the edge opens a stream back over that same connection for each public request — so traffic flows inbound to your app without your machine ever accepting an inbound connection.
Registration carries the identity token (or key-mode credential), the service manifest, and a signed proof bound to the current TLS session’s channel binding. When holder-of-key claims are present, this binding prevents a stolen managed token from being enough to register a different connector.
The transport stack is self-contained. Ordinary app routes are ephemeral and built from live connector registrations. Durable load-balanced endpoint routes are distributed by the control plane, but each edge still holds its route and backend pool only in memory; neither a shared routing database nor the control plane is on the visitor request path. A durable endpoint remains addressable with an empty pool and returns 503 until a ready backend joins.
Managed edges are grouped into regions sharing one wildcard domain; a connector registers each app or endpoint attachment on every edge of its region (its home set), and the region sits behind plain round-robin DNS — no inter-edge forwarding. For the full protocol, see the OpenTunnels whitepaper.
Security model
The edge fails closed. Before proxying any request it performs route lookup, checks the tunnel’s source-IP access restriction and base request limit, evaluates identity access and reusable firewall rules, and admits the stream. Unknown hosts collapse to a generic not-found response — they reveal nothing about what exists.
- Managed connector tokens can be holder-of-key bound to the local device key, so possession of the token alone is insufficient to impersonate a connector.
- Self-hosted key mode authenticates connectors with API-key hashes configured on the edge.
- Secrets are hashed locally. Bearer tokens are SHA-256 hashed on your machine before storage or edge registration — only the hash ever leaves the device.
- Edges keep no routing database. Both connector-owned routes and distributed endpoint routes are enforced from in-memory state; telemetry exports metadata only.
The security model is defense-in-depth around a few explicit boundaries. Identity
tokens are EdDSA (Ed25519) JWTs verified strictly — the algorithm is pinned, kid is
required, and exp/iss/aud are all enforced, failing closed. The one tenant
boundaries — a connector may only serve ordinary hostnames under its own verified
namespace, and may attach only to an endpoint owned by its verified account — are
enforced at registration. All cryptography is vetted RustCrypto/dalek primitives;
unsafe code is denied workspace-wide. The full threat model is in the
OpenTunnels whitepaper.