browser
*.opentunnel.xyz
opencode
localhost:47365api
localhost:3000webhooks
localhost:8080a cli and sdk to create end-to-end encrypted public urls forapps running on your machine reachable from anywhere in theworld
$ curl -fsSL https://opentunnel.xyz/install | sh
cli
$ opentunnel route add opencode 47365 creating tunnel... tunnel is ready. added route opencode → 127.0.0.1:47365 https://opencode.f7a2mx4kq9vn.opentunnel.xyz $ curl https://opencode.f7a2mx4kq9vn.opentunnel.xyz hello from localhost:47365
sdk
// bun add @opentunnel/client
import { create } from "@opentunnel/client"
const client = create()
const connection = await client.tunnel.connect({
routes: { opencode: "127.0.0.1:47365" },
})
console.log(`https://opencode.${connection.tunnel.hostname}`)
https://opencode.f7a2mx4kq9vn.opentunnel.xyzhow it works
your first route creates a tunnel: a random hostname, and aprivate key generated on your machine. the key never leaves it.
the cli sends a certificate request for that hostname. acertificate is issued and bound to your tunnel name. the relayonly ever sees the public half, and renews the certificate forthe same key before it expires.
a service on your machine keeps an encrypted bridge open tothe relay. apps using the sdk share the same tunnel, eachwith its own routes.
visitors hit your public url. the relay reads only the hostnamefrom the tls handshake and forwards the encrypted streamthrough the bridge.
your machine terminates tls with its private key and proxiesthe traffic to your local apps.
privacy
- the relay can't read your traffic
- connections are routed by the hostname in the tls handshake. thebytes stay encrypted until they reach your machine. the relay hasno key to decrypt them.
- your tunnel hostname is public
- anyone with your url can reach your services. when a tunnel iscreated, its certificate is published to certificate transparencylogs, so the hostname is discoverable by anyone watching them.
- route names are private, not secret
- the certificate is a wildcard, so route names never appear in anylog. they are still guessable, especially common names like api orpostgres, so don't treat them as authentication.
- put auth in the services themselves
- anything sensitive behind a tunnel should authenticate on its own.