Files
RustProxy/docs/ACCESS.md
T
gru eba9f89283 v0.35.1: performance, AGPL licensing and documentation overhaul
- Web Server reads static files inline; proxy middleware chain flattened
- About window with license summary and project links; AGPL-3.0-or-later
- Rewritten documentation: feature list, screenshots, performance guide
- Fix false spikes in per-Vhost request-rate charts
2026-11-05 18:29:56 +01:00

18 KiB

Access, authentication and traffic protection

Access control can be configured globally, on a Vhost and on selected Custom locations. Policies are cumulative: a more specific allow rule does not cancel a denial at a broader level. Changes should be tested with both an allowed and a denied client.

Global block / allow policy

Settings → Rules & headers → Global block / allow applies to public HTTP traffic across all vhosts, redirects and not-found hosts before upstream access. In addition to the existing User-Agent deny patterns, use the global country block/allow list (ISO two-letter codes), client IP/CIDR and allow-only DNS ACL, HTTP method policy, request Content-Type denylist and shared per-IP rate limit. All are disabled by default except previously configured User-Agent blocking. An explicit IP allow does not bypass the country policy: both must permit a request. Missing GeoIP country is allowed for country block mode and denied for country allow mode.

Global restrictions add to per-vhost and path rules. Rate-limit requests are counted for each client IP across vhosts. Prefer a conservative shared ceiling to avoid blocking shared NAT clients. A global method denial returns 405, the content-type/ACL/UA policy returns 403, and the shared rate limiter returns 429 with Retry-After. Admin and TCP/UDP stream listeners are outside this HTTP scope. For global response headers, use the adjacent Security headers subtab; see Security.

IP, country and DDNS rules

  • IP/CIDR ACL: allow or deny IPv4/IPv6 networks. Use reusable ACL profiles for settings shared by several domains. Both ordinary and Docker Vhosts use a searchable multi-select with selected badges and a preview of IP/CIDR rules, country restrictions and the default policy; the selection changes presentation only, not ACL evaluation. A Vhost can select up to eight profiles (acl_profile_ids, or one legacy acl_profile_id); Docker assignments can override or inherit the agent's profile selection.
  • DNS/DDNS: an ACL allow rule may use a hostname, such as allow office.example.ddns.net; deny with DNS is not supported. Records are refreshed periodically; unknown, failed or expired resolutions authorize nobody under the allow rule. This is appropriate for a trusted, controlled DDNS record, not a replacement for login.
  • Country access: allow-only or blocking based on the configured GeoIP database. Allow-only mode fails closed when a country cannot be determined. Keep the GeoIP database updated in Settings → GeoIP updates.
  • Cloudflare client IP: enable the integration only when traffic really arrives through a controlled Cloudflare/trusted-proxy boundary. Never trust arbitrary client-supplied forwarding headers as an identity proof.

Multiple profiles on one Vhost: For different explicit allowlists, allows are combined (logical OR). Explicit IP denies and blocked countries take precedence over allows from every selected profile. If no explicit allow or deny matches, fallback allows only when all selected profile defaults permit it (country allow-only requires a listed country). One selected profile uses the pre-existing ACL behavior exactly. The separate inline Vhost ACL, country policy, location ACL and global host ACL remain restrictive scopes (logical AND): a deny there cannot be overridden by a profile allow. Do not mix broadly permissive profiles with blocking profiles without checking the effective result from both an allowed and a blocked IP/country.

Default deny plus explicit allow exceptions is usually safer for private admin applications. Apply rules to a staging client before enforcing them on a live business-critical service.

In the Vhost → Security editor, Traffic policy groups reusable ACL profiles and the separate inline Vhost IP/CIDR access list together, followed by HTTP methods, request Content-Type filtering, per-IP rates, country policy, country-rate and User-Agent-rate controls. The inline list is not a second version of an assigned profile: both layers remain independently enforced; an allow in one does not cancel a deny in the other. The Vhost → Authentication tab first selects an identity provider, then a compatible integration method (Forward Auth, OIDC or Basic). A Vhost still uses only one active method; existing JSON settings are retained for compatibility. HSTS, security headers and User-Agent blocking are separate Security groups. Custom locations → Access separates its ACL profile, HTTP method, country and inline IP/CIDR fields. These are only layout changes; restriction scopes still combine as described above.

Content-Type request denylist

Ordinary Vhosts can reject selected MIME types under Vhosts → Security → Request Content-Type. With the option enabled, an exact media type such as multipart/form-data (including parameters) or a family such as application/* is rejected with 403 before proxy/Web Server/PHP routing or cache handling. Multiple entries are supported; missing Content-Type is not rejected. Ambiguous/malformed headers are denied when filtering is enabled. Docker vhost controls do not expose this setting. See Vhosts for a configuration example and limits.

HTTP methods and rate limits

Method policies allow, block or leave methods unrestricted. A denied method returns 405, while typical ACL/country denials return 403. Per-client rate limits can configure request count, window and burst with optional country overrides; exceeding the limit returns 429 with Retry-After. Limits are application controls, not a replacement for upstream DDoS protection.

Identity providers and authentication integration methods

Choose Identity provider → Integration method in Vhost → Authentication. Tinyauth, Authelia and authentik support both Forward Auth and OIDC when the installed identity service has the relevant endpoint enabled. Pocket ID and other generic OpenID Connect issuers use OIDC only. Built-in HTTP Basic remains available. Forward Auth uses the vendor-specific settings object and transport, while OIDC uses the shared oidc settings and an exact application callback. The protected app does not need to implement OIDC.

New Vhosts store an explicit authentication choice; old Vhosts with only tinyauth.enabled, authelia.enabled, authentik.enabled, basic_auth.enabled or oidc.enabled still load. An older OIDC configuration without a named provider appears as Other OIDC provider, retaining its issuer and client settings. The selected pair must agree with the enabled settings (e.g. authentication: {provider: authelia, method: oidc} requires oidc.enabled: true and authelia.enabled: false). Conflicting choices are rejected, not silently downgraded to an unprotected Vhost.

Existing integrations

  • Basic Auth: protect selected Vhosts with configured credentials. Use HTTPS so credentials are not sent over plaintext.

  • Tinyauth: add a verification URL and an HTTPS login URL. RustProxy makes a bounded, body-free authorization request and can pass specifically allowed identity headers upstream. An origin URL automatically uses /api/auth/nginx (or set that path explicitly). This Nginx auth-request integration sends X-Original-URL and X-Original-Method, with a validated X-Forwarded-For and X-Real-IP for Tinyauth IP ACLs. It does not send X-Forwarded-Host or X-Forwarded-URI to the verifier, avoiding the conflicting auth module headers rejection introduced in Tinyauth 5.2.0 while keeping compatibility with earlier versions that implement the Nginx endpoint. Tinyauth has its own timeout and private-backend policy.

  • Provider-neutral gateway error pages: One embedded src/admin/web/error_auth_provider.html template renders a self-contained HTML page for Tinyauth, Authelia, authentik, and future providers, using only the safe provider display name and the failure category. It replaces the three vendor-specific error_tinyauth_*.html source files while preserving the familiar Tinyauth response titles and statuses. For example: 502 Tinyauth connection error if its HTTP client cannot reach Tinyauth (DNS/TCP/TLS/transport), 504 Tinyauth timeout if the auth deadline expires, or 502 Tinyauth verification error for unexpected verifier status or invalid/oversized data. The page always retains the HTTP error status, Content-Type: text/html; charset=utf-8, Cache-Control: private, no-store and X-Content-Type-Options: nosniff. Backend URLs, protocol errors and identity data are not shown to visitors. All of these cases deny access to the protected origin. HTTP 401/403 and configured login redirects remain unchanged. These auth-specific pages take precedence over custom Vhost/general HTTP error pages so the failure remains distinguishable. The generic failure marker also protects Basic Auth denials and provider login redirects from being replaced by Vhost pages. HTTPS-verifier transport errors are classified as connection failures, truncated/oversized/invalid verifier responses as verification failures, and verification deadlines as timeouts.

  • Point the verifier URL directly at the private Tinyauth service (for example http://tinyauth:3000/api/auth/nginx), rather than routing it through a second public proxy that might inject conflicting headers. Do not disable Tinyauth's header-spoofing protections. Confirm that Tinyauth trusts only the actual RustProxy address/network when enabling Tinyauth IP-based access controls (TINYAUTH_AUTH_TRUSTEDPROXIES).

  • Authelia: select Authelia → Forward Auth under Vhost → Authentication. Enter the internal service origin (for example http://authelia:9091) and the public HTTPS login portal (for example https://auth.example.com); RustProxy calls /api/authz/forward-auth. It forwards trusted X-Forwarded-*, X-Original-URL and X-Original-Method metadata, verifies the provider result, returns provider-approved 302/303 login redirects only to the configured portal origin, and forwards configured Remote-* identity headers after stripping client-forged values. A 200 verifier response alone grants access. 401/403 deny; transport failures return 502 and timeouts 504. The Authelia session.cookies domains and authelia_url are defined in Authelia itself: protecting unrelated registered domains generally requires a login URL/cookie configuration within each domain, not one cookie from a single unrelated site.

  • authentik: select authentik → Forward Auth and enter the private outpost origin (for example http://authentik:9000), not an /if/flow login URL. RustProxy calls /outpost.goauthentik.io/auth/nginx, forwards verified X-Authentik-* identity headers, and responds to a 401 with a same-origin login start at /outpost.goauthentik.io/start?rd=.... RustProxy reserves /outpost.goauthentik.io (and descendants) on the protected application hostname and forwards them to the configured outpost without checking authentication again, after ordinary global/Vhost IP/country/rate rules. No manual Custom Location is needed for that path. In authentik create a separate Proxy Provider → Forward auth (single application) for each protected external application URL, assign it to the serving outpost, then enable that Vhost's integration. Multiple unrelated domains can share the same authentik installation; they do not share a browser cookie across domains.

  • OIDC (opt-in): choose Authelia → OIDC, authentik → OIDC, Pocket ID → OIDC or Other OIDC provider → OIDC for the protected Vhost. This switches to the shared OIDC implementation instead of the vendor's Forward Auth adapter. Provide the exact HTTPS Issuer, Client ID and confidential Client Secret, a strong unique Session Secret (openssl rand -hex 32), and https://YOUR-EXACT-APP-HOST/_rustproxy/oidc/callback as the Redirect URL. Register that exact callback as an allowed redirect URI in the identity provider. The issuer can be https://auth.example.com.cc while the protected hostname is app.linuxiarz.pl; browser cookies do not cross between them. The issuer's discovery /.well-known/openid-configuration, authorization, token and JWKS endpoints must resolve from RustProxy and use the issuer's HTTPS origin with trusted TLS. Use split DNS or the private-address opt-in if the issuer resolves to internal addresses; do not disable HTTPS certificate validation. OIDC currently requires a confidential client using client_secret_basic, authorization-code flow, and an RS256 or ES256 signing key. Public PKCE-only clients are not supported.

  • OIDC session and identity: RustProxy generates short-lived transaction state with S256 PKCE and nonce; requires a signed ID token with exact issuer, audience, validity and nonce; and encrypts a separate __Host- session cookie for the application host (default 3600 seconds, max 86400). The session is not continuously revalidated with the issuer; removing a user at the issuer does not invalidate an already-issued RustProxy session before its expiry or local logout (/_rustproxy/oidc/logout). Successful login injects Remote-Sub, Remote-Issuer, Remote-User and optional Remote-Email, Remote-Name, Remote-Groups; use (Remote-Issuer, Remote-Sub) for stable account identity and do not auto-link accounts solely by email or username. The backend must not be directly accessible from untrusted clients. Non-GET/HEAD requests without a valid session receive 401, and authentication endpoint failures return 502/504. The provider URL must not itself be protected by this Vhost's OIDC integration. For Authelia, enabling its Forward Auth portal alone is insufficient: also configure Authelia as an OIDC issuer under identity_providers.oidc, with at least one signing key, and register a confidential client for every callback URL (or separate clients per application). OIDC does not require any special support from the application being proxied, only from the remote identity provider.

  • Adding another provider: Register the vendor and supported methods in auth_provider::choice::IdentityProvider and in the Vhost editor. OIDC-compatible vendors reuse the shared oidc integration and may need no new Rust transport adapter. New Forward Auth adapters belong in src/<provider>/mod.rs with tests and may reuse forward_auth::Adapter; their compiled implementation implements the object-safe auth_provider::Provider trait. Runtime request handling continues through one CompiledFrontend.auth_provider slot and provider-neutral error_auth_provider.html. Preserve legacy Vhost configuration keys; add new providers without copying OIDC protocol code or HTML error templates.

  • Per-provider security: The verifier/outpost connection uses TLS certificate verification for HTTPS with optional additional CA, explicit private-backend opt-in and the existing safe-address/local-listener restrictions. Only allowlisted response identity fields and bounded session cookies reach applications/browsers. Inaccessible, malformed or timed-out authorization services deny origin access. Both Authelia and authentik are disabled by default; old Tinyauth settings are retained when inactive. Only one integration method can be enabled for one Vhost. Protected responses bypass shared caching. Confirm both allowed/denied requests, logins, sessions, redirects and WebSockets with the actual provider before rollout.

Minimal Vhost configuration examples (inside a Vhost object)

Authelia with Forward Auth:

"authentication": {"provider": "authelia", "method": "forward_auth"},
"authelia": {
  "enabled": true,
  "url": "http://authelia.internal:9091",
  "login_url": "https://auth.example.com",
  "allow_private": true
}

authentik with Forward Auth (same URL for the outpost check and reserved public path):

"authentication": {"provider": "authentik", "method": "forward_auth"},
"authentik": {
  "enabled": true,
  "url": "http://authentik.internal:9000",
  "allow_private": true
}

For central login from an unrelated application domain, select Authelia → OIDC and use the following Vhost fragment (also register this callback with the issuer):

"authentication": {"provider": "authelia", "method": "oidc"},
"oidc": {
  "enabled": true,
  "issuer_url": "https://auth.example.com.cc",
  "backend_url": "http://10.0.0.20:9091",
  "redirect_url": "https://app.linuxiarz.pl/_rustproxy/oidc/callback",
  "client_id": "app-client-id",
  "client_secret": "CHANGE_ME_CLIENT_SECRET",
  "session_secret": "CHANGE_ME_RANDOM_SECRET_AT_LEAST_32_BYTES",
  "scopes": "openid profile email",
  "allow_private": true
}

The client_secret and session_secret are illustrative placeholders and must be replaced with generated values. Disable other authentication settings for this Vhost. Set basic_auth.enabled, tinyauth.enabled, and the other provider's enabled to false for these examples. These are fragments, not whole Vhost documents. Protect the public provider portal with a separate Vhost without forward auth to avoid recursive redirects.

Do not use a User-Agent blocklist as the primary access control: HTTP clients can forge their User-Agent freely.

Headers, sessions and internal services

Custom request/response headers support set/append/remove within allowed names. Security headers can be configured at Vhost scope; check interactions with HSTS and CSP in browsers. Hostnames, forwarding identity, request IDs, hop-by-hop framing and WebSocket negotiation are protected by validation. Never expose the administration HTTP listener through a public Vhost just to bypass its local-access default.

Streams are separate. TCP/UDP Stream listeners do not run HTTP auth, GeoIP Vhost rules, headers, cache or TLS termination. Restrict them with firewall rules and protections on the actual protocol/backend.

Practical verification

Test allowed/denied IPs, private application login, denied HTTP methods, country policies, websocket handshakes and rate-limit recovery. Use Logs to identify 403/405/429 responses. For origin-side client IP settings, see Configuration and Security.