Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
WebSSH - Browser-based SSH Client
Multi-connection SSH client that runs in your browser with JWT authentication.
Features
- Multi-connection support: Manage multiple SSH connections simultaneously
- JWT Authentication: Secure login system with token-based authentication
- Password & SSH Key auth: Support for both password and SSH key authentication
- SFTP File Manager: Built-in file manager with upload/download capabilities
- Terminal emulator: Uses xterm.js for a full terminal experience
- Connection management: Sidebar with connection list, status indicators, and quick actions
- Version updates: Displays the running version and checks for a newer stable release every 24 hours, caching the response in the browser
- Remote load monitoring: Active SSH connections display the remote Linux 1/5/15-minute load average
- Session Recording: Automatic recording of SSH sessions in asciinema format with playback and configurable retention
- Dark theme: Modern dark UI design
- Single port: All services run through port 8080 (HTTP API + WebSocket)
Quick Start
1. Start the Backend
docker-compose -f deployment/docker-compose.yml up -d --build
2. Open the Client
Open http://localhost:8080 in your browser. The application is served via a Caddy reverse proxy.
3. Create the Administrator
On first start, create the administrator account in the browser. Use a password with at least 12 characters.
Configuration
Users
On a fresh installation, open the application to create the first administrator.
For an existing installation, users configured with WEBSSH_USERS are imported into the database once.
The first imported user becomes an administrator, the remaining imported users have the user role, and
each imported user must change their password at their next login. Remove WEBSSH_USERS after migration:
future user accounts are stored in the database.
To import legacy users via the environment variable in deployment/docker-compose.yml:
environment:
- WEBSSH_USERS=user1:pass1,user2:pass2
New passwords must contain at least 12 characters. Passwords are stored as salted PBKDF2-HMAC-SHA256 hashes. Administrators can create and delete accounts from Manage Users; new users must replace their temporary password at first login.
To reset an account password from a running Docker container, run the command interactively:
docker exec -it webssh-backend password-reset
The tool asks for the username (or accepts it as password-reset username), prompts for the new password without echoing it, invalidates existing sessions for that account, and requires the user to change the temporary password at their next login.
JWT Secret
Set custom JWT secret:
environment:
- JWT_SECRET=your-secret-key-here
If not set, a random secret is generated on startup.
Max Upload Size
Set maximum file upload size (default: 100MB):
environment:
- MAX_UPLOAD_SIZE=50M
Supported formats: 10M, 100MB, 1G, 1GB, or bytes as integer.
Session Recording
Configure automatic session recording (default: enabled, 30 days retention):
environment:
- RECORDING_ENABLED=true
- RECORDING_RETENTION_DAYS=30
RECORDING_ENABLED: Enable/disable session recording (trueorfalse)RECORDING_RETENTION_DAYS: Number of days to keep recordings before automatic deletion
Recordings are stored in /data/recordings/ in asciinema v2 format (gzip compressed).
Ports
8080- HTTP API and WebSocket (Caddy reverse proxy)
All traffic goes through port 8080. Caddy routes:
/ws→ WebSocket SSH server (internal port 8081)/api/→ HTTP API endpoints (internal port 8082)- Everything else → Static files (served from the repository
index.html+static/)
File Structure
web-ssh/
├── src/ # Application source code
│ ├── run.py # Backend entry point
│ ├── serve_static.py # Static file server
│ ├── index.html # Main client interface
│ ├── help.html # Help documentation
│ ├── static/ # Frontend assets
│ └── webssh_backend/ # Backend package
├── deployment/ # Docker and deployment files
│ ├── docker-compose.yml
│ ├── Dockerfile
│ ├── Caddyfile
│ ├── docker-entrypoint.sh
│ └── scripts/
├── requirements.txt # Python dependencies
├── run.py # Compatibility wrapper from repo root
├── serve_static.py # Compatibility wrapper from repo root
├── README.md # This file
└── .github/workflows/ # CI/CD
API Endpoints
POST /api/login
Login and get JWT token.
Request:
{
"username": "admin",
"password": "admin"
}
Response:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"username": "admin",
"expires": "2024-01-20T12:00:00+00:00"
}
POST /api/verify
Verify JWT token validity.
Request:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
Response:
{
"valid": true,
"username": "admin"
}
WebSocket Protocol
Connect to ws://localhost:8080/ws?token=<JWT_TOKEN>
After connection, send SSH credentials:
{
"host": "192.168.1.100",
"port": 22,
"username": "root",
"password": "secret",
"key": "-----BEGIN OPENSSH PRIVATE KEY-----..."
}
Reverse Proxy Configuration
Caddy
your-domain.com {
reverse_proxy localhost:8080
}
Caddy
{
auto_https off
}
:8080 {
handle_path /ws* {
reverse_proxy webssh:8081
}
handle_path /api/* {
reverse_proxy webssh:8082
}
route {
root * /srv
try_files {path} /index.html
file_server
}
}
Docker Hub
Pre-built multi-arch images available:
docker pull danaildr/webssh:latest
docker pull danaildr/webssh:0.6.0
Supported architectures: linux/amd64, linux/arm64, linux/arm/v7
Security Notes
- Always use HTTPS in production (configure reverse proxy with SSL)
- Create a strong administrator password during first-run setup
- Set a strong JWT_SECRET
- The backend uses
AutoAddPolicy()for SSH host keys (testing only - change for production) - Token expiry: 8 hours
- File upload limit: configurable via MAX_UPLOAD_SIZE (default 100MB)
Building and Publishing
Local Build
docker-compose up -d --build
Build for Docker Hub (Multi-arch)
docker login
./deployment/scripts/docker-build-and-push.sh --build
This builds and pushes linux/amd64, linux/arm64, and linux/arm/v7 images with tags latest and the configured version tag.
Version Management
./version-manager.sh
Interactive script to update version numbers across all files.
Development
# Install dependencies
pip install -r requirements.txt
# Run backend directly (for development)
python start_backend.py
# Note: When running directly, services use internal ports:
# - WebSocket SSH: port 8081
# - HTTP API: port 8082
# - WebSocket SFTP: port 8083
#
# Use docker-compose for production deployment with Caddy on port 8080