SSH over the Nym mixnet — connect to any machine running sshd through a
privacy-preserving onion network without exposing a public IP address or open port.
Your machine Nym mixnet Remote machine
──────────────────────────────────────────────────────────────────────────
ssh ──ProxyCommand──> ssh-nym client ──Nym packets──> ssh-nym server ──> sshd
- The server binds a persistent Nym address and forwards connections to local
sshd. - The client is used as an SSH
ProxyCommand; it tunnels stdin/stdout through Nym. - SSH provides its own encryption — Nym provides network-level anonymity.
- Packets are sequenced and retransmitted to handle mixnet reordering and loss.
Install on the machine you want to reach over SSH.
sudo dpkg -i ssh-nym-server_0.1.0_amd64.debThis installs /usr/bin/ssh-nym and a systemd service unit.
Enable and start the service:
sudo systemctl enable --now ssh-nymGet the server's Nym address (needed by clients):
sudo journalctl -u ssh-nym | grep "Server Nym address" -A1The address looks like:
3Cku2yn5AmyvpCeVKPruw4DxMtqnUdNW8Hj9ymkuMfkU.4QN5wd55HFoH6Ta5dxNUE9xgxXhenrQcxt6Eivnzxhau@J4FegtCGLtrybiNno2BKVpmHrgVe4X9tGgPS2rBGdDbk
This address is stable across restarts — the identity keys are stored in
/root/.local/share/ssh-nym (or ~/.local/share/ssh-nym for the user running the service).
Share it once; it never changes unless you delete the storage directory.
Override via a systemd drop-in:
sudo systemctl edit ssh-nym[Service]
ExecStart=
ExecStart=/usr/bin/ssh-nym server --sshd-addr 127.0.0.1:2222 --storage-dir /var/lib/ssh-nymsudo systemctl status ssh-nym # check status and see the Nym address
sudo systemctl restart ssh-nym # restart (address stays the same)
sudo systemctl stop ssh-nym # graceful stop (flushes SURB database)
sudo journalctl -u ssh-nym -f # live logsInstall on the machine you SSH from.
sudo dpkg -i ssh-nym-client_0.1.0_amd64.debInstalls /usr/bin/ssh-nym. No extra dependencies are pulled in.
Add a Host block to ~/.ssh/config, replacing <NYM_ADDRESS> with the address
printed by the server:
Host my-server
User root
ProxyCommand ssh-nym connect <NYM_ADDRESS>
Then connect normally:
ssh my-serverOr without editing the config:
ssh -o ProxyCommand="ssh-nym connect <NYM_ADDRESS>" root@localhostThe Nym client initialises on each run (fetches network topology, registers with a gateway). This takes 10–30 seconds before the SSH handshake begins — this is normal. Subsequent reconnections take the same time because the client identity is ephemeral on the client side.
Requires Rust and the x86_64-unknown-linux-musl target for static builds.
# Install the musl target if not already present
rustup target add x86_64-unknown-linux-musl
# Build both .deb packages (static binary, no glibc dependency)
./build-deb.sh
# Packages produced:
# target/deb/ssh-nym-client_<version>_amd64.deb
# target/deb/ssh-nym-server_<version>_amd64.debNote on vendored crates: Three upstream Nym crates (
nym-node-requests,nym-noise,nym-api-requests) are vendored invendor/with a one-line fix that aliases the renamed typeVersionedNoiseKey→VersionedNoiseKeyV1.
SSH hangs after running ssh my-server
- The first 10–30 s of silence is the Nym client initialising — wait for it.
- Enable verbose SSH output to distinguish a Nym timeout from an SSH error:
ssh -v my-server
- Check that the server is running:
sudo systemctl status ssh-nym
Error: Server error: sshd unreachable
- sshd is not listening on the address the server is configured to forward to
(default
127.0.0.1:22). - Check with
sudo systemctl status sshon the server machine.
Warning on server startup: loaded data is inconsistent
- The server was previously stopped with SIGKILL (e.g.
kill -9) instead ofsystemctl stop, leaving the SURB database in an inconsistent state. The Nym SDK recovers automatically by recreating the database. The Nym address is unaffected. Usesystemctl stop ssh-nymfor clean shutdowns.
GLIBC_2.38 not found
- You are running a binary built on a newer system. Rebuild with
./build-deb.shto produce a statically linked musl binary that has no glibc dependency.
| Variable | Effect |
|---|---|
RUST_LOG |
Log verbosity: error warn info debug |
Logs are written to stderr so they never interfere with the SSH data stream on stdout.
| File | Responsibility |
|---|---|
src/main.rs |
CLI entry point (server / connect subcommands) |
src/server.rs |
Persistent Nym identity, session multiplexing, sshd proxy, graceful shutdown |
src/client.rs |
Ephemeral Nym identity, stdin/stdout ProxyCommand bridge |
src/protocol.rs |
Msg enum (Connect / Data / Ack / Retransmit / Close / Error), bincode framing |
src/tunnel.rs |
Reliable ordered delivery: sequence numbers, sliding-window ACK, retransmit |
vendor/ |
Patched Nym crates |
GPL-3.0-only