Files
wraith/docs/architecture/overview.md
glm-5.1 af8e7e8b44 Review architecture specs, address critical/warning issues, mark reviewed
Address 5 critical and 7 warning issues from architecture review:
- Fix duplicate sentence in napi-and-pubsub.md server side section
- Add wraith- namespace reservation to server.md constraints (ADR-018)
- Document stealth mode TLS-only requirement in server.md
- Create ADR-019 for --proxy dual semantics (client vs server)
- Clarify NAPI connect() vs CLI wraith connect distinction
- Add SOCKS5h default as privacy design decision in client.md
- Expand reconnection section (always-on, re-register port forwards)
- Add graceful shutdown sections to client.md and server.md
- Specify OpenSSH key format for path-or-buffer inputs across all docs
- Resolve pubsub alternative approach ambiguity (ADR-018 is primary)
- Replace server.md handler impl block with behavioral description
- Standardize iroh endpoint ID terminology (base58-encoded)
- Remove iroh API implementation details from transport.md/server.md
- Add error handling pattern as cross-cutting concern in overview.md
- Update all document statuses from draft to reviewed
2026-06-02 07:44:42 +00:00

7.4 KiB

status, last_updated
status last_updated
reviewed 2026-06-02

Wraith Overview

Purpose

Wraith is a self-hostable SSH-based tunnel tool that provides VPN-like functionality without being a VPN protocol. It enables:

  • Private tunneling of services (Postgres, Redis, internal APIs) over SSH
  • Censorship circumvention — SSH over TLS on port 443 looks like HTTPS to DPI
  • NAT traversal — iroh transport allows peer-to-peer connections without public IPs or port forwarding
  • Service mesh connectivity — a lightweight transport layer for the pubsub/operations event system

The core insight: SSH tunnels work because SSH is fundamental infrastructure. Blocking it breaks the internet. Wraith makes SSH tunneling accessible through a simple CLI with pluggable transports.

Exports

Binary: wraith

A single binary with subcommands:

wraith serve     — Start the server (accepts SSH connections)
wraith connect  — Start the client (opens SSH session, exposes SOCKS5/port-forwards)

Library: wraith-core

The wraith-core crate exports the pluggable components for embedding or programmatic use:

  • Transport trait — produces a duplex stream for SSH to run over
  • TcpTransport — direct TCP connection
  • TlsTransport — TCP + tokio-rustls TLS
  • IrohTransport — iroh QUIC P2P connection
  • Socks5Server — local SOCKS5 proxy that forwards through SSH channels
  • PortForwarder — manages local/remote port forwards
  • ServerHandler — russh server handler with configurable auth and channel policies
  • ConnectOptions / ServeOptions — programmatic configuration structs (no file parsing)

Dependencies

Dependency Purpose Feature-gated
russh SSH client & server No (core)
tokio Async runtime No (core)
tokio-rustls TLS wrapping Yes (tls)
rustls TLS implementation Yes (tls)
rustls-acme ACME/Let's Encrypt auto-cert Yes (acme)
iroh P2P QUIC transport Yes (iroh)
clap CLI argument parsing No (core)
tracing Structured logging No (core)
anyhow / thiserror Error handling No (core)

Note: tun-rs is no longer a dependency. TUN support is deferred in favor of the external tun2proxy tool (ADR-014).

Architecture Constraints

  1. SSH runs over transport, not alongside — The transport layer produces a single AsyncRead+AsyncWrite+Unpin+Send stream. SSH runs over that stream via russh::client::connect_stream() / russh::server::run_stream(). The SSH layer never knows what transport it's on. (ADR-001, ADR-004)

  2. SOCKS5 is the primary client interface — Port forwarding is built on top of SOCKS5-like channel management. For VPN-like "route all traffic" behavior, users run tun2proxy alongside wraith's SOCKS5 proxy. TUN is not in the project scope. (ADR-005, ADR-014)

  3. No logging of tunnel destinations — The server logs auth attempts and connections (for fail2ban) but does not log channel_open_direct_tcpip destinations, DNS lookups, or bytes transferred. (ADR-006, ADR-013)

  4. Programmatic-first API — Configuration via CLI flags, library API structs (ConnectOptions, ServeOptions), and environment variables. No ~/.ssh/config parsing, no custom config files. (ADR-011)

  5. Feature flags control transport inclusiontls, iroh, acme are feature-gated so the base install is lean. Users opt in to heavier dependencies.

  6. Authentication is key-based — Ed25519 public key (default) and OpenSSH certificate authority. No password authentication over SSH. (ADR-012)

  7. NAPI exposes both connect() and serve() — The napi-rs wrapper provides client and server functionality, using napi-rs as the FFI bridge. The NAPI layer is transport-agnostic and not tied to pubsub. (ADR-015, ADR-016)

  8. Error handling follows a consistent layered pattern — Transport and auth errors cause reconnection (client, with exponential backoff) or connection rejection (server). Channel-level errors (target unreachable, proxy failure) close the individual channel without killing the session. Library API errors propagate via anyhow::Result / thiserror types. CLI reports errors to stderr with appropriate exit codes. NAPI errors are marshalled as JavaScript exceptions.

Design Decisions

ADR Decision Summary
001 Pluggable transport Transport trait produces AsyncRead+AsyncWrite+Unpin+Send, SSH consumes it
002 TUN shim separate Superseded — TUN is deferred, use tun2proxy (ADR-014)
003 iroh stream join tokio::io::join(recv, send) combines QUIC halves
004 SSH over transport SSH never accesses TCP/iroh/TLS directly
005 SOCKS5 first SOCKS5 is the primary interface; TUN is external (tun2proxy)
006 No logging of tunnel destinations Server logs auth and connections, not destinations
007 NAPI single stream NAPI exposes duplex streams, not SSH multiplexing
008 ACME/Let's Encrypt Auto-provision TLS certs, domain and IP paths
009 Default iroh relay n0 relay by default, --iroh-relay override
010 Transport chaining --proxy works with all transports natively
011 Programmatic-first No file-based config; options are structs, env vars, CLI flags
012 Key + cert-authority Ed25519 keys + OpenSSH CA; no password auth
013 Fail2ban-friendly Structured auth logs + built-in rate limiting
014 Defer TUN Use tun2proxy for VPN-like behavior; no wraith-tun binary
015 napi-rs Standard Node.js native addon tooling
016 connect + serve NAPI exposes both client and server from the start
017 Stealth mode Protocol multiplexing on port 443
018 Control channel Reserved wraith-control destination for pubsub
019 Proxy dual semantics --proxy routes transport on client, data on server

Open Questions

All open questions have been resolved. See open-questions.md for resolution details.

References