137 lines
9.3 KiB
Markdown
137 lines
9.3 KiB
Markdown
# 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 and forwarded metadata. On the same verified Cloudflare hop, a single
|
||
two-letter `CF-IPCountry` value is accepted as the country source for country policy,
|
||
logging and Traffic analytics. Missing, duplicate, invalid and Cloudflare `XX` values
|
||
fall back to the local GeoIP lookup of that verified effective client IP.
|
||
|
||
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 policy scopes **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 one policy scope, explicit IP deny rules and blocked countries take precedence.
|
||
When country mode is **Allow only**, a listed country or an explicit IP allow rule may
|
||
satisfy that scope; therefore `default=deny` can express e.g. private CIDRs **or** selected
|
||
countries. An unresolved country still fails closed unless the client matches an explicit
|
||
IP allow. This does not let a permitted IP skip another profile/vhost/location 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.
|
||
|
||
## HTTP method policy
|
||
|
||
Each vhost can leave method filtering **Off**, define an **Allow only** list, or define a **Block** list. Methods are validated as HTTP method tokens and normalized to uppercase. A denied request returns `405 Method Not Allowed` before authentication, cache, DNS or origin connection; allow-list mode also returns an `Allow` header containing the configured methods.
|
||
|
||
A Custom location has the same independent method policy. Vhost and location policies are cumulative: a location cannot re-enable a method rejected by its vhost. This makes patterns such as `GET, HEAD, POST` allow-only at host level and a stricter `GET, HEAD` allow-only policy on a read-only location explicit and fail-closed.
|
||
|
||
## 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 inline ACL. It can also select a reusable ACL profile, apply its own country
|
||
allow/block policy and define an HTTP method allow/block policy. These controls are cumulative with
|
||
the vhost policies and are enforced before a backend connection is opened. 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](CUSTOM_LOCATIONS.md) for examples and
|
||
the exact supported subset.
|
||
|
||
Reference: HTTP Basic security considerations, RFC 7617:
|
||
https://www.rfc-editor.org/rfc/rfc7617.html#section-4
|