mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(settings): ALLOWED_HOSTS lists the server's names instead of accepting any host
This commit is contained in:
parent
c1381318f1
commit
9f5e8fe1c4
8 changed files with 90 additions and 4 deletions
43
README.md
43
README.md
|
|
@ -84,10 +84,23 @@ Run WebVirtCloud in a container with persistent volumes for data and SSH keys:
|
|||
git clone https://github.com/retspen/webvirtcloud
|
||||
cd webvirtcloud
|
||||
|
||||
# 2. Start services:
|
||||
# 2. Create docker-compose.override.yml (below) with your settings
|
||||
|
||||
# 3. Start services:
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Local settings go in `docker-compose.override.yml`, which Compose merges into
|
||||
`docker-compose.yml` and which `git pull` never touches. At least list the
|
||||
names/IPs the panel is reached by:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
webvirtcloud:
|
||||
environment:
|
||||
- ALLOWED_HOSTS=wvc.example.com,192.0.2.10
|
||||
```
|
||||
|
||||
Access the panel at `http://<server-ip>` and noVNC console at port `6080`.
|
||||
|
||||
## Manual Installation
|
||||
|
|
@ -106,6 +119,13 @@ python3 conf/runit/secret_generator.py > data/secret_key
|
|||
chmod 600 data/secret_key
|
||||
```
|
||||
|
||||
### Allowed hosts
|
||||
|
||||
The template answers only to localhost. After copying it in step 3 below, list
|
||||
the names/IPs the panel and the cloud-init datasource are reached by in
|
||||
`webvirtcloud/settings.py`, e.g.
|
||||
`ALLOWED_HOSTS = ["wvc.example.com", "192.0.2.10", "localhost", "127.0.0.1", "[::1]"]`.
|
||||
|
||||
### Ubuntu 20.04 / 22.04 / 24.04 LTS & Debian 11 / 12
|
||||
|
||||
```bash
|
||||
|
|
@ -442,6 +462,15 @@ of `webvirtcloud/settings.py.template` into your `webvirtcloud/settings.py`, set
|
|||
(`sudo nginx -t && sudo systemctl reload nginx`). Re-running the installer
|
||||
replaces that file, including any TLS directives you added to it.
|
||||
|
||||
`ALLOWED_HOSTS` no longer defaults to `"*"`: the template allows localhost, the
|
||||
installer adds the server's name and IPs, and the `ALLOWED_HOSTS` env var
|
||||
(comma-separated) adds more. Docker: set `ALLOWED_HOSTS` in
|
||||
`docker-compose.override.yml` to the names/IPs you open the panel and the cloud-init datasource with; requests
|
||||
for any other host get 400. Bare metal (your settings.py is kept): replace
|
||||
`ALLOWED_HOSTS = ["*"]` with the names/IPs the panel and the datasource are
|
||||
reached by, and copy the `if extra_hosts := ...` lines below it from the
|
||||
template so the env var works.
|
||||
|
||||
```bash
|
||||
# Go to Installation Directory
|
||||
cd /srv/webvirtcloud
|
||||
|
|
@ -453,6 +482,18 @@ python3 manage.py collectstatic --noinput
|
|||
sudo systemctl restart supervisor # supervisord on RHEL / openSUSE
|
||||
```
|
||||
|
||||
Docker: each new container generates `settings.py` from the template and runs
|
||||
the migrations at start; the database and the secret key stay in the `data`
|
||||
volume. Keep your variables (at least `ALLOWED_HOSTS`) in
|
||||
`docker-compose.override.yml` (see Docker Deployment), then:
|
||||
|
||||
```bash
|
||||
cd webvirtcloud
|
||||
docker compose cp webvirtcloud:/srv/webvirtcloud/data/db.sqlite3 ./db.sqlite3.bak
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
> **Note on Settings Upgrade:**
|
||||
> When upgrading from earlier versions using `drf-yasg`, update your `webvirtcloud/settings.py`:
|
||||
> 1. In `INSTALLED_APPS`, replace `'drf_yasg'` with `'drf_spectacular'` and `'drf_spectacular_sidecar'`.
|
||||
|
|
|
|||
|
|
@ -58,3 +58,16 @@ wvc_install_nginx() {
|
|||
cp "$snippet" "$etc/conf.d/webvirtcloud.conf"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Python list literal for ALLOWED_HOSTS: the FQDN, the loopbacks and the given
|
||||
# IPs. IPv6 addresses are bracketed, as Django compares them.
|
||||
wvc_allowed_hosts() {
|
||||
local host out="" seen=" "
|
||||
for host in "$1" localhost 127.0.0.1 ::1 "${@:2}"; do
|
||||
case "$host" in *:*) host="[$host]" ;; esac
|
||||
case "$seen" in *" $host "*) continue ;; esac
|
||||
seen+="$host "
|
||||
out+="${out:+, }'$host'"
|
||||
done
|
||||
echo "[$out]"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,5 +66,9 @@ echo "OP_EDIT" > "$etc3/nginx.conf"
|
|||
wvc_install_nginx "$tmp/main_tpl" "$tmp/snippet" "$etc3"
|
||||
check "no-orig second run keeps operator edit" "[ \"\$(cat '$etc3/nginx.conf')\" = OP_EDIT ]"
|
||||
|
||||
# wvc_allowed_hosts: fqdn + loopbacks + IPs, IPv6 bracketed, no duplicates
|
||||
check "allowed hosts list" "[ \"\$(wvc_allowed_hosts wvc.example.com 192.0.2.10 2001:db8::1 127.0.0.1)\" = \"['wvc.example.com', 'localhost', '127.0.0.1', '[::1]', '192.0.2.10', '[2001:db8::1]']\" ]"
|
||||
check "allowed hosts without ips" "[ \"\$(wvc_allowed_hosts wvc.example.com)\" = \"['wvc.example.com', 'localhost', '127.0.0.1', '[::1]']\" ]"
|
||||
|
||||
[ "$fail" = 0 ] && echo "ALL PASS" || echo "FAILURES"
|
||||
exit "$fail"
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ class ConsoleViewsTestCase(TestCase):
|
|||
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()
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ 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
|
||||
# Host names/IPs the panel is reached by (comma-separated; "*" accepts any).
|
||||
# Without it only localhost works. Set it in docker-compose.override.yml.
|
||||
- ALLOWED_HOSTS=localhost
|
||||
- TZ=UTC
|
||||
volumes:
|
||||
# Persistent SQLite database and runtime data
|
||||
|
|
|
|||
|
|
@ -318,6 +318,9 @@ install_webvirtcloud () {
|
|||
done
|
||||
fi
|
||||
sed -i "s|^\\(CSRF_TRUSTED_ORIGINS = \\).*|\\1\[ \'http://$fqdn\', $host_ip ]|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
# shellcheck disable=SC2046
|
||||
allowed_hosts="$(wvc_allowed_hosts "$fqdn" $(hostname -I 2>/dev/null))"
|
||||
sed -i "s|^ALLOWED_HOSTS = .*|ALLOWED_HOSTS = $allowed_hosts|" "$APP_PATH/webvirtcloud/settings.py"
|
||||
else
|
||||
echo "* Keeping existing settings.py (not overwritten)."
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -29,7 +29,11 @@ DEBUG = False
|
|||
|
||||
MAC_OUI = '52:54:10'
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
# Host names the panel answers to. The installer writes the server's; add more
|
||||
# (comma-separated, "*" for any) through the environment.
|
||||
ALLOWED_HOSTS = ["localhost", "127.0.0.1", "[::1]"]
|
||||
if extra_hosts := os.getenv("ALLOWED_HOSTS"):
|
||||
ALLOWED_HOSTS.extend([host.strip() for host in extra_hosts.split(",") if host.strip()])
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = ["http://localhost", "http://127.0.0.1", "http://localhost:8000", "http://127.0.0.1:8000"]
|
||||
if extra_origins := os.getenv("CSRF_TRUSTED_ORIGINS"):
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import subprocess
|
|||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test import SimpleTestCase, TestCase, override_settings
|
||||
|
||||
# Env vars that change the settings; removed from the inherited environment so
|
||||
# every case starts from the defaults.
|
||||
CONFIG_VARS = ["WEBVIRTCLOUD_HTTPS"]
|
||||
CONFIG_VARS = ["WEBVIRTCLOUD_HTTPS", "ALLOWED_HOSTS"]
|
||||
|
||||
|
||||
def _env(env):
|
||||
|
|
@ -68,3 +68,20 @@ class HttpsProfileTestCase(TestCase):
|
|||
with override_settings(SECURE_SSL_REDIRECT=True):
|
||||
response = self.client.get("/accounts/login/", HTTP_X_FORWARDED_PROTO="https")
|
||||
self.assertNotEqual(response.status_code, 301)
|
||||
|
||||
|
||||
class AllowedHostsTestCase(SimpleTestCase):
|
||||
def hosts(self, env):
|
||||
return load_settings(env, ["ALLOWED_HOSTS"])["ALLOWED_HOSTS"]
|
||||
|
||||
def test_allowed_hosts_default_is_not_any_host(self):
|
||||
hosts = self.hosts({})
|
||||
self.assertNotIn("*", hosts)
|
||||
self.assertIn("localhost", hosts)
|
||||
|
||||
def test_allowed_hosts_extended_from_env(self):
|
||||
hosts = self.hosts({"ALLOWED_HOSTS": " wvc.example.com, ,192.0.2.10 "})
|
||||
self.assertEqual(hosts[-2:], ["wvc.example.com", "192.0.2.10"])
|
||||
|
||||
def test_allowed_hosts_star_escape(self):
|
||||
self.assertIn("*", self.hosts({"ALLOWED_HOSTS": "*"}))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue