A strict, cross-platform SSH server written in Rust.
esesätsch is a drop-in alternative to sshd for small-to-medium deployments where you want a tight modern crypto policy, central key/cert management, and an auditable codebase you can read end-to-end in an afternoon.
# Generate a host key, copy an example config, run.
cargo run --release -- gen-key --host-key ./host_key
cp examples/minimal.toml ./config.toml
cargo run --release -- serve --config ./config.toml --port 2222
# Then from another terminal:
ssh -p 2222 alice@127.0.0.1- Modern crypto only. No CBC ciphers, no SHA-1 MACs, no legacy DH. The wire policy is compiled into the binary — there is no runtime knob to weaken it. Includes ML-KEM/X25519 post-quantum hybrid KEX (the same one OpenSSH 9.9+ negotiates by default) so today's traffic isn't decryptable by tomorrow's quantum-capable attacker.
- Three auth methods, each independently toggleable:
- Public key against a central TOML allowlist
- OpenSSH certificate against a CA trust set with full validation (signature, validity window, principals, revocation list, fail-closed unknown critical options)
- OS-native password via PAM on Linux/macOS,
LogonUserWon Windows
- Real PTY support so vim / htop / tmux work over an interactive session (uses
portable-pty, which means Unix PTY on Linux/macOS and ConPTY on Windows). - Information-disclosure hygiene built into every auth path: uniform reject shape, constant-time pubkey/CA compares, sentinel-work on the unknown-user path so timing or branch analysis can't enumerate accounts. Per-call-site filtering plus a stderr-wrapping redaction layer keep
password=…fields and raw key bytes out of logs even at trace level. - Service installation built in:
esesätsch install-servicewrites a systemd unit / launchd plist (or prints the Windowssc.execommand) so the host OS supervises the binary. - Cross-platform. CI builds + tests on Linux x86_64, Linux ARM64, macOS aarch64, Windows x86_64, and Windows ARM64.
- Strict CI:
fmt,clippy::all + pedantic + nurserywith-D warnings, tests on three OSes, release builds for five targets, 100% line coverage gate on the core library. Conventional Commits enforced on every PR. - Fully automated releases. release-please opens a release PR on every
feat:/fix:push tomain, runs the full CI matrix against it, and on merge publishes a tagged GitHub Release with pre-built binaries for all 5 targets.
Pre-1.0 — the wire protocol is implemented and tested against the real russh client, but the package isn't on crates.io yet and the API surface may still shift between 0.x minor releases. See the CHANGELOG for what landed in each version.
Grab the archive for your platform from the latest release. Asset filenames follow the pattern esesätsch-<version>-<target>.<ext>:
| Platform | Asset |
|---|---|
| Linux x86_64 | esesätsch-<version>-x86_64-unknown-linux-gnu.tar.gz |
| Linux ARM64 | esesätsch-<version>-aarch64-unknown-linux-gnu.tar.gz |
| macOS Apple Silicon | esesätsch-<version>-aarch64-apple-darwin.tar.gz |
| Windows x86_64 | esesätsch-<version>-x86_64-pc-windows-msvc.zip |
| Windows ARM64 | esesätsch-<version>-aarch64-pc-windows-msvc.zip |
Each archive contains the esesätsch binary plus LICENSE, NOTICE, and README.md.
Prefer a native package? Each release also ships .deb, .rpm, Arch
.pkg.tar.zst, a macOS .pkg, and a Windows .msi for amd64 and arm64.
See packaging/README.md.
# Linux / macOS
tar -xzf esesätsch-v0.1.0-aarch64-apple-darwin.tar.gz
sudo install -m 0755 esesätsch-v0.1.0-aarch64-apple-darwin/esesätsch /usr/local/bin/
# Windows (PowerShell)
Expand-Archive esesätsch-v0.1.0-x86_64-pc-windows-msvc.zip
# Move esesätsch.exe somewhere on %PATH%# One-time: generate the server's host key
esesätsch gen-key --host-key ./host_key
# Copy a starting-point config and add your SSH public key under
# [auth.authorized_keys]
curl -O https://raw.githubusercontent.com/BentBr/esesaetsch/main/examples/minimal.toml
mv minimal.toml config.toml
$EDITOR config.toml
# Start the server
esesätsch serve --config ./config.tomlssh -p 2222 <your-username>@<host>See docs/user-guide/configuration.md for every config field and docs/user-guide/cli-reference.md for every CLI flag.
Want to build from a checkout instead of using a release binary? See docs/development.md — it covers Rust nightly, the libclang setup for PAM, the strict clippy/test/fmt commands, and the release workflow.
| Page | Contents |
|---|---|
| User guide — Configuration | Every TOML field with defaults, allowed values, and security notes |
| User guide — CLI reference | Every subcommand and flag with runnable examples |
| Development guide | Build/test/release workflow, project layout, libclang setup per OS |
packaging/README.md |
Native install packages, what they install, local builds |
examples/README.md |
Ready-to-edit example configs (minimal, pubkey-only, password, cert, full reference) |
docs/index.md |
Documentation hub |
russh0.60+ — pure-Rust SSH protocol, ML-KEM PQ KEX, nativeimpl Futuretraitsportable-pty— cross-platform PTY/ConPTYnonstick(Unix) — safe PAM bindings vialibpam-syswindows(Windows) —LogonUserW/CreateProcessAsUserWtokio— async runtimetracing— structured logging with stderr redactionssh-key— host-key generation + OpenSSH cert parsingclap— CLI
crates/
├── esesätsch-core/ # library: protocol, auth, session, config (OS-agnostic, 100% coverage target)
└── esesätsch/ # binary: CLI + OS-specific impls (PAM, LogonUserW, portable-pty, service installer)
examples/ # runnable example configs
docs/ # user / development guides
.github/workflows/ # ci.yml + release-please.yml + release-assets.yml
PRs welcome. CI requires:
- Conventional Commits:
feat:,fix:,chore:,docs:, etc. - Branch name:
<type>/<lowercase-kebab>, e.g.feat/cert-auth-wiring. - Strict clippy:
cargo +nightly clippy --workspace --all-targets -- -D clippy::all -D warnings -D clippy::pedantic -D clippy::nursery. - fmt:
cargo fmt --all -- --check. - All tests pass on Linux x86_64, macOS aarch64, Windows x86_64.
See docs/development.md for the full developer workflow.
Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
Copyright © 2026 Bent Brüggemann.
