shex is a small remote shell that uses Redis as a routing layer. OPAQUE
authenticates a shared code without sending that code to the host or Redis.
Commands and results use a ChaCha20-Poly1305 channel derived from the OPAQUE
session key.
Redis never receives plaintext credentials, commands, command output, or shell state. It sees the host and mailbox key names, encrypted payload sizes, and timing. This is end-to-end encrypted infrastructure rather than a generic zero-knowledge proof system.
This is an SSH-like shell, not an implementation of the SSH wire protocol.
cargo install shexUpgrade an existing installation:
cargo install shex --forceSet REDIS_URL in the environment or a local .env file. TLS Redis URLs use
the rediss scheme:
REDIS_URL="rediss://username:password@example-redis:6379".env is ignored by Git and excluded from published crates. Use Redis ACLs,
TLS, and a dedicated database or account in production.
Give a Redis URL a local name:
shex redis addWith no arguments, shex interactively asks for the name and hides the Redis URL while it is entered. Arguments remain available for automation:
shex redis add local redis://127.0.0.1:6379/When REDIS_URL is already set, only the name is needed. Shex sends a Redis
PING before saving. If the server cannot be reached, it asks whether the entry
should be kept anyway.
The URL is stored in macOS Keychain or Linux Secret Service. Only a private,
hashed marker is written under ~/.shex/redis. The most recently added server
becomes the default, so this uses it automatically:
shex latency testA saved name can also be selected explicitly anywhere that accepts
--redis-url:
shex latency test --redis-url cloud
shex auth quiet-otter:1738 --redis-url cloud
shex serve --redis-url localInitialize the host once. The authentication code is used to create an OPAQUE password record but is not retained by the host:
shex init --data-dir .shex
shex serve --data-dir .shexOn first use, serve assigns and saves a permanent name resembling:
quiet-otter:1738
Pass an explicit name to change it:
shex serve --data-dir .shex --hostname my-host:1738The new name is saved locally and registered permanently in Redis. Previous names remain reserved in Redis; global hostname reclamation is not implemented.
Use the hostname printed by serve:
shex auth quiet-otter:1738Authentication for every host is stored under ~/.shex/auth. Filenames are
hostname hashes. Each file contains the Redis location, hostname, server
fingerprint, reusable credential, and last-session identifier. Its payload is
encrypted with ChaCha20-Poly1305, while the random encryption key is held by
macOS Keychain or Linux Secret Service through the operating-system credential
manager. Re-running auth safely updates that host's entry.
shex authenticate remains an alias for shex auth.
exec creates a persistent host-local shell session by default:
shex exec quiet-otter:1738 -- pwd
shex exec quiet-otter:1738 -- cd /srv/appEach command without --past creates a different session. Reuse the most
recent session recorded in the selected auth file with:
shex exec --past quiet-otter:1738 -- pwdAn explicit session can also be selected:
shex exec --session 3ae162b90f944fa4654dbb49a36cc734 \
quiet-otter:1738 -- pwdLegacy or manually managed auth files remain usable with
shex exec --auth-file PATH -- COMMAND.
Delete the last session, its host process, and its Redis lookup:
shex close quiet-otter:1738Or delete a specific session:
shex close quiet-otter:1738 \
--session 3ae162b90f944fa4654dbb49a36cc734A new interactive connection is ephemeral: it is removed when the connection ends and does not create a Redis session lookup.
shex connect quiet-otter:1738An existing persistent exec session can be opened interactively:
shex connect quiet-otter:1738 \
--session 3ae162b90f944fa4654dbb49a36cc734Measure Redis command round-trip latency without contacting a host:
shex latency testAdd a saved hostname to also measure an authenticated, encrypted host round trip through Redis:
shex latency test quiet-otter:1738The report includes Redis minimum/average/maximum time, host round-trip time,
and an estimated additional encrypted host path. The estimate subtracts the
Redis PING baseline and is diagnostic rather than a one-way network measurement.
Use --count to select between 1 and 100 samples.
shex:v2:host:<hostname>is the small permanent host record.shex:v2:<hostname>:session:<hash>is one fixed lookup for each active persistent session. Actual shell state remains only in the host process.- Layer-two mailboxes contain at most one message in each direction, with only one present during the request/response flow.
- Mailbox payloads have a 60-second TTL. While a receiver is processing one, an authenticated lease refresh prevents long-running commands from expiring.
- Blocking one-shot readiness signals avoid polling while clients or hosts are idle; signals carry no command or output data.
- A received payload is compare-and-deleted only after authenticated processing.
- Closing a session deletes its session lookup. Host startup removes stale lookups because live shell processes cannot survive a host restart.
Redis may temporarily hold ciphertext in memory, replicas, RDB snapshots, or AOF according to its configuration. Disable Redis persistence for the shex database if ciphertext must never reach Redis disk.
- OPAQUE with Argon2 protects the authentication exchange.
- ChaCha20-Poly1305 authenticates and encrypts post-login traffic.
- Auth files are encrypted and bound to the authenticated host fingerprint.
- Saved Redis URLs are held by the operating-system credential store; local marker filenames are hashes of their aliases.
- Redis routing metadata, message sizes, and timing are not hidden.
- Use a high-entropy code; a short numeric code remains guessable.
- Redis access is local/private trust in 2.0. Redis ACLs remain important because an attacker with write access can deny service even without decrypting data.
- The host runs commands with the operating-system privileges of
shex. - There is no PTY emulation, file transfer, port forwarding, or full-screen terminal support.
All planned but unimplemented work is centralized in TODO.md.
Version 2.0 replaces direct TCP transport with Redis and is not wire-compatible
with 0.x. Upgrade hosts and clients together, configure REDIS_URL, restart the
host, and run shex auth <hostname> again to create a version-2 auth entry.