Release / verify (push) Canceled after 0s
CI / checks (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 0s
Release / test (push) Canceled after 0s
Release / publish (backend) (push) Canceled after 0s
Release / publish (frontend) (push) Canceled after 0s
Release / publish (proxy) (push) Canceled after 0s
Release / publish (updater) (push) Canceled after 0s
Vorgesehen als MINOR-Release **1.27.0** „Firewall-Oberfläche über OPNexus“. - **Firewall-Oberfläche über OPNexus:** Auf der Host-Seite öffnet **Oberfläche öffnen** die Weboberfläche der Firewall in einem neuen Tab, auch bei Firewalls hinter NAT im Management-Tunnel. Nur für Admins; jede Firewall läuft in einer eigenen Browser-Origin (Platz = Port), Cookies bleiben auf dem Server, das Ticket gilt einmalig 30 Sekunden, Inaktivitäts- und Gesamtlimit sind einstellbar, Ticket, Start und Ende stehen im Audit (Art „GUI-Zugriff“). Standardmäßig **aus**: braucht das Compose-Profil `gui`, `OPNEXUS_GUI_SITES`, `GUI_PORTS`, `GUI_GATEWAY_TOKEN`, `COOKIE_SECURE=true` und den Schalter unter Einstellungen (Handbuch, „Firewall-Oberfläche über OPNexus“). Live getestet auf OPNsense 26.7. - **Einschränkungen:** kein WebSocket, keine automatische Anmeldung, höchstens 4 Plätze gleichzeitig. OPNexus-Adresse vorher in die Whitelist des Anmeldeschutzes (sshguard) der Firewall eintragen, sonst können Fehlanmeldungen die API-Zugriffe von OPNexus aussperren. Nach einem Neustart des wg-hub braucht der Tunnel 2 bis 4 Minuten. - **Hinweis für Betreiber mit eigenen Skripten:** Bei HTTPS heißt das Sitzungs-Cookie jetzt `__Host-opnexus-session` (bestehende Sitzungen werden ohne Abmelden übernommen), und Cookie-Anfragen an `/api` mit `Sec-Fetch-Site: same-site/cross-site` werden abgelehnt. Zugriffe mit API-Token sind nicht betroffen.
100 lines
3.5 KiB
Caddyfile
100 lines
3.5 KiB
Caddyfile
# TLS front for OPNexus. Certificates come from Caddy's own internal CA, so
|
|
# they work for bare IP addresses and for names that exist in no DNS at all.
|
|
# Clients trust it once by importing the root certificate served at
|
|
# /opnexus-ca.crt.
|
|
#
|
|
# OPNEXUS_SITES is a comma-separated list of every address OPNexus is reached
|
|
# by, e.g. "10.0.0.5" or "10.0.0.5, opnexus.lan".
|
|
# OPNEXUS_DEFAULT_SNI is the primary one (normally the IP).
|
|
{
|
|
admin off
|
|
local_certs
|
|
# Clients that connect by bare IP send no SNI, and behind Docker the proxy
|
|
# cannot see which host IP was dialled - so name the certificate to use then.
|
|
default_sni {$OPNEXUS_DEFAULT_SNI}
|
|
# Redirect plain http://IP to https, but never serve anything over http.
|
|
auto_https disable_redirects
|
|
}
|
|
|
|
http:// {
|
|
redir https://{host}{uri} permanent
|
|
}
|
|
|
|
{$OPNEXUS_SITES} {
|
|
encode zstd gzip
|
|
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000"
|
|
X-Content-Type-Options "nosniff"
|
|
X-Frame-Options "DENY"
|
|
Referrer-Policy "no-referrer"
|
|
Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
|
|
Cross-Origin-Opener-Policy "same-origin"
|
|
Cross-Origin-Resource-Policy "same-origin"
|
|
# Next.js hydrates with inline scripts and React sets inline styles, hence
|
|
# 'unsafe-inline'. Everything else is locked to this origin: no third-party
|
|
# scripts, no framing, no plugins, the API is same-origin.
|
|
Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'"
|
|
-Server
|
|
-X-Powered-By
|
|
}
|
|
|
|
# Root certificate of the internal CA, for importing into browsers/OS.
|
|
handle /opnexus-ca.crt {
|
|
root * /data/caddy/pki/authorities/local
|
|
rewrite * /root.crt
|
|
header Content-Type "application/x-x509-ca-cert"
|
|
header Content-Disposition `attachment; filename="opnexus-root-ca.crt"`
|
|
file_server
|
|
}
|
|
|
|
handle /api/* {
|
|
# Every legitimate API body is small JSON; refuse anything bigger before
|
|
# it is buffered by the application.
|
|
request_body {
|
|
max_size 2MB
|
|
}
|
|
reverse_proxy backend:8000
|
|
}
|
|
|
|
handle {
|
|
reverse_proxy frontend:3000
|
|
}
|
|
}
|
|
|
|
# GUI remote access (optional, compose profile "gui"): every slot port is its
|
|
# own browser origin for one firewall web interface, served by the gui-gateway
|
|
# container. OPNEXUS_GUI_SITES lists the slot origins, e.g.
|
|
# "https://10.0.0.5:9441, https://10.0.0.5:9442". Unset, a localhost
|
|
# placeholder keeps the Caddyfile valid; without the gateway it answers 502.
|
|
# Certificates come from the same internal CA (bare IPs work).
|
|
{$OPNEXUS_GUI_SITES:https://localhost:9441} {
|
|
# The gateway sets CSP, X-Frame-Options, no-store etc. itself; no `encode`
|
|
# (it passes the firewall's own content encoding through) and no access log
|
|
# (the redeem URL carries a one-time ticket in its query string).
|
|
header {
|
|
Strict-Transport-Security "max-age=31536000"
|
|
-Server
|
|
-X-Powered-By
|
|
}
|
|
|
|
# The backend's internal gateway API is never reachable from outside, and
|
|
# the gateway would not forward it either; refuse it here as well.
|
|
handle /internal/* {
|
|
respond 404
|
|
}
|
|
|
|
handle {
|
|
# Config restore uploads go through the firewall GUI: same limit as the
|
|
# gateway (64 MB).
|
|
request_body {
|
|
max_size 64MB
|
|
}
|
|
reverse_proxy gui-gateway:8080 {
|
|
# The slot is the port this connection actually arrived on (not the
|
|
# client's Host header); any client-sent X-Onx-Slot is overwritten.
|
|
header_up X-Onx-Slot {http.request.local.port}
|
|
}
|
|
}
|
|
}
|