Hello!
I’ve done several searches, and I must admit I’m completely lost. I would like to do the following:
I’m providing a Python code and an HTML code that you can test on your side, and I would be happy to get your feedback on them.
Thanks in advance!
PS : The protocol wss or https does not impact the URL. So don't need to search the issue here
I’ve done several searches, and I must admit I’m completely lost. I would like to do the following:
- When I’m on a page of an external website (site.fr), API requests should be sent to my Proxmox.
- The requests sent should allow me to retrieve the console of a container (or a virtual machine) on site.fr.
- Use /vncproxy to get a ticket, and then use /vncwebsockets to obtain a wss link.
- Attempt to use the root@pam password and simulate a connection to the console URL of a VM (it works, but only if the browser is already logged into Proxmox). As you can imagine, I’m not going to give my users the Proxmox credentials so they can access their machine.
I’m providing a Python code and an HTML code that you can test on your side, and I would be happy to get your feedback on them.
Thanks in advance!
Python:
sudo apt update && apt upgrade -y
sudo apt install python3-pip
mkdir /var/www
mkdir /var/www/console
mkdir /var/www/console/templates
# On a LXC machine ?
sudo apt install python3-venv
python3 -m venv /var/www/console/venv
source /var/www/console/venv/bin/activate
cd /var/www/console/
pip3 install flask requests
Python:
# server.py
from flask import Flask, render_template, request, jsonify
import requests
app = Flask(__name__)
CONFIG = {
"base_url": "proxmoxUrl:8006/api2/json",
"token_id": "username@auth!tokenId",
"token_secret": "tokenSecret",
"node": "nodeName"
}
@app.route('/')
def index():
return render_template('index.html')
@app.route('/get_vnc_ticket', methods=['POST'])
def get_vnc_ticket():
# Retrieve container ID from the request
container_id = request.json.get("container_id")
if not container_id:
return jsonify({"error": "Container ID is required"}), 400
# Build the Proxmox API endpoint URL
url = f"{CONFIG['base_url']}/nodes/{CONFIG['node']}/lxc/{container_id}/vncproxy"
# Authenticate with Proxmox API and get the VNC ticket
headers = {
"Authorization": f"PVEAPIToken={CONFIG['token_id']}={CONFIG['token_secret']}"
}
try:
response = requests.post(url, headers=headers, verify=False)
response.raise_for_status()
data = response.json()["data"]
return jsonify({
"vncticket": data["ticket"],
"port": data["port"]
})
except requests.exceptions.RequestException as e:
return jsonify({"error": str(e)}), 500
@app.route('/get_vnc_websocket', methods=['GET'])
def get_vnc_websocket():
# Retrieve container ID, vncticket, port, and protocol
container_id = request.args.get("container_id")
vncticket = request.args.get("vncticket")
port = request.args.get("port")
protocol = request.args.get("protocol", "wss")
print(f"Received parameters - container_id: {container_id}, vncticket: {vncticket}, port: {port}, protocol: {protocol}")
if not container_id or not vncticket or not port:
return jsonify({"error": "Container ID, vncticket, and port are required"}), 400
# Ensure that the protocol is either "wss" or "https" (it was just for try the https://)
if protocol not in ["wss", "https"]:
return jsonify({"error": 'Protocol must be either "wss" or "https"'}), 400
# Build the WebSocket URL (with port first and vncticket second)
websocket_url = f"{protocol}://{CONFIG['base_url'].split('//')[1].split(':')[0]}:8006/api2/json/nodes/{CONFIG['node']}/lxc/{container_id}/vncwebsocket?port={port}&vncticket={vncticket}"
return jsonify({"websocket_url": websocket_url})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
# The server will be accessible with the IPv4 given on your machine
# For example, you can access the server with : 123.123.123.123:5000
# You can change the host to 127.0.0.1 if you want to try it on your local machine (if you don't have IPv4 or if you want to run it on your computer for example)
HTML:
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proxmox LXC Console</title>
</head>
<body>
<h1>Access LXC Console</h1>
<form id="vnc-form">
<label for="container_id">Container ID:</label>
<input type="text" id="container_id" name="container_id" required>
<label for="protocol">Protocol:</label>
<select id="protocol" name="protocol">
<option value="wss" selected>WSS</option>
<option value="https">HTTPS</option>
</select>
<button type="submit">Get Console</button>
</form>
<div id="output"></div>
<script>
document.getElementById('vnc-form').addEventListener('submit', async (e) => {
e.preventDefault();
const containerId = document.getElementById('container_id').value;
const protocol = document.getElementById('protocol').value;
try {
// Request VNC Ticket
const ticketResponse = await fetch('/get_vnc_ticket', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ container_id: containerId })
});
const ticketData = await ticketResponse.json();
if (ticketResponse.ok) {
const wsResponse = await fetch(`/get_vnc_websocket?container_id=${containerId}&vncticket=${encodeURIComponent(ticketData.vncticket)}&port=${ticketData.port}&protocol=${protocol}`);
const wsData = await wsResponse.json();
if (wsResponse.ok) {
document.getElementById('output').innerHTML = `
<p>WebSocket URL: <a href="${wsData.websocket_url}" target="_blank">${wsData.websocket_url}</a></p>
`;
} else {
document.getElementById('output').textContent = wsData.error || 'Failed to retrieve WebSocket URL.';
}
} else {
document.getElementById('output').textContent = ticketData.error || 'Failed to retrieve VNC Ticket.';
}
} catch (error) {
document.getElementById('output').textContent = error.message;
}
});
</script>
</body>
</html>
PS : The protocol wss or https does not impact the URL. So don't need to search the issue here
Last edited: