Skip to content

Hive Tunnel

Hive Tunnel lets clients reach a node without Tailscale, a VPN, or port forwarding. It is a premium feature: using it requires an active Hive license (see Accounts & Licensing).

  • Native apps (desktop and mobile) connect directly, peer to peer, using iroh with QUIC hole-punching. Traffic is end-to-end encrypted; relay servers only help set the connection up.
  • The web app (the PWA at hive.vazac.dev/app) cannot hole-punch from a browser, so it falls back to a cloud relay operated by Hive.

The tunnel adds reachability, not access. Every connection through it still authenticates with the node's normal Hive auth token, exactly like a direct connection. A node with the tunnel enabled but an unknown token is still closed to you.

Enabling it

The tunnel is off by default and enabled for the whole cluster at once, not node by node. It is license-gated.

  1. Open Settings > Cluster > Cluster Configuration. The Hive Tunnel row has a single Enable for cluster button. Without an active license the button is disabled and shows a requires an active license hint.
  2. Click Enable for cluster and confirm in the dialog.

Confirming enables the tunnel everywhere in one step:

  • The node you are connected to applies and persists the tunnel config, auto-generating its per-node secret key if it does not have one.
  • It fans the change out to every connected peer, which each apply and persist it too.
  • Every node then self-restarts so its iroh endpoint binds. Active terminal sessions keep running across the restart; clients briefly reconnect.

There is no config.toml to edit, no port to open, and no relay URL to enter - the default relay is baked in. (An operator can still override the relay with [tunnel] relay_url in config.toml; see Configuration.)

Offline nodes converge automatically

A node that is offline when you toggle the tunnel is not left behind. Cluster config sync carries the tunnel flag with a last-writer-wins timestamp, so the moment such a node reconnects it applies the change and restarts itself. Nodes adopted into the cluster later converge the same way.

Disabling it

Once the tunnel is on, the same button reads Disable for cluster. Disabling follows the same path: the change is persisted, fanned out to peers, and every node restarts.

One thing to know before you disable: if a peer is currently reached over the tunnel, dropping the tunnel drops the link you reach it through. When that is the case, the confirm dialog warns you and names the nodes that may become unreachable until the tunnel is switched back on.

A node that is both offline and reachable only over the tunnel cannot be told to disable - it never receives the change. It stays enabled until it gains some other link (a direct, LAN, or Tailscale route) over which the disable can reach it.

Status

The Cluster Configuration card's Hive Tunnel row shows the state as a badge:

  • disabled - the tunnel is off for this node.
  • enabled (restart pending) - the config is saved but the daemon has not yet finished restarting, so the endpoint is not bound.
  • active - the endpoint is bound and reachable.

When active, the row also shows the node's tunnel endpoint id - a 64-character hex public key - with a copy button. Nodes advertise this id to clients and peers automatically through cluster status, so there is nothing to configure on the client side.

Peer address pills - in the Cluster Configuration card and in the Cluster view - include a tunnel pill when a node has a tunnel address. The highlighted pill is the route actually in use, so you can tell at a glance whether a peer is reached over the tunnel or a direct address.

When the app's own connection to its node runs over the tunnel, the nav sidebar header shows a tunnel suffix.

How connections are chosen

Clients always prefer a direct path. When the app connects to a node it races every known address:

  • Direct addresses win. LAN, Tailscale, and other directly reachable addresses are dialed immediately and always win the race when they answer.
  • The tunnel is the fallback. The tunnel address joins the same race with a 500 ms penalty, so it takes over only when no direct address answers.

When the tunnel wins, the connection's address shows as iroh:<endpoint-id> in the app instead of a host and port.

Saved routes on every app

When a saved connection profile contains tunnel endpoint ids, desktop, mobile, and web always offer those routes during normal profile connections and reconnects. Route discovery does not wait for the client's locally cached account or license state, and it does not drop a saved tunnel route when that state is temporarily unavailable or out of date. This keeps auto-connect from stranding a mobile client that has no working direct route.

During a pinned-profile reconnect in the native desktop or mobile app, the pinned node's direct and tunnel routes get an 8-second head start. If none of them connects, routes for the profile's other cluster nodes join the same connection race. The reconnect remains one attempt from dialing through session loading, so a late route cannot replace and tear down a workspace that has already loaded.

The route uses the transport available on the current app:

  • Desktop and mobile hand the saved endpoint to the native shell, which connects over iroh P2P.
  • Web turns the same saved endpoint into an authenticated request to the Hive cloud relay. The relay checks the signed-in account and active license when the connection opens.

Offering a route is not an authorization decision. Native tunnel access remains license-gated, and an unlicensed or signed-out browser relay request is refused by the relay rather than hidden by transient client-side state.

The tunnel also carries the cluster mesh itself: when both nodes have the tunnel available, their peer link runs over it. The tunnel is the preferred node-to-node route - it works from anywhere and survives IP changes - so a laptop with its VPN off, or a node behind a NAT with no Tailscale, stays a full cluster member.

