After a long time struggling, I finally found a solution to this.
But first of all many thanks to all forum posters also trying to get this working and sharing their results – that helped a lot.
The following is a brief description of my setup:
Starting point is my lab cluster with tree nodes (not required, but that’s what I already had):
pvelab1 - 192.168.1.101
pvelab2 - 192.168.1.102
pvelab3 - 192.168.1.103
First, you need a (virtual) server for installing nginx. I am using a debian VM on my proxmox lab cluster for that.
To keep the setup simple I gave that server an IP address within the clusters subnet: 192.168.1.10
Install all packages needed ...
Code:
apt-get install nginx-full openssl php5-fpm php5-curl
Since we need a SSL certificate for this to work, create a self-signed certificate:
Code:
mkdir -p /etc/nginx/ssl
openssl genrsa -out /etc/nginx/ssl/server.key 2048
openssl req -new -sha256 -key /etc/nginx/ssl/server.key -out server.csr
openssl x509 -req -days 3650 -in server.csr -signkey /etc/nginx/ssl/server.key -out /etc/nginx/ssl/server.crt
Then configure nginx:
Code:
nano /etc/nginx/sites-available/proxmox-gui
ln -s /etc/nginx/sites-available/proxmox-gui /etc/nginx/sites-enabled/
/etc/nginx/sites-available/proxmox-gui contains these lines:
Code:
#
# upstream to proxmox cluster
#
upstream pvelab {
server 192.168.1.101:8006;
server 192.168.1.102:8006 backup;
server 192.168.1.103:8006 backup;
}
#
# private server with php supprt
#
server {
listen 127.0.0.1:5555;
root /var/www/html;
index index.php;
location ~ .php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
try_files $uri $uri/index.php;
}
}
#
# public server with ssl
# proxy two pve api methods (vncproxy and vncwebsocket)
# and redirect ererything else to the local server
#
server {
server_name _;
listen 443;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl on;
proxy_redirect off;
location ~* .*/(vncproxy|vncwebsocket)$ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass https://pvelab;
}
location / {
proxy_pass http://localhost:5555;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
On debian I needed an additional line in /etc/nginx/fastcgi_params:
Code:
fastcgi_param SCRIPT_FILENAME $request_filename;
To complete the nginx/php5-fpm setup restart both:
Code:
service php5-fpm restart
service nginx restart
Now we need to copy the noVNC files from our proxmox server(s):
Code:
mkdir -p /var/www/html/novnc/locale
scp root@192.168.1.101:/usr/share/pve-manager/locale/* /var/www/html/novnc/locale/
scp -r root@192.168.1.101:/usr/share/novnc-pve/* /var/www/html/novnc/
The file index.html.tpl (copied in the previous step) needs to be patched.
Save the following as patch file index.html.tpl.patch:
Code:
--- index.html.tpl 2017-03-10 08:37:24.000000000 +0100
+++ index.html.tpl 2017-05-13 21:44:01.000000000 +0200
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <title>[% nodename %] - Proxmox Console</title>
+ <title>noVNC</title>
<meta charset="utf-8">
@@ -14,11 +14,9 @@
<!-- Stylesheets -->
<link rel="stylesheet" href="/novnc/include/base.css" />
- [% IF langfile %]
- <script type='text/javascript' src='/pve2/locale/pve-lang-[% lang %].js'></script>
- [% ELSE %]
+
<script type="text/javascript">function gettext(buf) { return buf; }</script>
- [% END %]
+
<script type="text/javascript">
if (typeof(PVE) === 'undefined') PVE = {};
PVE.UserName = '[% username %]';
And apply it with:
Code:
patch -d /var/www/html/novnc < index.html.tpl.patch
Now download the PHP API class:
Code:
wget -O /var/www/html/pve2_api.class.php https://raw.githubusercontent.com/CpuID/pve2-api-php-client/master/pve2_api.class.php
That file also needs to be patched.
Save the following as patch file pve2_api.class.php.diff:
Code:
--- /var/www/html/pve2_api.class.php 2017-05-15 10:53:02.572000000 +0200
+++ /var/www/html/pve2_api.class.php 2017-05-15 11:06:13.000000000 +0200
@@ -131,6 +131,14 @@
setrawcookie("PVEAuthCookie", $this->login_ticket['ticket'], 0, "/");
}
+ # returns the CSRFPreventionToken
+ public function getCSRFPreventionToken() {
+ if (!$this->check_login_ticket()) {
+ throw new PVE2_Exception("Not logged into Proxmox host. No Login access ticket found or ticket expired.", 3);
+ }
+ return $this->login_ticket['CSRFPreventionToken'];
+ }
+
/*
* bool check_login_ticket ()
* Checks if the login ticket is valid still, returns false if not.
Again apply the patch with:
Code:
patch -d /var/www/html < pve2_api.class.php.diff
The last thing remaining is to create a PHP script that returns the noVNC page.
As this is only for demonstration purposes I included everything hard coded.
Save the following as file /var/www/html/index.php:
Code:
<?php
require("pve2_api.class.php");
$nodeaddress = "192.168.1.101";
$nodename = "pvelab1";
$nodeport = 8006;
$user = "testuser";
$pass = "testpass";
$auth = "pve";
$vmname = "test";
$vmid = 100;
$pve2 = new PVE2_API($nodeaddress, $user, $auth, $pass, $nodeport);
if ($pve2->login()){
$pve2->setCookie();
$userauth = sprintf("%s@%s", $user, $auth);
$token = $pve2->getCSRFPreventionToken();
$file = file_get_contents('novnc/index.html.tpl', FILE_USE_INCLUDE_PATH);
$searchTerms = array ( '[% vmname %]', '[% username %]', '[% token %]' );
$replacements = array ( $vmname, $userauth, $token );
print(str_replace( $searchTerms, $replacements, $file));
} else {
print("Login to Proxmox Host failed.\n");
}
?>
That’s it! You now should be able to start a noVNC session with the URI parameter you already know from the Proxmox GUI:
https://192.168.1.10/index.php?console=kvm&novnc=1&vmid=100&vmname=test&node=pvelab1&resize=1
Open issues:
Right now all the actions in the noVNC window (Reset, Shutdown, ...) show an error.
They seem to need additional API methods, but thats something I will sort out some time later ...
Hope this saves someone some time