This commit is contained in:
Mateusz Gruszczyński committed 2026-10-11 13:56:30 +02:00
1 parent 95c55da2ee
commit d942c1a35d
42 files changed
+1265 -109

No files matched your search

+66
View File
@@ -114,12 +114,78 @@ accepted only when `administration.tls` is true. Plain remote HTTP remains avail
"tls": true,
"certificate_id": "admin-example",
"allowed_hosts": ["admin.example.com"],
"public_origin": null,
"session_days": 30,
"panel_compression": {"zstd": true, "br": true, "gzip": true}
}
}
```
### Fixed public origin for a reverse-proxied panel (0.31.4)
For a **panel** reached through a trusted reverse proxy, set the optional
`administration.public_origin` in **Settings → Administration** to the exact
browser-facing HTTPS origin (for example `https://panel.example.test`).
**Do not duplicate that hostname in `administration.allowed_hosts`.** Its DNS
hostname is implicitly included in the runtime panel Host allowlist. **Restart
RustProxy**; this is a restart-bound access-control setting. Omit it (`null`) for
direct administration or when forwarded headers are canonical. This setting
is not a wildcard, does not accept HTTP or a URL path, and requires a DNS
hostname rather than an IP address. SQLite schema 9 remains unchanged.
The advanced **Additional allowed DNS hostnames** field controls independent,
extra hostnames only. Older configurations containing both values are
accepted; on editing/saving the redundant duplicate is omitted from the
persisted list. If `public_origin` changes or is cleared, its old hostname is
no longer implicitly allowed (unless explicitly retained as an additional host).
Example for the default **private loopback** administration listener behind an
HTTPS-terminating proxy:
```json
{
"administration": {
"allowed_hosts": [],
"public_origin": "https://panel.example.test"
}
}
```
The last hop must connect from loopback or an existing explicitly trusted proxy
CIDR. If it is not loopback, configure **only the actual proxy peer CIDR** under
Forwarding → Trusted proxies; be aware the general trusted-proxy setting also
applies to public traffic and must never include untrusted clients. The
administration listener should not be reachable directly from external clients.
Do **not** grant trust to public networks to work around Origin failures.
The pinned URL, not an element of `X-Forwarded-Proto`, defines the panel
scheme/authority. A trusted, bounded proxy chain `https, http` (HTTPS on the
browser side, HTTP on an internal hop) is permitted in this explicit mode.
An `http` first hop, malformed/too-long protocol chain, duplicate/conflicting
`X-Forwarded-Host`, different `Origin`, `Sec-Fetch-Site: cross-site`, and missing
CSRF protection for state-changing requests still result in HTTP 403. The
public proxy/vhost data plane is **not changed**, except that an already opted-in
self-admin vhost can recognize the pinned hostname for its reserved panel session
cookie; other upstreams continue to strip it. Credential-bearing certificate
automation retains its original TLS/forwarding checks.
Prefer fixing the proxy's forwarding headers rather than configuring the pin
when practical. For a TLS-only public entry, the closest trusted hop should
**replace**, not append, forwarded headers using known values, for example:
```nginx
proxy_set_header Host panel.example.test;
proxy_set_header X-Forwarded-Host panel.example.test;
proxy_set_header X-Forwarded-Proto https;
```
Only use that `https` setting on an entry that actually verifies external TLS;
never trust an arbitrary inbound `X-Forwarded-Proto`. If multiple intermediate
proxy hops must append protocol values, the pinned mode provides an explicit
server-side comparison target without accepting a client-supplied origin as
authoritative. Confirm deployment using a real mobile browser and the safe
`administration origin rejected` logs before production rollout.
**Administration → Panel content compression** (next to the admin listener/TLS settings)
controls Zstd, Brotli and gzip for the authenticated HTML document, JavaScript,
CSS and language bundles. Each browser request is negotiated using