From de34bb6b0b4654addfc0cbd64558b63793bf7fd1 Mon Sep 17 00:00:00 2001 From: host Date: Sat, 25 Jul 2026 02:01:52 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/proxmox_client.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/app/proxmox_client.py b/backend/app/proxmox_client.py index 5fdb505..630bced 100644 --- a/backend/app/proxmox_client.py +++ b/backend/app/proxmox_client.py @@ -9,6 +9,7 @@ import random import re import string import time +from urllib.parse import quote from proxmoxer import ProxmoxAPI @@ -29,6 +30,18 @@ def _client() -> ProxmoxAPI: ) +def _pve_origin_host() -> str: + """Хост, который нужно передавать Proxmox как origin для vncticket. + + PVE привязывает тикет к origin (схема+хост+порт), указанному в vncproxy. + По умолчанию используется хост из PVE_HOST (например, pve1.input.netcraze.pro). + Если задан PVE_PUBLIC_HOST — берётся он (для случая, когда backend внутри + сети использует внутренний адрес, а тикет нужно привязать к внешнему). + """ + origin = getattr(settings, "pve_public_host", "") or settings.pve_host + return origin.replace("https://", "").replace("http://", "").split(":")[0] + + def gen_password(length: int = 14) -> str: """Генерирует криптостойкий пароль из букв и цифр.""" alphabet = string.ascii_letters + string.digits @@ -289,11 +302,21 @@ def get_status(guest_type: str, vmid: int, node: str = None) -> dict: def get_vnc_ticket(guest_type: str, vmid: int, node: str = None) -> dict: - """Запрашивает у Proxmox одноразовый тикет для VNC/websocket-консоли.""" + """Запрашивает у Proxmox одноразовый тикет для VNC/websocket-консоли. + + Важно: Proxmox привязывает тикет к origin (схема+хост+порт). Чтобы + тикет работал через внешний адрес (например, pve1.input.netcraze.pro), + передаём параметр host= при запросе. Backend общается с Proxmox по + внутреннему адресу, но тикет будет валиден для внешнего. + """ node = node or settings.pve_node px = _client() endpoint = px.nodes(node).qemu(vmid) if guest_type == "vm" else px.nodes(node).lxc(vmid) - result = endpoint.vncproxy.post(websocket=1) + + # host=... — указывает, к какому origin привязать тикет (нужно для + # внешнего адреса, если backend подключается к Proxmox по внутреннему). + origin_host = _pve_origin_host() + result = endpoint.vncproxy.post(websocket=1, host=origin_host) return { "ticket": result["ticket"], "port": result["port"],