Add database-backed user management and password reset tooling.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
275 lines
7.1 KiB
Markdown
275 lines
7.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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`:
|
|
```yaml
|
|
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:
|
|
```bash
|
|
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:
|
|
```yaml
|
|
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):
|
|
```yaml
|
|
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):
|
|
```yaml
|
|
environment:
|
|
- RECORDING_ENABLED=true
|
|
- RECORDING_RETENTION_DAYS=30
|
|
```
|
|
|
|
- `RECORDING_ENABLED`: Enable/disable session recording (`true` or `false`)
|
|
- `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:
|
|
```json
|
|
{
|
|
"username": "admin",
|
|
"password": "admin"
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
|
|
"username": "admin",
|
|
"expires": "2024-01-20T12:00:00+00:00"
|
|
}
|
|
```
|
|
|
|
### POST /api/verify
|
|
Verify JWT token validity.
|
|
|
|
Request:
|
|
```json
|
|
{
|
|
"token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"valid": true,
|
|
"username": "admin"
|
|
}
|
|
```
|
|
|
|
## WebSocket Protocol
|
|
|
|
Connect to `ws://localhost:8080/ws?token=<JWT_TOKEN>`
|
|
|
|
After connection, send SSH credentials:
|
|
```json
|
|
{
|
|
"host": "192.168.1.100",
|
|
"port": 22,
|
|
"username": "root",
|
|
"password": "secret",
|
|
"key": "-----BEGIN OPENSSH PRIVATE KEY-----..."
|
|
}
|
|
```
|
|
|
|
## Reverse Proxy Configuration
|
|
|
|
### Caddy
|
|
|
|
```caddyfile
|
|
your-domain.com {
|
|
reverse_proxy localhost:8080
|
|
}
|
|
```
|
|
|
|
### Caddy
|
|
|
|
```caddyfile
|
|
{
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
docker-compose up -d --build
|
|
```
|
|
|
|
### Build for Docker Hub (Multi-arch)
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
./version-manager.sh
|
|
```
|
|
|
|
Interactive script to update version numbers across all files.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# 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
|
|
```
|