# dosh - Dormant Shell dosh is a low-latency remote terminal designed around fast attach and fast reconnect. It is mosh-shaped, but not a mosh clone: the server is a resident daemon, terminal sessions stay hot, and repeat connects try encrypted UDP before starting SSH. The core target is simple: - First secure trust establishment uses SSH. - Existing sessions attach in one encrypted UDP exchange whenever cached credentials allow it. - Reconnect after sleep, roaming, or network change resumes in one encrypted UDP exchange. - Cold SSH fallback stays competitive with plain `ssh` by doing less after auth. ## Why not just mosh? mosh is excellent at roaming and high-latency interactivity. Its startup path still has work dosh can avoid: 1. SSH connects to the host. 2. SSH starts `mosh-server`. 3. The client receives connection material over SSH. 4. SSH exits and the mosh UDP session begins. dosh keeps `dosh-server` running before the client arrives. Named PTY sessions can also be prewarmed, so attaching to `default` does not need to spawn a daemon, create a PTY, or start a shell on the user's critical path. This is not an encryption argument against mosh. dosh also encrypts its UDP data channel; the speed difference comes from keeping the server and session hot. ## Fast Path Order The client always tries the cheapest valid path first: 1. **UDP resume:** existing `ClientId` and session key. No SSH. One encrypted UDP request, one encrypted UDP reply. 2. **UDP attach ticket:** cached server-issued attach ticket for the same host/user/session/mode. No SSH. One encrypted UDP request, one encrypted UDP reply. 3. **SSH bootstrap:** `ssh -T user@host dosh-auth ...`, then one encrypted UDP attach. 4. **New session:** same as attach, but the server must create the PTY/shell unless the session was prewarmed. The fastest path is not a custom SSH replacement. SSH remains the first trust root; dosh removes SSH from repeat attaches when the server has already issued valid credentials. Attach tickets are implemented because they are the way a fresh client process can skip SSH after a recent successful bootstrap. ## Connection Speed Contract dosh is measured by terminal-ready time: elapsed time from running `dosh host` to the first usable terminal screen. - UDP resume: <= one measured UDP RTT + local render time. - UDP attach ticket: <= one measured UDP RTT + local render time. - Warm attach with ControlMaster: <= `ssh host true` over the existing master + one measured UDP RTT. - Cold attach without ControlMaster: <= cold `ssh host` terminal-ready time + one measured UDP RTT. - New session: measured separately because it may need PTY and shell creation. The client emits timing spans for credential lookup, SSH bootstrap, UDP resume, UDP ticket attach, and terminal-ready time. ## Architecture ```text dosh-server UDP socket on one configurable port session table keyed by name one PTY per named session optional prewarmed sessions, default ["default"] terminal parser/screen state per session client table per session encrypted UDP protocol tiny SSH-invoked dosh-auth helper mode dosh-client terminal raw mode local credential cache UDP resume/attach first SSH bootstrap fallback PTY input/output forwarding reconnect and roaming state machine ``` ## Install Default UDP port: `50000`. This is intentionally inside the common forwarded range `50000-52000/udp`. Put this repo on your Gitea server, then install on each Linux server you want to attach to: ```bash curl -fsSL https://gitea.example.com/you/dosh/raw/branch/main/install.sh \ | DOSH_REPO=https://gitea.example.com/you/dosh.git DOSH_PORT=50000 sh -s -- server ``` Install the client on macOS: ```bash curl -fsSL https://gitea.example.com/you/dosh/raw/branch/main/install.sh \ | DOSH_REPO=https://gitea.example.com/you/dosh.git DOSH_SERVER=user@host DOSH_PORT=50000 sh -s -- client ``` Install the client on Windows PowerShell: ```powershell $env:DOSH_REPO="https://gitea.example.com/you/dosh.git"; $env:DOSH_SERVER="user@host"; $env:DOSH_PORT="50000"; irm https://gitea.example.com/you/dosh/raw/branch/main/install.ps1 | iex ``` Attach: ```bash dosh-client user@host ``` Use named sessions: ```bash dosh-client --session work user@host ``` Press `Ctrl-]` to detach the current client while leaving the server session alive. If SSH and UDP use different public names, specify the UDP address: ```bash dosh-client --dosh-host public.example.com --dosh-port 50000 user@host ``` ## Develop Build: ```bash cargo build ``` Attach locally, using local bootstrap instead of SSH: ```bash target/debug/dosh-client --local-auth --no-cache local ``` Benchmark local attach: ```bash target/debug/dosh-bench --local-auth --server local --iterations 5 ``` Benchmark a remote host over SSH bootstrap: ```bash target/release/dosh-bench --server user@host --ssh-port 22 --iterations 3 ``` Benchmark the ControlMaster-backed SSH bootstrap path: ```bash target/release/dosh-bench --server user@host --controlmaster --iterations 3 ``` Run the Docker OpenSSH benchmark gate used by CI. It checks both cold SSH bootstrap and ControlMaster-backed SSH bootstrap against a containerized `sshd` plus resident `dosh-server`: ```bash make bench-docker-ssh ``` The CI workflow includes an optional remote benchmark job. It runs when `DOSH_BENCH_HOST`, `DOSH_BENCH_USER`, and `DOSH_BENCH_SSH_KEY` repository secrets are configured. Install release binaries and the user systemd service: ```bash make install ``` ## Performance Rules The stack is performance-driven, not fixed by taste. Rust is the default because the likely bottlenecks are network RTT, SSH startup/auth, PTY/shell creation, packet size, and terminal rendering. Change language or runtime only if measurements show they are the bottleneck. Hot-path rules: - Custom UDP protocol with AEAD for v0; no QUIC handshake on attach. - Fixed binary packet headers for terminal traffic; no JSON on the protocol path. - Preallocated buffers; avoid per-packet heap churn. - Single-thread event loop is preferred for the hot path. - No PTY allocation, shell spawn, shell rc files, or MOTD on attach to an existing session. - Initial snapshot should be sent in the first UDP reply when it fits under the packet budget. ## Goals - Connection speed as specified above. - UDP roaming and reconnect. - Encrypted terminal data. - Reuse SSH pubkeys for first trust establishment. - Named persistent sessions. - Multiple clients attached to one session. - Optional view-only clients. - Single server port, not one port per session. - Static server and client binaries where practical. ## Non-Goals - Replacing SSH as the first public-key trust mechanism. - Multi-user access control. - Windows support in v0. - Full mosh compatibility. - Perfect predictive local echo in the first MVP. ## Status Rust implementation is present in this repository. It contains `dosh-server`, `dosh-client`, `dosh-auth`, `dosh-bench`, shared auth/crypto/protocol modules, a resident PTY server, encrypted UDP bootstrap attach, UDP resume, sealed UDP attach tickets, client ACKs, server retransmit bookkeeping, sliding replay protection, server-side `vt100` screen snapshots/diffs, a hardened user systemd unit, an install script, Docker SSH benchmark gates, CI, and protocol/integration tests.