Skip to content

Architecture

mytunnel has two separate planes. Keeping them separate is the main reliability and security design choice.

Control-plane diagram

The client uses short SSH commands for lease operations:

Terminal window
ssh -T mytunnel-edge mytunneld ctl allocate --local-port 3000 --name portal
ssh -T mytunnel-edge mytunneld ctl list
ssh -T mytunnel-edge mytunneld ctl release --lease <lease_id>

The daemon returns JSON DTOs or JSON error envelopes. The client turns known error codes into actionable hints.

Important properties:

  • The edge derives owner identity from the remote SSH OS user.
  • --owner exists for client compatibility but is ignored by the server.
  • ls, heartbeat, release, and delete are owner-scoped.
  • --force slug takeover is restricted to root and users in MYTUNNEL_ADMIN_USERS.
  • Short control commands may use SSH ControlMaster multiplexing.
Data-plane diagram

The data plane is a long-running SSH reverse tunnel:

Terminal window
ssh -N \
-o ExitOnForwardFailure=yes \
-R 127.0.0.1:21000:127.0.0.1:3000 \
mytunnel-edge

The client intentionally disables ControlMaster reuse for this process. That keeps the tunnel from inheriting a short-lived control connection and exiting immediately after requesting the reverse forward.

Caddy routes public hostnames to the loopback edge port:

https://portal.tunnel.example.com -> Caddy -> 127.0.0.1:21000 -> ssh -R -> 127.0.0.1:3000
Lease lifecycle diagram

Lease states:

StateMeaningSlug reuse
activeRoute and edge bind port are live.Not reusable.
releasedRoute was removed by stop, rm, or client shutdown.Reusable immediately; stored slug/host are tombstoned.
expiredCleanup removed a lease after missed heartbeats.Reusable after cleanup tombstones slug/host.

Defaults:

SettingDefault
Lease TTL2m
Heartbeat intervallease TTL divided by 3, minimum 10s
Cleanup interval30s
Reconcile interval60s
Health timeout5s

The daemon cleanup loop scans active leases. If a lease is stale, it deletes the Caddy route first. Only after route deletion succeeds does it mark the lease expired.

That ordering prevents the daemon from freeing a port while Caddy might still route traffic to it.

The daemon reconcile loop compares active DB leases against Caddy managed routes. It detects:

  • Missing routes for active leases.
  • Stale managed routes without active leases.
  • Drifted routes where the host or upstream port does not match the DB lease.

Use dry-run first:

Terminal window
mytunneld ctl reconcile --dry-run --json

Then apply if the report shows drift:

Terminal window
mytunneld ctl reconcile --apply --json
Reconnect and release diagram

When the SSH tunnel drops, mytunnel http reconnects with jittered exponential backoff from 1s to 60s. Known SSH errors raise the minimum backoff:

Error shapeBackoff floor
connection refused5s
remote port forwarding failed10s

On SIGINT or SIGTERM, the client retries release for up to 90s. If release still fails, it prints a recovery command:

recovery: mytunnel rm <lease_id> --edge <edge>