Some checks failed
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
277 lines
8.0 KiB
Markdown
277 lines
8.0 KiB
Markdown
# SSH Web Terminal Feature
|
|
|
|
This document describes the SSH web terminal feature integrated into the Homelab Dashboard.
|
|
|
|
## Overview
|
|
|
|
The SSH Web Terminal allows users to connect to bootstrapped hosts directly from the web interface using [ttyd](https://github.com/tsl0922/ttyd) as the terminal emulator backend.
|
|
|
|
## Features
|
|
|
|
- **Embedded Terminal**: Opens in a slide-over drawer panel within the Hosts page
|
|
- **Pop-out Terminal**: Opens in a standalone window (or new tab if popups are blocked)
|
|
- **Session Management**: Automatic expiration, session limits per user
|
|
- **Security**: Token-based authentication, no SSH keys exposed to browser
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Web Browser │────▶│ FastAPI │────▶│ ttyd Process │
|
|
│ (iframe) │ │ Backend │ │ (per session) │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
│ │
|
|
│ ▼
|
|
│ ┌─────────────────┐
|
|
│ │ SSH Client │
|
|
│ │ automation@ │
|
|
│ │ <host> │
|
|
│ └─────────────────┘
|
|
▼
|
|
┌─────────────────┐
|
|
│ SQLite DB │
|
|
│ (sessions) │
|
|
└─────────────────┘
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
### 1. Install ttyd
|
|
|
|
#### Linux (Debian/Ubuntu)
|
|
```bash
|
|
sudo apt-get install ttyd
|
|
```
|
|
|
|
#### Linux (from source)
|
|
```bash
|
|
git clone https://github.com/tsl0922/ttyd.git
|
|
cd ttyd && mkdir build && cd build
|
|
cmake ..
|
|
make && sudo make install
|
|
```
|
|
|
|
#### macOS
|
|
```bash
|
|
brew install ttyd
|
|
```
|
|
|
|
#### Windows (WSL)
|
|
```bash
|
|
sudo apt-get install ttyd
|
|
```
|
|
|
|
#### Docker
|
|
ttyd can also be run via Docker, but the current implementation spawns ttyd processes directly.
|
|
|
|
### 2. SSH Key Configuration
|
|
|
|
Hosts must be bootstrapped with the `automation` user and SSH key configured. The bootstrap process:
|
|
1. Creates the `automation` user on the target host
|
|
2. Deploys SSH public key for passwordless authentication
|
|
3. Configures sudo without password for the automation user
|
|
|
|
### 3. Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `TERMINAL_SESSION_TTL_MINUTES` | `30` | Session timeout in minutes |
|
|
| `TERMINAL_MAX_SESSIONS_PER_USER` | `3` | Maximum concurrent sessions per user |
|
|
| `TERMINAL_PORT_RANGE_START` | `7680` | First port for ttyd instances |
|
|
| `TERMINAL_PORT_RANGE_END` | `7700` | Last port for ttyd instances |
|
|
| `TERMINAL_SSH_USER` | `automation` | SSH username for connections |
|
|
| `TTYD_PATH` | `ttyd` | Path to ttyd binary |
|
|
|
|
## API Endpoints
|
|
|
|
### Check Terminal Feature Status
|
|
```http
|
|
GET /api/terminal/status
|
|
```
|
|
Returns whether ttyd is installed and terminal feature is available.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"available": true,
|
|
"ttyd_installed": true,
|
|
"max_sessions_per_user": 3,
|
|
"session_ttl_minutes": 30,
|
|
"active_sessions": 2
|
|
}
|
|
```
|
|
|
|
### Create Terminal Session
|
|
```http
|
|
POST /api/terminal/{host_id}/terminal-sessions
|
|
Authorization: Bearer <token>
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"mode": "embedded" // or "popout"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"session_id": "abc123...",
|
|
"url": "/terminal/connect/abc123...?token=xyz...",
|
|
"websocket_url": "ws://localhost:7680/ws",
|
|
"expires_at": "2024-12-17T20:00:00Z",
|
|
"ttl_seconds": 1800,
|
|
"mode": "embedded",
|
|
"host": {
|
|
"id": "host-id",
|
|
"name": "server01",
|
|
"ip": "192.168.1.100",
|
|
"status": "online",
|
|
"bootstrap_ok": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### List Active Sessions
|
|
```http
|
|
GET /api/terminal/sessions
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
### Close Terminal Session
|
|
```http
|
|
DELETE /api/terminal/sessions/{session_id}
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
### Connect to Terminal
|
|
```http
|
|
GET /api/terminal/connect/{session_id}?token=<session_token>
|
|
```
|
|
Returns HTML page with embedded terminal iframe.
|
|
|
|
## Security Considerations
|
|
|
|
### Authentication
|
|
- All API endpoints require JWT Bearer token authentication
|
|
- Session tokens are generated per-session and hashed before storage
|
|
- Token verification on every terminal page load
|
|
|
|
### Session Isolation
|
|
- Each terminal session spawns a dedicated ttyd process
|
|
- ttyd uses `--once` flag to exit after client disconnects
|
|
- Sessions are bound to specific users
|
|
|
|
### Rate Limiting
|
|
- Maximum sessions per user (default: 3)
|
|
- Session TTL prevents resource exhaustion
|
|
- Expired sessions are automatically cleaned up
|
|
|
|
### Audit Logging
|
|
- Session creation logged with user and host info
|
|
- Session closure logged
|
|
- No sensitive data (tokens, keys) in logs
|
|
|
|
### SSH Security
|
|
- SSH keys never exposed to browser
|
|
- `StrictHostKeyChecking=accept-new` for initial connections
|
|
- Uses dedicated `automation` user with limited sudo
|
|
|
|
## UI Components
|
|
|
|
### Terminal Button (Host Card)
|
|
- **Enabled**: When host is online AND bootstrap OK
|
|
- **Disabled**: When host is offline OR bootstrap not completed
|
|
- Shows tooltip explaining why disabled
|
|
|
|
### Terminal Drawer
|
|
- Slides in from right side of screen
|
|
- Header: Host name, IP, connection status
|
|
- Body: Embedded ttyd iframe
|
|
- Footer: SSH command copy, reconnect, session timer
|
|
- Close with Escape key or X button
|
|
|
|
### Pop-out Window
|
|
- Opens in new window with minimal UI
|
|
- Fullscreen terminal experience
|
|
- PWA hint for toolbar-free experience
|
|
|
|
## Troubleshooting
|
|
|
|
### "ttyd is not installed"
|
|
Install ttyd using the instructions above. Verify with:
|
|
```bash
|
|
which ttyd
|
|
ttyd --version
|
|
```
|
|
|
|
### "Host not bootstrapped"
|
|
Run bootstrap on the host first:
|
|
1. Go to Hosts section
|
|
2. Click "Bootstrap" button on the target host
|
|
3. Enter root password when prompted
|
|
4. Wait for bootstrap to complete
|
|
|
|
### "Maximum sessions reached"
|
|
Close existing terminal sessions before opening new ones.
|
|
|
|
### Pop-up blocked
|
|
If the browser blocks the pop-out window, the terminal will open in a new tab instead.
|
|
|
|
### Session expired
|
|
Click "Reconnect" button to create a new session.
|
|
|
|
## PWA / Toolbar-free Window
|
|
|
|
Modern browsers don't allow complete removal of the URL bar via `window.open()`. To get a true "app-like" experience:
|
|
|
|
### Option 1: Chrome/Edge App Mode
|
|
Create a shortcut with:
|
|
```bash
|
|
chrome --app=https://your-dashboard.com/terminal/connect/SESSION_ID?token=TOKEN
|
|
```
|
|
|
|
### Option 2: Install as PWA
|
|
1. Open the dashboard in Chrome/Edge
|
|
2. Click the install icon in the address bar
|
|
3. Launch terminals from the installed PWA
|
|
|
|
## Database Schema
|
|
|
|
```sql
|
|
CREATE TABLE terminal_sessions (
|
|
id VARCHAR(64) PRIMARY KEY,
|
|
host_id VARCHAR NOT NULL,
|
|
host_name VARCHAR NOT NULL,
|
|
host_ip VARCHAR NOT NULL,
|
|
user_id VARCHAR,
|
|
username VARCHAR,
|
|
token_hash VARCHAR(128) NOT NULL,
|
|
ttyd_port INTEGER NOT NULL,
|
|
ttyd_pid INTEGER,
|
|
mode VARCHAR(20) DEFAULT 'embedded',
|
|
status VARCHAR(20) DEFAULT 'active',
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
closed_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
```
|
|
|
|
## Files
|
|
|
|
### Backend
|
|
- `app/models/terminal_session.py` - SQLAlchemy model
|
|
- `app/schemas/terminal.py` - Pydantic schemas
|
|
- `app/crud/terminal_session.py` - Database operations
|
|
- `app/services/terminal_service.py` - ttyd process management
|
|
- `app/routes/terminal.py` - API endpoints
|
|
|
|
### Frontend
|
|
- `app/main.js` - Terminal methods in DashboardManager
|
|
- `app/index.html` - CSS styles for terminal drawer
|
|
|
|
### Migration
|
|
- `alembic/versions/0013_add_terminal_sessions_table.py`
|
|
|
|
### Tests
|
|
- `tests/backend/test_terminal.py`
|