Routes & exposure#
A route connects a public address to an internal target. Until a device has a route, its tunnel is up but nothing is exposed. Routes are created per device and take effect on the relay immediately — no restart.
Anatomy of a route#
- Exposure mode — how the public reaches it: hostname (SNI) or port.
- Public address — the hostname or port assigned (or chosen).
- Internal target — the
host:portthe agent bridges the connection to. - Enabled — a toggle to take the route on- or offline without deleting it.
Exposure modes#
Hostname (SNI)#
The route is published at a subdomain — by default your-slug.tollan.app — served on the relay's shared :443. The relay reads the SNI from the incoming TLS handshake and demuxes to the owning device. Because routing happens on the unencrypted SNI field, the relay never has to decrypt your traffic — this is passthrough, and it's what makes the tunnel zero-knowledge.
Use hostname mode for HTTPS and other TLS services. It scales to many devices on one IP and one port.
Port#
The route is published at a dedicated public TCP port on the relay, e.g. relay.tollan.ie:19000. The relay opens a listener per port-route and forwards everything on it to the device.
Use port mode for non-HTTP TCP protocols, or when the client can't send SNI. You can preview the next free port in the console before committing.
| Hostname (SNI) | Port | |
|---|---|---|
| Reached at | name.tollan.app | relay-host:PORT |
| Best for | HTTPS / TLS services | arbitrary TCP |
| Relay sees plaintext? | No (passthrough) | Only if you use terminate mode |
Uses shared :443 | Yes | No (own port) |
Internal targets#
The internal target is where the agent connects on your side:
127.0.0.1:8080— a service on the same host as the agent (handler/local).192.168.1.50:80— a different host on the LAN (forwarding mode).
The agent will only ever bridge to targets it's allowed to. That allowlist is the security boundary — see below.
Forwarding mode#
One agent can front many hosts on its network. In forwarding mode the agent dials the relay-named host:port and pipes bytes, so a single cheap box (or ESP32) becomes a proxy for a printer, NAS, camera, or PLC.
The device only dials targets on its allowlist. The relay can name a target in an OPEN frame, but if it isn't on the device's allowlist the channel is refused. This is defense in depth: even a compromised relay can't pivot your device to an arbitrary internal host.
Keep the device's allowlist in lockstep with its route internal-targets:
- Go agent — set
LOCAL_TARGETS(and optionally sync from the control plane viaTARGETS_URL). - ESP32 library — set
cfg.forwardTargets/cfg.defaultTarget.
Passthrough vs terminate#
- Passthrough (default for SNI routes) — the relay forwards the encrypted stream untouched. Your service terminates TLS. The relay is zero-knowledge.
- Terminate — the relay terminates TLS at the edge using a wildcard/custom-domain certificate, then forwards plaintext to the device. Required when you want the relay to enforce HTTP-layer access rules or use a custom domain with managed certificates.
Custom domains#
On paid plans you can attach your own domain to a route instead of a *.tollan.app subdomain. Add the domain in the console, point DNS at the relay, and Tollan obtains and renews a TLS certificate for it automatically (ACME). The relay then routes that hostname's SNI to your device.
How a route change reaches the relay#
You never touch relay config. When you create, edit, enable, or delete a route:
- The control plane persists the change and notifies the relay.
- The relay picks up the updated routing over its authenticated, private channel.
- The relay atomically swaps the table — existing tunnels stay up, and new routing takes effect at once.
That's why route edits feel instant and never drop unrelated traffic.
Next: put a gate in front of a route with Access control.