How it works:

  • When two nodes connect, each learns the other's tunnel endpoint id. If the link came up over a direct address first (direct TCP wins the initial race), the mesh dials the tunnel shortly after and upgrades the link to it; the direct route becomes the standing fallback.
  • If the tunnel link dies (relay outage, endpoint restart), the mesh fails over to a direct address within seconds and keeps retrying the tunnel in the background, upgrading back once it answers.
  • The tunnel address is persisted and gossiped with the node's other addresses, so peers can still dial a tunnel-only node after a daemon restart.
  • Tunnel links are still peer-to-peer where possible: iroh hole-punches a direct QUIC path (including on the same LAN) and uses the relay only when hole-punching fails.
  • Peer links over the tunnel authenticate with the normal cluster token, exactly like direct peer connections.

Only the node being dialed needs the tunnel enabled - any node in the cluster can dial out to it, even nodes with their own tunnel switched off. In practice: enable the tunnel on the machines that leave your network (laptops, phones' home nodes), and the rest of the cluster keeps them in the mesh.

A node linked over the tunnel shows the Hive Tunnel pill as its active address in cluster status, with its peer address as tunnel:<endpoint-id>.

The web relay

Browsers cannot do QUIC hole-punching, so the web client uses a cloud relay instead of direct P2P. It connects over WebSocket to wss://hive.vazac.dev/relay/connect?node=<endpoint-id>, authenticated by your signed-in session cookie (same origin as the web app).

The relay requires and enforces:

  • A signed-in account with an active license. Without both, relay connections are refused.
  • At most 8 concurrent relay connections per account.
  • A 120-second idle timeout - idle relay connections are closed and the app reconnects on demand.

The relay is a blind pipe: it forwards bytes between your browser and the node and cannot read or forge Hive traffic. Hive protocol authentication (the node token sent as the first message) still happens end to end between the browser and the node.

Reliability

The tunnel recovers from transient failures on its own:

  • Endpoint bind retries with backoff. If a node cannot bind its iroh endpoint at startup - for example the network is not up yet - it keeps retrying with backoff, so a boot-time network hiccup heals itself without intervention.
  • Dials retry with backoff. A failed tunnel dial is retried on a backoff capped at 5 minutes, so a relay outage recovers automatically once the relay is back; you do not need to restart anything.
  • One relay per cluster. All nodes in a cluster are expected to use the same relay. A custom relay hint learned from a peer is not persisted across a daemon restart, so if you run your own relay, set [tunnel] relay_url in config.toml on every node rather than relying on it propagating.

Configuration

The daemon side lives in config.toml under a [tunnel] section (see the Configuration reference):

toml
[tunnel]
# Off by default. Enabled cluster-wide from Settings > Cluster; the daemon
# self-restarts to apply. You do not normally set this by hand.
enabled = true

# Auto-generated when the tunnel is first enabled: the node's iroh secret key
# (base64, ed25519). Its public half is the node's tunnel endpoint id shown in
# the app. Do not set manually and do not share it.
# secret_key = "..."

# Optional override for the iroh relay used for connection setup and fallback.
# Defaults to the Hive-hosted relay.
# relay_url = "https://relay.vazac.dev:8443"
FieldTypeDefaultDescription
enabledboolfalseTurns the tunnel listener on for this node
secret_keyOption<String>auto-generatedBase64 ed25519 secret key; the public half is the node's tunnel endpoint id
relay_urlOption<String>https://relay.vazac.dev:8443Custom iroh relay URL for connection setup and fallback

You normally never edit this by hand - the Enable for cluster button in Settings > Cluster writes it for every node.

Security model

  • Unguessable endpoint. The tunnel endpoint id is an ed25519 public key (64 hex chars). Knowing it is required to even attempt a connection, and it cannot be enumerated.
  • End-to-end encryption. iroh provides a TLS 1.3 encrypted, key-authenticated transport between the client and the node. The relay servers used for connection setup (and as the fallback path) cannot read or tamper with the traffic.
  • Token auth unchanged. The tunnel only makes the node reachable. The client must still present the node's Hive auth token, which the node verifies itself - the relay cannot bypass or forge that check.

Troubleshooting

State stuck on enabled (restart pending). Enabling the tunnel makes each node restart itself, so this state is normally brief and clears on its own once the daemon comes back and binds its endpoint. If it persists, the daemon did not finish restarting - check that hived is running on that node and restart it if needed; the state then becomes active and the endpoint id appears.

Node unreachable through the tunnel. The tunnel does not keep an offline node reachable - if the node or its daemon is down, the tunnel is down with it. Check that the node is running and that [tunnel] enabled = true is active (state active, not restart pending).

Node shows offline in the cluster when only the tunnel is available. The node being dialed must have the tunnel active (not restart pending) - peer links run over the tunnel only toward nodes whose endpoint is bound. Confirm the tunnel is enabled cluster-wide, then let that node connect directly once (so peers learn its tunnel endpoint), after which the mesh reaches it through the tunnel from anywhere.

Web app: relay connection refused. The relay requires being signed in to your Hive account with an active license. Sign in at the web app and check your license state under Settings > Account (see Accounts & Licensing). Free or expired accounts cannot use the relay.

Web app: connections dropping or refusing to open. You may be at the 8 concurrent relay connections per-account cap - close unused tabs or devices. Idle relay connections are also closed after 120 seconds; the app reconnects automatically when you return.

Native app connects, but slowly or via iroh:. The tunnel won the race because no direct address answered. If you expect a direct path (same LAN, Tailscale up), fix that path - direct addresses always win when reachable, and the tunnel is only the fallback.

Hive - remote AI coding agents over WebSocket.