Architecture
mytunnel has two separate planes.
Keeping them separate is the main reliability and security design choice.
Control plane
Section titled “Control plane”The client uses short SSH commands for lease operations:
ssh -T mytunnel-edge mytunneld ctl allocate --local-port 3000 --name portalssh -T mytunnel-edge mytunneld ctl listssh -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.
--ownerexists for client compatibility but is ignored by the server.ls,heartbeat,release, anddeleteare owner-scoped.--forceslug takeover is restricted torootand users inMYTUNNEL_ADMIN_USERS.- Short control commands may use SSH ControlMaster multiplexing.
Data plane
Section titled “Data plane”The data plane is a long-running SSH reverse tunnel:
ssh -N \ -o ExitOnForwardFailure=yes \ -R 127.0.0.1:21000:127.0.0.1:3000 \ mytunnel-edgeThe 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:3000Lease lifecycle
Section titled “Lease lifecycle”Lease states:
| State | Meaning | Slug reuse |
|---|---|---|
active | Route and edge bind port are live. | Not reusable. |
released | Route was removed by stop, rm, or client shutdown. | Reusable immediately; stored slug/host are tombstoned. |
expired | Cleanup removed a lease after missed heartbeats. | Reusable after cleanup tombstones slug/host. |
Defaults:
| Setting | Default |
|---|---|
| Lease TTL | 2m |
| Heartbeat interval | lease TTL divided by 3, minimum 10s |
| Cleanup interval | 30s |
| Reconcile interval | 60s |
| Health timeout | 5s |
Cleanup loop
Section titled “Cleanup loop”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.
Reconcile loop
Section titled “Reconcile loop”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:
mytunneld ctl reconcile --dry-run --jsonThen apply if the report shows drift:
mytunneld ctl reconcile --apply --jsonReconnect and release behavior
Section titled “Reconnect and release behavior”When the SSH tunnel drops, mytunnel http reconnects with jittered exponential backoff from 1s to 60s.
Known SSH errors raise the minimum backoff:
| Error shape | Backoff floor |
|---|---|
connection refused | 5s |
remote port forwarding failed | 10s |
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>