Announcing ssh-obi — keeping SSH shells alive across disconnects, sleeps, and network roams
A lightweight, per-user persistence layer for interactive SSH sessions: no system service, no custom port, no in-band escape commands — and unlike mosh, your local terminal's scrollback keeps working.
A lightweight, per-user persistence layer for interactive SSH sessions: no system service, no custom port, no in-band escape commands — and unlike mosh, your local terminal's scrollback keeps working.
Published by the Human-life Information Platforms Institute (Menhera.org)
May 2026
TL;DR
We have released ssh-obi v0.1.0, a small Rust tool that keeps your remote shell alive when the SSH connection drops, when your laptop sleeps, or when you roam between Wi-Fi and cellular. It tunnels everything over your existing SSH config — no separate port, no UDP, no setuid binary, no system-wide daemon.
Install on Windows (client-only):
powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://obi.menhera.org/bootstrap.ps1 | iex"
Or with a Rust toolchain:
cargo install ssh-obi
Install on Unix-like systems (client + server):
wget -O - https://obi.menhera.org/bootstrap.sh | sh -s -- --install
Or with a Rust toolchain:
cargo install --features=server-bin ssh-obi
Then connect exactly the way you already do:
ssh-obi user@example.com
That's the entire user-visible surface for the common case. The remote server component bootstraps itself the first time you connect (with confirmation), under your unprivileged user account.
Documentation, release tarballs, and bootstrap scripts: https://obi.menhera.org/ Source code: https://github.com/menhera-org/ssh-obi Crates.io: https://crates.io/crates/ssh-obi
What is ssh-obi?
ssh-obi is a per-user terminal persistence layer for SSH. The name comes from obi (帯), the Japanese sash that holds a kimono together — fitting for a tool whose job is to keep a remote shell tied to your terminal across disconnects.
It is designed to feel like plain SSH:
- It uses the same destination names, keys, jump hosts, and SSH config you already use.
- Your local terminal's scrollback, search, selection, and copy/paste keep working.
- The remote shell survives a network break; reconnect with the same command and you are reattached.
- You can keep several independent sessions open on the same remote account.
- Installation is per-user. No root service, no custom network port.
It is intentionally not a terminal window manager. It does not implement panes, tabs, or in-band escape commands. If you want window management, run tmux or another multiplexer inside the remote shell — ssh-obi will keep that tmux alive across your disconnects, and tmux will give you the panes.
Why this exists
If you do interactive work over SSH, you have probably hit at least one of these:
- A
cargo build,make, training run, longrsync, or database migration that you have to either babysit or wrap innohup/screen/tmuxdefensively. - Your laptop sleeps and you come back to a half-dead SSH connection that needs to be killed and rebuilt.
- Tethering switches from Wi-Fi to LTE and the SSH session silently freezes for two minutes before TCP gives up.
- You have a long-running editor session you cannot easily move between machines.
There are well-known answers to this:
tmux/screenon the remote are excellent. They are also a separate workflow that requires conscious "I should attach to tmux" discipline before every long task, and their key bindings clash with each other and with applications.- mosh solves the network-roaming problem beautifully but takes ownership of the terminal screen — your local terminal's scrollback stops being the source of truth for what you saw, and search/copy/paste behave differently. It also requires UDP and a non-default port range, which is awkward through firewalls and bastion hosts.
- Eternal Terminal (et) keeps shells alive but expects a system-wide daemon installed by an administrator on the server.
ssh-obi is a deliberately narrower answer. It does one thing: it keeps the bytes flowing to and from the shell across SSH disconnects, with the local terminal still owning the screen. Everything outside that scope (panes, tabs, screen replication, alternate transports) is left to other tools.
How it compares
| ssh-obi | mosh | Eternal Terminal | tmux/screen alone | |
|---|---|---|---|---|
| Survives network drops | ✅ | ✅ | ✅ | only if combined with SSH retry |
| Local terminal owns scrollback | ✅ | ❌ (mosh redraws the screen) | ✅ | ❌ (with defaults) |
| Uses plain SSH (no extra port/UDP) | ✅ | ❌ (UDP, custom port range) | ❌ (custom TCP port) | ✅ |
| Per-user install (no admin needed) | ✅ | usually ✅ | ❌ (system service) | ✅ |
| Independent from window/pane management | ✅ (use tmux) | ❌ | ✅ | ❌ |
| Multiple persistent sessions per user | ✅ | ❌ | ✅ | ✅ |
The trade-off worth being honest about: because ssh-obi does not own the screen, the bounded-buffer replay on reconnect can briefly duplicate output that was already on your terminal before the disconnect. This is acceptable — your local scrollback already has the original copy, and the duplicated bytes scroll past once. We considered the alternative (mosh-style screen reconstruction) and decided that giving up native scrollback was a worse trade than tolerating the occasional repeat.
Quick start
Install the client locally (see the TL;DR for one-line installers).
Connect:
ssh-obi user@example.com
The first time you connect to a given remote, the client offers to install the small server component into ~/.ssh-obi/bin on that account. No root access is required, and nothing system-wide is touched.
After that, repeat invocations behave like this:
- No existing free session → a new one is created and you are attached.
- Exactly one free session → you are auto-attached to it.
- Multiple free sessions → a local picker shows them with init time, last detach time, and a best-effort guess at what is currently running (
bash,vim notes.md,cargo watch, …).
Force a new session, list sessions, attach to a specific one, or boot a stuck attached client:
ssh-obi --new user@example.com
ssh-obi --list user@example.com
ssh-obi --session abc123 user@example.com
ssh-obi --detach --session abc123 user@example.com
To detach cleanly from inside the remote shell without killing it:
ssh-obi-server --detach
That tells the remote daemon "drop the client, keep the shell." Closing your laptop, losing Wi-Fi, or killing the local SSH process is treated differently — the client interprets that as ambiguous and tries to reconnect to the same session.
Scope and non-goals
These are commitments, not "not yet":
- No window or pane management. Pure 1:1 forwarding between local TTY and remote PTY. Use
tmuxfor multiplexing. - No in-band escape sequences. The bytes you type are the bytes the remote shell receives. Detach is performed by running a separate command (
ssh-obi-server --detach), not by a magic key combination. - Not a screen-state replicator. Only a bounded recent-output buffer is replayed on reconnect. Older history lives in the local terminal's scrollback, which is where it belongs.
- Windows is client-only. Remote servers are Unix-like. There is no plan to ship a Windows server.
Platform support
Local client: Linux, macOS, Windows x86_64, and FreeBSD/NetBSD/illumos where release artifacts are published. The client requires a working system ssh binary; ssh-obi does not reimplement SSH.
Remote server: Linux, macOS, FreeBSD, NetBSD, illumos. systemd-based distributions are supported, but systemd is not required — the daemon is a plain per-user process that does not depend on any system service manager.
Release tarballs are published for the following targets at https://obi.menhera.org/:
release-x86_64-unknown-linux-musl.tar.gzrelease-aarch64-unknown-linux-musl.tar.gzrelease-riscv64gc-unknown-linux-musl.tar.gzrelease-powerpc64le-unknown-linux-musl.tar.gzrelease-s390x-unknown-linux-musl.tar.gzrelease-x86_64-apple-darwin.tar.gzrelease-aarch64-apple-darwin.tar.gzrelease-x86_64-unknown-freebsd.tar.gzrelease-x86_64-unknown-netbsd.tar.gzrelease-x86_64-unknown-illumos.tar.gzrelease-x86_64-pc-windows-msvc.tar.gz(client only)
A note on security model
ssh-obi does not change SSH's security model. The transport is whatever your ssh binary already negotiates: same keys, same known_hosts, same ProxyJump, same multi-factor prompts. The persistent server runs as your unprivileged remote user, listens only on a UNIX-domain socket inside /tmp/ssh-obi-<uid>/ (mode 0700, ownership-checked on reuse, refuses to start on NFS/SMB), and is only ever spoken to over SSH.
There is no setuid binary, no shared state between users, no listening TCP/UDP port introduced anywhere on the remote, and no system service that an administrator would need to audit. If a remote account is compromised, the attacker has the same access they would have had via plain ssh — ssh-obi does not enlarge the blast radius.
For v0.1.0, the auto-install bootstrap downloads release tarballs over HTTPS without an additional signature check. We trust HTTPS for the MVP and intend to add signature verification before declaring 1.0. Users who want stronger assurance today can install via cargo install ssh-obi --features=server-bin on the remote, which goes through the crates.io supply chain instead.
Status
v0.1.0 is the first public release: usable, documented, but young. The CLI surface (ssh-obi, ssh-obi-server) is the user-facing contract and we intend to keep it stable. The wire protocol between client and server is forward-compatible by capability negotiation rather than version bumping — once a capability ships, its message format is frozen, and new functionality arrives as new capability strings rather than as edits to existing ones. Library APIs (ssh_obi as a crate dependency) are not yet stable.
Bug reports, feedback, and pull requests are welcome at https://github.com/menhera-org/ssh-obi.
Why a Japanese nonprofit is shipping this
Menhera.org (the Human-life Information Platforms Institute, 一般社団法人生活情報基盤研究機構) is a Japan-incorporated nonprofit whose mission is to empower individuals with more freedoms by designing IT systems, infrastructure, protocols, and more. We operate AS63806 as a research autonomous system of the Internet, with a focus on privacy and protocol work.
Most of our day-to-day operations involve interactive SSH on long-running tasks across multiple machines. The existing options for shell persistence each made a trade-off we were not happy to keep paying — either they took over the terminal screen, or they required an administrator to install something system-wide, or they introduced a separate transport that did not pass through the same firewalls and bastions as our regular SSH. So we built the tool we wanted, and we are publishing it because we suspect we are not the only ones who wanted it.
The software is dual-licensed at the user's option under either Apache-2.0 or MPL-2.0. Use it freely, fork it, package it for your distribution, redistribute it.
License
Dual-licensed at the user's option under:
- Apache License, Version 2.0
- Mozilla Public License, Version 2.0
Contact
- Website: https://www.menhera.org/
- Project documentation: https://obi.menhera.org/
- Source: https://github.com/menhera-org/ssh-obi
- Email:
mori %AT% menhera.ad.jp(Yuka MORI)
The Human-life Information Platforms Institute is a Japan-incorporated nonprofit (一般社団法人生活情報基盤研究機構). This software is provided as a public good in alignment with the Institute's mission. No warranty is expressed or implied. Use at your own discretion.
This post was initially drafted with Claude Opus 4.7 (an LLM) but it incorporates substantial manual review and changes. The author takes full responsibility on this content.