Files
alknet/docs/architecture/overview.md
glm-5.1 13b0991fb8 Resolve all architecture open questions, add 13 ADRs, update specs
Resolved all 11 open questions based on project guidance:

Transport:
- OQ-01/OQ-07: ACME/Let's Encrypt with domain + IP paths (ADR-008)
- OQ-02: Default to n0 relay, --iroh-relay override (ADR-009)
- OQ-05: Transport chaining supported natively (ADR-010)

Client:
- OQ-06: Programmatic-first API, no ~/.ssh/config (ADR-011)

Server:
- OQ-04: Ed25519 + OpenSSH cert-authority, no password auth (ADR-012)
- OQ-08: fail2ban-friendly logging + built-in rate limiting (ADR-013)

TUN:
- OQ-03/OQ-09: Deferred entirely, recommend tun2proxy (ADR-014)
- tun-shim.md marked deprecated

NAPI:
- OQ-10: Expose both connect() and serve() (ADR-016)
- OQ-11: Use napi-rs for FFI bridge (ADR-015)

Additional ADRs created during review:
- ADR-006: No logging of tunnel destinations (was phantom reference)
- ADR-017: Stealth mode protocol multiplexing
- ADR-018: Control channel for pubsub over SSH

Fixed: ADR-002 status → Superseded, ADR-007 title typo,
WRAUTH_SERVER typo, ADR-005 stale wraith-tun refs,
undefined ACL feature removed from server.md,
--proxy semantic difference documented.
2026-06-01 17:31:28 +00:00

6.8 KiB

status, last_updated
status last_updated
draft 2026-06-01

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)

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

Open Questions

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

References