7.7 KiB
Vhost access and visual locations
0.8.0 edge traffic controls
The Security/Traffic policy section now includes per-client-IP request limits, burst,
window length, country-specific limit overrides, country blocking or allow-only mode,
per-vhost HTTP/3 enable/disable, optional Server-Timing, and a Cloudflare real-client-IP
switch. Country rules use the install-time GeoIP country database. Allow-only mode
fails closed when a country cannot be resolved; block mode only blocks resolved matches.
Exceeded limits return 429 plus Retry-After; country policy denial returns 403. Both
use built-in HTML pages unless a configured custom error page replaces them.
Cloudflare mode trusts CF-Connecting-IP only when the direct peer is inside the
compiled Cloudflare edge CIDRs. An arbitrary client sending that header directly does
not become trusted. The verified address becomes the effective client IP for ACLs,
rate limiting, country lookup and forwarded metadata.
Vhost listener editing is now selection-only. Listener addresses/IPs and transport settings live under Settings > Listeners; a vhost selects one or more named endpoints. Existing inline/legacy bindings are promoted to named endpoints when the vhost is saved.
New backend rows use the HTTPS-by-IP debugging defaults: include in the default LB pool, allow private origin, HTTP/1.1, preserve client Host and backend TLS verification OFF. The panel shows the risk and asks before saving an HTTPS-by-IP backend that does not match the complete preset. Existing backend values are not rewritten automatically.
Health mode off disables active probes only. Passive Backend Health is a separate
opt-in policy and defaults to OFF. With the default policy, normal request failures are
still counted but never mark a backend healthy/unhealthy; an administrator may explicitly
enable passive health even while active probe mode remains off.
WebSockets
vhosts[].websockets controls HTTP/1.1 Upgrade forwarding for that host. Existing
configuration omitting it retains the previous enabled behavior. New hosts created
in the panel default to disabled. Disabled valid upgrades return 403 without opening
an upstream connection; normal HTTP continues. Basic Auth/Tinyauth and ACLs still
apply to an allowed handshake. This does not implement WebSockets over HTTP/3,
WebTransport or generalized CONNECT, and does not terminate already open tunnels
when toggled; it governs subsequent handshakes. After a successful 101, normal TCP
EOF/reset/abort/broken-pipe closure is recorded as tunnel closure rather than an invalid
proxy request; handshake/protocol errors remain errors.
Basic Auth and ACL
The Authentication tab selects None, Tinyauth or HTTP Basic. Basic and Tinyauth
cannot both be enabled. The Basic editor manages users, realm, TLS requirement
and whether verified Authorization: Basic ... is passed to the backend.
Only bounded Argon2id password hashes are persisted. New/changed passwords are
sent to POST /api/basic-auth/hash through the protected administrator API; no
password is stored in browser storage, desired configuration, audit or access logs.
An empty password while editing keeps the saved hash. New passwords use the existing
12-128 byte administrator password policy; Basic credentials cannot contain control
characters. Usernames are case-sensitive, up to 128 UTF-8 bytes, without colons or
control characters. This is not an htpasswd/APR1/bcrypt importer.
TLS is required by default and is checked from the accepted connection, not
X-Forwarded-Proto. Plaintext HTTP is allowed only by an explicit host option; avoid
that outside a deliberately protected TLS-termination network. HTTP Basic encodes,
not encrypts, the username/password. Keep the frontend and any credential-carrying
upstream hop protected. Administrator access defaults to loopback; direct remote access is supported when Administration HTTPS is enabled and the bind/hostname policy is configured.
Successful credentials are removed before forwarding by default. Selecting forward
passes the original verified Basic Authorization header, not a password from
configuration or an unverified client value. The final enforcement step runs after
custom request-header rules, which cannot reintroduce removed credentials.
Remote-User/Remote-Email are stripped in Basic mode; the separate Tinyauth mode
continues to use verified identity headers from that service.
Global host policies, reusable ACL profiles, vhost ACLs and location ACLs remain
cumulative: access requires all applicable policies and successful authentication.
An ACL profile can be defined once under ACL profiles, combine default allow/deny
IPv4/IPv6 CIDR rules with country block/allow-only policy, then be attached to several
vhosts. Per-vhost rules remain available and are evaluated in addition to the profile.
Within an IP ACL, deny takes precedence. This is not an Nginx satisfy any mode: a
permitted IP cannot skip another applicable policy or a password. The graphical inline
ACL editor still supports default allow/deny and IPv4/IPv6 CIDR rules.
Trusted-proxy settings control which peer can contribute the effective client IP;
untrusted forwarding headers do not grant network access.
Authentication runs before static pages, cache, origin connections and upgrades.
401 responses include a Basic challenge and private, no-store; custom pages or
header rules cannot convert these failures into successful access. Protected vhosts
bypass shared response caching. A process-wide limit allows two Argon2 workers;
failed-password accounting is bounded to 4096 IPs, with ten failures per minute
blocking that address for the rest of the window. Busy hashing returns 503; a
blocked address returns 429 with Retry-After. This is abuse resistance, not MFA or
a replacement for perimeter rate limiting, especially for many clients behind NAT.
Custom locations
The Custom locations tab supports ordinary prefix, priority prefix (^~), exact (=),
case-sensitive regex (~) and case-insensitive regex (~*) matching. Exact matches win first;
a selected priority prefix skips regex evaluation; regexes are tested in declaration order; the
longest ordinary prefix is the fallback. Exact paths preserve a meaningful trailing slash.
A proxy location can use the normal pool, pin one backend, inherit/override cache behavior and
apply an additional ACL. Path handling can preserve the public URL, strip a prefix, replace a
prefix or perform a capture-based regex rewrite. Query parameters are preserved. Repeated literal
slashes are normalized only for routing/ACL decisions; without an explicit rewrite the backend
receives the original target, including //. Encoded separators, percent double-decoding and dot
segments remain rejected.
A location can alternatively Return custom response with a 200–599 status, Content-Type and
body without opening a backend connection. Route/vhost ACL and authentication still apply. A 3xx
return plus a visual Location response-header rule is the supported simple redirect pattern.
Request/response headers have a graphical set/append/remove builder, inline documentation
and a synchronized Advanced JSON view. Protected framing, forwarding-identity, request-ID and
WebSocket handshake headers cannot be overridden. The full routes JSON remains available as an
automation/escape hatch, but invalid/unknown fields are rejected rather than silently ignored.
RustProxy intentionally implements an explicit safe subset, not arbitrary Nginx configuration:
location-level try_files, filesystem root/alias, embedded scripting, arbitrary if and
module directives are not accepted. See Custom locations for examples and
the exact supported subset.
Reference: HTTP Basic security considerations, RFC 7617: https://www.rfc-editor.org/rfc/rfc7617.html#section-4