Proxmox API - Websocket

WhiteFox

New Member
Jan 13, 2025
2
0
1
Guten Tag,
ich versuche seit ungefähr 5 Tagen Nettozeit, eine Console via. den Websocket in meinem CP anzeigen zu lassen. Allerdings erhalte ich immer den selben Fehler:

Code:
console.js:29 WebSocket connection to 'wss://127.0.0.1:8006/api2/json/nodes/node01/lxc/501/vncwebsocket?port=5…' failed:

Ich bin echt am verzweifeln und ich weiß nicht mehr, was ich tun sollte.
Ich würde, wenn mir jemand helfen kann, dass du fixen, ein bisschen vergüten. Ich brauche endlich mal schlaf ~

Vielleicht Relevant: Webserver läuft auf einen VM - eigene IP.
Proxmox IP ist einen IPv4.

Es wird aufjedenfall einer erstellt, eine Verbindung + Port.
Output generell, wenn man es im Browser öffnet ist positiv.
JSON:
{"data":{"port":"5900"}}

Wenn ich es via. SSH Prüfe:
Bash:
root@node01 ~ # wscat -c "wss://xxxx/wss/node01/501/?port=5900&vncticket=PVEVNC%3A678E0403....%2FmZ%2FJNBufsg4lpIGHMd1MCGUh8IsoJpoefvShr1FNjUIw8O15zDTWyemINcrK0iO9ZoBuPg%3D%3D"
error: Unexpected server response: 401

Mein PHP Code:
PHP:
    include_once('authToken.php');
    $authToken = authToken(
        '127.0.0.1',
        '8006',
        'root@pam',
        'xxx'
    );
    if(!$authToken) {
        die(json_encode(['status' => false, 'message' => 'Failed to connect to Proxmox.'], JSON_UNESCAPED_UNICODE));
    }
    $ticket = $authToken['ticket'];
    $csrfToken = $authToken['csrfToken'];



function createVNCProxy($hostname, $node, $vmid, $ticket, $csrfToken, $useWebSocket = false, $width = null, $height = null) {
        // Basis-URL für die Proxmox-API
        $url = "https://$hostname:8006/api2/json/nodes/$node/lxc/$vmid/vncproxy";
 
        // POST-Felder vorbereiten
        $postFields = [
            'websocket' => $useWebSocket ? '1' : '0',
        ];
 
        // Optional: Breite und Höhe hinzufügen
        if (!is_null($width)) {
            $postFields['width'] = (int)$width;
        }
 
        if (!is_null($height)) {
            $postFields['height'] = (int)$height;
        }
 
        // cURL-Session initialisieren
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($postFields),
            CURLOPT_HTTPHEADER => [
                "Authorization: PVEAuthCookie=$ticket",
                "CSRFPreventionToken: $csrfToken",
            ],
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
 
        // API-Anfrage senden
        $response = curl_exec($ch);
 
        if ($response === false) {
            // Fehler bei der cURL-Anfrage
            throw new Exception("VNC Proxy Error: " . curl_error($ch));
        }
 
        $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
 
        // cURL-Session schließen
        curl_close($ch);
 
        // Antwort decodieren
        $result = json_decode($response, true);
 
        // Rückgabe der Daten
        return [
            'port' => $result['data']['port'] ?? null,
            'ticket' => $result['data']['ticket'] ?? null,
            'cert' => $result['data']['cert'] ?? null,
        ];
    }

Meine JS:
JavaScript:
async function startVNCConsole() {
    try {
        const vmid = getVMIDFromURL();
        const node = "node01";

        if (!vmid) {
            console.error("Keine VMID gefunden.");
            return;
        }

        // API-Aufruf, um die VNC-Details zu erhalten
        const response = await fetch(`/xxx/getVNC.php?vmid=${vmid}`);
        if (!response.ok) {
            console.error("Fehler beim Abrufen der VNC-Daten:", response.statusText);
            return;
        }

        const { port, ticket } = await response.json();

        if (!port || !ticket) {
            console.error("Ungültige VNC-Daten:", { port, ticket });
            return;
        }

        // Die korrekte WebSocket-URL für die Verbindung
        const wsURL = `wss://127.0.0.1:8006/api2/json/nodes/${node}/lxc/${vmid}/vncwebsocket?port=${port}&vncticket=${encodeURIComponent(ticket)}`;

        // WebSocket-Verbindung starten
        const socket = new WebSocket(wsURL);

        // Erstelle ein Canvas innerhalb des Divs mit der ID "console"
        const consoleDiv = document.getElementById("console");
        if (!consoleDiv) {
            console.error('Element mit ID "console" nicht gefunden.');
            return;
        }

        const canvas = document.createElement("canvas");
        consoleDiv.appendChild(canvas);

        const ctx = canvas.getContext("2d");

        // WebSocket-Ereignisse behandeln
        socket.onopen = () => {
            console.log("WebSocket-Verbindung aufgebaut.");
        };

        socket.onmessage = (event) => {
            console.log("Nachricht vom Server erhalten.");
            const data = new Uint8Array(event.data);
        };

        socket.onerror = (error) => {
            console.error("WebSocket-Fehler:", error);
        };

        socket.onclose = () => {
            console.log("WebSocket-Verbindung geschlossen.");
        };

    } catch (error) {
        console.error("Fehler beim Starten der VNC-Konsole:", error);
    }
}

function getVMIDFromURL() {
    const url = window.location.pathname;
    const parts = url.split('/');
    return parts[parts.length - 1];
}

// Starte die Verbindung
startVNCConsole();
 
Last edited:
Problem gelöst! Endlich! Omg!

Lösung für andere:
Ich habe eine Subdomain angelegt und via. Letsencrypt ein Zertifikat erstellt. Dieses Zertifikat hab ich ebenfalls Proxmox gegeben. (Weil ich keine Domain direkt auf Proxmox laufen habe).

Apache2 Config:
Bash:
<VirtualHost *:443>
    ServerName [Deine Subdomain]

    SSLEngine on
    SSLProxyEngine on
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyAddHeaders On

    ProxyPass "/api2/json/" "https://[Dein Proxmox]:8006/api2/json/"
    ProxyPassReverse "/api2/json/" "https://[Dein Proxmox]:8006/api2/json/"

    <Location /api2/json/>
        Require all granted
        RewriteEngine On
        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteCond %{HTTP:Connection} upgrade [NC]
        RewriteRule .* "wss://[Dein Proxmox]:8006%{REQUEST_URI}" [P]
    </Location>

    ErrorLog ${APACHE_LOG_DIR}/vnc_error.log
    CustomLog ${APACHE_LOG_DIR}/vnc_access.log combined

    SSLCertificateFile /etc/letsencrypt/live/[Deine Subdomain]/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/[Deine Subdomain]/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>

Ebenfalls ein Cookie erstellt mit dem root@pam token.
Somit:
JavaScript:
const wsURL = `wss://[Deine Subdomain]/api2/json/nodes/${node}/lxc/${vmid}/vncwebsocket?port=${data.port}&vncticket=${data.ticket}`;