#!/usr/bin/env node /** * WebSocket-Proxy: Browser → Panel → Proxmox VNC * Start: CONSOLE_PROXY_SECRET=... CONSOLE_VALIDATE_URL=https://panel/api/console/validate node scripts/console-ws-proxy.mjs */ import http from 'http'; import { WebSocketServer, WebSocket } from 'ws'; const PORT = parseInt(process.env.CONSOLE_PROXY_PORT || '6090', 10); const SECRET = process.env.CONSOLE_PROXY_SECRET || ''; const VALIDATE = process.env.CONSOLE_PROXY_VALIDATE_URL || 'http://127.0.0.1:8000/api/console/validate'; const server = http.createServer(); const wss = new WebSocketServer({ server, path: '/ws/vm' }); wss.on('connection', async (clientWs, req) => { const token = req.url?.split('/').pop()?.split('?')[0]; if (!token) { clientWs.close(4001, 'missing token'); return; } try { const res = await fetch(`${VALIDATE}/${token}`, { headers: { 'X-Console-Proxy-Secret': SECRET }, }); if (!res.ok) { clientWs.close(4003, 'invalid session'); return; } const data = await res.json(); const proxmoxWs = new WebSocket(data.proxmox_ws_url, ['binary']); proxmoxWs.on('open', () => { clientWs.on('message', (msg) => proxmoxWs.readyState === WebSocket.OPEN && proxmoxWs.send(msg)); proxmoxWs.on('message', (msg) => clientWs.readyState === WebSocket.OPEN && clientWs.send(msg)); }); proxmoxWs.on('error', () => clientWs.close(1011, 'upstream error')); clientWs.on('close', () => proxmoxWs.close()); proxmoxWs.on('close', () => clientWs.close()); } catch { clientWs.close(1011, 'proxy error'); } }); server.listen(PORT, '127.0.0.1', () => { console.log(`Console WS proxy on 127.0.0.1:${PORT}/ws/vm/{token}`); });