SSH Term is a full-featured SSH client that runs entirely in your web browser.
The core client is written in Go and compiled to WebAssembly (WASM), allowing it to run client-side. It uses xterm.js for the terminal interface and connects to standard SSH servers through a tlsproxy WebSocket proxy.
- Connect to any SSH server, including via jump hosts.
- SFTP client with streaming uploads and downloads.
- In-memory SSH agent and agent forwarding.
- Public key authentication with certificates.
- WebAuthn support for security keys and passkeys.
- Generate, import, and export SSH keys (rsa, ecdsa, ecdsa-sk, ed25519).
- Backup and restore configuration and keys.
- Keyboard-interactive authentication.
- Persistence of data to browser local storage.
You can get started by either downloading a pre-built release or by building the project from source.
Option 1: Download a Release
You can find pre-packaged releases on the releases page. Download the sshterm-docroot-${VERSION}.tar.gz
file, which contains all the necessary files ready to be deployed.
Option 2: Build from Source
If you have Go and Node.js installed, you can build the project yourself:
git clone https://github.com/c2FmZQ/sshterm.git
cd sshterm
./build.sh
After the build completes, the docroot/
directory will contain all the required application files.
SSH Term connects to SSH servers via a WebSocket proxy. You will need to configure tlsproxy
to forward connections.
-
Configure
tlsproxy
Create a
tlsproxy
configuration file. Here is a minimal example:backends: - serverNames: - ssh.example.com mode: local documentRoot: /path/to/your/docroot/ webSockets: - endpoint: wss://ssh.example.com/myserver address: 192.168.0.100:22
Update the
serverNames
,documentRoot
,endpoint
, andaddress
to match your environment. -
Configure the Endpoint in the App
Open the SSH Term URL in your browser (e.g.,
https://ssh.example.com
). The first time you use it, you must configure the server endpoint with theep
command:ep add myserver wss://ssh.example.com/myserver
The URL can also be a relative path, e.g.
./myserver
. Alternatively, you can provide this configuration in aconfig.json
file in thedocroot
directory.
As an alternative to configuring endpoints manually with the ep
command, you can create a config.json
file in the docroot/
directory to pre-configure the application. This is useful for deploying SSH Term with a default set of connections and settings.
Copy config.json.example
to config.json
and modify it to fit your needs.
Here is an example with explanations of the fields:
{
"persist": false,
"theme": "dark",
"certificateAuthorities": [{
"name": "my_ca_example_com",
"publicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOO4jC9AcVsCOfapTGboTKOuMbil0Z8jKnt3pb3M8eqi",
"hostnames": [ "*.example.com" ]
}],
"endpoints": [{
"name": "myserver.example.com",
"url": "./websocket"
}],
"hosts": [{
"name": "myserver.example.com",
"key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINqyuT/sFvC37z1qMY0may2TMKqg2nxdjxBxyfXeieot"
}],
"generateKeys": [{
"name": "default",
"type": "ed25519",
"identityProvider": "./cert",
"addToAgent": true
}],
"autoConnect": {
"username": "username",
"hostname": "myserver.example.com",
"identity": "default",
"command": "uname -a",
"forwardAgent": false
}
}
persist
: Controls whether settings are saved to the browser's local storage. Whenfalse
, all data is cleared on reload.theme
: Sets the visual theme (e.g., "dark", "light").certificateAuthorities
: Specifies trusted Certificate Authorities for verifying host certificates.name
: A unique name for the CA.publicKey
: The public key of the CA inauthorized_keys
format.hostnames
: A list of hostnames or wildcard patterns for which this CA is trusted.
endpoints
: Pre-defines WebSocket endpoints, equivalent to using theep add
command.name
: A friendly name for the endpoint.url
: The WebSocket URL (e.g.,wss://ssh.example.com/proxy
or a relative path./proxy
).
hosts
: Pre-defines known host keys to avoid interactive prompts.name
: The hostname of the server.key
: The public key of the host.
generateKeys
: Can be used to generate a new SSH key on first use if no keys exist.name
: The name to give the new key.type
: The key type (e.g.,ecdsa
,ecdsa-sk
,ed25519
,rsa
).identityProvider
: If specified, the application will send a request to this URL to get the newly generated public key signed, creating a certificate.addToAgent
: Iftrue
, the new key will be automatically added to the in-memory agent.
autoConnect
: Automatically connect to a specified host on startup.username
: The user to connect as.hostname
: The host to connect to (must match an endpoint name).identity
: The name of the key to use for authentication.command
: An optional command to run on the remote server.forwardAgent
: Iftrue
, enables agent forwarding for the session.
This section explains how to use the SSH Term application, from initial setup to a complete command reference.
Follow these steps to get connected for the first time.
-
Configure the Server Endpoint
Before you can connect, you must tell SSH Term how to reach your SSH server via its WebSocket proxy. Use the
ep add
command to add a new endpoint.ep add my-server wss://ssh.example.com/my-server
Replace
my-server
with a name of your choice and the URL with the one provided by yourtlsproxy
configuration. The URL can be absolute or relative. -
Generate an SSH Key
Next, generate a new SSH key to use for authentication. The
keys generate
command creates a new key and adds it to the local keystore.keys generate -t ed25519 my-key
This creates a new
ed25519
key namedmy-key
. You can see your new key by runningkeys list
. Don't forget to add the public key to your server's~/.ssh/authorized_keys
file. -
Connect to Your Server
Now you can connect to your server using the
ssh
command.ssh user@my-server
SSH Term will use the endpoint you configured to establish the connection.
SSH Term supports connecting through one or more jump hosts using the -J
or --jump-hosts
flag. The connection to the first jump host is made via a configured WebSocket endpoint, while subsequent hops are standard SSH connections made through the established tunnel.
For this to work, you only need a configured endpoint for the first jump host.
-
Configure Endpoint for the Jump Host:
ep add jump-server wss://ssh.example.com/jump-proxy
Here,
jump-server
is the name of the endpoint that points to your first jump host. -
Connect:
ssh -J user@jump-server [email protected]
This command tells SSH Term to: a. Connect to
jump-server
using the configured WebSocket endpoint. b. Fromjump-server
, establish a standard SSH connection tointernal-host.example.com
.The hostname
internal-host.example.com
does not need its own endpoint; it is resolved from the jump host.
Here is a list of all available commands. Most commands follow a command <sub-command> [arguments]
pattern.
ssh [options] [user@]hostname [command]
- Starts an SSH connection.-i, --identity <keyname>
: The key to use for authentication.-J, --jump-hosts <jump-hosts>
: Connect by going through jump hosts.-A, --forward-agent
: Forwards access to the local SSH agent.
sftp [options] [user@]hostname
- Starts an interactive SFTP session.- (Options are the same as
ssh
)
- (Options are the same as
keys list
- Lists all keys.keys generate [options] <name>
- Generates a new key.-t, --type <type>
: The type of key to generate (ecdsa
,ecdsa-sk
,ed25519
,rsa
).-b, --bits <bits>
: The key size in bits.--idp <url>
: The URL of the identity provider to use.
keys delete <name>
- Deletes a key.keys show <name>
- Shows a key's public part and certificate details.keys change-pass <name>
- Changes a key's passphrase.keys import <name>
- Imports a private key from a file.keys export [-p] <name>
- Exports a key. With-p
or--private
, exports the private key.keys import-cert <key-name>
- Imports a certificate for an existing key.
ep list
- Lists all configured server endpoints.ep add <name> <url>
- Adds a new server endpoint.ep delete <name>
- Deletes a server endpoint.
agent list
- Lists keys in the SSH agent.agent add <key-name>
- Adds a key to the agent.agent remove [-all] [<name>]
- Removes a key (or all keys with--all
) from the agent.agent lock
- Locks the agent with a passphrase.agent unlock
- Unlocks the agent.
hosts list
- Lists all known hosts.hosts delete <name>
- Deletes a known host.
ca list
- Lists all certificate authorities.ca import <name> [hostname...]
- Imports a CA public key.ca delete <name>
- Deletes a certificate authority.ca add-hostname <name> <hostname>...
- Adds trusted hostnames to a CA.ca remove-hostname <name> <hostname>...
- Removes hostnames from a CA.
db persist [on|off|toggle]
- Manages whether the database is persisted to local storage.db wipe
- Deletes everything from the database.db backup
- Creates an encrypted backup of the database.db restore
- Restores the database from a backup.
cd [dir]
- Changes the remote directory.pwd
- Shows the current remote directory.ls [-l] [path...]
- Lists remote files.get <remote-file>...
- Downloads one or more files.put
- Uploads one or more files.mkdir [-p] <directory>...
- Creates a remote directory.rm [-R] <path>...
- Removes a remote file or directory.rmdir <directory>...
- Removes a remote directory.mv <old> <new>
- Renames a remote file or directory.chmod <mode> <path>...
- Changes file permissions.ln [-s] <target> <link>
- Creates a hard or symbolic link.help
or?
- Shows available SFTP commands.exit
orquit
- Exits the SFTP session.
set theme <light|dark|green>
- Sets the color theme.clear
- Clears the terminal screen.reload
- Reloads the application page.help
- Shows a list of available commands.exit
- Exits the application.
Contributions are welcome! We appreciate help with bug fixes, feature development, and documentation.
- Clone the repository:
git clone https://github.com/c2FmZQ/sshterm.git cd sshterm
For a detailed explanation of the project's architecture and design, please see DESIGN.md.
The codebase is organized into the following main directories:
go/
: Contains all the Go source code for the SSH client. This code is compiled into a WebAssembly (.wasm
) module.go/internal/app/
: Defines all the application's commands (ssh
,keys
,ep
, etc.).go/internal/indexeddb/
: A Go wrapper for the browser's IndexedDB API for local storage.go/internal/jsutil/
: Utilities for Go-to-JavaScript interoperability.go/internal/terminal/
: A Go wrapper for thexterm.js
terminal to handle I/O.go/internal/shellwords/
: Handles shell-style command-line parsing.go/internal/websocket/
: Implements anet.Conn
interface over a browser WebSocket.go/internal/webauthnsk/
: Implements theecdsa-sk
(WebAuthn) key type.go/internal/tests/
: Contains internal end-to-end tests for the Go application, which are also compiled to WASM and run in a browser.go/internal/testserver/
: A backend server used for running the internal Go tests, providing a mock SSH server and other endpoints.
docroot/
: The web root for the application. It contains the mainindex.html
, the compiledssh.wasm
binary, and the necessary JavaScript and CSS assets. This is the directory you would serve to users.xterm/
: Contains thexterm.js
frontend component and its dependencies, which provides the terminal UI.tests/
: Contains scripts and Docker configurations for running the end-to-end browser tests.build.sh
: The main build script that compiles the Go code into WASM and moves all necessary assets into thedocroot/
directory.
-
Run the tests: You can run the test suite to verify your changes.
-
Headless Mode (Requires Docker): To run the tests in a headless browser, Docker is required. The test environment is containerized to ensure consistency.
./tests/run-headless-tests.sh
-
Interactive Mode (Requires Docker): To run the tests in your own browser for debugging, start the test server. The test server runs in a Docker container.
./tests/run-test-server.sh
Then, open
http://<hostname>:8443/tests.html
in your browser.
-
We follow a standard GitHub pull request workflow.
- Fork the repository on GitHub.
- Create a new branch for your changes.
- Make your changes and commit them with a clear message.
- Push your branch to your fork.
- Open a pull request against the
main
branch of the original repository.
- Tests: Please ensure that your changes are covered by new or existing tests. You can run the test suite locally using the instructions in the "Development Setup" section. All pull requests must pass the automated CI checks.
- Documentation: If you introduce a new command, option, or user-facing feature, please update the relevant sections of this
README.md
file.