v0.24.5
This commit is contained in:
commit
5e23e9af02
240 files changed
+99957
No files matched your search
+404
@@ -0,0 +1,404 @@
|
||||
> 0.7 adds graphical locations, Basic Auth, cumulative IP ACL editing and a
|
||||
> WebSocket toggle. See [host access and locations](VHOST_ACCESS.md).
|
||||
|
||||
# Virtual hosts, frontend bindings and backend pools - 0.2.0
|
||||
|
||||
This is the source implementation contract. Rust compilation and runtime acceptance
|
||||
were not performed in the packaging environment; see TEST_REPORT.md.
|
||||
|
||||
## One vhost, one backend pool
|
||||
|
||||
A `vhosts` entry owns an `id`, `enabled`, `frontend`, `backends`, `load_balancing`,
|
||||
`routes`, optional `acl`, `headers` and `security_headers`. The pre-production top-level
|
||||
routing and inline-listener formats are no longer accepted. Unknown JSON fields are
|
||||
rejected. The examples are complete documents, not JSON merge patches:
|
||||
|
||||
- `examples/vhosts-private.json`: explicit loopback IP, two existing HTTP origins,
|
||||
adaptive balancing, HTTP health checks, keepalive, no cache or cookie affinity.
|
||||
- `examples/vhosts-balanced.json`: explicitly public HTTP 80 and TLS 443, cookie
|
||||
affinity and a deliberately short HSTS value; requires a trusted, imported `app`
|
||||
certificate/key and real origins. It does not create those services or files.
|
||||
|
||||
In the examples, both origins need `/health` to return a quick 2xx response. Adjust
|
||||
that path/status range for the real service. New pools start quarantined until
|
||||
`rise` successful checks; an unavailable or misconfigured check deliberately causes
|
||||
503 instead of sending traffic to an unverified member. `mode: off` opts out.
|
||||
|
||||
The editor includes frontends, members, balancing, health, connection reuse, sticky
|
||||
sessions and response protection. Custom locations have graphical match/action/rewrite/ACL/header
|
||||
controls plus synchronized Advanced JSON for automation. Unsaved drafts survive translation/SSE refreshes. A stale draft must be
|
||||
reloaded before saving: the panel does not silently merge competing revisions.
|
||||
|
||||
Existing vhost IDs can be renamed in the dashboard as long as the new ID is valid and
|
||||
unique. The rename keeps the configured frontend hostnames, routes and backend IDs, but it
|
||||
intentionally starts a new vhost runtime identity for metrics/log attribution and current
|
||||
health/traffic history. Because the vhost configuration participates in cache compatibility,
|
||||
a rename also rotates that compatibility identity and invalidates incompatible cached objects.
|
||||
The editor warns before applying the rename.
|
||||
|
||||
## Frontend selection and private IP isolation
|
||||
|
||||
`frontend.hosts` is a normalized hostname-pattern list. Exact hostnames and a single
|
||||
leading wildcard such as `*.example.com` are supported; regex and mid-label wildcards
|
||||
are not. Routing tries the exact hostname first, then the longest matching wildcard.
|
||||
This means `api.example.com` can have its own vhost while `*.example.com` handles other
|
||||
subdomains on the same listener without stealing the exact route.
|
||||
`frontend.listener_ids` references named `listeners.endpoints` configured under
|
||||
Settings. A listener owns its IP:port, TLS flag and H2/H3 transport capabilities;
|
||||
a vhost never stores a listening address directly. For a new dashboard vhost, the
|
||||
editor preselects both an enabled HTTP listener on port 80 and an enabled TLS listener
|
||||
on port 443 when they exist (public-scope listeners are preferred). Existing vhost
|
||||
bindings are never replaced by that convenience default.
|
||||
|
||||
`force_ssl` defaults to false. When enabled, any cleartext request that matches this
|
||||
vhost receives HTTP `308 Permanent Redirect` to the same normalized hostname and
|
||||
original path/query. At least one selected plain HTTP listener and one selected TLS
|
||||
listener are required so there is both an ingress to redirect and an HTTPS target. If
|
||||
several TLS ports are selected, port 443 is preferred; otherwise the selected TLS target
|
||||
port must be unique.
|
||||
|
||||
`forward_client_ip` defaults to true. Normal vhosts therefore receive the sanitized
|
||||
`Forwarded`, `X-Forwarded-For` and `X-Real-IP` client identity generated by RustProxy.
|
||||
Set it to false for applications whose own trusted-proxy/bypass logic must see the
|
||||
RustProxy TCP peer instead. Only the backend application request loses those three
|
||||
client-IP headers; ACLs, GeoIP, rate limiting and Tinyauth still use the effective client
|
||||
address, and origin metadata such as `X-Forwarded-Proto`, `X-Forwarded-Host`,
|
||||
`X-Forwarded-Port` and `X-Forwarded-URI` remains available to the backend.
|
||||
|
||||
`websockets` enables WebSocket handling for the vhost. The dashboard defaults new WebSocket
|
||||
vhosts to the nginx-compatible HTTP/1.1 Upgrade transport. `websocket_legacy_support: true` is
|
||||
a separate per-vhost compatibility switch for older appliances and embedded servers. It affects
|
||||
only WebSocket handshakes: RustProxy forces an HTTP/1.1 upstream WebSocket hop, uses the configured backend authority as upstream `Host`,
|
||||
rewrites `Origin` to the matching upstream scheme + backend authority, and tolerates legacy `101 Switching Protocols` response
|
||||
framing while keeping the `Sec-WebSocket-Accept` proof and offered subprotocol checks strict.
|
||||
Ordinary HTTP requests are unchanged. `websocket_rfc8441: true` and `websocket_rfc9220: true` are
|
||||
separate opt-ins for HTTP/2 and HTTP/3 Extended CONNECT and are valid only when WebSocket
|
||||
support is enabled. They are presented together in the vhost editor.
|
||||
RFC 8441 requires an H2-capable selected listener (TLS ALPN or cleartext h2c prior knowledge).
|
||||
Because the RFC 9220 advertisement is QUIC-connection scoped, one opted-in vhost causes the
|
||||
shared QUIC listener to advertise Extended CONNECT, while request routing still rejects RFC
|
||||
9220 on non-opted-in vhosts.
|
||||
|
||||
`http2_enabled` and `http3_enabled` are per-vhost opt-outs (both default true). The
|
||||
panel presents the two switches together and enables each only when at least one
|
||||
selected listener provides that protocol. For TLS H2, ClientHello/SNI selects H2+HTTP/1.1 or HTTP/1.1-only ALPN for
|
||||
the matched vhost. H3 remains a shared UDP listener capability; disabling it on a
|
||||
vhost removes Alt-Svc and rejects H3 for that host.
|
||||
|
||||
Each vhost can optionally set `tls_policy` with `tls12`, `tls13` and a list of rustls
|
||||
cipher-suite names. Omitting it inherits `tls.policy` from Settings. The override is
|
||||
selected from ClientHello/SNI before the TCP TLS handshake, so a vhost can for example
|
||||
run TLS 1.2 only while another frontend continues to use the global TLS 1.2/1.3 policy.
|
||||
At least one protocol version and a compatible effective cipher suite are required.
|
||||
Because HTTP/3 shares QUIC TLS on the UDP listener and requires TLS 1.3, a vhost with
|
||||
HTTP/3 enabled must use the same TLS policy as the global setting. Disable HTTP/3 on
|
||||
that vhost before using a differing per-vhost TLS policy.
|
||||
|
||||
Routing checks Host/HTTP authority, actual accepted local IP, local port and actual
|
||||
TLS state. Neither `Forwarded` nor `X-Forwarded-*` can create frontend access. A
|
||||
request for a private hostname on a different local IP is not routed to that host.
|
||||
Unknown or unmatched hosts return 404.
|
||||
|
||||
Bindings must be local addresses assigned to the OS. The process does not add IPs,
|
||||
manage routes, configure firewall rules, acquire virtual IPs or run Keepalived/VRRP.
|
||||
A missing IP, occupied port or permission error aborts startup without wildcard
|
||||
fallback. Low ports may need deployment capabilities; see `../deploy/README.md`.
|
||||
|
||||
Identical or same-family wildcard sockets are consolidated only when the named
|
||||
listener transport capabilities agree. Vhost routing restrictions are not
|
||||
consolidated: a wildcard TCP listener can accept on a public IP while still rejecting
|
||||
a private vhost there. Per-vhost H2 is narrowed by SNI and therefore does not require
|
||||
a second TCP socket. IPv4/IPv6 wildcard overlap is rejected; use explicit addresses.
|
||||
Native IPv4 binds are required instead of mapped IPv6 literals. The administration
|
||||
port is reserved even on a different IP.
|
||||
|
||||
IP isolation is not client authentication. A firewall, router, NAT or preceding
|
||||
proxy can forward external clients to the private destination IP; RustProxy sees
|
||||
that local destination and the connecting peer. Use network ACLs, firewall rules
|
||||
and application authentication too. Trusted forwarding headers have a separate explicit CIDR policy (see
|
||||
INTEGRATIONS_040.md); PROXY protocol is not implemented. Interface changes require config
|
||||
reload/restart to refresh the upstream loop-guard's local-address enumeration.
|
||||
|
||||
The same literal hostname pattern may occur only where its listener bindings remain
|
||||
unambiguous. Exact and wildcard patterns are distinct ownership keys, so an exact host
|
||||
and its parent wildcard may coexist. Disabled vhosts reserve their patterns and are
|
||||
still validated, but create no pool or additional active listener.
|
||||
|
||||
## Paths, policies and migration
|
||||
|
||||
`routes` contains per-vhost paths: `id`, `path_prefix`, `enabled`, nullable `cache`,
|
||||
optional `acl`, `headers` and `backend_id`. An empty array becomes one enabled root route. Longest
|
||||
segment-boundary prefix wins. Origins receive the original path/query; prefixes
|
||||
are not stripped. IDs must use ASCII letters, digits, hyphens and underscores.
|
||||
Host-policy, reusable ACL-profile, vhost and route ACLs are ANDed before pool
|
||||
selection/DNS/cache. A vhost can attach one reusable `acl_profile_id`; the profile may
|
||||
contain an IP ACL plus a country block/allow-only rule. Inline vhost/location controls
|
||||
remain independent and cannot be weakened by the profile. Their client identity is the
|
||||
validated effective peer address, not an untrusted forwarding header.
|
||||
|
||||
There is no legacy routing UI/runtime or automatic importer in 0.8.0. Development
|
||||
databases using the old top-level routes or inline frontend listeners must be reset
|
||||
or migrated explicitly before startup. An omitted path backend ID selects from the
|
||||
balanced pool; a specified ID must belong to the same vhost and does not fail over to a
|
||||
different application's member. Imported health checks start OFF. Ambiguous names,
|
||||
unreferenced old backends and invalid/oversized documents stop migration before
|
||||
saving. See MIGRATION.md before updating an existing installation.
|
||||
|
||||
## Backend members and connection reuse
|
||||
|
||||
Each member has `id`, HTTP(S) origin `url`, `weight` (1..256), `enabled` (true),
|
||||
`backup` (false), `drain` (false), `allow_private` (false),
|
||||
`accept_local_listener_risk` (false), `preserve_host` (true), `protocol` (`http1`),
|
||||
`address_allowlist`, optional `tls_server_name`, `tls_verify` (false) and optional
|
||||
`tls_ca_pem`. `tls_server_name` is an HTTPS-only DNS hostname
|
||||
used for SNI and, while verification is enabled, certificate hostname verification;
|
||||
DNS/TCP still targets the configured `url`. `tls_verify` defaults to false. HTTPS connections remain encrypted, but backend certificate authentication is skipped until an administrator explicitly sets `tls_verify: true`; this includes compatibility with legacy certificate encodings that modern webpki validation rejects. Address/DNS policy remains enforced; local-listener self-targeting has only the explicit risk exception described below. `tls_ca_pem` is ignored while verification is disabled.
|
||||
Backend IDs are unique inside a vhost. URLs cannot contain credentials, paths,
|
||||
queries or fragments.
|
||||
Every DNS answer and every configured literal must pass the same upstream policy
|
||||
for health probes and forwarding. Active, pending and prior-snapshot frontend
|
||||
addresses and local administration are guarded against self-proxying by default.
|
||||
For an intentional local target such as `http://127.0.0.1:9090`, enable both
|
||||
`allow_private: true` and `accept_local_listener_risk: true`. The latter is a narrow,
|
||||
explicit acceptance of loop/control-plane exposure risk; metadata/link-local and other
|
||||
special-address blocks are not bypassed. In the dashboard this risk checkbox is hidden
|
||||
unless the entered backend URL directly targets an administration listener reported by
|
||||
persisted configuration or live status. Startup-owned/locked administration sockets are
|
||||
therefore handled too. On the same administration port, loopback spellings such as
|
||||
`localhost`, `127.0.0.1` (and the rest of `127.0.0.0/8`) and `::1` are treated as
|
||||
equivalent for showing the explicit risk control, so it is not presented as a normal
|
||||
backend option.
|
||||
|
||||
A vhost can independently enable two proxy-owned response diagnostics:
|
||||
|
||||
- `backend_header: true` -> `X-RustProxy-Backend: <backend-id>`,
|
||||
- `backend_timing_header: true` -> `X-RustProxy-Backend-Time: <milliseconds>ms`.
|
||||
|
||||
The timing value covers the origin request through receipt of the backend response
|
||||
headers; it is not full response-body duration. Both proxy-owned names are protected
|
||||
from custom header rules and any upstream values are removed before RustProxy optionally
|
||||
writes its own value. The former `X-Rust-Proxy-Backend-Time` spelling is also stripped
|
||||
as a legacy lookalike but is never emitted. Responses served without contacting an
|
||||
origin do not expose a selected backend or stale origin timing.
|
||||
`timing_headers` remains the separate opt-in `Server-Timing` diagnostic.
|
||||
|
||||
`keepalive` controls **connection pooling**, not an HA service:
|
||||
|
||||
| Field | Default | Accepted range |
|
||||
|---|---|---|
|
||||
| `enabled` | true | Boolean |
|
||||
| `idle_timeout_seconds` | 30 | 1..3600 |
|
||||
| `max_idle_per_host` | 4 | 1..64 |
|
||||
| `tcp_keepalive_seconds` | 30 | 1..3600 |
|
||||
|
||||
These configure HTTP idle reuse and TCP keepalive; HTTP/2 also uses pings for active
|
||||
connections, with a 10-second ping timeout and no pinging solely to keep idle
|
||||
connections alive. Disabling reuse sets the idle pool limit to zero and disables
|
||||
those keepalive probes. It does not abort already active requests/tunnels. The idle
|
||||
limit is not a separate per-backend active-request cap; global connection/exchange
|
||||
bounds still apply. HTTP health probes use separate no-reuse HTTP/1.1 connections.
|
||||
|
||||
`http2` over HTTPS prefers h2 but keeps HTTP/1.1 ALPN compatibility. Over plaintext,
|
||||
`http2` remains explicit prior-knowledge h2c with no retry-based downgrade. `auto`
|
||||
over HTTP is HTTP/1.1. `http2`/`auto` require `preserve_host: false` to keep origin
|
||||
URI/authority/TLS identity consistent. HTTPS backend certificate verification is disabled when `tls_verify` is omitted. Enable `tls_verify: true` when origin identity must be validated; for IP-based origins use a DNS `tls_server_name` present in the certificate and provide `tls_ca_pem` when the issuer is private.
|
||||
|
||||
## Scheduling
|
||||
|
||||
| `algorithm` | Decision |
|
||||
|---|---|
|
||||
| `round_robin` | Smooth weighted round-robin |
|
||||
| `least_connections` (default) | Lowest `(active exchanges + 1) / effective weight` |
|
||||
| `least_traffic` | Lowest recent EWMA payload rate plus active-exchange allowance, divided by effective weight |
|
||||
| `adaptive` | Combines active exchanges, EWMA time-to-headers and payload rate, divided by effective weight |
|
||||
| `ip_hash` | Weighted rendezvous hash of vhost/member and canonical actual peer IP |
|
||||
|
||||
An active exchange spans upload, response body and upgraded tunnel, not just the
|
||||
wait for response headers. Slow-start gradually increases effective weight after
|
||||
initial success/recovery (`slow_start_seconds`: 10, allowed 0..300; 0 disables it).
|
||||
IP hashing uses configured weights instead of slow-start to keep assignments stable.
|
||||
These are explicit heuristics, not workload predictions or benchmark-backed claims.
|
||||
No remote host CPU measurement is used by the scheduler.
|
||||
|
||||
Only enabled, healthy, non-draining primary members receive new assignments. If
|
||||
none exists, eligible backups are used. All unavailable means 503 with Retry-After;
|
||||
there is no fallback into another vhost. Balanced routes may retry a body-free `GET`,
|
||||
`HEAD` or `OPTIONS` on another healthy member according to `load_balancing.retry`:
|
||||
|
||||
| Retry field | Default | Accepted range / meaning |
|
||||
|---|---|---|
|
||||
| `max_retries` | 1 | 0..3; zero disables failover retry |
|
||||
| `retry_connect_errors` | true | Retry connection establishment failures |
|
||||
| `retry_timeouts` | true | Retry the response-header timeout |
|
||||
| `retry_statuses` | `[502,503,504]` | Up to 8 HTTP 5xx statuses |
|
||||
|
||||
A backend already attempted in the same exchange is excluded from later attempts.
|
||||
Path-pinned routes and WebSocket handshakes are not retried. POST/PUT/PATCH and any
|
||||
request with a body are never automatically replayed. Failed attempts still feed the
|
||||
normal passive-health policy and retry counters/logs; successful failover updates sticky
|
||||
affinity to the backend that actually answered.
|
||||
|
||||
## Health checks and recovery
|
||||
|
||||
| Field | Default | Accepted range / meaning |
|
||||
|---|---|---|
|
||||
| `mode` | `tcp` | `off`, `tcp`, `http` |
|
||||
| `path` | `/` | Leading slash, up to 1024 bytes; no authority/fragment |
|
||||
| `host` | null | Optional validated HTTP Host override |
|
||||
| `interval_ms` | 5000 | 250..300000 |
|
||||
| `timeout_ms` | 2000 | 50..60000; no greater than interval |
|
||||
| `slow_response_ms` | 1500 | 0 disables; otherwise no greater than timeout |
|
||||
| `fall` / `rise` | 3 / 2 | 1..20 consecutive failed/successful checks |
|
||||
| `expected_status_min` / `max` | 200 / 399 | Inclusive, ordered HTTP status range within 100..599 |
|
||||
|
||||
TCP checks verify that an approved origin address accepts a connection. HTTP checks
|
||||
perform GET on the configured path, without redirects, cookies or authorization.
|
||||
They use HTTP/1.1, including verified TLS when appropriate, and measure time to
|
||||
headers, not the full body. For an h2c-only service, use TCP checks. Slow probes
|
||||
count as active failures. Active TCP/HTTP health is independent from `passive_health`.
|
||||
|
||||
`passive_health.enabled` defaults to `false`. With that default, normal user traffic
|
||||
never changes the shared backend healthy/unhealthy state: HTTP 5xx, connection errors,
|
||||
timeouts, response-body I/O failures and slow responses are still counted/logged but
|
||||
cannot quarantine the member. When explicitly enabled, the administrator can choose
|
||||
`count_connect_errors`, `count_timeouts`, `count_io_errors`, `count_http_5xx` and
|
||||
`count_slow_responses`, with optional passive `fall`/`rise` overrides. Missing overrides
|
||||
inherit the active health thresholds. Active and passive streaks are separate, so a
|
||||
successful user request cannot erase an active-probe failure streak and an active probe
|
||||
cannot erase a passive failure streak. `mode: off` disables only active probes; an
|
||||
explicitly enabled passive policy may still quarantine a backend.
|
||||
|
||||
One cancellation-aware supervisor schedules at most 16 probes, one per member,
|
||||
with a rotating window for fairness. The tick is 250 ms; configured intervals are
|
||||
best-effort under resource pressure, not precise service-level guarantees. DNS
|
||||
workers have their own bounded slots. Probe bodies are not collected or cached.
|
||||
|
||||
## Sticky sessions and drain
|
||||
|
||||
`sticky.mode` is `off`, `cookie` or `ip_hash`. IP mode overrides the normal algorithm
|
||||
using the actual peer IP. Users behind one NAT/proxy share that identity.
|
||||
|
||||
Cookie mode uses a random 32-character opaque member token, not a backend URL.
|
||||
The default name is `RP_AFFINITY_<vhost-id>`; custom names accept 1..96 ASCII letters,
|
||||
digits, underscores or hyphens and cannot use the admin session name. TTL defaults
|
||||
to 3600 seconds (60..604800), with Path=/, HttpOnly, SameSite=Lax and Secure on TLS.
|
||||
`__Host-`/`__Secure-` names require every frontend to use TLS. Cookies are host-only,
|
||||
so aliases have independent browser cookies. They do not authenticate users.
|
||||
|
||||
Cookie-affine requests always bypass shared cache. The dedicated routing cookie
|
||||
is stripped before forwarding; origins cannot override it via Set-Cookie. Unknown,
|
||||
duplicate or unhealthy-target tokens are ignored/reassigned. Existing valid cookie
|
||||
sessions may continue on a healthy draining/backup member; new sessions do not
|
||||
choose a draining member. Disabling a member prevents all new assignments,
|
||||
including existing cookie sessions, while already admitted exchanges finish.
|
||||
|
||||
Affinity tokens, health and traffic observations survive compatible hot edits.
|
||||
A changed origin/health policy or re-enabled member is checked afresh. Process
|
||||
restart resets tokens/counters; clients can be reassigned. Session data itself is
|
||||
never replicated: applications needing durable sessions require a shared store.
|
||||
|
||||
## Response protection
|
||||
|
||||
`security_headers` supports `hsts` (`enabled`, `max_age_seconds`,
|
||||
`include_subdomains`, `preload`), `nosniff`, `frame_options` (`preserve`, `deny`,
|
||||
`sameorigin`), `referrer_policy`, `content_security_policy` and `permissions_policy`.
|
||||
Header values are validated against splitting and bounded to 8192 bytes.
|
||||
|
||||
HSTS is configured only for TLS responses. For a matched vhost, plaintext responses
|
||||
remove Strict-Transport-Security even if an origin/custom rule adds it. On TLS,
|
||||
disabled HSTS means no forced replacement of an origin value; use a custom remove
|
||||
rule to suppress that value. Enabled HSTS overrides generic rules. `max_age_seconds`
|
||||
accepts 0..63072000 (default31536000); setting zero is available for explicit expiry.
|
||||
Preload is opt-in and requires enabled HSTS, includeSubDomains and at least one year.
|
||||
This only emits the directive; it does not register a hostname in a preload list.
|
||||
Start with a short lifetime and verify every affected hostname before increasing it.
|
||||
|
||||
Request rules run global -> vhost -> path, then protected identity fields are
|
||||
regenerated. Response rules run global -> vhost -> path, followed by dedicated
|
||||
security/Server policy and optional compression. Security headers cover cache hits
|
||||
and matched-host synthetic errors/ACL denials too. Protected transport fields
|
||||
remain uneditable. `false`, `preserve` or null security settings otherwise leave
|
||||
origin values unchanged. CSP and Permissions-Policy must suit the application;
|
||||
RustProxy validates header encoding, not the semantic correctness of those policies.
|
||||
|
||||
## Live state, cache and limits
|
||||
|
||||
The dashboard defaults a newly created vhost to `cache.enabled: false`. When the
|
||||
effective cache state is disabled, the editor hides the remaining per-vhost cache
|
||||
controls; enabling cache (or explicitly choosing inheritance from an enabled global
|
||||
cache) reveals them. This is a UI default for new drafts, not a migration that rewrites
|
||||
existing vhost cache settings.
|
||||
|
||||
|
||||
`GET /api/backends` requires an admin session and returns `pools`,
|
||||
`active_frontends`, `desired_frontends`. `/api/status` and SSE contain `backend_pools`
|
||||
and complete active/desired endpoint plans. The dashboard renders per-member state,
|
||||
active exchanges, request/error totals, EWMA header latency and payload traffic.
|
||||
Prometheus adds bounded vhost/member labels; access logs include `backend` as
|
||||
`vhost/member` for actual pool forwarding (null when no upstream exchange is made).
|
||||
|
||||
Bytes are observed payload, not NIC throughput; response counters include the
|
||||
client-delivered encoded representation. Header latency includes connection/setup and any request upload; it is not full
|
||||
exchange time. Active probes use body-free requests for an independent measurement.
|
||||
Health mode off is labeled as checks off, not proof of a probe passing. Statistics
|
||||
are observations, not persisted configuration. They reset on process restart.
|
||||
|
||||
Cookie affinity bypasses cache entirely. A pool with no eligible member does not invent
|
||||
an unselected cached fallback. Config changes invalidate incompatible cache state.
|
||||
RFC 5861/request `max-stale` behavior is owned by the shared cache and does not alter
|
||||
backend member selection; request coalescing remains separate from stale-while-revalidate
|
||||
deduplication.
|
||||
|
||||
Limits: 64 vhosts; hostname lists are not capped by an application-level item count;
|
||||
listener entries remain capped at 16 per host, with 32 members and 64 paths per host;
|
||||
128 backend definitions and 256 paths across all vhosts;
|
||||
128 additional declared frontend entries plus two globals; 256 KiB serialized
|
||||
configuration. Existing request/connection/DNS/queue bounds remain in force.
|
||||
|
||||
Every successful config publication rebuilds upstream connection pools. Compatible
|
||||
member observations/tokens and in-flight exchanges survive, but idle sockets are
|
||||
not retained across publication. Listener/address/ALPN changes are saved immediately
|
||||
and require restart; routing changes apply to existing bound sockets immediately.
|
||||
When moving a host away from an old IP, it can become unavailable until restart
|
||||
rather than being served on an address no longer permitted by desired policy.
|
||||
|
||||
## Per-vhost operations in 0.3.0
|
||||
|
||||
The compact list opens a tabbed editor rather than displaying a full form beside
|
||||
the list. Health summaries update on the list and editor without replacing unsaved
|
||||
form controls. Header rules have a visual request/response editor; Advanced JSON
|
||||
remains available and stays synchronized with those rows.
|
||||
|
||||
The SSL tab selects an existing certificate ID or uploads a chain/private-key
|
||||
pair into private staging. Only Save activates the selection. A shared global SNI
|
||||
resolver cannot serve different certificates for the same DNS name by destination
|
||||
IP, so conflicting selections are rejected. Browser upload is local-admin only;
|
||||
there is no ACME, encrypted-key password prompt, certificate download or automated
|
||||
cleanup. Details and limits: MANAGEMENT.md.
|
||||
|
||||
Cache overrides inherit field by field and use one shared memory budget. The list
|
||||
and Cache tab offer selective purge. An explicitly disabled global cache can still be
|
||||
overridden by an explicitly enabled vhost. Path exclusions and sticky-cookie safeguards
|
||||
remain in force. See CACHE.md.
|
||||
|
||||
The **Transform** tab is a separate vhost opt-in. `transform.enabled` defaults to false
|
||||
for every vhost even when the global transform engine is enabled. JavaScript, CSS, HTML,
|
||||
SVG and JSON can inherit or override global format switches, and the extension list may
|
||||
be replaced per vhost. Eligible origin responses are transformed before shared-cache
|
||||
storage and before downstream compression. Origin `Cache-Control: no-transform` always
|
||||
wins and cannot be overridden from the vhost.
|
||||
|
||||
Pages offers a static/maintenance response, a fallback for unassigned paths, and
|
||||
error overrides. Vhosts still retain their configured backend pool; static mode
|
||||
avoids forwarding but is not a backend-less static-file server. Host/path ACLs run
|
||||
first. Explicit error-status overrides change presentation, not authorization.
|
||||
Empty/inherit means use the global error policy; to disable one inherited error
|
||||
page specifically, configure an explicit replacement rather than expecting null
|
||||
to override inheritance. See MANAGEMENT.md for exact precedence.
|
||||
|
||||
|
||||
### Backend Host compatibility
|
||||
|
||||
New backends use the backend URL host for the upstream `Host` header by default, matching nginx `proxy_pass` behavior. Enable **Preserve client Host** only when the application intentionally routes on the public hostname. This is especially important for embedded/lighttpd-style administration panels that may close or reject requests carrying an unknown Host. Existing explicit settings are preserved during upgrades.
|
||||
|
||||
When an upstream request fails before an HTTP response is received, access logs include a bounded `upstream_error` field in addition to `upstream_status`.
|
||||
Reference in new issue
Block a user