Are you sure?

>_ jssh

Getting started

jssh gives you audited SSH to devices behind NAT. Each device runs a small agent that dials out to the relay (no inbound ports); you open a point-in-time SSH session to one device at a time.

1 · Get a device online

Create an enrollment token in the dashboard (Tokens) — it hands you a copy-paste one-liner with the token baked in. Run it on the device:

# Linux — works from a root shell or a sudo-capable user:
curl -fsSL https://get.jssh.io | JSSH_ENROLL_TOKEN=<ENROLLMENT_TOKEN> JSSH_RELAY_URL=https://staging.jssh.io sh

It auto-detects the CPU + init system, installs the agent as a service, enrolls the device, and (on Linux) enables signed auto-update — the update trust anchor ships inside the binary, so the token is all you need.

macOS: the same one-liner as Linux — it asks for your sudo password and installs a launchd service.

Android (Termux; no root — install the packages, open a new session, then run the one-liner; sshd listens on 8022):

pkg install termux-services openssh
curl -fsSL https://get.jssh.io | JSSH_ENROLL_TOKEN=<ENROLLMENT_TOKEN> JSSH_RELAY_URL=https://staging.jssh.io sh

Docker: use the Docker tab on the token page — or run the image without a token and approve the code it prints to docker logs.

2 · Connect from your computer

curl -fsSL https://get.jssh.io/cli | sh   # install the operator CLI
jssh login --relay https://staging.jssh.io   # opens your browser to authorize this machine
jssh devices   # list your fleet
jssh ssh <device>   # or native: ssh <device>.jssh.dev

Windows (PowerShell, no elevation needed):

iwr https://get.jssh.io/cli.ps1 -OutFile install-cli.ps1
powershell -ExecutionPolicy Bypass -File .\install-cli.ps1
jssh login --relay https://staging.jssh.io

jssh login also wires up your SSH config, so you can use native tooling with no jssh prefix — ssh <device>.jssh.dev, and the same host works with scp, rsync, and VS Code Remote-SSH:

ssh <device>.jssh.dev                     # native shell (no jssh prefix)
scp file.txt <device>.jssh.dev:~/         # copy a file
rsync -a ./dir <device>.jssh.dev:/opt/    # sync a directory

jssh only carries the encrypted tunnel — authentication is the device's own SSH. Put your public key in the device's ~/.ssh/authorized_keys (or use a password) first, or SSH returns Permission denied (publickey).

3 · Troubleshooting

  • Device offline — the agent isn't connected. On the device check systemctl status jssh-agent (or systemctl --user status jssh-agent on Ubuntu Core) and journalctl -u jssh-agent. The agent dials out over wss:// on 443.
  • Permission denied — your SSH key isn't on the device yet (see step 2).
  • Behind a corporate firewall — allowlist the relay host's SNI, and export HTTPS_PROXY before the install command if outbound goes through a proxy.
  • Device won't connect at all — confirm it can reach https://staging.jssh.io over HTTPS (443); the relay is the only outbound endpoint the agent needs.
  • Doctor — on the device, jssh-agent doctor checks DNS / 443 / TLS / proxy; from your computer, jssh doctor <device> checks your config, token, and the device's live status.

4 · Services beyond SSH

A device can expose more than sshd: declare [[service]] entries in its agent config, or enable a built-in (rdp, vnc, http, https, postgres, redis) from the device page — the device resolves the target itself; the relay never picks a destination. Connect with jssh rdp <device>, jssh vnc <device> or jssh connect <device> --service <name>; each command prints the localhost address to point your client at. Every service is end-to-end encrypted between the CLI and the agent — not just SSH — so the relay carries ciphertext it cannot read. The final hop on each machine is a local connection in the clear, as with an SSH port-forward.

5 · Manual install (unsupported init)

The installer supports systemd, OpenRC, procd, SysV, launchd, Termux and Batocera — on anything else it refuses BEFORE enrolling, so your token isn't spent. Manually: download the binary for your arch from get.jssh.io/latest, run jssh-agent enroll (browser approval), then wire jssh-agent run into your init with a restart-on-failure policy. Service templates live in the client repo's deploy/ directory.