NoVNC webconsole using the API of Proxmox

DBS

Renowned Member
Oct 21, 2013
13
2
68
Veenendaal, The Netherlands
Hi All,

I've written a web based manager for Proxmox using the API of Proxmox to access a LXC console.
However, I'm missing something:

When using the created web based manager (php) all info is correct but an error is thrown when connecting to the console:
Connection failed (Error 401: No ticket)

Login_401.png

But, When logging on to the Proxmox PVE manager and then to the web based manager (php) a connection is made.

proxmox_login.png

Login_OK.png

In short:
NO Login on Proxmox PVE GUI >> Login on LXC Console = No Console
Logged in on Proxmox PVE GUI >> login on LXC Console = OK

The complete code below (and as an attachement), maybe it will help you guys for your own designs.
I have stripped the code to prevent issues (security e.g.) and use the credentials in the code for testing, it all works.

Keep in mind, if you are using for your own project, no security is implemented!!

Any help is appreciated.


PHP:
<?php
# Proxmox credentials and details

    $proxmox_host    = 'your.proxmox.host';
    $port            = '8006';
    $realm            = 'pve';
    $username        = 'remoteuser';
    $password        = 'Dt#rDNlUyJTa';
    $username        = $username .'@'. $realm; // No, this is not conflicting with the earlier defined "username"
    $node            = 'pve';
    $vmid            = '105';
    $name           = 'Test02';

    $api_call         = '/api2/json';
    $ticket_call     = '/access/ticket';
    
#  Normally these input fields are send from an input form:
/*
    $proxmox_host    = $_POST['proxmox_host'];
    $port            = $_POST['port'];
    $realm            = $_POST['realm'];
    $username        = $_POST['username'] .'@'. $_POST['realm'];
    $password        = $_POST['password'];
    $node            = $_POST['node_name'];
    $vmid            = $_POST['vmid'];
    $name           = $_POST['name'];
*/

###################################################
# Check 1, are the values correct?
#
    echo 'proxmox_host:    '. $proxmox_host .'<br/>';
    echo 'port:            '. $port .'<br/>';
    echo 'username:        '. $username .'<br/>';
    echo 'realm:        '. $realm .'<br/>';
    echo 'password:        '. $password .'<br/>';
    echo 'node:            '. $node .'<br/>';
    echo 'vmid:            '. $vmid .'<br/>';
    echo 'vmname:        '. $name .'<br/>';

    echo 'api_call:        '. $api_call .'<br/>';
    echo 'ticket_call:    '. $ticket_call .'<br/>';

    echo '--------------------------------------------------------';
    echo '<br/>';
###################################################


# Function to make a POST request and return the response
#
function make_post_request($url, $data, $headers = []) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

    // Set custom headers if provided
    if (!empty($headers)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }

    // Ignore SSL certificate verification (not recommended for production)
    # DEACTIVATED for testing purposes 
    // No, this is not causing problems
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    $response = curl_exec($ch);
    if ($response === false) {
        throw new Exception('Curl error: ' . curl_error($ch));
    }

    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    return ['response' => json_decode($response, true), 'http_code' => $http_code];
}

# Authenticate to get the ticket and CSRF token
#
$auth_url = "https://". $proxmox_host .":". $port . $api_call . $ticket_call;
$auth_data = [
    'username' => $username,
    'password' => $password
];
$auth_result = make_post_request($auth_url, $auth_data);

############################################################
# Check 2, are the Authenticate values correct?
#
echo '<br/>';
echo '>> Check 2, Authenticate URL. <br/>';
echo 'auth_url: '. $auth_url .'<br/>';
    echo '--------------------------------------------------------';
    echo '<br/>';
############################################################

if ($auth_result['http_code'] != 200 || !isset($auth_result['response']['data'])) {
    die('Authentication failed: ' . json_encode($auth_result));
}

$ticket = $auth_result['response']['data']['ticket'];
$csrf_token = $auth_result['response']['data']['CSRFPreventionToken'];

#############################################################################
# Check 3, are the $auth_result values correct?
#
echo '<br/>';
echo '>> Check 3, if you can see this $auth_result are OK. <br/>';

    echo '$ticket:'. $ticket .'<br/>';
    echo '$csrf_token: '. $csrf_token .'<br/>';
    echo '--------------------------------------------------------';
    echo '<br/>';
#############################################################################

# Generate the VNC ticket
#
$vnc_url = "https://". $proxmox_host .":". $port ."/api2/json/nodes/$node/lxc/$vmid/vncproxy";
$headers = [
    "CSRFPreventionToken: $csrf_token",
    "Cookie: PVEAuthCookie=$ticket"
];
$vnc_data = [];
$vnc_result = make_post_request($vnc_url, $vnc_data, $headers);

if ($vnc_result['http_code'] != 200 || !isset($vnc_result['response']['data'])) {

################################################################################
    echo '<br/>';
    echo '--------------------------------------------------------';
    echo 'ERROR!';
    echo '<br/>';
################################################################################

    die('<p style="font-size: 1em; font-family: Quicksand, sans-serif;">Failed to generate VNC ticket: ' . json_encode($vnc_result) . '<br/>Is your Virtual Machine running?</p>');
}

$vnc_ticket = $vnc_result['response']['data']['ticket'];
$vnc_port = $vnc_result['response']['data']['port'];

# PHP logic to retrieve Proxmox credentials
# Assuming you've already authenticated and obtained the CSRFPreventionToken and username
#
$pve_user_name = $username;
$pve_csrf_token = $csrf_token;

#############################################################################
# Check 4, are the "Generate the VNC ticket" values correct?
#
echo '<br/>';
echo '>> Check 4, if you can see this "Generate the VNC ticket" is OK. <br/>';

    echo '$pve_user_name :'. $pve_user_name .'<br/>';
    echo '$pve_csrf_token :'. $pve_csrf_token .'<br/>';
    echo '----------------------------------------------------------------';
    echo '<br/>';

#################################################################################

?>

<script type="text/javascript">
    if (typeof(PVE) === 'undefined') PVE = {};
    PVE.UserName = '<?php echo $pve_user_name; ?>'; // Set the user name dynamically
    PVE.CSRFPreventionToken = '<?php echo $pve_csrf_token; ?>'; // Set the CSRF token dynamically
</script>

<?php

#################################################################################
# Check 4, are the "Generate the VNC ticket" values correct?
#
echo '<br/>';
echo '>> Check 5, NoVNC URL secrets';
echo '<br/>';
    
    echo 'PVE.UserName :'. $pve_user_name .'<br/>';
    echo 'PVE.CSRFPreventionToken :'. $pve_csrf_token .'<br/>';
    echo '----------------------------------------------------------------<br/>';
    echo '<br/>';
#################################################################################

# Open the noVNC session
#
# Generate Link to get access to the Console from external
$novnc_url = "https://$proxmox_host:$port/?console=lxc&xtermjs=1&vmid=$vmid&node=$node&resize=off&port=$vnc_port&PVE.UserName=$username&PVE.CSRFPreventionToken=" . urlencode($csrf_token);

?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo 'VM'.$vmid.' '.$name ; ?></title>
<style>
html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    width: 100%;
    overflow: hidden; /* Prevent scrollbars */
    }

iframe {
    border: none; /* Remove border */
    width: 100vw; /* Full viewport width */
    height: 100vh; /* Full viewport height */
    display: block; /* Ensure it’s a block element */
    }
    </style>
</head>

<body>
<iframe target='_blank' src="<?php echo $novnc_url; ?>" allowfullscreen></iframe>
</body>
</html>
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!