mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
feat(console): the VNC console uses the panel's own address
The console pages connect to /novncd/ on the address, scheme and port the page itself was loaded from; nginx proxies it to novncd, which listens on the loopback only. There is nothing to configure: the console works on HTTPS (wss), behind another proxy and on any published port. Before, the page connected to WS_PUBLIC_HOST/PORT/PATH, port 6080 by default: straight to novncd, past nginx and without TLS, so an HTTPS panel and a Docker container published on another port had no console until the public port was set by hand, and novncd listened on every interface. Gone: WS_PUBLIC_PORT, WS_PUBLIC_HOST, WS_PUBLIC_PATH and WS_CERT, the installer's two public console questions and its 6080 firewall rule, the Docker image's WS_PUBLIC_PORT and its init script lines, the manual install's firewall rule for 6080 and nginx's unused /websockify location. WS_HOST defaults to 127.0.0.1. A VM with a QEMU websocket port is still reached on that port of the panel's host name (left for a separate decision).
This commit is contained in:
parent
82af555d45
commit
68b104dfe4
14 changed files with 43 additions and 164 deletions
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
|
|
@ -197,7 +197,6 @@ jobs:
|
|||
- name: Console Through Nginx Only
|
||||
run: |
|
||||
[ "$(docker inspect -f '{{json .Config.ExposedPorts}}' webvirtcloud:ci)" = '{"80/tcp":{}}' ]
|
||||
docker exec wvc grep -qx 'WS_PUBLIC_PORT = 80' /srv/webvirtcloud/webvirtcloud/settings.py
|
||||
code=$(curl -s -m 5 -o /dev/null -w '%{http_code}' -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
|
||||
-H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGVzdGtleXRlc3RrZXk9PQ==' http://127.0.0.1:8080/novncd/ || true)
|
||||
[ "$code" = 101 ] || { echo "websocket upgrade through nginx: $code"; exit 1; }
|
||||
|
|
|
|||
|
|
@ -27,10 +27,6 @@ FROM phusion/baseimage:noble-1.0.3
|
|||
|
||||
EXPOSE 80
|
||||
|
||||
# The browser reaches the console through nginx on the panel's port (the init
|
||||
# script writes this into settings.py); set it to the published port if not 80.
|
||||
ENV WS_PUBLIC_PORT=80
|
||||
|
||||
# Use baseimage-docker's init system. my_init force-stops services after
|
||||
# KILL_PROCESS_TIMEOUT seconds (default 30); the worker drains jobs for 60 s.
|
||||
ENV KILL_PROCESS_TIMEOUT=80
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ semanage fcontext -a -t httpd_sys_content_t "/srv/webvirtcloud(/.*)" 2>/dev/null
|
|||
restorecon -R /srv/webvirtcloud 2>/dev/null || true
|
||||
setsebool -P httpd_can_network_connect on 2>/dev/null || true
|
||||
firewall-cmd --add-service=http --permanent 2>/dev/null || true
|
||||
firewall-cmd --add-port=6080/tcp --permanent 2>/dev/null || true
|
||||
firewall-cmd --reload 2>/dev/null || true
|
||||
systemctl daemon-reload && systemctl enable --now webvirt-cloud webvirt-novncd webvirt-socketiod webvirt-worker
|
||||
systemctl enable nginx && nginx -t && systemctl restart nginx
|
||||
|
|
@ -295,7 +294,6 @@ If libvirt warns `Host SMBIOS information is not available`, install `dmidecode`
|
|||
| `EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_HOST_USER`, `EMAIL_HOST_PASSWORD`, `EMAIL_USE_TLS` | SMTP for e-mail OTP |
|
||||
| `WEBVIRTCLOUD_LOG_FILE` | log file (default `data/webvirtcloud.log`, rotated at 10 MB × 5) |
|
||||
| `SECRET_KEY` | Django secret key (default: the `data/secret_key` file) |
|
||||
| `WS_PUBLIC_PORT`, `WS_PUBLIC_HOST`, `WS_PUBLIC_PATH` | Docker only: public console address; `WS_PUBLIC_PORT` must be the port the panel is published on (default 80) |
|
||||
|
||||
Where to set them:
|
||||
|
||||
|
|
@ -309,7 +307,6 @@ For a panel served over HTTPS:
|
|||
|
||||
- set `WEBVIRTCLOUD_HTTPS=1`: session and CSRF cookies become HTTPS-only, HTTP is redirected to HTTPS (except `/datasource/`, which VMs fetch over HTTP), and HSTS is sent for one year;
|
||||
- add the HTTPS origin to `CSRF_TRUSTED_ORIGINS`, e.g. `CSRF_TRUSTED_ORIGINS=https://wvc.example.com` and `WEBVIRTCLOUD_HTTPS=1` in `/etc/default/webvirtcloud`;
|
||||
- set the public noVNC port to the proxy's port (the bundled nginx config already proxies `/novncd/`): `WS_PUBLIC_PORT = 443` in `webvirtcloud/settings.py`, or `WS_PUBLIC_PORT=443` in `docker-compose.override.yml` for Docker;
|
||||
|
||||
TLS can end at the bundled nginx or at a proxy in front of it; such a proxy must send `X-Forwarded-Proto: https`. Failed logins are counted per client address, which the bundled nginx passes in `X-Real-IP`. A proxy that replaces the bundled nginx must set `X-Real-IP` itself, and its address must be in `LOGIN_TRUSTED_PROXIES` in `settings.py`. With a proxy in front of the bundled nginx, configure nginx's `set_real_ip_from` / `real_ip_header` for that proxy, or all clients share its address.
|
||||
|
||||
|
|
@ -610,7 +607,7 @@ A version from before v3.0.0 has no worker: `systemctl disable --now webvirt-wor
|
|||
- With the bundled nginx config, browsers revalidate static files on each load (304 when unchanged), so an update or a theme change shows without a hard reload. Files cached before this update can stay until a hard reload (Ctrl+F5) of each affected page, or until the site's browser cache is cleared once; an external caching proxy may need a purge.
|
||||
- External snapshots use libvirt's snapshot API and need libvirt 9.9 or newer on the compute hosts. They work on UEFI VMs and running, paused or shut-off VMs, can save memory too or, on a running VM with a connected QEMU guest agent, freeze the guest's file systems (the default there), and a revert keeps disks added later (it detaches them). A snapshot is refused when a storage pool with the VM's disks has less free space than a share of those disks (10%, at least 1 GiB; both on the Settings page) plus, for the pool of the memory file, the VM's memory; this is checked before the snapshot only, nothing is reserved. A VM's snapshots form one chain: after a revert, delete the newer snapshots before taking another. Snapshot names no longer get an `s1.` prefix; existing ones keep theirs and can still be reverted and deleted, except that a snapshot an older version took of a UEFI VM can only be deleted. On NFS, libvirt removes merged snapshot files as the qemu user, who needs write access to the image directory; files it could not remove are named in a warning after the delete or revert. Deleting a VM with its data removes its snapshot files too, except a template it grew from and files another VM uses.
|
||||
- A storage volume a VM still needs (a disk, a backing file or a snapshot's file) is no longer deleted from the storage page or the API; the delete is refused with the reason. Only VMs on the same compute are checked.
|
||||
- Docker no longer publishes port 6080; the console goes through nginx on the panel's port (`WS_PUBLIC_PORT`, default 80).
|
||||
- The VNC console connects to `/novncd/` on the panel's own address, scheme and port, through nginx: it works on HTTPS, behind another proxy and on any published port without settings. `WS_PUBLIC_PORT`, `WS_PUBLIC_HOST`, `WS_PUBLIC_PATH` and `WS_CERT` are gone; remove them from `docker-compose.override.yml`, `/etc/default/webvirtcloud` or a kept `settings.py`, set `WS_HOST = "127.0.0.1"` in a kept `settings.py`, and close port 6080 in the firewall.
|
||||
- The serial console works (off by default, see [Serial console](#serial-console)); `SOCKETIO_PUBLIC_HOST`/`_PORT`/`_PATH` are gone, the page uses the panel's own address.
|
||||
- Long operations run as jobs in a worker process (`manage.py run_worker`); follow them on the VM page and on the Jobs page.
|
||||
- Cloning a VM or a volume and creating a VM run as jobs: the page returns at once and the job panel follows them. The API's VM create answers 202 with the job and needs a new `submission_key` per request. The create form no longer takes a console password; set it on the VM page.
|
||||
|
|
@ -697,7 +694,7 @@ Run every step as your normal user, not with `sudo`: if `manage.py` ever runs as
|
|||
python manage.py runserver 0.0.0.0:8000 --settings=webvirtcloud.settings-dev
|
||||
```
|
||||
|
||||
Open `http://127.0.0.1:8000`. For the browser console, run `python console/novncd` (port 6080) in a separate terminal.
|
||||
Open `http://127.0.0.1:8000`. The browser consoles connect to `/novncd/` and `/socket.io/` on the panel's own address, which the dev server does not proxy: try them in the Docker image, or behind nginx with `conf/nginx/webvirtcloud.conf`.
|
||||
|
||||
### Running tests
|
||||
|
||||
|
|
|
|||
|
|
@ -49,12 +49,6 @@ server {
|
|||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 1h;
|
||||
}
|
||||
location /websockify {
|
||||
proxy_pass http://wsnovncd;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
||||
upstream wsnovncd {
|
||||
|
|
|
|||
|
|
@ -20,17 +20,6 @@ if [ -z "$SECRET_KEY" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Apply optional WebSocket configuration from environment
|
||||
if [ -n "$WS_PUBLIC_PORT" ]; then
|
||||
sed -i "s|^WS_PUBLIC_PORT = .*|WS_PUBLIC_PORT = $WS_PUBLIC_PORT|" "$APP_DIR/webvirtcloud/settings.py"
|
||||
fi
|
||||
if [ -n "$WS_PUBLIC_HOST" ]; then
|
||||
sed -i "s|^WS_PUBLIC_HOST = .*|WS_PUBLIC_HOST = \"$WS_PUBLIC_HOST\"|" "$APP_DIR/webvirtcloud/settings.py"
|
||||
fi
|
||||
if [ -n "$WS_PUBLIC_PATH" ]; then
|
||||
sed -i "s|^WS_PUBLIC_PATH = .*|WS_PUBLIC_PATH = \"$WS_PUBLIC_PATH\"|" "$APP_DIR/webvirtcloud/settings.py"
|
||||
fi
|
||||
|
||||
# Persist SQLite database in DATA_DIR
|
||||
if [ ! -f "$DATA_DIR/db.sqlite3" ] && [ -f "$APP_DIR/db.sqlite3" ] && [ ! -L "$APP_DIR/db.sqlite3" ]; then
|
||||
mv "$APP_DIR/db.sqlite3" "$DATA_DIR/db.sqlite3"
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ from urllib.parse import parse_qs, urlparse
|
|||
import argparse
|
||||
from console.sshtunnels import close_tunnel, open_tunnel, tunnel_target
|
||||
from vrtManager.connection import CONN_SOCKET, CONN_SSH
|
||||
from webvirtcloud.settings import WS_CERT, WS_HOST, WS_PORT
|
||||
from webvirtcloud.settings import WS_HOST, WS_PORT
|
||||
|
||||
|
||||
def get_parser(default_host=WS_HOST, default_port=WS_PORT or 6080, default_cert=WS_CERT or CERT):
|
||||
def get_parser(default_host=WS_HOST, default_port=WS_PORT or 6080, default_cert=CERT):
|
||||
parser = argparse.ArgumentParser(description="WebVirtCloud noVNC daemon")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
|
|
|
|||
|
|
@ -176,10 +176,9 @@
|
|||
bindKeyAction('ctrlaltf' + (i + 1), () => sendCtrlAltFN(i));
|
||||
}
|
||||
|
||||
let fullPath = '{{ ws_path|escapejs }}';
|
||||
if (fullPath.startsWith('/')) {
|
||||
fullPath = fullPath.substring(1);
|
||||
}
|
||||
// novncd behind the panel's own address (nginx's /novncd/); a VM with a
|
||||
// QEMU websocket port is reached on that port of the panel's host name
|
||||
let fullPath = 'novncd/';
|
||||
const token = '{{ token|escapejs }}';
|
||||
if (token) {
|
||||
fullPath += (fullPath.includes('?') ? '&' : '?') + 'token=' + encodeURIComponent(token);
|
||||
|
|
@ -195,10 +194,12 @@
|
|||
{% endif %}
|
||||
};
|
||||
|
||||
const https = window.location.protocol === 'https:';
|
||||
const mandatory = {
|
||||
host: '{{ ws_host|escapejs }}',
|
||||
port: {{ ws_port|default:6080 }},
|
||||
host: window.location.hostname,
|
||||
port: Number('{{ console_websocket_port|default_if_none:""|escapejs }}' || window.location.port || (https ? 443 : 80)),
|
||||
path: fullPath,
|
||||
encrypt: https,
|
||||
};
|
||||
|
||||
UI.start({ settings: { defaults, mandatory } });
|
||||
|
|
@ -345,16 +346,16 @@
|
|||
</li>
|
||||
<li>
|
||||
<label for="noVNC_setting_host">Host:</label>
|
||||
<input id="noVNC_setting_host" type="text" value="{{ ws_host }}">
|
||||
<input id="noVNC_setting_host" type="text">
|
||||
</li>
|
||||
<li>
|
||||
<label for="noVNC_setting_port">Port:</label>
|
||||
<input id="noVNC_setting_port" type="number" value="{{ ws_port }}">
|
||||
<input id="noVNC_setting_port" type="number">
|
||||
</li>
|
||||
<li>
|
||||
<label for="noVNC_setting_path">Path:</label>
|
||||
<!-- <input id="noVNC_setting_path" type="text" value="websockify"> -->
|
||||
<input id="noVNC_setting_path" type="text" value="{{ ws_path }}">
|
||||
<input id="noVNC_setting_path" type="text">
|
||||
</li>
|
||||
</ul></div>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -265,10 +265,11 @@
|
|||
bindKeyAction('ctrlaltf' + (i + 1), () => sendCtrlAltFN(i));
|
||||
}
|
||||
|
||||
// The proxy the server names, never one from the link: the page sends
|
||||
// it a console token
|
||||
const host = '{{ ws_host|escapejs }}';
|
||||
let port = '{{ ws_port|escapejs }}';
|
||||
// novncd behind the panel's own address (nginx's /novncd/), never a host
|
||||
// from the link: the page sends it a console token. A VM with a QEMU
|
||||
// websocket port is reached on that port of the panel's host name.
|
||||
const host = window.location.hostname;
|
||||
let port = '{{ console_websocket_port|default_if_none:""|escapejs }}' || window.location.port;
|
||||
|
||||
{% if perms.instances.passwordless_console and console_passwd %}
|
||||
const password = '{{ console_passwd|escapejs }}';
|
||||
|
|
@ -276,7 +277,7 @@
|
|||
const password = readQueryVariable('password');
|
||||
{% endif %}
|
||||
|
||||
const path = '{{ ws_path|escapejs }}';
|
||||
const path = 'novncd/';
|
||||
|
||||
// | | | | | |
|
||||
// | | | Connect | | |
|
||||
|
|
|
|||
|
|
@ -89,8 +89,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
self.assertEqual(
|
||||
unsigned, f"{self.compute.id}:{self.instance.uuid}:{self.admin_user.id}"
|
||||
)
|
||||
self.assertEqual(response.context["ws_path"], "novncd/")
|
||||
self.assertEqual(response.context["ws_port"], 6080)
|
||||
self.assertEqual(response.context["console_passwd"], "vncsecret")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
|
|
@ -106,7 +104,7 @@ class ConsoleViewsTestCase(TestCase):
|
|||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "console-vnc-full.html")
|
||||
self.assertEqual(response.context["ws_port"], 5900)
|
||||
self.assertEqual(response.context["console_websocket_port"], 5900)
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
def test_the_lite_console_switches_scaling_from_its_menu(self, mock_wvm):
|
||||
|
|
@ -247,7 +245,7 @@ class ConsoleViewsTestCase(TestCase):
|
|||
self.assertNotContains(response, "attacker.example")
|
||||
for name in ("host", "port", "path"):
|
||||
self.assertNotContains(response, f"readQueryVariable('{name}'")
|
||||
self.assertContains(response, "const host = 'testserver';")
|
||||
self.assertContains(response, "const host = window.location.hostname;")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
def test_the_page_sets_no_token_cookie(self, mock_wvm):
|
||||
|
|
@ -278,60 +276,18 @@ class ConsoleViewsTestCase(TestCase):
|
|||
self.assertTemplateNotUsed(response, "console-vnc-lite.html")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
@override_settings(WS_PUBLIC_PATH="/novncd/")
|
||||
def test_console_ws_path_normalization_leading_slash(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
def test_both_pages_connect_to_novncd_behind_the_panels_own_address(self, mock_wvm):
|
||||
# nginx proxies /novncd/ on the panel's own scheme, host and port: no
|
||||
# console address to configure, HTTPS gives wss
|
||||
mock_wvm.return_value.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value.get_console_websocket_port.return_value = None
|
||||
self.client.force_login(self.admin_user)
|
||||
url = reverse("console") + f"?token={self.token}"
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["ws_path"], "novncd/")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
@override_settings(WS_PUBLIC_PATH="novncd/")
|
||||
def test_console_ws_path_normalization_clean(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
url = reverse("console") + f"?token={self.token}"
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["ws_path"], "novncd/")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
@override_settings(WS_PUBLIC_PATH="/")
|
||||
def test_console_ws_path_root_slash(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
url = reverse("console") + f"?token={self.token}"
|
||||
response = self.client.get(url)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["ws_path"], "")
|
||||
|
||||
@override_settings(ALLOWED_HOSTS=["panel.example.com"])
|
||||
@patch("console.views.wvmInstance")
|
||||
def test_console_ws_host_strip_port(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
url = reverse("console") + f"?token={self.token}"
|
||||
response = self.client.get(url, HTTP_HOST="panel.example.com:8080")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context["ws_host"], "panel.example.com")
|
||||
lite = self.client.get(reverse("console") + f"?token={self.token}&view=lite")
|
||||
self.assertContains(lite, "const host = window.location.hostname;")
|
||||
self.assertContains(lite, "const path = 'novncd/';")
|
||||
full = self.client.get(reverse("console") + f"?token={self.token}&view=full")
|
||||
self.assertContains(full, "host: window.location.hostname,")
|
||||
self.assertContains(full, "encrypt: https,")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
def test_console_xss_protection_query_parameters(self, mock_wvm):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# pylint: disable=no-name-in-module,no-member
|
||||
import re
|
||||
|
||||
from appsettings.settings import app_settings
|
||||
from console import tokens
|
||||
|
|
@ -112,20 +111,6 @@ def console(request):
|
|||
console_websocket_port = None
|
||||
console_passwd = None
|
||||
|
||||
ws_public_port = getattr(settings, "WS_PUBLIC_PORT", 6080)
|
||||
ws_public_host = getattr(settings, "WS_PUBLIC_HOST", None)
|
||||
ws_public_path = getattr(settings, "WS_PUBLIC_PATH", "/")
|
||||
|
||||
ws_port = console_websocket_port if console_websocket_port else ws_public_port
|
||||
ws_host = ws_public_host if ws_public_host else request.get_host()
|
||||
ws_path = ws_public_path if ws_public_path else "/"
|
||||
|
||||
if ":" in ws_host:
|
||||
ws_host = re.sub(":[0-9]+", "", ws_host)
|
||||
|
||||
if ws_path:
|
||||
ws_path = ws_path.strip("/") + "/" if ws_path.strip("/") else ""
|
||||
|
||||
if console_type and not running: # a shut-off VM has no console to connect to
|
||||
console_error = _("The VM is not running: start it to open its console.")
|
||||
response = render(request, "console-vnc-lite.html", locals())
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ The platform provides:
|
|||
| Web Browser / Client |
|
||||
+--------------+--------------+
|
||||
|
|
||||
HTTP / HTTPS (Port 80/443) WebSockets (Port 6080)
|
||||
| |
|
||||
v v
|
||||
HTTP / HTTPS and WebSockets (Port 80/443)
|
||||
|
|
||||
v
|
||||
+------------------------------------------------------------------------------------+
|
||||
| Nginx Reverse Proxy |
|
||||
| ├── /static/ --> Static Assets (WhiteNoise / Nginx) |
|
||||
| ├── / --> Gunicorn (Django WSGI Application) |
|
||||
| └── :6080 --> WebSockify (novncd background service) |
|
||||
| ├── /novncd/ --> novncd (VNC console proxy, 127.0.0.1:6080) |
|
||||
| └── /socket.io/ --> socketiod (serial console, 127.0.0.1:6081) |
|
||||
+-------------------------------------+----------------------------------------------+
|
||||
|
|
||||
v
|
||||
|
|
@ -160,7 +161,7 @@ Built on Django REST Framework with `drf-nested-routers`, providing a structured
|
|||
## 6. Deployment & Service Lifecycle
|
||||
|
||||
1. **Gunicorn**: WSGI application server running `webvirtcloud.wsgi:application` (binds to a Unix socket or port 8000).
|
||||
2. **novncd**: Background WebSockify daemon translating VNC TCP ports to WebSockets on port 6080.
|
||||
2. **novncd**: Background WebSockify daemon translating VNC TCP ports to WebSockets; it listens on 127.0.0.1:6080 behind nginx's `/novncd/`.
|
||||
3. **Nginx**: Front-facing reverse proxy handling ports 80/443, serving static assets directly, proxying dynamic web requests to Gunicorn, and routing WebSocket console traffic to `novncd`.
|
||||
4. **systemd / runit**: systemd units on hosts (`conf/systemd/`) and runit services in the Docker image (`conf/runit/`) run Gunicorn, novncd, socketiod and the job worker with automatic restarts.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ services:
|
|||
# - SECRET_KEY=your-custom-secret-key-here
|
||||
# Optional: comma-separated trusted CSRF origins (e.g. http://wvc.example.com,https://wvc.example.com)
|
||||
# - CSRF_TRUSTED_ORIGINS=http://localhost,http://127.0.0.1
|
||||
# The console goes through nginx on the panel's port: set this to the
|
||||
# published port if it is not 80 (443 behind TLS)
|
||||
# - WS_PUBLIC_PORT=443
|
||||
# Optional: PostgreSQL instead of the bundled sqlite (also WEBVIRTCLOUD_DB_PORT/_NAME/_USER)
|
||||
# - WEBVIRTCLOUD_DB_HOST=db.example.com
|
||||
# - WEBVIRTCLOUD_DB_PASSWORD=change-me
|
||||
|
|
|
|||
|
|
@ -307,14 +307,10 @@ install_webvirtcloud () {
|
|||
# settings.py reads data/secret_key, so the key persists across re-runs.
|
||||
tzone_escape="$(echo -n "$tzone"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
||||
novncd_port_escape="$(echo -n "$novncd_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
||||
novncd_public_port_escape="$(echo -n "$novncd_public_port"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
||||
novncd_host_escape="$(echo -n "$novncd_host"|sed -e 's/[](){}<>=:\!\?\+\|\/\&$*.^[]/\\&/g')"
|
||||
|
||||
#TODO escape SED delimiter in variables
|
||||
sed -i "s|^\\(TIME_ZONE = \\).*|\\1$tzone_escape|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
sed -i "s|^\\(WS_PORT = \\).*|\\1$novncd_port_escape|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
sed -i "s|^\\(WS_PUBLIC_PORT = \\).*|\\1$novncd_public_port_escape|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
sed -i "s|^\\(WS_HOST = \\).*|\\1\'$novncd_host_escape\'|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
|
||||
# set CSRF TRUSTED ORIGINS
|
||||
host_ip="'http://127.0.0.1', "
|
||||
|
|
@ -362,12 +358,8 @@ install_webvirtcloud () {
|
|||
|
||||
set_firewall () {
|
||||
if test -n "$(command -v firewall-cmd)" && test "$(firewall-cmd --state)" == "running"; then
|
||||
echo "* Configuring firewall to allow HTTP & novnc traffic."
|
||||
echo "* Configuring firewall to allow HTTP traffic."
|
||||
log "firewall-cmd --zone=public --add-port=http/tcp --permanent"
|
||||
log "firewall-cmd --zone=public --add-port=$novncd_port/tcp --permanent"
|
||||
#firewall-cmd --zone=public --add-port=$novncd_port/tcp --permanent
|
||||
log "firewall-cmd --zone=public --add-port=$novncd_public_port/tcp --permanent"
|
||||
#firewall-cmd --zone=public --add-port=$novncd_public_port/tcp --permanent
|
||||
log "firewall-cmd --reload"
|
||||
#firewall-cmd --reload
|
||||
fi
|
||||
|
|
@ -536,22 +528,6 @@ fi
|
|||
echo " Setting novnc service port $novncd_port"
|
||||
echo ""
|
||||
|
||||
echo -n " Q. NOVNC public port number for reverse proxy(e.g: 80 or 443)?(Default: 6080) "
|
||||
read -r novncd_public_port
|
||||
if [ -z "$novncd_public_port" ]; then
|
||||
readonly novncd_public_port=6080
|
||||
fi
|
||||
echo " Setting novnc public port $novncd_public_port"
|
||||
echo ""
|
||||
|
||||
echo -n " Q. NOVNC host listen ip?(Default: 0.0.0.0) "
|
||||
read -r novncd_host
|
||||
if [ -z "$novncd_host" ]; then
|
||||
readonly novncd_host="0.0.0.0"
|
||||
fi
|
||||
echo " Setting novnc host ip $novncd_host"
|
||||
echo ""
|
||||
|
||||
echo "========="
|
||||
echo "distro: ${distro}"
|
||||
echo "========="
|
||||
|
|
|
|||
|
|
@ -275,23 +275,10 @@ LOGGING = {
|
|||
# WebVirtCloud settings
|
||||
#
|
||||
|
||||
# Websock port
|
||||
# The VNC console proxy (novncd). Browsers reach it through nginx's /novncd/
|
||||
# on the panel's own address, so it listens on the loopback only.
|
||||
WS_PORT = 6080
|
||||
|
||||
# Websock host
|
||||
WS_HOST = "0.0.0.0"
|
||||
|
||||
# Websock public port - 80 or 443 if reverse-proxy, else 6080
|
||||
WS_PUBLIC_PORT = 6080
|
||||
|
||||
# Websock public host
|
||||
WS_PUBLIC_HOST = None
|
||||
|
||||
# Websock public path
|
||||
WS_PUBLIC_PATH = "novncd/"
|
||||
|
||||
# Websock Certificate for SSL
|
||||
WS_CERT = None
|
||||
WS_HOST = "127.0.0.1"
|
||||
|
||||
# Serial console (xterm.js over socketiod) for VMs without graphics. socketiod
|
||||
# accepts only the console page's signed token (as noVNC does); while this is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue