WebSSH2 is an HTML5 web-based terminal emulator and SSH client. It uses SSH2 as a client on a host to proxy a Websocket / Socket.io connection to an SSH2 server.
- Node.js 22 LTS (Jod) or later
# Clone repository
git clone https://github.com/billchurch/webssh2.git
cd webssh2
# Install dependencies
npm install --production
# Start server
npm startAccess WebSSH2 at: http://localhost:2222/ssh
- Preferred registry:
ghcr.io/billchurch/webssh2 - Docker Hub mirror:
docker.io/billchurch/webssh2 - Architectures:
linux/amd64,linux/arm64
Pull the latest build from GitHub Container Registry:
docker pull ghcr.io/billchurch/webssh2:latestRun the container exposing the default port:
docker run --rm -p 2222:2222 ghcr.io/billchurch/webssh2:latestTo pin to a specific release (example: webssh2-server-v2.3.2):
docker run --rm -p 2222:2222 \
ghcr.io/billchurch/webssh2:2.3.2The same tags are available on Docker Hub if you prefer the legacy namespace:
docker run --rm -p 2222:2222 docker.io/billchurch/webssh2:2.3.2WebSSH2 prefers environment variables for configuration (following 12-factor app principles):
# Basic configuration
export WEBSSH2_LISTEN_PORT=2222
export WEBSSH2_SSH_HOST=ssh.example.com
export WEBSSH2_HEADER_TEXT="My WebSSH2"
# Allow only password and keyboard-interactive authentication methods (default allows all)
export WEBSSH2_AUTH_ALLOWED=password,keyboard-interactive
npm startFor detailed configuration options, see Configuration Documentation.
http://localhost:2222/ssh/host/192.168.1.100http://localhost:2222/ssh?port=2244&sshterm=xterm-256colordocker run --rm -it \
-p 2222:2222 \
-e WEBSSH2_SSH_HOST=ssh.example.com \
-e WEBSSH2_SSH_ALGORITHMS_PRESET=modern \
-e WEBSSH2_AUTH_ALLOWED=password,publickey \
ghcr.io/billchurch/webssh2:latestNeed the Docker Hub mirror instead? Use docker.io/billchurch/webssh2:latest.
- Quick Start Guide - Get up and running in 5 minutes
- Installation Guide - Detailed installation instructions
- Docker Setup - Docker and Kubernetes deployment
- Migration Guide - Upgrading from older versions
- Configuration Overview - Configuration methods and priority
- Environment Variables - Complete environment variable reference
- URL Parameters - Query string parameters
- Authentication Methods - Password, key-based, and SSO
- Private Key Authentication - SSH key setup and usage
- Exec Channel - Non-interactive command execution
- Environment Forwarding - Pass environment variables
- Host Key Verification - MITM protection and key management
- Contributing Guide - How to contribute
- Development Setup - Setting up development environment
- API Documentation - WebSocket and REST APIs
- Build & Packaging Guide - Reproducible release flow and manifest format
- Container Integration - Using the packaged bundle in images and CI
- Troubleshooting - Common issues and solutions
- Breaking Changes - Version migration notes
- 🌐 Web-based SSH - No client software required
- 🔐 Multiple Auth Methods - Password, private key, keyboard-interactive
- 📱 Responsive Design - Works on desktop and mobile
- 🎨 Customizable - Themes, fonts, and terminal settings
- 🔌 WebSocket - Real-time bidirectional communication
- 🐳 Docker Ready - Official Docker images available
- 🔧 Exec Channel - Run commands without opening a shell
- 🌍 Environment Variables - Pass custom environment to SSH sessions
- 🛡️ Subnet Restrictions - IPv4/IPv6 CIDR subnet validation for access control
- 📁 SFTP Support - File transfer capabilities (v2.6.0+)
Host key verification protects SSH connections against man-in-the-middle (MITM) attacks by validating the public key presented by the remote SSH server. When enabled, WebSSH2 compares the server's host key against a known-good key before allowing the connection to proceed. This is the same trust-on-first-use (TOFU) model used by OpenSSH.
The feature is disabled by default and must be explicitly enabled in configuration.
Add the hostKeyVerification block under ssh in config.json:
{
"ssh": {
"hostKeyVerification": {
"enabled": true,
"mode": "hybrid",
"unknownKeyAction": "prompt",
"serverStore": {
"enabled": true,
"dbPath": "/data/hostkeys.db"
},
"clientStore": {
"enabled": true
}
}
}
}The mode setting is a shorthand that controls which key stores are active. Explicit serverStore.enabled and clientStore.enabled flags override the mode defaults when set.
| Mode | Server Store | Client Store | Description |
|---|---|---|---|
server |
on | off | Keys are verified exclusively against the server-side SQLite database. The client is never prompted. Best for locked-down environments where an administrator pre-seeds all host keys. |
client |
off | on | The server delegates verification to the browser client. The client stores accepted keys locally (e.g. in IndexedDB). Useful when no server-side database is available. |
hybrid |
on | on | The server store is checked first. If the key is unknown there, the client is asked. Provides server-enforced trust with client-side fallback for new hosts. (default) |
When a host key is not found in any enabled store, the unknownKeyAction setting determines what happens:
| Action | Behavior |
|---|---|
prompt |
Emit a hostkey:verify event to the client and wait for the user to accept or reject the key. Connection is blocked until the user responds or the 30-second timeout expires. (default) |
alert |
Emit a hostkey:alert event to the client as a notification, but allow the connection to proceed. The key is not stored; the alert will appear again on the next connection. |
reject |
Emit a hostkey:rejected event and refuse the connection immediately. Only pre-seeded keys in the server store will be accepted. |
All host key settings can be configured via environment variables. Environment variables override config.json values.
| Variable | Config Path | Type | Default | Description |
|---|---|---|---|---|
WEBSSH2_SSH_HOSTKEY_ENABLED |
ssh.hostKeyVerification.enabled |
boolean | false |
Enable or disable host key verification |
WEBSSH2_SSH_HOSTKEY_MODE |
ssh.hostKeyVerification.mode |
string | hybrid |
Verification mode: server, client, or hybrid |
WEBSSH2_SSH_HOSTKEY_UNKNOWN_ACTION |
ssh.hostKeyVerification.unknownKeyAction |
string | prompt |
Action for unknown keys: prompt, alert, or reject |
WEBSSH2_SSH_HOSTKEY_DB_PATH |
ssh.hostKeyVerification.serverStore.dbPath |
string | /data/hostkeys.db |
Path to the SQLite host key database |
WEBSSH2_SSH_HOSTKEY_SERVER_ENABLED |
ssh.hostKeyVerification.serverStore.enabled |
boolean | true |
Enable the server-side SQLite store |
WEBSSH2_SSH_HOSTKEY_CLIENT_ENABLED |
ssh.hostKeyVerification.clientStore.enabled |
boolean | true |
Enable the client-side (browser) store |
The server store uses a SQLite database that is opened in read-only mode at runtime. You must create and populate the database ahead of time using the seeding script (see below).
Creating the database:
# Probe a host to create and populate the database
npm run hostkeys -- --host ssh.example.comThe script automatically creates the database file (and parent directories) at the configured dbPath if it does not exist.
Docker volume mounting:
When running in Docker, mount a volume to the directory containing your database so it persists across container restarts. The mount path must match the dbPath value in your configuration:
docker run --rm -p 2222:2222 \
-v /path/to/local/hostkeys:/data \
-e WEBSSH2_SSH_HOSTKEY_ENABLED=true \
-e WEBSSH2_SSH_HOSTKEY_DB_PATH=/data/hostkeys.db \
ghcr.io/billchurch/webssh2:latestThe npm run hostkeys command manages the SQLite host key database. It probes remote hosts via SSH to capture their public keys and stores them for later verification.
npm run hostkeys -- --helpProbe a single host (default port 22):
npm run hostkeys -- --host ssh.example.comProbe a host on a non-standard port:
npm run hostkeys -- --host ssh.example.com --port 2222Bulk import from a hosts file (one host[:port] per line, # comments allowed):
npm run hostkeys -- --hosts servers.txtImport from an OpenSSH known_hosts file:
npm run hostkeys -- --known-hosts ~/.ssh/known_hostsList all stored keys:
npm run hostkeys -- --listRemove all keys for a host:port pair:
npm run hostkeys -- --remove ssh.example.com:22Use a custom database path:
npm run hostkeys -- --list --db /custom/path/hostkeys.dbIf --db is not specified, the script reads dbPath from config.json, falling back to /data/hostkeys.db.
The following Socket.IO events are used for host key verification. This reference is intended for CLI clients and third-party implementors integrating with the WebSSH2 WebSocket protocol.
Server to Client:
| Event | Payload | Description |
|---|---|---|
hostkey:verify |
{ host, port, algorithm, fingerprint, key } |
Server is requesting the client to verify an unknown host key. The client must respond with hostkey:verify-response. key is the base64-encoded public key; fingerprint is the SHA256:... hash. |
hostkey:verified |
{ host, port, algorithm, fingerprint, source } |
The host key was successfully verified. source is "server" or "client" indicating which store matched. Informational only; no response required. |
hostkey:mismatch |
{ host, port, algorithm, presentedFingerprint, storedFingerprint, source } |
The presented key does not match the stored key. The connection is refused. source indicates which store detected the mismatch. |
hostkey:alert |
{ host, port, algorithm, fingerprint } |
An unknown key was encountered and unknownKeyAction is set to alert. The connection proceeds. Informational only. |
hostkey:rejected |
{ host, port, algorithm, fingerprint } |
An unknown key was encountered and unknownKeyAction is set to reject. The connection is refused. |
Client to Server:
| Event | Payload | Description |
|---|---|---|
hostkey:verify-response |
{ action } |
Client response to a hostkey:verify prompt. action must be "accept", "reject", or "trusted" (key was already known to the client). If no response is received within 30 seconds, the connection is refused. |
Feature appears to have no effect:
Host key verification is disabled by default (enabled: false). Set WEBSSH2_SSH_HOSTKEY_ENABLED=true or "enabled": true in config.json to activate it.
Database not found at runtime:
The server store opens the database in read-only mode. If the file at dbPath does not exist, all lookups return "unknown" and the store operates in degraded mode. Run npm run hostkeys to create and seed the database before starting the server.
Host key mismatch:
A hostkey:mismatch event means the SSH server is presenting a different key than what is stored in the database. This can happen after a legitimate server reinstall or key rotation. To resolve:
- Verify the new key is legitimate (contact the server administrator).
- Remove the old key:
npm run hostkeys -- --remove host:port - Re-probe the host:
npm run hostkeys -- --host <hostname> --port <port>
If you receive frequent mismatches for hosts you did not change, investigate for potential MITM attacks.
Client verification times out:
When using prompt mode, the client has 30 seconds to respond to a hostkey:verify event. If the client does not respond in time, the connection is refused. Ensure the client application handles the hostkey:verify Socket.IO event.
- Development: Run
npm install(ornpm ci) and continue using scripts such asnpm run devandnpm run build. The TypeScript sources remain the source of truth. - Release pipeline: Use
npm ci --omit=dev,npm run build, thennode dist/scripts/create-release-artifact.jsto producewebssh2-<version>.tar.gz,manifest.json, and a.sha256checksum. GNU tar is required to guarantee deterministic archives. - Packaged consumers (containers, downstream services): Download and verify the tarball, extract it, run
npm ci --omit=devfrom the extracted root (alongsidepackage.json), and start withNODE_ENV=production npm start. Theprestartscript detects the precompiled bundle and skips rebuilding.
If you like what I do and want to support me, you can buy me a coffee!


