MoltSSH is a resumable OpenSSH ProxyCommand over WebSocket.
The current MVP uses WebSocket transport. Existing relay tools provide reachability; MoltSSH provides session resume, path probing, and path switching.
View Releases · Changelog · Report Bug · Request Feature
- About The Project
- Built With
- Getting Started
- Usage
- Troubleshooting
- Configuration
- Roadmap
- Contributing
- Security
- License
- Contact
- Acknowledgments
MoltSSH keeps the server-side TCP connection to sshd stable while the client
reconnects through the healthiest configured WebSocket path. This lets an
OpenSSH session continue through client-side network churn, relay restarts, and
path changes that preserve the MoltSSH server process.
Current capabilities:
- OpenSSH
ProxyCommandcompatibility. - TOML based
proxy,server, andprobecommands. - WebSocket subprotocol
moltssh.v1with explicit binary frames. - Server-side TCP bridge to a single configured target such as
127.0.0.1:22. - In-memory resume state with session IDs, epochs, ACKs, FIN, offsets, and replay buffers.
- Probe driven path selection with RTT, failure threshold, success threshold, and switch cooldown settings.
- Parallel phased dialing, reusable probe connections, advisory last-known-good path startup, in-session heartbeat, and jittered reconnect backoff.
- GitHub Actions CI, release binaries, issue templates, and Docker SSH smoke coverage.
See docs/mvp.md for the protocol plan and ADR 0001 for the transport decision.
- Go
- golang.org/x/net/websocket
- OpenSSH
- Docker for the repository smoke test
- Go 1.26.5+
- OpenSSH client
- Docker for
scripts/docker-ssh-smoke.sh
Download a release binary from GitHub Releases.
Release assets use this naming pattern:
moltssh_<version>_<os>_<arch>
moltssh_<version>_windows_amd64.exe
SHA256SUMS
Install the latest tagged version with Go:
go install github.com/jingyijun/moltssh/cmd/moltssh@latestThe binary is installed into GOBIN when it is set, otherwise into
$(go env GOPATH)/bin. Make sure that directory is on PATH.
@latest follows the newest semantic-version tag, which can lag behind
features listed under Unreleased.
Build from source:
git clone https://github.com/JingYiJun/MoltSSH.git
cd MoltSSH
go build -o moltssh ./cmd/moltsshVerify any installation:
moltssh --helpFor source builds and tagged releases that include the version command, inspect build provenance with:
moltssh versionRun local checks:
go test ./...
go test -race ./...
scripts/docker-ssh-smoke.shFor a writable Go cache path:
GOCACHE=/tmp/moltssh-go-build go test ./...Start a MoltSSH server beside the target sshd:
moltssh server --config /etc/moltssh/example.tomlProbe configured client paths:
moltssh probe --config ~/.config/moltssh/example.tomlUse MoltSSH as an OpenSSH ProxyCommand:
Host example-host
HostName example-host
User example-user
ProxyCommand moltssh proxy --config ~/.config/moltssh/example.tomlOpen an SSH session:
ssh example-hostInspect command-specific help:
moltssh help proxy
moltssh help server
moltssh help probeStart with the probe command whenever a proxy path cannot connect:
moltssh probe --config ~/.config/moltssh/example.tomlFor moltssh probe, the failed_phase field narrows the failure to dns,
tcp, tls, websocket_upgrade, or probe. Common checks:
dns: verify the endpoint hostname and resolver.tcp: verify the port, relay process, firewall, and route.tls: verify the certificate name, trust chain, and reverse-proxy TLS setup.websocket_upgrade: verifyserver.http_path, reverse-proxy WebSocket forwarding, and themoltssh.v1subprotocol.probe: the WebSocket connected, but the MoltSSH ping/pong check failed; verify client/server compatibility and reverse-proxy frame forwarding.
Proxy-session logs can instead report failed_phase=moltssh_hello or
unknown session. Verify client/server compatibility and confirm that the
MoltSSH server process did not restart.
Run moltssh help COMMAND for required flags and command-specific guidance.
Errors include a next diagnostic action where one is available.
Warning
MoltSSH has no application-layer authentication. Do not expose the raw
moltssh server WebSocket listener to the public internet. Bind it to
loopback or place it behind a protected private access layer or authenticated
reverse proxy. See SECURITY.md.
MoltSSH uses one TOML schema for client and server commands:
schema_version = 1
name = "example-host"
[server]
listen = "127.0.0.1:8080"
http_path = "/moltssh"
connect = "127.0.0.1:22"
[resume]
timeout = "60s"
buffer_bytes = 33554432
[probe]
interval = "3s"
timeout = "2s"
switch_cooldown = "10s"
active_failure_threshold = 2
candidate_success_threshold = 3
better_rtt_min_delta = "30ms"
better_rtt_ratio = 0.25
[[paths]]
name = "direct"
transport = "ws"
endpoint = "ws://127.0.0.1:8080/moltssh"
priority = 100
enabled = trueDeployment guidance:
- Use
ws://for trusted localhost, LAN, and already protected tunnel paths. - Use
wss://through a reverse proxy, relay, gateway, or local tunnel endpoint that terminates TLS. - Place the MoltSSH server behind a protected access layer for public relay paths.
- Keep private keys, credentials, certificates, tokens, and machine-specific host details in local deployment files.
Path performance and runtime state:
- On a cold start, enabled paths are probed concurrently, with at most eight
probes in flight. A successful probe WebSocket is promoted directly by
sending
hello; MoltSSH does not redial the selected path. - After an accepted session,
proxystores only the accepted path name in an advisory last-known-good cache. The cache is$XDG_CACHE_HOME/moltssh/path-state/<config-hash>.jsonwhenXDG_CACHE_HOMEis set, otherwise it is under the operating system user cache directory. The hash identifies the canonical config-file path. - A warm start dials the saved path immediately while probing alternatives in the background. Missing, stale, disabled, malformed, or unwritable cache state never prevents connection fallback. Removing this cache is safe.
- Cache directories use mode
0700, files use0600, and the JSON contains onlyversionandpath. Sessions, epochs, offsets, payload bytes, endpoints, and credentials remain memory-only and are never cached. - The active session uses application
ping/pongheartbeat on its existing WebSocket. Only inactive paths get new probe connections. A promoted inactive probe keeps the same WebSocket for the resumehello. - Reconnect uses capped exponential backoff with full jitter: a
200msbase, a5scap, and delays clipped to the remainingresume.timeoutbudget. - Formal attempts emit one
event=proxy_dialrecord withdns,tcp,tls,websocket_upgrade,moltssh_hello,probe_rtt, andtotal. Endpoints and secret query values are not logged. These optimizations do not change themoltssh.v1wire protocol or add TOML fields.
- WebSocket transport.
- TOML config validation.
- OpenSSH
ProxyCommandbridge. - Session resume with replay buffers.
- Probe command and path switching.
- Docker SSH smoke test.
- GitHub CI and release binaries.
- More protocol conformance tests.
- Operational examples for common relay tools.
- QUIC exploration after WebSocket resume and path switching mature.
See the open issues for active work items.
Contributions are welcome through focused issues and pull requests. Read CONTRIBUTING.md for the development workflow and CODE_OF_CONDUCT.md before participating.
Read SECURITY.md before deploying MoltSSH or reporting a vulnerability. Security-sensitive reports should not be filed as public issues.
Distributed under the MIT License. See LICENSE for more information.
Project Link: https://github.com/JingYiJun/MoltSSH
- Best-README-Template for the README structure.
- OpenSSH for the integration target.
- Go for the implementation toolchain.
