The relay can route your data.
It can never read it.
Cloud Relay is how SQLly reaches a database that lives behind your firewall - no VPN, no jump box, no inbound port. This page explains exactly how it works and exactly what the security design guarantees, in the same detail we hold ourselves to in the code.
β in progress The transport described here is built and under test. It ships with SQLly Cloud, which is not available yet.
Three parties, one tunnel, zero trust required
Your app and your bridge both dial out to a relay. The relay introduces them, then forwards encrypted bytes it cannot open. That’s the whole trick.
SQLly app
The desktop app you already run. Holds one end of the encrypted tunnel.
outbound only
Relay
A dumb, fast forwarder. Routes opaque encrypted frames between your paired devices - and nothing else.
outbound only
Bridge
A small service you install on any machine that can see your database. Holds the other end of the tunnel.
network
Your database
Never exposed to the internet. The bridge talks to it exactly like a local SQLly install would.
Because the bridge dials out, you never open an inbound firewall port, never set up a VPN, and never put your database on the public internet. One naming note: the pricing page calls the bridge the onsite connector - same thing.
How a connection actually happens
No hand-waving. This is the real sequence, straight from the protocol spec.
-
1
You pair your devices - once, explicitly
From the app, you authorize a pair: this device may talk to that bridge. Pairs are tied to your account, listed on your Relays page, and revocable there with one click. No pair, no traffic - the relay refuses to forward so much as a handshake between unpaired devices.
-
2
Both sides dial out and authenticate
The app and the bridge each open an outbound TLS connection to a relay and present a short-lived, device-bound token. From that moment the relay pins the connection to that device identity - every frame the device sends must carry it, or the frame is dropped. Nobody gets to claim to be a device they didn’t authenticate as.
-
3
The two endpoints run a key exchange the relay can’t join
App and bridge perform a mutual-authentication Noise handshake through the relay (pattern
Noise_XX: X25519 key agreement, ChaCha20-Poly1305 encryption, BLAKE2s hashing). The relay forwards the handshake messages but is never a party to them - the session keys exist only on your two devices. -
4
Each side checks the other’s identity against your account
Every device has a long-lived identity key that lives in its OS keychain and never leaves it. After the handshake, each endpoint compares the key the peer just proved it holds against the public key registered to your account. Any mismatch aborts the session before a single byte of data moves - so even a fully compromised relay can’t slip itself into the middle.
-
5
Encrypted traffic flows; the relay just forwards
Your queries and results travel as encrypted chunks. The relay reads only a small routing header - which device, to which device, chunk number - and copies the sealed payload byte-for-byte. It never decrypts, never reassembles a message, and never logs a body.
What our servers can see - and what they never can
“Zero-knowledge” is a strong claim, so here is its exact shape. The relay and the SQLly API are designed to work even if you assume they’re compromised and curious.
π What the relay can see
Routing metadata - the minimum needed to forward frames.
- β’Which of your devices are talking, and whensource and destination device ids, connection timing
- β’The size and count of encrypted chunksciphertext lengths - never contents
- β’Your authorized device pairsids only - that a pair exists, not what flows through it
- β’Devices’ public identity keyspublic halves only, used for pinning
π« What it can never see
Everything inside the tunnel. There are no keys to it on our side.
- βYour SQL - not one query, ever
- βYour results - not a row, not a cell
- βYour database credentialsthey exist only on the bridge machine, in its local config or OS keychain
- βPrivate keys or session keysidentity keys never leave a device’s keychain; session keys are negotiated endpoint-to-endpoint
Designed against a hostile relay, not just a broken one
The threat model assumes the worst. Here’s what each defense actually stops.
A relay can’t man-in-the-middle
A compromised relay could try substituting its own key during the handshake. It fails: each endpoint pins the peer’s registered public key and verifies the handshake against it. Mismatch means abort - before any data frame is exchanged.
A relay can’t rewrite headers unnoticed
The routing header is necessarily readable by the relay - so every encrypted chunk carries an authenticated copy of that header inside the ciphertext. The receiving end compares them field by field; any divergence and the chunk is rejected. The relay can drop traffic, but it can’t silently misroute or reorder it.
A device can’t impersonate another
The relay binds each connection to the device identity proven at authentication and rejects any frame claiming a different sender. Self-declared identity is never trusted - only the authenticated connection’s.
No pair, not even a knock
Authorization is checked for the handshake itself, not just for data - an authenticated-but-unpaired device can’t even spam your bridge with connection attempts. Grants come only from pairs you created, and revoking one removes the route promptly.
Captured traffic can’t be replayed
Within a session, the cipher’s advancing nonce state rejects replayed messages. Across sessions, every connection negotiates fresh keys - a recorded frame from yesterday simply doesn’t decrypt today.
Tokens can’t change hats
User sign-in tokens, device relay tokens, and relay-server credentials are three separate audiences with separate signing keys. A relay token can’t act as you, your app token can’t drive relay infrastructure, and the validators reject any crossover in both directions.
Floods hit hard limits, not your memory
Every buffer in the path is bounded: per-connection rate limits, byte budgets for slow consumers, capacity caps that mark a relay full, and reassembly limits on the endpoints. A misbehaving peer gets disconnected; it doesn’t take the service - or your laptop - down with it.
Logs can’t leak what they never contain
Relay and bridge logging never includes message bodies, keys, or tokens - by construction, enforced in code review and tests. Diagnostics get ids, sizes, and error codes. That’s enough to debug routing, and nothing more.
The honest fine print
Every security page should have this section. Almost none do.
Traffic patterns are visible
The relay necessarily knows which of your devices talked, when, how often, and how many encrypted bytes moved. That metadata is inherent to routing and is not hidden. What’s inside the frames is protected; the fact that frames flowed is not.
A hostile relay can drop your connection
A compromised relay can’t read or tamper undetected - but it can refuse to forward. That’s a denial of service, and the design accepts it: confidentiality and integrity are guaranteed, uptime against a hostile forwarder is not.
Your devices are the perimeter
If the machine running the app or the bridge is itself compromised, its plaintext and local credentials are exposed - no transport can prevent that. The tunnel protects data in motion, not a stolen laptop.
One session per bridge, for now
Today a bridge serves one live session at a time; a second device connecting while one is active will fail until the first disconnects. Multi-session support is on the roadmap - and this paragraph will change when it lands.
Your database, reachable. Your data, unreadable.
Cloud Relay ships with SQLly Cloud. Create a free account and we’ll tell you the moment it’s ready.