Files
vps_monitoring/server/api/ssh_ws.py
Андрей Бобырев e6e88314d5 feat: initial VPS monitoring platform
- FastAPI backend with auth, server CRUD, metrics collection
- Web dashboard with dark theme, server cards, SSH terminal (xterm.js)
- Telegram bot with inline keyboards, server management, reboot
- Telegram Mini App for mobile monitoring
- Background monitoring via asyncssh (CPU, RAM, Disk, Network, Uptime)
- Alert system with configurable thresholds
- WebSocket SSH terminal in browser
- One-command install script
- Systemd service configuration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 05:47:28 +03:00

84 lines
2.3 KiB
Python

import asyncio
import logging
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
import asyncssh
from server.auth import verify_token
from server.config import load_servers
logger = logging.getLogger(__name__)
router = APIRouter()
@router.websocket("/ws/ssh/{server_id}")
async def ssh_websocket(websocket: WebSocket, server_id: str):
"""WebSocket SSH terminal."""
await websocket.accept()
# Auth check
token = websocket.cookies.get("access_token")
if not verify_token(token):
await websocket.send_text("Authentication required")
await websocket.close()
return
servers = load_servers()
server = None
for srv in servers:
if srv.get("id") == server_id or srv["host"] == server_id:
server = srv
break
if not server:
await websocket.send_text("Server not found")
await websocket.close()
return
try:
conn_kwargs = {
"host": server["host"],
"port": server.get("port", 22),
"username": server.get("username", "root"),
"known_hosts": None,
"connect_timeout": 15,
}
if server.get("password"):
conn_kwargs["password"] = server["password"]
elif server.get("ssh_key"):
conn_kwargs["client_keys"] = [server["ssh_key"]]
async with asyncssh.connect(**conn_kwargs) as conn:
process = await conn.create_process(
term_type="xterm-256color",
term_size=(120, 40),
)
async def read_output():
try:
while True:
data = await process.stdout.read(4096)
if not data:
break
await websocket.send_text(data)
except Exception:
pass
read_task = asyncio.create_task(read_output())
try:
while True:
data = await websocket.receive_text()
process.stdin.write(data)
except WebSocketDisconnect:
pass
finally:
read_task.cancel()
process.close()
except Exception as e:
await websocket.send_text(f"\r\nConnection error: {e}\r\n")
await websocket.close()