Complete API reference for the Web CLI application. All endpoints return JSON responses unless otherwise specified.
- Quick Reference
- Authentication
- Health Check
- SSH Keys Management
- Server Management
- Local Users Management
- System Information
- Command Execution
- Saved Commands Management
- Command History
- Environment Variables Management
- Bash Scripts Management
- Script Presets Management
- Vault Integration
- Interactive Terminal
- Error Responses
- Security Considerations
http://localhost:7777/api
Default port is 7777, configurable via -port flag or PORT environment variable.
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Server health check |
/keys |
GET | List all SSH keys |
/keys |
POST | Create SSH key |
/keys/{id} |
GET | Get single SSH key |
/keys/{id} |
PUT | Update SSH key |
/keys/{id} |
DELETE | Delete SSH key |
/servers |
GET | List all servers |
/servers |
POST | Create server |
/servers/{id} |
GET | Get single server |
/servers/{id} |
PUT | Update server |
/servers/{id} |
DELETE | Delete server |
/local-users |
GET | List all local users |
/local-users |
POST | Create local user |
/local-users/{id} |
GET | Get single local user |
/local-users/{id} |
PUT | Update local user |
/local-users/{id} |
DELETE | Delete local user |
/system/current-user |
GET | Get current system user |
/terminal/ws |
WS | Interactive terminal (WebSocket) |
/commands/execute |
POST | Execute command (local/remote) |
/saved-commands |
GET | List all saved commands |
/saved-commands |
POST | Create saved command |
/saved-commands/{id} |
GET | Get single saved command |
/saved-commands/{id} |
PUT | Update saved command |
/saved-commands/{id} |
DELETE | Delete saved command |
/history |
GET | List command history |
/history/{id} |
GET | Get single history entry |
/env-variables |
GET | List all environment variables |
/env-variables |
POST | Create environment variable |
/env-variables/{id} |
GET | Get single environment variable |
/env-variables/{id} |
PUT | Update environment variable |
/env-variables/{id} |
DELETE | Delete environment variable |
/bash-scripts |
GET | List all bash scripts |
/bash-scripts |
POST | Create bash script |
/bash-scripts/{id} |
GET | Get single bash script |
/bash-scripts/{id} |
PUT | Update bash script |
/bash-scripts/{id} |
DELETE | Delete bash script |
/bash-scripts/execute |
POST | Execute a bash script |
/bash-scripts/{id}/presets |
GET | Get presets for a script |
/script-presets |
GET | List all script presets |
/script-presets |
POST | Create script preset |
/script-presets/{id} |
GET | Get single script preset |
/script-presets/{id} |
PUT | Update script preset |
/script-presets/{id} |
DELETE | Delete script preset |
/vault/config |
GET | Get Vault configuration |
/vault/config |
POST | Create/update Vault configuration |
/vault/config |
DELETE | Delete Vault configuration |
/vault/status |
GET | Get Vault connection status |
/vault/test |
POST | Test Vault connection |
/vault/ssh-keys |
GET | List SSH keys from Vault |
/vault/ssh-keys |
POST | Create SSH key in Vault |
/vault/servers |
GET | List servers from Vault |
/vault/servers |
POST | Create server in Vault |
/vault/env-variables |
GET | List environment variables from Vault |
/vault/env-variables |
POST | Create environment variable in Vault |
/vault/bash-scripts |
GET | List bash scripts from Vault |
/vault/bash-scripts |
POST | Create bash script in Vault |
Authentication is disabled by default for development convenience. In production, enable authentication using environment variables.
# Enable authentication
export AUTH_ENABLED=true
# Option 1: HTTP Basic Authentication
export AUTH_USERNAME="admin"
export AUTH_PASSWORD="your-secure-password"
# Option 2: API Token (Bearer)
export AUTH_API_TOKEN="your-api-token-here"HTTP Basic Auth:
curl -u admin:password http://localhost:7777/api/keysBearer Token:
curl -H "Authorization: Bearer your-token" http://localhost:7777/api/keysThe /api/health endpoint is exempt from authentication to allow Docker health checks, Kubernetes probes, and load balancer monitoring to work without credentials.
- Constant-time credential comparison (prevents timing attacks)
- Supports both Basic Auth and Bearer token simultaneously
- Bearer token takes precedence if both are provided
- bcrypt password hashing for stored credentials
- Health endpoint excluded from auth for container orchestration compatibility
Note: In production environments, always enable authentication and use HTTPS.
Check if the server is running and responsive. This endpoint does not require authentication, making it suitable for Docker health checks, Kubernetes probes, and load balancer health monitoring.
Endpoint: GET /health
Authentication: None required
Response: 200 OK
{
"status": "ok"
}Example:
# No authentication needed
curl http://localhost:7777/api/health
# Also works with HTTPS when TLS is enabled
curl -k https://localhost:7777/api/healthManage SSH private keys used for remote server authentication. All keys are encrypted with AES-256-GCM before storage.
Retrieve all stored SSH keys.
Endpoint: GET /keys
Response: 200 OK
[
{
"id": 1,
"name": "production-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "dev-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----",
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
curl http://localhost:7777/api/keysRetrieve a specific SSH key by ID.
Endpoint: GET /keys/{id}
Path Parameters:
id(integer, required): SSH key ID
Response: 200 OK
{
"id": 1,
"name": "production-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: SSH key not found
Example:
curl http://localhost:7777/api/keys/1Add a new SSH private key to the system.
Endpoint: POST /keys
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "new-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----"
}Fields:
name(string, required): Descriptive name for the SSH keyprivate_key(string, required): PEM-encoded SSH private key
Response: 201 Created
{
"id": 3,
"name": "new-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or missing required fields
Example:
curl -X POST http://localhost:7777/api/keys \
-H "Content-Type: application/json" \
-d '{
"name": "new-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----"
}'Update an existing SSH key.
Endpoint: PUT /keys/{id}
Path Parameters:
id(integer, required): SSH key ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "updated-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----"
}Fields:
name(string, required): Updated name for the SSH keyprivate_key(string, required): Updated PEM-encoded SSH private key
Response: 200 OK
{
"id": 1,
"name": "updated-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz...\n-----END OPENSSH PRIVATE KEY-----",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-11T11:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body404 Not Found: SSH key not found
Example:
curl -X PUT http://localhost:7777/api/keys/1 \
-H "Content-Type: application/json" \
-d '{
"name": "updated-server-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----"
}'Delete an SSH key from the system.
Endpoint: DELETE /keys/{id}
Path Parameters:
id(integer, required): SSH key ID
Response: 204 No Content
Error Responses:
404 Not Found: SSH key not found
Example:
curl -X DELETE http://localhost:7777/api/keys/1Manage remote servers for SSH connections.
Retrieve all configured servers.
Endpoint: GET /servers
Response: 200 OK
[
{
"id": 1,
"name": "production-server",
"ip_address": "192.168.1.100",
"port": 22,
"username": "admin",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "dev-server",
"ip_address": "192.168.1.101",
"port": 2222,
"username": "ubuntu",
"created_at": "2025-11-10T12:05:00Z",
"updated_at": "2025-11-10T12:05:00Z"
}
]Example:
curl http://localhost:7777/api/serversRetrieve a specific server by ID.
Endpoint: GET /servers/{id}
Path Parameters:
id(integer, required): Server ID
Response: 200 OK
{
"id": 1,
"name": "production-server",
"ip_address": "192.168.1.100",
"port": 22,
"username": "admin",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Server not found
Example:
curl http://localhost:7777/api/servers/1Add a new server configuration.
Endpoint: POST /servers
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "staging-server",
"ip_address": "192.168.1.102",
"port": 22,
"username": "deploy"
}Fields:
name(string, optional): Descriptive server name (must follow hostname conventions if provided)ip_address(string, optional): Server IP address or hostnameport(integer, optional): SSH port number (default: 22)username(string, optional): SSH username (default: "root")
Note: At least one of name or ip_address must be provided.
Response: 201 Created
{
"id": 3,
"name": "staging-server",
"ip_address": "192.168.1.102",
"port": 22,
"username": "deploy",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or validation error
Example:
curl -X POST http://localhost:7777/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "staging-server",
"ip_address": "192.168.1.102",
"port": 22,
"username": "deploy"
}'Update an existing server configuration.
Endpoint: PUT /servers/{id}
Path Parameters:
id(integer, required): Server ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "production-server-updated",
"ip_address": "192.168.1.100",
"port": 2222,
"username": "root"
}Fields: All fields are optional; only provided fields will be updated.
Response: 200 OK
{
"id": 1,
"name": "production-server-updated",
"ip_address": "192.168.1.100",
"port": 2222,
"username": "root",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-11T11:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body404 Not Found: Server not found
Example:
curl -X PUT http://localhost:7777/api/servers/1 \
-H "Content-Type: application/json" \
-d '{
"port": 2222
}'Delete a server configuration.
Endpoint: DELETE /servers/{id}
Path Parameters:
id(integer, required): Server ID
Response: 204 No Content
Error Responses:
404 Not Found: Server not found
Example:
curl -X DELETE http://localhost:7777/api/servers/1Manage local user accounts that can be used for command execution.
Retrieve all stored local users.
Endpoint: GET /local-users
Response: 200 OK
[
{
"id": 1,
"name": "admin",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "deploy",
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
curl http://localhost:7777/api/local-usersRetrieve a specific local user by ID.
Endpoint: GET /local-users/{id}
Path Parameters:
id(integer, required): Local user ID
Response: 200 OK
{
"id": 1,
"name": "admin",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Local user not found
Example:
curl http://localhost:7777/api/local-users/1Add a new local user to the system.
Endpoint: POST /local-users
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "jenkins"
}Fields:
name(string, required): Username (must be unique)
Response: 201 Created
{
"id": 3,
"name": "jenkins",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or duplicate username
Example:
curl -X POST http://localhost:7777/api/local-users \
-H "Content-Type: application/json" \
-d '{
"name": "jenkins"
}'Update an existing local user.
Endpoint: PUT /local-users/{id}
Path Parameters:
id(integer, required): Local user ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "jenkins-updated"
}Response: 200 OK
{
"id": 3,
"name": "jenkins-updated",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T11:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body404 Not Found: Local user not found
Example:
curl -X PUT http://localhost:7777/api/local-users/3 \
-H "Content-Type: application/json" \
-d '{
"name": "jenkins-updated"
}'Delete a local user from the system.
Endpoint: DELETE /local-users/{id}
Path Parameters:
id(integer, required): Local user ID
Response: 204 No Content
Error Responses:
404 Not Found: Local user not found
Example:
curl -X DELETE http://localhost:7777/api/local-users/3Retrieve system information about the server running the application.
Retrieve information about the user running the Web CLI application.
Endpoint: GET /system/current-user
Response: 200 OK
{
"username": "jdoe",
"uid": "1000",
"gid": "1000",
"name": "John Doe",
"home_dir": "/home/jdoe"
}Fields:
username(string): System usernameuid(string): User IDgid(string): Group IDname(string): Full namehome_dir(string): Home directory path
Example:
curl http://localhost:7777/api/system/current-userExecute commands locally or on remote servers via SSH.
Execute a bash command either locally or on a remote server.
Endpoint: POST /commands/execute
Request Headers:
Content-Type: application/json
Request Body (Local Execution):
{
"command": "ls -la /tmp",
"user": "root",
"sudo_password": "your-sudo-password",
"save_as": "list-tmp"
}Request Body (Remote Execution):
{
"command": "uptime",
"user": "root",
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"ssh_password": "fallback-password-if-needed",
"save_as": "check-uptime"
}Fields:
command(string, required): Bash command to executeuser(string, optional): User to run as (root,current, or custom username). Default:"root"sudo_password(string, optional): Sudo password for local root executionssh_password(string, optional): SSH password for remote execution (fallback if key auth fails). Never stored in historyis_remote(boolean, optional): Set totruefor remote execution. Default:falseserver_id(integer, optional): Server ID for remote execution (required ifis_remoteistrue)ssh_key_id(integer, optional): SSH key ID for remote authentication (optional)save_as(string, optional): Save command as template with this name
Response: 200 OK
{
"command": "uptime",
"output": " 13:46:21 up 5 days, 3:21, 2 users, load average: 0.52, 0.58, 0.59",
"exit_code": 0,
"user": "root",
"execution_time_ms": 245,
"executed_at": "2025-11-11T13:46:21Z"
}Fields:
command(string): Executed commandoutput(string): Combined stdout and stderr outputexit_code(integer): Command exit code (0 = success)user(string): User who executed the commandexecution_time_ms(integer): Execution time in millisecondsexecuted_at(string): Timestamp of execution (ISO 8601 format)
Error Responses:
400 Bad Request: Invalid request body or missing required fields404 Not Found: Server or SSH key not found (for remote execution)500 Internal Server Error: Command execution failed
Security Notes:
- Commands are automatically saved to history
- SSH passwords are NEVER stored in history (security feature)
- Sudo passwords are required for local root execution
- SSH key authentication is preferred over password authentication
Example (Local):
curl -X POST http://localhost:7777/api/commands/execute \
-H "Content-Type: application/json" \
-d '{
"command": "whoami",
"user": "current"
}'Example (Remote with SSH Key):
curl -X POST http://localhost:7777/api/commands/execute \
-H "Content-Type: application/json" \
-d '{
"command": "df -h",
"user": "root",
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2
}'Example (Remote with Password Fallback):
curl -X POST http://localhost:7777/api/commands/execute \
-H "Content-Type: application/json" \
-d '{
"command": "uptime",
"user": "admin",
"is_remote": true,
"server_id": 1,
"ssh_password": "secure-password"
}'Manage reusable command templates for both local and remote execution.
Retrieve all saved command templates.
Endpoint: GET /saved-commands
Response: 200 OK
[
{
"id": 1,
"name": "check-disk-space",
"command": "df -h",
"description": "Check disk space usage",
"user": "root",
"is_remote": false,
"server_id": null,
"ssh_key_id": null,
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "remote-uptime",
"command": "uptime",
"description": "Check server uptime",
"user": "admin",
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
curl http://localhost:7777/api/saved-commandsRetrieve a specific saved command by ID.
Endpoint: GET /saved-commands/{id}
Path Parameters:
id(integer, required): Saved command ID
Response: 200 OK
{
"id": 1,
"name": "check-disk-space",
"command": "df -h",
"description": "Check disk space usage",
"user": "root",
"is_remote": false,
"server_id": null,
"ssh_key_id": null,
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Saved command not found
Example:
curl http://localhost:7777/api/saved-commands/1Create a new saved command template.
Endpoint: POST /saved-commands
Request Headers:
Content-Type: application/json
Request Body (Local Command):
{
"name": "list-processes",
"command": "ps aux",
"description": "List all running processes",
"user": "root"
}Request Body (Remote Command):
{
"name": "remote-memory-check",
"command": "free -h",
"description": "Check memory usage on remote server",
"user": "admin",
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2
}Fields:
name(string, required): Descriptive name for the commandcommand(string, required): Bash command to executedescription(string, optional): Additional descriptionuser(string, optional): User to run as. Default:"root"is_remote(boolean, optional): Whether this is a remote command. Default:falseserver_id(integer, optional): Server ID for remote commandsssh_key_id(integer, optional): SSH key ID for remote authentication
Response: 201 Created
{
"id": 3,
"name": "list-processes",
"command": "ps aux",
"description": "List all running processes",
"user": "root",
"is_remote": false,
"server_id": null,
"ssh_key_id": null,
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or missing required fields
Example:
curl -X POST http://localhost:7777/api/saved-commands \
-H "Content-Type: application/json" \
-d '{
"name": "list-processes",
"command": "ps aux",
"description": "List all running processes",
"user": "root"
}'Update an existing saved command template.
Endpoint: PUT /saved-commands/{id}
Path Parameters:
id(integer, required): Saved command ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "updated-command-name",
"command": "df -h /",
"description": "Updated description",
"user": "admin"
}Fields: All fields are optional; only provided fields will be updated.
Response: 200 OK
{
"id": 1,
"name": "updated-command-name",
"command": "df -h /",
"description": "Updated description",
"user": "admin",
"is_remote": false,
"server_id": null,
"ssh_key_id": null,
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-11T11:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body404 Not Found: Saved command not found
Example:
curl -X PUT http://localhost:7777/api/saved-commands/1 \
-H "Content-Type: application/json" \
-d '{
"description": "Updated description"
}'Delete a saved command template.
Endpoint: DELETE /saved-commands/{id}
Path Parameters:
id(integer, required): Saved command ID
Response: 204 No Content
Error Responses:
404 Not Found: Saved command not found
Example:
curl -X DELETE http://localhost:7777/api/saved-commands/1View execution history for all commands (local and remote).
Retrieve command execution history.
Endpoint: GET /history
Query Parameters:
limit(integer, optional): Maximum number of results to return. Default: 100offset(integer, optional): Number of results to skip. Default: 0server(string, optional): Filter by server name (e.g., "local", "production-server")
Response: 200 OK
[
{
"id": 1,
"command": "ls -la /tmp",
"output": "total 0\ndrwxrwxrwt 10 root wheel 320 Nov 11 12:00 .\ndrwxr-xr-x 20 root wheel 640 Nov 11 10:00 ..\n",
"exit_code": 0,
"server": "local",
"user": "root",
"execution_time_ms": 12,
"executed_at": "2025-11-11T12:00:00Z"
},
{
"id": 2,
"command": "uptime",
"output": " 13:46:21 up 5 days, 3:21, 2 users, load average: 0.52, 0.58, 0.59",
"exit_code": 0,
"server": "production-server",
"user": "admin",
"execution_time_ms": 245,
"executed_at": "2025-11-11T13:46:21Z"
}
]Fields:
id(integer): History entry IDcommand(string): Executed command (encrypted in database)output(string): Command output (encrypted in database)exit_code(integer): Exit code (0 = success)server(string): Server name or "local" for local commandsuser(string): User who executed the commandexecution_time_ms(integer): Execution time in millisecondsexecuted_at(string): Timestamp of execution (ISO 8601 format)
Example:
# Get all history
curl http://localhost:7777/api/history
# Get first 10 entries
curl "http://localhost:7777/api/history?limit=10"
# Get local commands only
curl "http://localhost:7777/api/history?server=local"
# Pagination
curl "http://localhost:7777/api/history?limit=20&offset=40"Retrieve a specific history entry by ID.
Endpoint: GET /history/{id}
Path Parameters:
id(integer, required): History entry ID
Response: 200 OK
{
"id": 1,
"command": "ls -la /tmp",
"output": "total 0\ndrwxrwxrwt 10 root wheel 320 Nov 11 12:00 .\ndrwxr-xr-x 20 root wheel 640 Nov 11 10:00 ..\n",
"exit_code": 0,
"server": "local",
"user": "root",
"execution_time_ms": 12,
"executed_at": "2025-11-11T12:00:00Z"
}Error Responses:
404 Not Found: History entry not found
Example:
curl http://localhost:7777/api/history/1Manage encrypted environment variables that can be injected into script executions. All values are encrypted with AES-256-GCM before storage.
Retrieve all stored environment variables. Values are masked by default for security.
Endpoint: GET /env-variables
Query Parameters:
show_values(boolean, optional): Set totrueto show actual values. Default:false
Response: 200 OK
[
{
"id": 1,
"name": "API_KEY",
"value": "••••••••",
"description": "External API key",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "DATABASE_URL",
"value": "••••••••",
"description": "Database connection string",
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
# List with masked values
curl http://localhost:7777/api/env-variables
# List with actual values
curl "http://localhost:7777/api/env-variables?show_values=true"Retrieve a specific environment variable by ID.
Endpoint: GET /env-variables/{id}
Path Parameters:
id(integer, required): Environment variable ID
Query Parameters:
show_value(boolean, optional): Set totrueto show actual value. Default:false
Response: 200 OK
{
"id": 1,
"name": "API_KEY",
"value": "sk-1234567890abcdef",
"description": "External API key",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Environment variable not found
Example:
curl "http://localhost:7777/api/env-variables/1?show_value=true"Add a new encrypted environment variable.
Endpoint: POST /env-variables
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "SECRET_TOKEN",
"value": "super-secret-value-123",
"description": "Authentication token for external service"
}Fields:
name(string, required): Variable name (e.g.,API_KEY,DATABASE_URL)value(string, required): Variable value (will be encrypted)description(string, optional): Description of the variable
Response: 201 Created
{
"id": 3,
"name": "SECRET_TOKEN",
"value": "••••••••",
"description": "Authentication token for external service",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or missing required fields
Example:
curl -X POST http://localhost:7777/api/env-variables \
-H "Content-Type: application/json" \
-d '{
"name": "SECRET_TOKEN",
"value": "super-secret-value-123",
"description": "Authentication token"
}'Update an existing environment variable.
Endpoint: PUT /env-variables/{id}
Path Parameters:
id(integer, required): Environment variable ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "UPDATED_TOKEN",
"value": "new-secret-value",
"description": "Updated description"
}Fields: All fields are optional; only provided fields will be updated.
Response: 200 OK
Error Responses:
400 Bad Request: Invalid request body404 Not Found: Environment variable not found
Example:
curl -X PUT http://localhost:7777/api/env-variables/1 \
-H "Content-Type: application/json" \
-d '{
"value": "new-secret-value"
}'Delete an environment variable from the system.
Endpoint: DELETE /env-variables/{id}
Path Parameters:
id(integer, required): Environment variable ID
Response: 204 No Content
Error Responses:
404 Not Found: Environment variable not found
Example:
curl -X DELETE http://localhost:7777/api/env-variables/1Manage stored bash scripts that can be executed locally or remotely. Script content is encrypted with AES-256-GCM before storage.
Retrieve all stored bash scripts. Script content is not included in list view for performance.
Endpoint: GET /bash-scripts
Response: 200 OK
[
{
"id": 1,
"name": "deploy-app",
"description": "Deploy application to production",
"content": "",
"filename": "deploy.sh",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "backup-database",
"description": "Backup PostgreSQL database",
"content": "",
"filename": "backup.sh",
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
curl http://localhost:7777/api/bash-scriptsRetrieve a specific bash script by ID, including full content.
Endpoint: GET /bash-scripts/{id}
Path Parameters:
id(integer, required): Bash script ID
Response: 200 OK
{
"id": 1,
"name": "deploy-app",
"description": "Deploy application to production",
"content": "#!/bin/bash\nset -e\n\necho \"Deploying...\"\ncd /opt/app\ngit pull origin main\nsystemctl restart app\necho \"Done!\"",
"filename": "deploy.sh",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Bash script not found
Example:
curl http://localhost:7777/api/bash-scripts/1Add a new bash script to the system.
Endpoint: POST /bash-scripts
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "system-check",
"description": "Check system health",
"content": "#!/bin/bash\nset -e\necho \"CPU Usage:\"\ntop -bn1 | head -5\necho \"\\nDisk Usage:\"\ndf -h\necho \"\\nMemory:\"\nfree -h",
"filename": "system-check.sh"
}Fields:
name(string, required): Display name for the scriptcontent(string, required): Bash script contentdescription(string, optional): Description of what the script doesfilename(string, optional): Original filename if uploaded
Response: 201 Created
{
"id": 3,
"name": "system-check",
"description": "Check system health",
"content": "#!/bin/bash\nset -e\n...",
"filename": "system-check.sh",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or missing required fields
Example:
curl -X POST http://localhost:7777/api/bash-scripts \
-H "Content-Type: application/json" \
-d '{
"name": "system-check",
"description": "Check system health",
"content": "#!/bin/bash\necho \"Hello World\""
}'Update an existing bash script.
Endpoint: PUT /bash-scripts/{id}
Path Parameters:
id(integer, required): Bash script ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "updated-script-name",
"description": "Updated description",
"content": "#!/bin/bash\necho \"Updated script\""
}Fields: All fields are optional; only provided fields will be updated.
Response: 200 OK
Error Responses:
400 Bad Request: Invalid request body404 Not Found: Bash script not found
Example:
curl -X PUT http://localhost:7777/api/bash-scripts/1 \
-H "Content-Type: application/json" \
-d '{
"description": "Updated description"
}'Delete a bash script from the system.
Endpoint: DELETE /bash-scripts/{id}
Path Parameters:
id(integer, required): Bash script ID
Response: 204 No Content
Error Responses:
404 Not Found: Bash script not found
Example:
curl -X DELETE http://localhost:7777/api/bash-scripts/1Execute a stored bash script locally or on a remote server, optionally injecting environment variables.
Endpoint: POST /bash-scripts/execute
Request Headers:
Content-Type: application/json
Request Body (Local Execution):
{
"script_id": 1,
"user": "root",
"sudo_password": "your-sudo-password",
"env_var_ids": [1, 2, 3]
}Request Body (Remote Execution):
{
"script_id": 1,
"user": "admin",
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"ssh_password": "fallback-password",
"env_var_ids": [1, 2]
}Fields:
script_id(integer, required): ID of the script to executeuser(string, optional): User to run as. Default:"root"sudo_password(string, optional): Sudo password for local root executionssh_password(string, optional): SSH password fallback for remote executionis_remote(boolean, optional): Set totruefor remote execution. Default:falseserver_id(integer, optional): Server ID for remote executionssh_key_id(integer, optional): SSH key ID for remote authenticationenv_var_ids(array of integers, optional): Environment variable IDs to inject
Response: 200 OK
{
"script_id": 1,
"script_name": "deploy-app",
"output": "Deploying...\nDone!",
"exit_code": 0,
"user": "root",
"server": "local",
"execution_time_ms": 1234,
"env_vars_injected": 3
}Fields:
script_id(integer): ID of executed scriptscript_name(string): Name of executed scriptoutput(string): Combined stdout and stderr outputexit_code(integer): Exit code (0 = success)user(string): User who executed the scriptserver(string): "local" or server name for remote executionexecution_time_ms(integer): Execution time in millisecondsenv_vars_injected(integer): Number of environment variables injected
Error Responses:
400 Bad Request: Invalid request body or missing required fields404 Not Found: Script, server, or SSH key not found500 Internal Server Error: Script execution failed
Example (Local with Env Vars):
curl -X POST http://localhost:7777/api/bash-scripts/execute \
-H "Content-Type: application/json" \
-d '{
"script_id": 1,
"user": "root",
"env_var_ids": [1, 2]
}'Example (Remote Execution):
curl -X POST http://localhost:7777/api/bash-scripts/execute \
-H "Content-Type: application/json" \
-d '{
"script_id": 1,
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"env_var_ids": [1]
}'Retrieve all presets associated with a specific script.
Endpoint: GET /bash-scripts/{id}/presets
Path Parameters:
id(integer, required): Bash script ID
Response: 200 OK
[
{
"id": 1,
"name": "Production Deploy",
"description": "Deploy to production server",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"user": "deploy",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}
]Error Responses:
404 Not Found: Script not found
Example:
curl http://localhost:7777/api/bash-scripts/1/presetsManage saved script execution configurations. Presets store which environment variables to inject and optionally remote execution settings.
Retrieve all stored script presets.
Endpoint: GET /script-presets
Response: 200 OK
[
{
"id": 1,
"name": "Production Deploy",
"description": "Deploy to production server",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"user": "deploy",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
},
{
"id": 2,
"name": "Local Test",
"description": "Run script locally for testing",
"script_id": 1,
"env_var_ids": [3],
"is_remote": false,
"server_id": null,
"ssh_key_id": null,
"user": "current",
"created_at": "2025-11-10T13:00:00Z",
"updated_at": "2025-11-10T13:00:00Z"
}
]Example:
curl http://localhost:7777/api/script-presetsRetrieve a specific script preset by ID.
Endpoint: GET /script-presets/{id}
Path Parameters:
id(integer, required): Script preset ID
Response: 200 OK
{
"id": 1,
"name": "Production Deploy",
"description": "Deploy to production server",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 1,
"ssh_key_id": 2,
"user": "deploy",
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}Error Responses:
404 Not Found: Script preset not found
Example:
curl http://localhost:7777/api/script-presets/1Create a new script execution preset.
Endpoint: POST /script-presets
Request Headers:
Content-Type: application/json
Request Body (Local Preset):
{
"name": "Local Dev Test",
"description": "Run locally with dev environment",
"script_id": 1,
"env_var_ids": [1, 3],
"is_remote": false,
"user": "current"
}Request Body (Remote Preset):
{
"name": "Staging Deploy",
"description": "Deploy to staging server",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 2,
"ssh_key_id": 1,
"user": "deploy"
}Fields:
name(string, required): Display name for the presetscript_id(integer, required): ID of the associated bash scriptdescription(string, optional): Description of the presetenv_var_ids(array of integers, optional): Environment variable IDs to injectis_remote(boolean, optional): Whether this is for remote execution. Default:falseserver_id(integer, optional): Server ID for remote executionssh_key_id(integer, optional): SSH key ID for remote authenticationuser(string, optional): User to run as. Default:"root"
Response: 201 Created
{
"id": 3,
"name": "Staging Deploy",
"description": "Deploy to staging server",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 2,
"ssh_key_id": 1,
"user": "deploy",
"created_at": "2025-11-11T10:00:00Z",
"updated_at": "2025-11-11T10:00:00Z"
}Error Responses:
400 Bad Request: Invalid request body or missing required fields
Example:
curl -X POST http://localhost:7777/api/script-presets \
-H "Content-Type: application/json" \
-d '{
"name": "Staging Deploy",
"script_id": 1,
"env_var_ids": [1, 2],
"is_remote": true,
"server_id": 2,
"ssh_key_id": 1
}'Update an existing script preset.
Endpoint: PUT /script-presets/{id}
Path Parameters:
id(integer, required): Script preset ID
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "Updated Preset Name",
"env_var_ids": [1, 2, 3],
"user": "admin"
}Fields: All fields are optional; only provided fields will be updated.
Response: 200 OK
Error Responses:
400 Bad Request: Invalid request body404 Not Found: Script preset not found
Example:
curl -X PUT http://localhost:7777/api/script-presets/1 \
-H "Content-Type: application/json" \
-d '{
"env_var_ids": [1, 2, 3]
}'Delete a script preset from the system.
Endpoint: DELETE /script-presets/{id}
Path Parameters:
id(integer, required): Script preset ID
Response: 204 No Content
Error Responses:
404 Not Found: Script preset not found
Example:
curl -X DELETE http://localhost:7777/api/script-presets/1HashiCorp Vault integration allows you to store and retrieve secrets (SSH keys, servers, environment variables, and bash scripts) from an external Vault server. This provides centralized secrets management with additional security features.
Retrieve the current Vault configuration (token is never returned).
Endpoint: GET /vault/config
Response: 200 OK
{
"id": 1,
"address": "https://vault.example.com:8200",
"namespace": "admin",
"mount_path": "secret",
"enabled": true,
"has_token": true,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}Fields:
address(string): Vault server URLnamespace(string): Optional Vault namespacemount_path(string): KV secrets engine mount path (default: "secret")enabled(boolean): Whether Vault integration is activehas_token(boolean): Indicates if a token is configured (token value never exposed)
Example:
curl http://localhost:7777/api/vault/configConfigure or update the Vault connection settings.
Endpoint: POST /vault/config
Request Headers:
Content-Type: application/json
Request Body:
{
"address": "https://vault.example.com:8200",
"token": "hvs.your-vault-token",
"namespace": "admin",
"mount_path": "secret",
"enabled": true
}Fields:
address(string, required): Vault server URLtoken(string, required for new config): Vault authentication token (encrypted with AES-256-GCM before storage)namespace(string, optional): Vault namespace for enterprise deploymentsmount_path(string, optional): KV secrets engine mount path (default: "secret")enabled(boolean, optional): Enable/disable Vault integration
Response: 200 OK
{
"id": 1,
"address": "https://vault.example.com:8200",
"namespace": "admin",
"mount_path": "secret",
"enabled": true,
"has_token": true,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}Error Responses:
400 Bad Request: Missing required fields (address or token)
Example:
curl -X POST http://localhost:7777/api/vault/config \
-H "Content-Type: application/json" \
-d '{
"address": "https://vault.example.com:8200",
"token": "hvs.your-vault-token",
"mount_path": "secret",
"enabled": true
}'Remove the Vault configuration.
Endpoint: DELETE /vault/config
Response: 204 No Content
Example:
curl -X DELETE http://localhost:7777/api/vault/configCheck the current Vault connection status.
Endpoint: GET /vault/status
Response: 200 OK
{
"configured": true,
"enabled": true,
"connected": true,
"address": "https://vault.example.com:8200",
"vault_sealed": false
}Fields:
configured(boolean): Whether Vault settings existenabled(boolean): Whether Vault integration is enabledconnected(boolean): Whether connection test passedaddress(string): Vault server URLerror(string, optional): Error message if connection failedvault_sealed(boolean, optional): Whether Vault is sealed
Example:
curl http://localhost:7777/api/vault/statusTest the connection to Vault and initialize the secrets structure.
Endpoint: POST /vault/test
Response: 200 OK
{
"configured": true,
"enabled": true,
"connected": true,
"address": "https://vault.example.com:8200",
"vault_sealed": false
}Note: On successful connection, this endpoint automatically initializes the Vault secrets structure (webcli/ssh-keys, webcli/servers, webcli/env-variables, webcli/bash-scripts).
Example:
curl -X POST http://localhost:7777/api/vault/testRetrieve all SSH keys stored in Vault.
Endpoint: GET /vault/ssh-keys
Response: 200 OK
[
{
"name": "production-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
"group": "production",
"created_at": "2025-01-15T10:00:00Z"
}
]Error Responses:
400 Bad Request: Vault not configured or disabled
Example:
curl http://localhost:7777/api/vault/ssh-keysStore a new SSH key in Vault.
Endpoint: POST /vault/ssh-keys
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "production-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
"group": "production"
}Fields:
name(string, required): Key identifierprivate_key(string, required): PEM-encoded SSH private keygroup(string, optional): Group for organization (default: "default")
Response: 201 Created
{
"name": "production-key",
"group": "production",
"created_at": "2025-01-15T10:00:00Z",
"source": "vault"
}Error Responses:
400 Bad Request: Missing required fields or Vault not configured
Example:
curl -X POST http://localhost:7777/api/vault/ssh-keys \
-H "Content-Type: application/json" \
-d '{
"name": "production-key",
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----",
"group": "production"
}'Retrieve all server configurations stored in Vault.
Endpoint: GET /vault/servers
Response: 200 OK
[
{
"name": "prod-web-01",
"ip_address": "10.0.0.50",
"port": 22,
"username": "deploy",
"group": "production"
}
]Error Responses:
400 Bad Request: Vault not configured or disabled
Example:
curl http://localhost:7777/api/vault/serversStore a new server configuration in Vault.
Endpoint: POST /vault/servers
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "prod-web-01",
"ip_address": "10.0.0.50",
"port": 22,
"username": "deploy",
"group": "production"
}Fields:
name(string, optional): Server name/alias (at least one of name or ip_address required)ip_address(string, optional): Server IP address or hostnameport(integer, optional): SSH port (default: 22)username(string, optional): SSH username (default: "root")group(string, optional): Group for organization (default: "default")
Response: 201 Created
{
"name": "prod-web-01",
"ip_address": "10.0.0.50",
"port": 22,
"username": "deploy",
"group": "production",
"source": "vault"
}Error Responses:
400 Bad Request: Missing required fields or Vault not configured
Example:
curl -X POST http://localhost:7777/api/vault/servers \
-H "Content-Type: application/json" \
-d '{
"name": "prod-web-01",
"ip_address": "10.0.0.50",
"port": 22,
"username": "deploy",
"group": "production"
}'Retrieve all environment variables stored in Vault.
Endpoint: GET /vault/env-variables
Response: 200 OK
[
{
"name": "API_SECRET",
"value": "super-secret-value",
"description": "External API authentication secret",
"group": "production"
}
]Note: Unlike local environment variables, Vault env variables are returned with full values (not masked).
Error Responses:
400 Bad Request: Vault not configured or disabled
Example:
curl http://localhost:7777/api/vault/env-variablesStore a new environment variable in Vault.
Endpoint: POST /vault/env-variables
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "API_SECRET",
"value": "super-secret-value",
"description": "External API authentication secret",
"group": "production"
}Fields:
name(string, required): Variable namevalue(string, required): Variable valuedescription(string, optional): Descriptiongroup(string, optional): Group for organization (default: "default")
Response: 201 Created
{
"name": "API_SECRET",
"description": "External API authentication secret",
"group": "production",
"source": "vault"
}Error Responses:
400 Bad Request: Missing required fields or Vault not configured
Example:
curl -X POST http://localhost:7777/api/vault/env-variables \
-H "Content-Type: application/json" \
-d '{
"name": "API_SECRET",
"value": "super-secret-value",
"description": "External API authentication secret",
"group": "production"
}'Retrieve all bash scripts stored in Vault.
Endpoint: GET /vault/bash-scripts
Response: 200 OK
[
{
"name": "deploy-script",
"description": "Production deployment script",
"content": "#!/bin/bash\necho \"Deploying...\"",
"filename": "deploy.sh",
"group": "production"
}
]Error Responses:
400 Bad Request: Vault not configured or disabled
Example:
curl http://localhost:7777/api/vault/bash-scriptsStore a new bash script in Vault.
Endpoint: POST /vault/bash-scripts
Request Headers:
Content-Type: application/json
Request Body:
{
"name": "deploy-script",
"description": "Production deployment script",
"content": "#!/bin/bash\nset -e\necho \"Deploying...\"\ncd /opt/app\ngit pull\nsystemctl restart app",
"filename": "deploy.sh",
"group": "production"
}Fields:
name(string, required): Script namecontent(string, required): Bash script contentdescription(string, optional): Descriptionfilename(string, optional): Original filenamegroup(string, optional): Group for organization (default: "default")
Response: 201 Created
{
"name": "deploy-script",
"description": "Production deployment script",
"filename": "deploy.sh",
"group": "production",
"source": "vault"
}Error Responses:
400 Bad Request: Missing required fields or Vault not configured
Example:
curl -X POST http://localhost:7777/api/vault/bash-scripts \
-H "Content-Type: application/json" \
-d '{
"name": "deploy-script",
"description": "Production deployment script",
"content": "#!/bin/bash\necho \"Deploying...\"",
"group": "production"
}'All API endpoints use standard HTTP status codes and return JSON error responses.
{
"error": "Error message describing what went wrong"
}| Status Code | Meaning | Description |
|---|---|---|
200 OK |
Success | Request succeeded |
201 Created |
Created | Resource created successfully |
204 No Content |
No Content | Request succeeded, no response body |
400 Bad Request |
Client Error | Invalid request body or parameters |
404 Not Found |
Not Found | Resource does not exist |
500 Internal Server Error |
Server Error | Server encountered an error |
400 Bad Request:
{
"error": "Command is required"
}404 Not Found:
{
"error": "Server not found"
}500 Internal Server Error:
{
"error": "Failed to execute command"
}Opens an interactive terminal session via WebSocket with full PTY support.
Endpoint: WS /api/terminal/ws
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
shell |
string | No | Shell to use: bash, sh, or zsh (default: bash) |
sshKeyId |
integer | No | SSH key ID to inject into terminal session for SSH connections |
WebSocket URL:
ws://localhost:7777/api/terminal/ws?shell=bash&sshKeyId=1
Authentication:
WebSocket connections require the same Basic Auth credentials as regular API requests. Include credentials in the connection URL or headers.
Features:
- SSH Key Integration: When
sshKeyIdis provided, the SSH key is automatically available for SSH connections within the terminal - Server Name Resolution: Servers configured in Admin Panel are automatically available as SSH hostname aliases (e.g.,
ssh prod-serverresolves to the configured IP/port/username) - Multiple Shells: Support for Bash, Zsh, and Sh
- Dynamic Resize: Terminal dimensions can be changed dynamically
- 256-Color Support: Full terminal emulation with TERM=xterm-256color
Message Format:
- Client → Server (Input): Send raw text or binary data for terminal input
- Client → Server (Resize): Send JSON:
{"type": "resize", "cols": 80, "rows": 24} - Server → Client (Output): Binary data containing terminal output
Example (JavaScript):
const ws = new WebSocket('ws://localhost:7777/api/terminal/ws?shell=bash&sshKeyId=1');
ws.binaryType = 'arraybuffer';
ws.onopen = () => {
console.log('Connected');
// Send resize message
ws.send(JSON.stringify({ type: 'resize', cols: 80, rows: 24 }));
};
ws.onmessage = (event) => {
const text = new TextDecoder().decode(event.data);
console.log(text);
};
// Send input
ws.send('ls -la\n');
// SSH to a server configured in Admin Panel (using alias)
ws.send('ssh prod-server\n');Server Alias Resolution:
When servers are configured in the Admin Panel, they become available as SSH hostname aliases:
# If Admin Panel has server "prod" with IP 10.0.0.5, port 22, user "deploy"
ssh prod # Automatically connects to deploy@10.0.0.5:22Connection Lifecycle:
- Client connects via WebSocket with Basic Auth
- Server creates temporary session directory with SSH config and optional key
- Server spawns PTY with specified shell and configured environment
- Bidirectional data flow until either side disconnects
- Server cleans up PTY resources and temporary files on disconnect
Security:
- SSH keys are written to temporary files with 0600 permissions
- Temporary session directories are cleaned up on disconnect
- Server configs are validated to prevent SSH config injection
- Terminal dimensions are validated (max 500x500)
- All SSH private keys are encrypted with AES-256-GCM before storage
- Environment variable values are encrypted at rest
- Bash script content is encrypted at rest
- Command output is encrypted in the database
- Encryption key is stored in
.encryption_keyfile (backup this file!) - System entropy is verified before generating encryption keys (Linux)
- SSH passwords are NEVER stored in command history (security feature)
- Sudo passwords are only used for command execution and discarded immediately
- Passwords hashed with bcrypt (cost factor 12) when stored
- Constant-time comparison prevents timing attacks
- HTTP Basic Authentication supported
- Bearer token (API token) authentication supported
- Production deployment requires enabling authentication (
AUTH_ENABLED=true) - Supports both methods simultaneously (token takes precedence)
- Native TLS support with
-tls-certand-tls-keyflags - Optional HTTPS enforcement with
-require-https - Security headers included (X-Frame-Options, X-Content-Type-Options, etc.)
- Host key verification against
~/.ssh/known_hosts - Trust-on-first-use (TOFU) mode for development
- Man-in-the-middle attack detection
- IP addresses validated (IPv4/IPv6)
- Hostnames validated (RFC 1123 compliant)
- Port numbers validated (1-65535)
- SSH private keys format validated
- Unix usernames validated
- Command names checked for malicious content
- Enable authentication in production (
AUTH_ENABLED=true) - Use HTTPS - either native TLS or reverse proxy
- Backup encryption key - data cannot be recovered without it
- Use SSH key authentication over passwords when possible
- Configure CORS - set
CORS_ALLOWED_ORIGINSfor production - Monitor command history for suspicious activity
- Limit API access to trusted networks
- Set up proper HTTP timeouts - configured automatically for DoS protection
Currently, there is no rate limiting implemented. Consider implementing rate limiting in production to prevent abuse.
Current API version: v1
The API does not currently use versioning in the URL path. Future versions may use /api/v2/ prefix.
For API issues or questions:
- GitHub Issues: https://github.com/pozgo/web-cli/issues
- Documentation: README.md and CLAUDE.md
- Docker Deployment:
- Official Docker image on Docker Hub (
polinux/web-cli) - Multi-platform support (linux/amd64, linux/arm64)
- Debian Bookworm base for full bash support
- Docker Compose configuration included
- GitHub Actions CI/CD for automated builds
- Trivy security scanning
- Official Docker image on Docker Hub (
- Security Enhancements:
- Added bcrypt password hashing (cost factor 12)
- Added SSH host key verification with TOFU support
- Added comprehensive input validation
- Added native TLS/HTTPS support
- Added HTTPS enforcement option
- Added security headers middleware
- Added system entropy verification for key generation
- Added detailed decryption audit logging
- Configuration:
- Added Viper configuration management
- Support for config files (YAML, JSON, TOML)
- Support for WEBCLI_ prefixed environment variables
- Multiple config file search paths
- New Features:
- Added Environment Variables Management (5 endpoints)
- Added Bash Scripts Management (7 endpoints)
- Added Script Presets Management (5 endpoints)
- Total API endpoints: 41
- Authentication:
- HTTP Basic Auth support
- Bearer token support
- Configurable via environment variables
- Fixed saved commands filter in LocalCommands component
- Local commands now properly filtered to exclude remote commands
- Remote commands only appear in RemoteCommands dropdown
- Complete isolation between local and remote saved command templates
- Added remote command execution support
- Added
is_remote,server_id,ssh_key_idfields to saved commands - Added SSH password fallback authentication
- Added system information endpoint
- Enhanced command execution with remote capability
- Added current user endpoint
- Enhanced user selection with local users
- Initial local command execution
- Command history tracking
- Saved commands management
- SSH key management
- Server management
- Local user management
- Admin panel foundation
Last Updated: December 7, 2025 API Version: 1.1.0