tollan docs

Device groups (private networking)#

A device group lets your devices talk to each other by name — mymac22.tollan.myteam.internal — without anything being exposed to the internet. There's no public DNS record, no certificate, no public listener: an internal name is unreachable from outside the group by construction, not by obscurity.

Use it for the machine-to-machine half of a fleet: a sensor pushing to a collector, SSH between your own boxes, a dashboard reading a database on another site — all over the devices' existing tunnels.

How it works#

Every device already holds an authenticated tunnel to the relay. A group connection uses those tunnels end to end: the initiating agent asks the relay to connect it to an internal name, the relay checks that both devices are members of the route's group (and the same organization, and the route is enabled — anything else is refused), then splices the two tunnel legs together. The receiving device just sees an ordinary incoming channel to its local target.

  • Internal names never exist publicly. They're never written to DNS, never issued a certificate, and the public ingress won't route them — .internal is an ICANN-reserved TLD that cannot publicly resolve.
  • Plain TCP works. Unlike public hostname routes (which route on TLS SNI), the internal plane doesn't need the connection to be TLS — SSH, Postgres, HTTP, MQTT all work as-is.
  • The privacy note. Group traffic is mTLS-protected between each device and the relay, but the relay splices the stream, so for the strongest posture run TLS (or mTLS — your devices already have CA-issued certs) inside the group connection. Self-encrypting protocols like SSH give you this for free.

Set it up#

1. Create the group. Console → Fleet → GroupsNew group. Add the member devices. Membership is the authorization boundary — only members can reach (or be reached by) the group's routes.

2. Publish a service to the group. On the serving device's page, add a route with Exposure: internal (group) (the option appears once the device is in a group), pick the group, and set the internal target as usual — e.g. 127.0.0.1:22. The console shows the assigned internal name:

mymac22.tollan.myteam.internal

The name is {device-slug}{port}.tollan.{group-slug}.internal — one internal route per service, so a device can expose several ports to the group under distinct names.

**3. Enable peer sync on the devices that will initiate connections** (Go agent). Add to the device's agent.env:

PEERS_URL=https://app.<your-apex>/device/peers

(the same origin as TARGETS_URL). Optional: PEERS_REFRESH_INTERVAL (default 15m) and HOSTS_FILE (default /etc/hosts). The agent then maintains a managed hosts-file block mapping each peer name to a local loopback address and listens there, so the names resolve only on group members.

Two practical notes:

  • Writing /etc/hosts and binding a low port (like :22 for SSH parity) needs privileges — for a systemd unit, AmbientCapabilities=CAP_NET_BIND_SERVICE covers the port part.
  • Devices that only receive group connections need no changes at all — not even an agent update. Older agents and ESP32 boards can host group services as they are; initiating from an ESP32 uses the library's dialPeer(hostname) call.

4. Connect from any member device:

bash
ssh pi@mymac22.tollan.myteam.internal        # by name, as typed
curl http://collector80.tollan.myteam.internal/
psql "host=dbbox5432.tollan.myteam.internal port=5432 …"

Group SSH vs public SSH#

Both work — they solve different problems:

Public port routeInternal group route
Reachable fromanywhere on the internetmember devices only
Addressrelay-host:PORTname.tollan.group.internal
Exposurea real public listener (use keys!)none — nothing to scan
Client needsany SSH clientthe device's agent with peer sync

If only your own devices ever need to reach a box, an internal route is strictly the safer choice: there is no public artifact to protect.

Limits & notes#

  • Group traffic transits the relay (hub-and-spoke, not peer-to-peer) and shares the device's tunnel with its public traffic.
  • The receiving agent's target allowlist still applies — the relay can't steer a device to a target its operator didn't authorize, group or no group.
  • Initiating devices need an agent speaking tollan.v2; the console flags devices whose agent needs an update. Receivers work on any version.