This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 09:29:10 +02:00
1 parent 2e4aa4df4d
commit 87e571c170
106 files changed
+17952 -6185

No files matched your search

+54 -537
View File
@@ -1,9 +1,9 @@
# RustProxy 0.24.10
# RustProxy 0.25.0
Independent Rust reverse proxy with a dashboard, SQLite configuration,
Independent Rust reverse proxy and static Web Server with a dashboard, SQLite configuration,
streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhosts and backend pools.
**0.24.10 release source.**
**0.25.0 release source.**
## Layer-4 streams
@@ -11,529 +11,45 @@ Raw TCP/UDP forwarding has its own **Streams** page in the primary navigation, a
Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners.
## What changed in 0.24.10
- Make Error File a first-class revisioned Settings section so enable/path/format persist through the same section-save pattern as the rest of the panel, including across SQLite reopen/restart.
- Keep Error File independent from structured access logging in the UI and remove the redundant ERROR/logrotate help sentence.
- Keep response-time history permanently expanded and add the same compact information control used by Process, explaining that the chart is the sampled cumulative mean of completed HTTP exchanges.
- Update package/source/UI/OpenAPI/release identity to 0.24.10.
## What changed in 0.24.9
- Add a central encrypted Secret Store backed by SQLite ciphertext and a private local master key, with migration of Cloudflare, OVH and RFC2136 ACME credentials away from persistent plaintext files.
- Add password-encrypted full backup/restore with Argon2id-derived backup keys, authenticated AES-256-GCM encryption, explicit manifests/checksums, private staging and rollback-safe data-directory activation.
- Add an optional ERROR-only file sink integrated with the existing tracing pipeline, supporting JSON/RAW output, bounded asynchronous writes, secret redaction and external `logrotate` rotation.
- Update package/source/UI/OpenAPI/release identity to 0.24.9.
## What changed in 0.24.8
- Expand the overview **Cache RAM** block with live HOT RAM occupancy against its configured limit, transient cache RAM history split into fill / COLD queue / COLD I/O, and COLD storage occupancy against its disk budget.
- Move the long process/cache RSS accounting explanation behind an accessible information control in the **Process** heading so the dashboard remains compact while the accounting caveat stays available on demand.
- Keep COLD disk bytes separate from process RAM: only fill, queue and COLD I/O buffers are shown as transient cache RAM.
- Update package/source/UI/OpenAPI/release identity to 0.24.8.
## What changed in 0.24.7
- Make the process-wide transformation memory budget configurable in **Settings -> Transform**, with a 1 MiB..2 GiB range. The budget remains a ceiling for estimated temporary buffers and is not pre-allocated.
- Add a configurable global maximum for simultaneous transformation attempts. When the limit is busy, transformation fails open with `concurrency_pressure` instead of queueing additional full-body work.
- Add persisted transform resource presets: **RAM saver** (32 MiB / 1 MiB body / 8 concurrent), **Recommended** (128 MiB / 2 MiB / 32), **Performance** (512 MiB / 8 MiB / 64) and **Uber performance** (1 GiB / 32 MiB / 128). Manual resource edits switch the preset indicator to Custom.
- Keep format switches and extension allow-lists independent from resource presets so selecting a performance profile does not silently change transformation semantics.
- Show live transform RAM reservations and active transform slots in the Transform dashboard, and add overview RAM accounting for HOT cache, transient cache, transform reservations and the remaining non-cache process RSS.
- Show current COLD storage occupancy against its disk/object limits in the overview cache block while keeping disk usage separate from process RAM.
- Map bounded transform response collection errors explicitly into `anyhow::Error` so the new memory-bounded transform path compiles with the boxed Axum body error type used by the current dependency set.
- Clean the remaining compiler warnings in transient cache lease ownership and CSS minification without suppressing lints or changing runtime behavior.
- Make global transform representation/eligibility settings part of cache compatibility identity while excluding resource-only preset/budget/concurrency metadata. Changing JSON/HTML/etc. or the max transformable body now invalidates incompatible cached representations; changing only resource capacity does not.
- Update package/source/UI/OpenAPI/release identity to 0.24.7.
## What changed in 0.24.6
- Persist the explicitly selected HOT memory preset and COLD policy preset inside the revisioned cache configuration stored in SQLite. The Settings page restores the selected state after reload, while the numeric cache limits remain authoritative.
- Add a **Recommended** COLD policy preset that enables idle/LRU/shutdown demotion, uses conservative GC timings and sizes the COLD writer queue from transient RAM without replacing the administrator's disk path, disk budget or object limit.
- Bound transformation memory globally to 128 MiB of estimated temporary buffers, bound response aggregation even when an upstream lies about `Content-Length`, and keep decompression allocation growth inside the configured transform body ceiling.
- Reduce transform allocation churn: JSON validation no longer materializes a full `serde_json::Value`, HTML raw-tag detection avoids per-tag lowercase strings, and CSS minification no longer scans the full output to recover the last character on normal paths.
- Bound cache background retention: stale-while-revalidate work is capped at 8 keys, proactive sleeping refresh tasks at 256, COLD cleanup is single-flight, COLD candidate selection retains only the requested best candidates, and saturated COLD delete fallback work cannot create unlimited detached tasks.
- Add Rust-independent memory-contract checks covering transform/cache bounds plus logging, diagnostics, DNS, backend health, streams, listener supervisors, ACME, Docker and update-check background workers.
- Update package/source/UI/OpenAPI/release identity to 0.24.6.
## What changed in 0.24.5
- Fix HTTP/3 requests with an actually empty, length-unknown body when forwarding to an HTTP/1.1 upstream. RustProxy now observes the H3 body end before handing the request to Hyper so methods such as `DELETE`, `POST`, `PUT` and `PATCH` are represented as a known zero-length body instead of being emitted as `Transfer-Encoding: chunked`.
- Preserve streaming semantics for non-empty HTTP/3 request bodies: the first inspected frame is replayed and the remaining body continues streaming; declared `Content-Length` bodies and HTTP/2 upstreams are left unchanged.
- Add focused regressions for bodyless HTTP/3 `DELETE`, non-empty `DELETE`, declared-length requests, HTTP/2 upstreams and the generic bodyless method set.
- Harden the existing HOT -> COLD cache model with allocation-aware HOT admission, bounded transient fill/tier-transfer RAM, a byte-bounded COLD writer queue and incremental `max_object_bytes` enforcement before buffer growth.
- Track HOT logical and allocated/charged bytes separately, preserve body allocation accounting through revalidation/COLD promotion, make global cache disable authoritative over vhost overrides, and remove the old artificial 1 GiB HOT/object ceiling.
- Add host/cgroup-aware conservative/recommended/performance cache presets in Settings. The panel shows the recommended values for detected effective RAM and warns about high cache share, low current headroom, an oversized COLD queue or a maximum object that cannot fit in transient RAM.
- Keep the source package consistent with its existing release contracts by dropping the stale unreferenced `src/system_stats/bsd.rs` file and updating the offline container check to the already-shipped Debian 13/Trixie base images.
- Update package/source/UI/OpenAPI/release identity to 0.24.5.
## What changed in 0.24.4
- On Linux, opt the RustProxy process out of Transparent Huge Pages with `prctl(PR_SET_THP_DISABLE)` before Tokio creates worker threads. This keeps the memory policy process-local and avoids requiring a host-wide `/sys/kernel/mm/transparent_hugepage/enabled` change.
- Keep the existing managed `MALLOC_ARENA_MAX=2`, transform allocation reductions and bounded `malloc_trim(0)` paths from 0.24.3.
- Update package/source/UI/OpenAPI/release identity to 0.24.4.
## What changed in 0.24.3
- Reduce long-running Linux/glibc RSS retention by shipping `MALLOC_ARENA_MAX=2` in the managed systemd service while keeping `/etc/rustproxy/environment` available as the administrator override.
- Reduce transform-path temporary allocations: identity bodies are borrowed instead of copied during decode, JavaScript/CSS no longer build a full `Vec<char>` or copy the completed output buffer again, successful transforms release origin/decode buffers early, and large glibc transform churn gets a throttled `malloc_trim(0)`.
- Keep HTTP/2 and HTTP/3 transport enablement together in **Settings -> Listeners** and make both connection-tuning pages listener-scoped. **Settings -> HTTP connections -> HTTP/2** now edits lifecycle/GOAWAY limits per H2/h2c listener, while **HTTP/3** edits per-listener QUIC limits; listener rows link directly to the matching tuning page. Legacy top-level `http2` values remain a read-time fallback for older configurations.
- Rename the dashboard **Proxy process** card to **Process** and hide unsupported process metrics/charts instead of rendering `unknown`/`N/A` placeholders for platform-specific fields.
- Add targeted hot reload for manual/file-backed certificates with `POST /api/certificates/{certificate_id}/reload`; the operation keeps the configuration revision stable and is available to the scoped Certificate API credential as well as administrator sessions.
- Expand the scoped Certificate API to up to 32 independently revocable tokens, each with a non-secret operator comment; cleartext tokens remain one-time responses and only hashes are persisted.
- Replace the dashboard **Core State** table with a live connection/activity chart, move **Uptime** into **Process** directly below process start, split **Payload transferred** into upload/download counters, and let operators hide individual network-interface charts in browser-local preferences.
- Update package/source/UI/OpenAPI/release identity to 0.24.3.
## What changed in 0.24.2
- Version-only release bump from 0.24.1 to 0.24.2; no runtime or configuration behavior changes.
## What changed in 0.24.1
- Restore network interface/RX/TX diagnostics after the statistics-library refactor. Network inventory and byte counters now use `sysinfo::Networks` as the primary API and merge in `systemstat` as a library-level supplement/fallback, including targets where the primary API has no inventory; the implementation does not shell out to `netstat`/`sysctl` or reintroduce per-OS network parsers.
- Fix the portable system-uptime build error by using the duration API exposed by `systemstat` and remove the stale H2 `Future` import warning.
- Remove application-level item-count ceilings for certificate hostnames/SAN requests and the hostname lists that feed certificate selection (vhosts, redirects, 404 hosts, administration allowed hosts, host policies and Docker aliases). DNS syntax/length validation, certificate/key size bounds, global configuration size and other resource-safety limits remain in place.
- Replace the hand-written BSD statistics backend with shared library APIs: `systemstat` for portable host metrics, `sysinfo::Networks` for network inventory/counters, and `metrics-process` for process metrics. `systemstat` remains the library-level network supplement/fallback where `sysinfo` has no native inventory or returns only a partial view. Unsupported values remain null instead of being synthesized.
- Preserve Linux `/proc` and cgroup fields as additive Linux-only details so existing Linux names, units and semantics remain compatible.
- Expose additional portable diagnostics when available: system swap/uptime and process virtual memory, descriptor limit, start time, RSS and thread count.
- Add authenticated runtime metadata to `/api/status`: platform, statistics source, resolved data directory and database path. The UI does not guess installation paths.
- Make local CLI data-directory discovery platform-aware: Linux convention `/var/lib/rustproxy`, BSD/OPNsense convention `/var/db/rustproxy`, while an explicit `--data-dir` always wins.
- Move Logging from the primary navigation into **Settings -> Logging** and keep `/logging` as a compatibility redirect/canonical route.
- Update package/source/UI/OpenAPI/release identity to 0.24.1.
This workspace does not provide a Rust toolchain by default. Compiler/type/runtime acceptance and resolver-generated `Cargo.lock` for the new statistics dependencies must be completed on a compiler-enabled release host. See [the 0.24.1 specification audit](docs/V0.24.1_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.24.0
- Rework downstream HTTP/2 connection retirement into graceful `GOAWAY -> drain -> TCP close`: idle shutdown now checks active streams and recent frame traffic before retiring a connection, and a bounded drain timeout prevents indefinite hangs.
- Add independent global HTTP/2 `idle_timeout_seconds`, `max_connection_lifetime_seconds` (`0` disables it) and `drain_timeout_seconds` settings, exposed through the Settings UI and section API. Lifetime expiry uses the same graceful path rather than an abrupt socket close.
- Keep RFC 8441 WebSocket-over-H2 streams inside the active-stream drain accounting, so existing tunnels may finish while new H2 streams are refused after GOAWAY.
- Extract system/process sampling into `system_stats` platform backends. Linux keeps the existing `/proc`/cgroup field names, units and semantics; FreeBSD/OpenBSD/NetBSD use native `sysctl`/system interfaces where available and leave unsupported metrics null.
- Show the runtime platform in **Proxy Process** and export `rust_proxy_platform_info{platform=...}`.
- Group protocol tuning under **Settings -> HTTP connections**, with HTTP/2 and HTTP/3 sub-tabs. H3/QUIC remains listener-scoped and restart-required, but its enablement and limits are edited from the HTTP/3 sub-tab instead of the listener editor.
- Update package/source/UI/OpenAPI/release identity to 0.24.0 and add H2 lifecycle/configuration regressions.
This workspace does not provide `cargo`, `rustc` or `rustfmt`, so compiler/type/runtime acceptance remains a release-host gate. See [the 0.24.0 specification audit](docs/V0.24.0_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.23.3
- Add per-vhost **Enable WebSocket legacy support** compatibility mode for older appliances and embedded WebSocket servers such as iLO-class management controllers.
- In legacy mode, force the upstream WebSocket hop to HTTP/1.1, force the legacy WebSocket `Host` to the configured backend authority, align `Origin` to that backend scheme + authority, and tolerate legacy `101 Switching Protocols` framing while retaining strict `Sec-WebSocket-Accept` and subprotocol validation.
- Keep the compatibility behavior scoped only to WebSocket handshakes; ordinary HTTP traffic and vhosts without the option are unchanged.
- Add dashboard/OpenAPI/language-pack controls, source regressions and release verification for the new compatibility switch.
- Update source/package/UI identity and release verification contracts to 0.23.3.
Rust compiler/type/runtime acceptance remains a release-host gate in this workspace when `cargo`, `rustc` or `rustfmt` are unavailable. See [the 0.23.3 specification audit](docs/V0.23.3_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.23.2
- Add a selectable live-chart history window for Cache and Transformation: 60, 120, 300 or 600 samples (about 3, 6, 15 or 30 minutes at the existing 3-second refresh). Each workspace remembers its choice in browser local storage and remains bounded.
- Fix `rust-proxy --livelogs` when administration TLS is enabled. The CLI now probes the local administration listener, switches to HTTPS after the expected HTTP 308 redirect, and pins the presented TLS leaf certificate to certificates stored in the private RustProxy data directory.
- Reuse the same HTTP/HTTPS-aware local administration client for CLI configuration and certificate API calls, so local commands no longer fail solely because the administration listener is HTTPS.
- Update source/package/UI identity and release verification contracts to 0.23.2.
Rust compiler/type/runtime acceptance remains a release-host gate in this workspace when `cargo`, `rustc` or `rustfmt` are unavailable. See [the 0.23.2 specification audit](docs/V0.23.2_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.23.1
- Add a collapsible, full-width **live Cache activity** chart to the Cache workspace. It samples the selected scope and plots HIT, MISS and BYPASS rates while preserving the existing 3-second live refresh.
- Add a matching collapsible, full-width **live Transformation activity** chart. It plots transformed responses, transformed cache HITs, skipped/fail-open responses and errors for the selected scope.
- Keep both charts collapsed by default, retain their in-memory history while the workspace stays active, and reset chart history when the selected vhost scope changes.
- Update source/package/UI identity and release verification contracts to 0.23.1.
## What changed in 0.23.0
- Add a scoped **Certificate API** credential configured from **Settings → Certificate API**. External automation uses `X-RustProxy-Certificate-Key` plus `Authorization: Bearer ...`; only deploy/reload are authorized, the token is stored only as a hash, and non-loopback use requires HTTPS.
- Keep production local certificate rotation independent of development tooling: call `rust-proxy tls deploy --id ID --cert fullchain.pem --key privkey.pem` or `rust-proxy tls reload` directly from a Certbot deploy hook or administrator shell.
- Add `rust-proxy --livelogs`, an interactive all-vhost request stream modeled after varnishlog but using structured commands instead of regex expressions. Filters include host/vhost/backend/route/client/method/transport/cache/status/path, errors and slow requests; `show ID` prints the complete stored event.
- Feed live logs through a bounded non-blocking broadcast/SSE path. If a viewer cannot keep up, RustProxy emits an explicit dropped-entry count rather than silently pretending the stream is complete.
- Split **Settings → Cache** into four sub-tabs: **General**, **Resilience**, **Cold cache**, and **Static & diagnostics**. The form still saves one cache policy atomically.
- Add SQLite schema v5, OpenAPI security definitions, audit/status metadata, translations and regression coverage for the new control-plane capabilities.
## What changed in 0.22.3
- Add standards-oriented downstream HTTP/1.1 `Upgrade: h2c` on cleartext listeners that already enable `h2c`, while preserving the existing HTTP/2 prior-knowledge path. The initiating body-free H1 request is reconstructed as HTTP/2 stream 1 after `101 Switching Protocols`; malformed upgrades are rejected before switching.
- Add authenticated certificate hot reload through `POST /api/certificates/reload` and `rust-proxy tls reload`. Configured public certificate/key files are re-read and validated without changing the desired configuration revision; new public TLS/H2/H3 handshakes use the refreshed snapshot while existing sessions continue.
- Add external certificate deployment for local issuers such as system Certbot: `rust-proxy tls deploy --id ID --cert fullchain.pem --key privkey.pem`. The CLI resolves/checks local Certbot files and calls authenticated loopback `POST /api/certificates/deploy`; the running RustProxy service validates the pair/SANs, creates immutable generation files with its own filesystem identity and convergently creates a missing manual certificate id or atomically rotates an existing one used by any number of vhosts; identical RustProxy-owned material is a no-op.
- Reject external deployment into RustProxy-managed ACME certificate ids to avoid dual renewal ownership, roll back staged files when publication fails, and explicitly report that startup-fixed administration TLS needs a process restart when it selects the changed certificate.
- Extend the Certificates workspace with an explicit **Reload certificate files** action plus OpenAPI, audit logging, translations, source regressions and the 0.22.3 verification/audit documentation.
Rust compiler/type/runtime acceptance remains a release-host gate in this workspace because `cargo`, `rustc` and `rustfmt` are unavailable. See [the 0.22.3 specification audit](docs/V0.22.3_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.22.2
- Add replay-safe bounded backend failover retry for empty `GET`, `HEAD` and `OPTIONS` exchanges, with per-vhost retry policy, passive-health integration, logs and Prometheus counters.
- Send ordinary requests to explicit `protocol=http2` backends as HTTP/2 and retain a real Hyper h2c prior-knowledge upstream regression.
- Add per-backend `max_concurrent_requests` with a bounded capacity wait (`queue_timeout_ms`), immediate/timeout `503` rejection, dashboard controls and rejection/queue-timeout metrics. A TCP socket-count limit remains deliberately separate and is not claimed by this setting.
- Add detailed upstream failure classification and last-failure diagnostics for DNS, TLS, connect, response-header timeout, read/send timeout and I/O failures, plus health ejection/recovery timestamps.
- Extend the backend dashboard table with configured concurrency, last failure/reason and last recovery while retaining health, request/error, traffic and latency data in one operational view.
- Parse public leaf-certificate metadata for issuer, SANs, validity window, days remaining and expiry state; surface renewal status/last attempt/error in the certificate inventory without reading private keys.
- Update OpenAPI, translations, metrics documentation, regression sources and the 0.22.2 audit/TODO for the expanded release scope.
Rust compiler/type/runtime acceptance remains a release-host gate in this workspace because `cargo`, `rustc` and `rustfmt` are unavailable. See [the 0.22.2 specification audit](docs/V0.22.2_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.22.1
- Use one shared overview stats grid for primary and transport/WebSocket metrics, so both visual rows have identical card sizing and spacing. Cache **Target** and **Cache key / tags** cells copy their full untruncated value on click or keyboard activation.
- Move selective **Purge / Ban** and **Active BANs** into dedicated Cache modals next to **Purge selected scope**; operation results use null-safe inline feedback styled like the login form.
- Add opt-in HTTP/2 RFC 8441 WebSocket Extended CONNECT beside the existing RFC 9220 per-vhost option. The listener advertises Extended CONNECT only when an opted-in vhost is bound to that H2 endpoint.
- Support RFC 8441 H2 clients through RustProxy to an HTTP/1.1 WebSocket upstream bridge or an explicitly configured HTTP/2 upstream. Lifecycle handling includes shutdown cancellation, idle timeout and byte counters.
- Add explicit cleartext HTTP/2 **h2c prior-knowledge** listeners. HTTP/1.1 `Upgrade: h2c` is intentionally not exposed because the current Hyper integration cannot safely reconstruct the required HTTP/2 stream 1 bootstrap.
- Add stable active-tunnel IDs, inventory (`client`, `host`, `upstream`, protocol, duration, RX/TX), authenticated kill with operator reason, and `tunnel.kill` audit records.
- Consolidate WebSocket visibility on the main dashboard as total active plus H1 / H2 RFC 8441 / H3 RFC 9220, while ordinary H2/H3 request counters remain separate.
- Retain the full 0.22.0 cache feature set: single-flight fills, cached single-range 206, selective PURGE/BAN, configurable stale-if-error and proactive refresh.
- Update release/package/UI/OpenAPI/Debian/Grafana/tooling identity to 0.22.1.
The source package includes Rust regression definitions and Rust-independent release checks. This workspace does not contain `cargo`, `rustc` or `rustfmt`, so compiler/type/runtime acceptance remains a required release-host gate. See [the 0.22.1 specification audit](docs/V0.22.1_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.21.0
- Shard Cold Cache objects by the first two SHA-256 hex characters, add bounded asynchronous 90% -> 80% garbage collection, and expose selective asynchronous cleanup in the Cache panel.
- Implement RFC 5861 `stale-while-revalidate` / `stale-if-error`, request `max-stale`, age-aware request `max-age=N`, and correct shared-cache `must-revalidate` / `proxy-revalidate` semantics while retaining `s-maxage` precedence.
- Add a formal decode -> transform -> canonical cache -> encode stage for JS/CSS plus optional HTML/SVG/JSON transformations, with strict origin `no-transform`, separate origin/representation validators, transformed Content-Length, canonical `Accept-Encoding` handling and safe incomplete-fill behavior.
- Keep route cache overrides tri-state (`inherit` / enabled / disabled) and report effective vhost/route cache and transform decisions in access diagnostics.
- Make Passive Backend Health opt-in and disabled by default for ordinary and Docker-generated vhosts; active TCP/HTTP health remains independent and ordinary traffic errors remain observable even when they do not affect backend health.
- Add global Settings, vhost and Docker-discovery controls for transformation, plus OpenAPI/admin coverage and expanded cache/transform/health regressions.
- Add a dedicated **Transform** monitoring workspace with global/per-vhost runtime effectiveness counters, mark transformed objects in Cache, and expose transformed representations through the standardized `Cache-Status` diagnostic.
- Tighten Docker-vhost desktop layout so the transform switch stays with the other primary switches and Passive Backend Health fields remain readable when enabled, including checkbox sizing in the expanded editor.
- Add a transformed-response series to **Live traffic** and show **Core state** uptime in compact minute/hour/day/year form.
- Keep `/transform` refreshable as a first-class dashboard route; use a square-aligned Cache transformed badge and a dedicated violet color for the transformed live-traffic series.
- Rename the backend timing diagnostic to `X-RustProxy-Backend-Time`, while stripping the former `X-Rust-Proxy-Backend-Time` spelling as an untrusted upstream lookalike.
- Split the former monolithic `src/cache.rs` into a responsibility-based `src/cache/` module and remove the unused mutable background-revalidation binding.
- Keep package/source/UI/OpenAPI/Debian/Grafana/tooling identity at 0.21.0.
The 0.21.0 feature scope is closed for release packaging. The conservative JS/CSS transformers remain supported as-is for this release; parser-backed replacements are deferred. This workspace still cannot execute the Rust compiler/runtime gate, so a release host must run that gate and live protocol acceptance before deployment. See [the 0.21.0 specification audit](docs/V0.21.0_AUDIT.md) and [verification report](docs/TEST_REPORT.md).
## What changed in 0.20.0
- Rebuild **Certificates** as a three-tab workspace: **Installed**, **Renewal** and **Generate**, matching the Settings tab interaction and responsive layout.
- Move certificate generation/import/existing-file controls into the Generate tab so the workflow remains visible instead of opening a separate modal.
- Add clear ACME operation states and show the exact private Certbot `logs/` directory when issuance or renewal fails; persisted renewal failures also expose the corresponding profile log path.
- Improve renewal cards with provider/environment context, structured last/next/expiry fields and clearer action grouping.
- Update release/package/UI/OpenAPI/Debian/Grafana/tooling identity to 0.20.0.
## What changed in 0.19.4
- Align the Docker-vhost Aliases chip editor with neighboring 38px controls and remove the inherited extra label margin that made the field look like it started on a new line.
- Keep backend traffic formatting explicit: idle is `0.0 KiB/s`, while any positive rate below 0.1 KiB/s is rendered as `<0.1 KiB/s` in backend rows and aggregate vhost traffic.
- Add an All / Cache enabled / Cache disabled selector to **Cache -> Domains and effectiveness**. Filtering affects only the domain table; aggregate cache statistics remain scoped by the selected vhost and are not changed by the presentation filter.
- Update release/package/UI/OpenAPI/Debian/Grafana/tooling identity to 0.19.4.
## What changed in 0.19.3
- Fix the update-checker body collection error conversion so compiler-enabled Rust builds do not require `anyhow::Context` on Hyper/http-body-util's boxed body error.
- Add a dark/light administration theme selector in Settings. The preference is account-scoped in SQLite, defaults to the existing dark theme, and uses a small local cache only to prevent first-paint theme flicker before the authenticated preference is loaded.
- Consolidate theme-sensitive CSS around shared surface/text/border variables while preserving the RustProxy accent palette.
- Make the Live Logs column chooser a compact, scrollbar-free standard-checkbox list; on short screens it switches to two columns rather than adding internal scrollbars.
- Fix the remaining Live Logs checkbox inflation caused by broad `.log-tools input` text-field rules; checkbox/radio controls are now excluded from both sizing blocks.
- Simplify the dashboard footer to API latency + dropped-log count and add a fail-soft hourly release check against the official repository Cargo manifest; a newer version is linked in the footer without performing any automatic upgrade.
- Re-authenticate expired sessions through the minimal login page while preserving the exact panel and Settings sub-tab; embedded login errors are inline and the authenticated shell no longer flashes during the redirect.
- Canonicalize `/configuration` to `/settings?tab=manual-config` and persist every Settings tab in the URL for reliable F5/re-login restoration.
- Use a shared form-saving state that disables the active submit action, shows `Saving…`, restores translated labels and blocks duplicate saves.
- Highlight/focus the actual invalid field for local validation problems in Logging JSON, listeners, Docker agents, TLS policy, ACL profiles, Manual config and certificate forms.
- Keep selected certificate/key files after failed import/save attempts.
- Show a subtle unsaved-change marker on the affected Settings tab and preserve dirty Manual config text across live refreshes.
- Update package, UI, OpenAPI, release checks and tooling identity to 0.19.3.
## What changed in 0.19.2
- Restore the local-listener risk checkbox for administration backends even when the administration listen socket is startup-owned/locked, including loopback equivalence between `localhost`, `127.0.0.0/8` and `::1` on the administration port.
- Make the vhost **Discard changes** action restore the persisted vhost instead of resetting the editor to a blank/default vhost.
- Use descriptive HTTP status labels in Settings -> Default responses, matching the 404-host editor.
- Let Live logs temporarily expand from the 256-entry live window to a continuously updated 4096-entry client buffer until the log window closes.
- Align inline checkbox/text controls and compact the Docker-vhost Aliases editor.
- Render idle backend traffic as `0.0 KiB/s`; positive sub-0.1 KiB/s activity renders as `<0.1 KiB/s` instead of a misleading zero.
- Replace native browser confirmation dialogs with RustProxy-styled confirmation modals and prefix API failures with the panel area that failed.
- Style sign-in failures inline under the login form, including `Incorrect username or password.` / its selected-language equivalent.
- Add `/opt/rustproxy/current` (or the selected prefix) to new login-shell `PATH` through `/etc/profile.d/rustproxy-path.sh` on install; managed update only verifies and warns about that profile.
- Keep placeholder/static/default pages strictly non-cacheable and suppress cache diagnostics/validators on those locally generated responses.
- Allow an existing vhost ID to be renamed with collision checks and an explicit warning about the new metric/log/cache identity and reset live health/traffic history.
- Update package, UI, OpenAPI, release checks and tooling identity to 0.19.2.
## What changed in 0.19.1
- Fix **Settings -> Default responses** saves by sending the standard section-update `value` payload and accepting the `pages` section in the administration API.
- Include the frontend HTTP/HTTPS scheme in the shared-cache primary key so scheme-dependent origin responses cannot cross protocols.
- Keep the live log stream at 256 rows while retaining up to 4096 completed requests for a one-shot **Load history** action; filters are applied before the requested history limit.
- Make backend traffic rates use KiB/s as the smallest display unit, using fractional KiB/s for small traffic instead of large raw B/s values.
- Polish Live Logs column selection, vertically align generic checkbox labels and place Docker-vhost Advanced switches beside Backend protocol on wide layouts; the alias editor no longer adds a redundant help line.
- Reduce stale simulated UI screenshots to two explicitly labelled legacy references and add a documentation index that identifies historical/version-labelled material.
- Restore the integration-test sources and independent Argon2id fixture required by the source/release checks so the 0.19.1 archive is self-contained for compiler-enabled `cargo test`.
- Update source, UI, API schema, release checks and package identity to 0.19.1.
## What changed in 0.19.0
- Harden managed updates against systemd `200/CHDIR` failures by repairing the managed data-root owner/mode and verifying that the saved service account can traverse it before the running service is stopped; inaccessible parent directories now fail early with an actionable error.
- Persist per-administrator **Live access logs** column visibility in SQLite. The preference changes only the dashboard table; filtered JSON export still contains every field present in each log entry.
- Render the Live Logs column picker with the same compact checkbox controls used elsewhere in the dashboard.
- Make backend `tls_verify=false` fully bypass X.509 certificate authentication/parsing callbacks used by webpki, restoring compatibility with legacy appliance certificates that fail with `UnsupportedCertVersion` while keeping TLS encryption and address/DNS/loop protections.
- Keep expanded upstream connect diagnostics with the nested Hyper/rustls/io error chain in Live Logs and the service journal.
- Remove the duplicate RustProxy version label from the top-right toolbar; the release version remains visible in the footer.
- Add SQLite schema v4 for administrator view preferences and update the administration API/release package identity to 0.19.0.
## What changed in 0.18.8
- Expand failed-upstream diagnostics so access/live logs preserve the nested Hyper/rustls/io error chain plus origin, effective TLS request origin, certificate-verification mode and elapsed connection time; connect failures are also emitted to the service journal at warning level, and Live access logs show the detail in a dedicated Upstream error column.
Follow-up fixes keep the four Docker-vhost per-app switches in one compact row and add regression coverage that generated Docker vhosts inherit the global `Server` response-header policy when they do not define an override.
- Replace the Docker-vhost alias CSV input with the same chip-style add/remove interaction used by hostname editors.
- Add per-Docker-vhost HTTP-to-HTTPS redirect, WebSocket and cache switches. New Docker assignments default the redirect on when the selected agent listeners can support it; existing pre-0.18.8 assignments keep their previous redirect-off behavior until saved with the new switch.
- Add an agent-level default ACL-profile selector next to the frontend certificate selector. Per-app ACL-profile selections still override the agent default, and inline per-app ACL rules remain unchanged.
- Remove the compression-codec explanatory sentence from the Overview dashboard.
- Update source, UI, API schema, release checks and package identity to 0.18.8.
## What changed in 0.18.7
- Keep **Response time history** collapsed by default while continuing to collect and update its live series.
- Make per-interface RX/TX history use the same 60 px plotting geometry, grid and RX/TX line treatment as aggregate network history, without nested background cards.
- Normalize expanded Docker-vhost routing and ACL field layout so text/select/checkbox controls share a stable label/control baseline and ACL selects retain normal control height.
- Update source, UI, release checks and package identity to 0.18.7.
## What changed in 0.18.6
- Add per-interface Linux network diagnostics from `/proc/net/dev`, with separate RX/TX history rows for every non-loopback interface in **Network and responses** while keeping Prometheus label cardinality unchanged.
- Strengthen compression telemetry verification with explicit quality-weight negotiation cases for gzip, Brotli, Zstd and deflate, and clarify in the UI that the counters represent the codec actually selected for each response.
- Polish **Settings -> Docker agents** field alignment/status controls and add a clear visual gap after listener selection before **Add Docker agent**.
- Update source, UI, EN/PL language packs, release checks and package identity to 0.18.6.
## What changed in 0.18.5
- Fix compression telemetry accounting by attaching an internal marker for the codec RustProxy actually applied; gzip, Brotli, Zstd and deflate now have independent counter regression coverage.
- Add an HTTP/1.1 request counter and show total/H1.1/H2/H3 request rates as separate colored series on the Overview chart.
- Add **Open app** to published Docker vhosts and show the primary Docker proxied domain beside generated pool IDs in **Backends**.
- Remove the page-level **Open proxy** shortcut.
- Make **Compact** density substantially tighter than **Dense** across dashboard cards, controls, tables and Docker/vhost rows.
- Give ordinary and Docker vhosts explicit proxy timeout defaults (10 s connect, 120 s response headers, 60 s read and 60 s send) so new/defaulted editors never start blank.
- Replace the Docker-agent Listener IDs text field with the shared named-listener selector, and keep Enabled immediately to the left of the centered connection-status badge.
- Update source, UI, EN/PL language packs, release checks and package identity to 0.18.5.
## What changed in 0.18.4
- Default new/missing backend health-check configuration to **TCP** instead of HTTP. Existing explicitly configured HTTP/off checks remain unchanged.
- Rework **Docker vhosts** into a summary-first view: each service keeps Publish, runtime health and visibility actions visible while route, ACL, timeout and health-check configuration stays collapsed until that service is edited. Agent diagnostics are collapsed behind **Agent details**.
- Rework **Settings -> Security** around compact account/session and host-policy sections, with password and policy editors collapsed until needed.
- Move **Administration audit** out of the Security page into a dedicated modal and load audit rows only when that modal is opened or refreshed.
- Retain the 0.18.3 HTTP/1 upstream title-case compatibility behavior and upstream-error diagnostics used for legacy/custom origin troubleshooting.
- Update source, UI, EN/PL language packs, release checks and package identity to 0.18.4.
## What changed in 0.18.3
- Add configurable per-vhost access-log files (`logging.file.per_vhost`) with a dedicated directory and `_unmatched.jsonl` fallback while preserving the combined JSONL mode.
- Treat explicitly supplied systemd/CLI/environment HTTP, HTTPS and administration binds as startup-owned: their addresses cannot be changed/removed in Settings, while non-startup listeners remain editable. Remote plain HTTP administration needs `--allow-remote-admin` but no second risk-acknowledgement flag.
- Make Compact density tighter, rename the cache settings surface to **Cache**, display Redirect targets on cards, and let 404 Hosts choose any final HTTP status from 200 to 599.
- Show the effective global TLS cipher list in Settings, mark ACME certificates as managed/read-only, require unassignment before certificate deletion (including administration/default usage), and default new ACME requests to Production.
- Keep WebSocket support on the nginx-compatible HTTP/1.1 Upgrade path by default. RFC 9220 WebSocket over HTTP/3 remains available only as an explicit experimental vhost option.
- Separate Docker discovery/vhost observability from ordinary vhost/backend Prometheus families. Docker assignments now export dedicated `rust_proxy_docker_vhost_*` and `rust_proxy_docker_backend_*` series instead of appearing under `rust_proxy_vhost_*` / `rust_proxy_backend_*`.
- Add an independent **Docker vhosts** collector switch under **Settings -> Prometheus -> Metric groups**, enabled by default and live-applied like the other collector switches.
- Export bounded Docker agent/assignment/domain inventory plus Docker-vhost traffic/status/duration and the full backend readiness/health/request/error/byte/latency/EWMA/failure/probe observations.
- Add regression coverage that verifies Docker pools never leak into ordinary vhost/backend Prometheus families.
- Update OpenAPI, Prometheus documentation, release checks and package identity to 0.18.3.
## What changed in 0.18.2
- Add optional Docker host discovery through a standalone Go agent in `docker-agent/`, with Bearer-token inventory access, systemd packaging helpers, multi-address host discovery and complete published-TCP binding discovery. The agent serves HTTPS by default with a persistent self-signed ECDSA certificate generated on first start.
- Pin the Docker agent certificate by SHA-256 in RustProxy instead of accepting arbitrary self-signed certificates. Public-CA agents remain supported without a pin; plaintext HTTP is an explicit compatibility mode only.
- Add **Settings -> Docker agents** and a main **Docker vhosts** page. Multiple agents each keep their own base domain (for example `docker1.lab.local` / `docker2.lab.local`), while each service can use a short name, an arbitrary FQDN and multiple aliases.
- Allow every Docker vhost to select a concrete detected Docker-host IP; wildcard bindings follow the selected IPv4/IPv6 address, while explicit Docker bindings retain their own host port. Agent-level default target IP remains optional.
- Reconcile enabled Docker assignments into ephemeral RustProxy vhosts without creating configuration revisions. Changed Docker published bindings/IP observations update routes on the next poll.
- Give Docker vhosts the same backend health engine used by ordinary vhosts. Per service, HTTP/TCP/off checks, path/Host/status/interval/timeout/rise/fall controls and live up/down/checking, latency, last-result, request/error/active diagnostics are available directly on the Docker vhosts page.
- Move the cache **Live** toggle to the right side of the cache action toolbar.
- Remove all dedicated `X-Rust-Proxy-Revision` response-header behavior. RustProxy no longer creates, strips, protects or migrates that header; if an upstream/operator provides it, it is treated like an ordinary response header. Internal configuration revision CAS remains unchanged.
- Replace production password-recovery guidance with `rust-proxy admin reset-password` and reorganize the Settings navigation for Docker-agent configuration.
- Update source, UI, OpenAPI, release tooling and package identity to 0.18.2.
## What changed in 0.17.0
- Add a complete `debian/` packaging workflow for a native `rustproxy` package: hardened systemd service, dedicated `rustproxy` user, `/var/lib/rustproxy` and `/var/log/rustproxy`, daily three-day `gzip -9` log rotation, package/repository build scripts and repository layout suitable for `https://rustproxy.linuxiarz.pl/`.
- Expand the Prometheus exporter to cover every field in the current bounded OS/process diagnostics view, plus GeoIP, certificate renewal, backend probe/EWMA/passive-failure, redirect/404-host, stream and structured-log diagnostics. Add an explicit trusted-CIDR option that can allow scraping without a bearer token while always using the real transport peer.
- Ship `grafana/rustproxy-overview.json` with traffic, vhost/backend, cache, memory, protocol, stream, logging, inventory and certificate panels.
- Add a dedicated **404 hosts** editor. A local-response host owns domains/listeners/certificates like a redirect/vhost but never opens an upstream; it can return the built-in placeholder, an empty status response or bounded custom HTML.
- Make the built-in `RustProxy is running` placeholder strictly `no-store` and strip optional RustProxy server, cache, backend, diagnostic, security and compression headers from that minimal response.
- Reuse the vhost-style hostname chip editor for Redirect source domains and keep the 0.16.x UX improvements intact.
- Update source, UI, OpenAPI, release tooling and package identity to 0.17.0.
## What changed in 0.16.1
- Keep the 0.16.0 proxy, cache, administration, H3 and editor behavior unchanged while polishing save feedback: successful configuration saves no longer expose the internal configuration revision number in modal/toast feedback. Revision CAS remains fully active internally for stale-write protection and is still available in operational status/diagnostics.
- Update source, UI, OpenAPI, release tooling and packaging identity to 0.16.1.
## What changed in 0.16.0
- Separate the main vhost backend from **Custom locations**. Custom locations are now overrides only; when none matches, routing always falls back to the vhost pool. An untouched legacy synthetic `root /` route is normalized away, while a deliberately customized `/` location remains a valid override.
- Fix publishing the administration panel through an explicitly configured RustProxy vhost. The reserved `rustproxy_session` cookie is still stripped for ordinary upstreams, but is preserved for a tightly guarded HTTPS self-admin route that directly targets the configured admin listener, has `accept_local_listener_risk=true`, and uses a hostname listed in `administration.allowed_hosts`.
- Harden RFC 9220 WebSocket setup: RustProxy now completes the backend HTTP/1.1 `OnUpgrade` before returning downstream HTTP/3 success, avoiding a `200` followed by an immediate H3 reset when backend takeover fails. Access logs gain HTTP version/transport, WebSocket phase/error, H3 reset and upstream-status fields.
- Split memory diagnostics into process RSS categories and RustProxy cache allocations. The panel now shows total RSS, anonymous/file/shared RSS, data/swap plus hot cache and transient fill/cold-queue/cold-I/O bytes. Existing allocator page release (`malloc_trim` on supported glibc/Linux paths) is retained; 0.16.0 does not add a new cache-memory throttle.
- Refine the Vhost/Redirect editor UX: new vhosts select standard HTTP `:80` and HTTPS `:443` listeners together when available, H2/H3 switches sit side by side, Redirects reuse the exact same listener selector, Authentication separates the IP access list from provider settings, TinyAuth advanced fields stay collapsed, and disabled vhost cache hides all subordinate options. New vhost drafts explicitly start with cache disabled.
- Rework backend cards and add opt-in origin diagnostics: `X-RustProxy-Backend` exposes the selected member ID and `X-RustProxy-Backend-Time` exposes origin response-header latency. Both headers are proxy-owned/protected and are omitted when a response is served without contacting an origin. The local-listener risk control appears only when the entered backend URL actually targets the configured RustProxy administration listener.
## What changed in 0.15.1
- Fix EN/PL language-pack placement for the 0.15 custom-location controls so documentation, match modes, rewrite controls and the visual header-rule builder render translated text instead of raw keys.
- Rework the visual header-rule editor into numbered rule cards with clearer operation/name/value fields, empty-state guidance and protected-header help.
- Add a live effective-behavior preview to every Custom location showing matching, proxy/local response, rewrite, cache, ACL and request/response header-rule counts before saving.
- Restructure the in-panel Custom locations documentation into matching, handling/policy and common-example sections.
- Add a combined live HIT/MISS/BYPASS activity chart based on per-sample counter deltas, while retaining the RAM-residency history.
- Add live process CPU and RSS charts to balance the dashboard process diagnostics card.
## What changed in 0.15.0
- **Custom locations** now support prefix, priority-prefix (`^~`), exact, case-sensitive regex and case-insensitive regex matching. Proxy locations can preserve, strip, replace or regex-rewrite the upstream path; local locations can return a configured status/body/content type without opening a backend connection.
- Location request/response header rules now have a visual builder plus inline documentation; the Advanced JSON representation remains available for copy/paste and automation. See [Custom locations](docs/CUSTOM_LOCATIONS.md).
- Add `nagios/` checks for admin API RTT, backend availability, backend latency and dropped-work counters. See [Nagios / Icinga checks](nagios/README.md).
- Move `Server-Timing` and verified Cloudflare client-IP diagnostics to the main vhost frontend/details page.
- Add live dashboard histories for RAM cache, network RX/TX and mean response latency. The compact footer also exposes measured administration API RTT and cold/log drop counters.
- Split cold-cache demotion into explicit idle age and maximum hot-tier residency age, while retaining independent LRU and shutdown policies.
- Live logs now include the effective source IP after trusted-proxy/verified Cloudflare processing; requests rejected before that processing still record the transport peer.
- Remove the runtime legacy renewal-observation JSON importer. Stopped source upgrades remove the obsolete observation sidecar as the final upgrade step without importing it or retaining a second legacy copy; the application itself uses SQLite only.
- Repeated literal slashes are normalized for route/ACL matching but preserved toward the backend unless a rewrite is selected, so requests such as `/static/js//events.js?v=bf9b5489` are accepted without allowing encoded separator or traversal ambiguity.
## What changed in 0.14.0
- Fix administration behind a trusted reverse proxy: the optional DNS allowlist now validates the browser-facing authority without forcing the internal admin port, while direct IP/`localhost` access remains tied to the real administration port and stays available. Trusted `X-Forwarded-Host`/`X-Forwarded-Proto` are used for same-origin checks and Secure session cookies.
- Implement RFC 9220 WebSocket bootstrapping on HTTP/3 with Extended CONNECT. RustProxy advertises `SETTINGS_ENABLE_CONNECT_PROTOCOL`, validates `:protocol=websocket`, translates the bootstrap to the backend HTTP/1.1 Upgrade handshake, returns downstream `200`, and bridges WebSocket bytes over H3 DATA with FIN/reset handling. Generic CONNECT and unsupported Extended CONNECT protocols remain rejected.
- Switch the HTTP/3 integration to `hpx-h3 2.5.19` with its Quinn transport feature so the protocol layer can represent RFC 9220 Extended CONNECT without a local parser bypass.
- Rename dashboard labels: Backend pools -> Backends, debug-origin preset -> recommended preset, health/restore tab -> Backend health, per-host response security -> Security, and Pages -> Error pages (with corresponding Polish labels).
- Bump source, UI, OpenAPI, release tooling and documentation to 0.14.0. No `certificates.json` metadata store is present; certificate state remains in the current SQLite/PEM paths, while the separate historical `certs/renewals.json` importer is retained only for renewal-observation migration.
## What changed in 0.13.2
- Fix direct dashboard refresh/session restoration: authenticated panel routes now validate the existing cookie before selecting the login or application shell, and restored browser-history login pages re-check the server session instead of showing a stale logged-out view.
- Preserve cache across managed software updates when the cold tier is enabled. RustProxy 0.13.2+ recognizes the updater's one-shot marker and forces a bounded hot-to-cold handoff even when ordinary `cold_on_shutdown` is disabled; RAM-only cache still cannot survive a process exit when cold storage is disabled.
- Persist non-secret automatic-certificate-renewal observations in SQLite and preload them before the administration listener starts. Existing `certs/renewals.json` observations are imported once, so **Check now** is no longer required after a restart just to repopulate last/next/expiry/result data.
- Move the raw full-document editor out of primary navigation into **Settings -> Manual config**. The old `/configuration` browser route remains as a compatibility alias that opens that Settings block.
- Add schema-v3 migration/release regressions, update OpenAPI/UI/docs and bump the source/package identity to 0.13.2.
## What changed in 0.13.1
- Extend administrator browser sessions from the old short 8-hour/30-minute-idle behavior to a configurable absolute **7–30 day** lifetime (default 30 days). The setting is live, session cookies are refreshed only up to the server-side absolute expiry, and password/revoke/logout invalidation is unchanged.
- Add an explicit per-backend `accept_local_listener_risk` switch. Together with `allow_private=true` where required, it can intentionally proxy to a local RustProxy listener such as `127.0.0.1:9090`; the default remains blocked to prevent loops/control-plane exposure. The Vhost editor requires an explicit risk confirmation.
- Update OpenAPI, English/Polish UI, security/transport documentation, regression contracts and release identity for 0.13.1.
## What changed in 0.13.0
- Add first-class **Redirects** beside Vhosts/Streams. Redirect hosts use named listeners and certificate assignments, support exact/prefix and HTTP/HTTPS matching, URL/host/path targets, 301/302/303/307/308, path append/strip/replace, query preserve/drop and explicit redirect cache lifetime.
- Redirects are resolved locally before proxy routing, never open an upstream connection, retain global host ACL enforcement and reject overlapping hostname/listener ownership with vhosts or other redirect hosts.
- Backend HTTPS certificate verification now defaults to **off** when `tls_verify` is omitted. Administrators can explicitly enable chain/identity verification per backend; Tinyauth and other verifier clients keep their independent secure defaults.
- TLS certificate cards now show DNS SAN coverage as compact vhost-style badges, keep verbose bindings/file/assignment data collapsed by default, and live-inspect older/manual public PEM files when `covered_hosts` metadata is missing.
- Update OpenAPI, English/Polish UI, regression contracts, documentation and release identity to 0.13.0.
## What changed in 0.12.1
- Split ordinary dashboard saves into revisioned `PUT /api/config/{section}` endpoints while retaining full-document PUT for intentional multi-section transactions. Cache invalidation is decoupled from the global configuration revision so unrelated control-plane saves no longer discard hot/cold objects.
- Add explicit browser routes for dashboard subpages and History API synchronization so refreshing `/vhosts`, `/cache`, `/tls` and the other primary panels returns the same guarded application shell instead of the landing page.
- Extend cold-cache policy with separate idle, LRU-pressure and graceful-shutdown persistence switches, reduce queued body retention, flush hot objects directly to cold storage during graceful shutdown, and release allocator pages after large demotions on glibc/Linux.
- Show certificate DNS SubjectAltName coverage separately from active SNI bindings for uploaded and ACME-managed certificates.
- In 0.12.1 backend TLS verification still defaulted on when `tls_verify` was omitted; 0.13.0 intentionally changes that default to off. The debug-origin preset already wrote an explicit `tls_verify=false`.
- Update OpenAPI, regressions, release tooling and source identity to 0.12.1.
## What changed in 0.12.0
- Promote TCP/UDP streams from Settings to the main navigation directly below Vhosts, with searchable stream cards and the same modal editing workflow used by vhosts.
- Add fixed-cardinality per-stream runtime telemetry for active connections/sessions, accepted/completed sessions, rejects, errors, bytes and UDP packets. The dashboard derives live RX/TX rates from those backend counters and keeps compact lifetime charts for the open panel session.
- Make restart-bound state explicit: desired stream configuration is shown separately from the active startup listeners, and changed/new/removed stream listeners remain marked pending until RustProxy restarts.
- Restyle named HTTP/HTTPS listener bind-address editing as address chips, matching the vhost hostname editor while preserving the existing 1–16 address validation and wildcard restrictions.
- Keep raw TCP/UDP forwarding outside HTTP ACL/cache/header/compression handling and retain bounded TCP connections / UDP client sessions.
- Bump the source release, panel, OpenAPI, upgrade tooling and package identity to 0.12.0 and extend offline regression checks for the Streams navigation/UI/telemetry contracts.
## What changed in 0.11.5
- Rework shared-cache identity around Varnish built-in semantics: the primary object hash is vhost scope + normalized Host authority + exact URL, while response `Vary` selects representation variants. Unrelated request headers, frontend scheme and the selected load-balanced backend member no longer fragment the cache.
- Treat `GET` and `HEAD` as the cacheable methods. A cacheable HEAD shares the GET object and a HEAD miss fetches/stores the GET representation; other methods pass to the backend without implicitly clearing unrelated cached objects.
- Fix `X-Cache-Resident-Age` continuity. Resident time now survives successful 304 revalidation and hot/cold demotion/promotion instead of resetting to zero when metadata is refreshed or a cold object returns to RAM.
- Bump cold-cache metadata to format 2 for the Vary and resident-age fields, add variant-schema safety checks, and extend cache regressions for Vary selection, key sharing, HEAD eligibility and resident age.
## What changed in 0.11.4
- Make Force SSL validation match redirect behavior: a selected plain HTTP listener is required, port 443 is preferred when several TLS ports are present, and ambiguous non-standard TLS targets get a clearer error.
- Replace the reusable ACL-profile free-form rule list with a compact visual rule builder plus an optional bulk import. Bulk parsing normalizes invisible Unicode spacing and reports the exact bad line instead of a generic syntax error.
- Suppress RustProxy cache diagnostic response headers entirely when the effective vhost cache is disabled, while keeping internal cache counters.
- In the dashboard backend-pool table, disabled vhosts are rendered muted and explicitly labeled Disabled instead of looking like failed backends.
## What changed in 0.11.3
- Add a per-vhost **Forward client IP to backend** switch. It defaults ON; when disabled, application requests omit `Forwarded`, `X-Forwarded-For` and `X-Real-IP` while RustProxy, ACLs, rate limits, GeoIP and Tinyauth still use the authenticated client address.
- Add a compact Vhost search box that filters by vhost ID, hostname/wildcard, backend ID and backend URL without changing configuration.
- Fix the release manifest to use the resolved `quinn 0.11.12` already present in `Cargo.lock`, and stop `dev.sh` from regenerating a valid application lockfile on every run.
- Make the managed systemd service writable at `/var/log/rustproxy` so the JSONL file sink works with `ProtectSystem=strict`; the service now creates/manages the log directory through systemd.
## What changed in 0.11.2
- Fix administration HTTPS over HTTP/2: the control-plane Host guard now accepts the protocol-native `:authority` value exposed by Hyper through the request URI instead of requiring a legacy `Host` field that browsers commonly omit on H2.
- Keep HTTP/1.x strict single-Host handling and reject absolute-form targets; on H2/H3, reject conflicting `Host` and `:authority` values rather than silently choosing one.
- Add regression tests for H2 authority handling and the real administration `/healthz` route so HTTPS administration works without forcing HTTP/1.1.
- Add per-vhost **Force SSL** directly below frontend selection. Plain HTTP receives a `308` to the same hostname/path/query on the selected HTTPS port; TLS listeners for a forced vhost must use one unambiguous port.
- Map Nginx Proxy Manager `ssl_forced` to RustProxy `force_ssl` during SQLite migration, retaining both HTTP and HTTPS listener bindings so the redirect actually works.
## What changed in 0.11.1
- Fix managed-update health checks for administration HTTPS and persisted administration bind changes. The deployment checker now follows `administration.listen`, `administration.tls` and the configured Host allowlist instead of always probing the install-time address over plain HTTP.
- Add `scripts/migrate_npm.py`, a read-first Nginx Proxy Manager SQLite migrator for proxy-host names/backends. It preserves WebSocket/enabled/H2 intent, maps NPM TLS hosts to RustProxy TLS using the application default certificate, reports unsupported NPM features for manual review, writes a JSON plan and requires explicit `--apply` before changing RustProxy.
- Add offline regression coverage for the NPM migration planner and persisted HTTPS administration health-target resolution.
## What changed in 0.11.0
- Add reusable ACL Profiles with country allow/block policy and IP/CIDR rules. Profiles can be attached to vhosts while existing per-vhost and route ACLs remain available and are enforced cumulatively.
- Improve hostname editing with chip-style input and leading `*.` wildcard domains. Exact hostnames take precedence, then the longest matching wildcard, so exact and wildcard vhosts can coexist on the same listener.
- Add compact per-vhost request-rate charts that retain the current browser panel session by progressively compacting older samples.
- Add the missing built-in HTTP 401 page and stop benign WebSocket EOF/reset/abort/broken-pipe closes after a successful upgrade from being reported as proxy body errors.
- Administration HTTPS now redirects plaintext requests on the HTTPS admin socket to the same authority/path over HTTPS. With no explicit admin hostname allowlist, valid DNS Host values are accepted; a configured allowlist remains strict.
- Named frontend listeners can bind the same policy to up to 16 explicit local addresses. Multi-address listeners reject wildcard `0.0.0.0`/`::` binds.
- Restyle the structured-log field builder to match the Vhost configuration modal and place its Configure fields action beside the preset selector.
- Source archives are now reproducible: sorted entries, deterministic timestamps/permissions and `SOURCE_DATE_EPOCH` support are verified by the release smoke test.
## What changed in 0.10.0
- Cache now has two bounded tiers: hot RAM plus optional persistent cold disk storage. LRU/idle hot objects are demoted asynchronously; fresh cold hits are integrity-checked and promoted back to RAM.
- Cold cache settings expose the relative data path, disk/object limits and idle demotion delay. The Cache panel reports hot/cold objects, RAM/disk bytes, promotions, demotions, cold hits and errors.
- Cache diagnostics now distinguish browser hard-reload revalidation (`request_no_cache`, `request_max_age`, `request_pragma_no_cache`) from true cache misses. Normal browser cache can satisfy navigation without sending a request to RustProxy; use repeated `curl` GETs for proxy-level HIT testing.
- Logging format configuration adds Standard, Nginx-style, ECS-style and Minimal presets plus a graphical field picker/renamer with JSON preview. Advanced raw JSON mapping remains available.
- Logging sink cards reuse the shared square application card styling instead of release-specific rounded fieldset CSS.
- A baseline multi-stage Docker/OCI image is included. It runs as an unprivileged user, persists `/var/lib/rustproxy` and keeps administration loopback by default. Docker discovery uses the separate `docker-agent/`; the RustProxy container itself never needs the Docker socket.
## What changed in 0.9.0
- Vhosts use readable cards with listener/protocol/TLS/cache identity and live backend health, request, active, error, latency and traffic metrics.
- Structured access logging can write configurable JSON/JSONL to one combined file or separate files per vhost, plus Logstash TCP and Loki HTTP(S), from a bounded asynchronous queue; sink delivery/drop/error counters are visible in the panel.
- Cache stored-object inspection reports body bytes, resident bytes and metadata overhead, with optional `X-Cache-Resident-Age`.
- Settings adds full-width Administration and TLS policy pages. The panel can run on HTTPS using the application-managed certificate or a selected certificate; a non-loopback bind is allowed when HTTPS is enabled.
- TLS 1.2/1.3 and rustls cipher suites are configurable globally and per vhost for TCP TLS. HTTP/3 remains tied to the global TLS 1.3 policy.
- Logging is a dedicated navigation page; Settings tabs fill the available width.
- Roadmap items completed here include remote HTTPS administration and `X-Cache-Resident-Age`.
## What changed in 0.8.1
- Cache is enabled by default.
- Browser validators no longer cause blanket BYPASS: fresh `If-None-Match` / `If-Modified-Since` requests can be answered as local conditional HITs, including `304 Not Modified`.
- Request `no-cache`, `max-age` freshness constraints, `min-fresh` and legacy `Pragma: no-cache` use validator-based backend revalidation when a safe stored validator exists; backend `304` refreshes metadata and reuses the cached body.
- Request `no-store` remains a hard BYPASS. Response `Cache-Control: no-cache` may be stored when it has a usable validator, but is validated before every reuse; response `no-store`/`private` remain uncacheable.
- `cache.max_object_bytes` now permits values up to 1 GiB (still bounded by `cache.max_bytes`). Large fills grow incrementally and consume more fill permits instead of preallocating the configured object ceiling.
- Cache diagnostics add `cache_conditional_hit`, `cache_revalidated`, `request_no_cache`, `request_no_store` and related revalidation reasons.
- Release identity, tests, panel limits and cache documentation are updated to 0.8.1.
## What changed in 0.8.0
- Per-vhost rate limiting plus country-specific limits and country block/allow-only rules, with built-in 429/403 pages.
- GeoIP country data is downloaded on first install from `sapics/ip-location-db` and verified against publisher SHA-256 files. Each managed update compares local files with the current publisher checksums and downloads only stale/missing assets.
- Optional Cloudflare real-client-IP forwarding per vhost, trusted only from Cloudflare edge CIDRs.
- Per-vhost HTTP/2 and HTTP/3 opt-outs live next to named frontend selection. Listener IP/ports and protocol capabilities stay in Settings; H2 ALPN is narrowed by SNI for vhosts that disable it.
- Health-check mode `off` now disables both active probes and passive health classification.
- New backend rows use the HTTPS-by-IP debugging defaults requested for preserved Host routing: default pool ON, private origin ON, HTTP/1.1, preserve Host ON and backend TLS verification OFF. The panel warns about this insecure TLS choice and about incomplete/mismatched debug settings. Existing backend values are not silently rewritten.
- Static-cookie cache boost is now visible globally and per vhost. The global defaults include common images, CSS/JS/WASM, fonts, audio/video and static downloads; matching assets ignore request Cookie while `Set-Cookie`, `private`/`no-store` and `Vary: Cookie` still forbid shared storage.
- Cache `Age` now follows corrected received age plus response delay without rounding sub-second delay up to a full second.
- Cargo, panel, OpenAPI, packaging and source-update metadata are 0.8.0.
The 0.7.2 Swagger build fix remains in place: the pinned UI assets are prepared by
this project and embedded at build time without a mandatory Cargo environment setting.
The [0.7.1 source audit](docs/SECURITY_AUDIT.md) remains historical and is not a new
audit or proof of live security in 0.8.0.
## Existing 0.7.0 foundation
Managed certificates imported into the library renew automatically unless disabled.
Initial issuance/import is still explicit and staging-first; imported PEM alone is
not auto-managed. Existing 0.6 issuer metadata enables renewal by default, so review
managed certificates before upgrade. Nothing silently switches from staging to the
production CA. See [renewal and recovery](docs/RENEWAL.md).
## What changed in 0.25.0
- Add reusable **Web Services** configured independently from vhosts. Each service owns its document root, optional ordered index-file list and directory-listing policy.
- Let the main vhost source and every custom location choose **Reverse Proxy** or **Web Server**, with Web Server locations referencing an existing Web Service instead of duplicating filesystem settings. A single vhost can mix static files and reverse-proxied applications.
- Add static `GET`/`HEAD`, MIME types, `Content-Length`, streaming file bodies, index lookup, directory slash redirects and optional escaped directory listings.
- Add HTTP validators (`ETag`, `Last-Modified`, `If-None-Match`, `If-Modified-Since`) plus one-range `Range`/`If-Range` handling with `206` and `416`.
- Confine local files to the configured document root with decoded-path validation and race-resistant Unix `openat`; symlinks are denied by default, with an explicit Linux-only static mode that follows only targets verified inside the root.
- Keep ACL/authentication, headers, security headers, custom error pages, compression and H1/H2/H3 transport in the existing vhost pipeline. The Web Server adds no second URL router, error-page subsystem or object cache.
- Add the **Web Server** dashboard workspace, API/OpenAPI schema, Polish/English UI strings, regression tests and dedicated operator documentation.
- Add Web Service MIME overrides, a fallback MIME type and optional `Cache-Control`; keep static data in filesystem/OS page cache instead of duplicating it into the reverse-proxy object cache.
- Expand Web Services with ordered `try_files`, internal/redirect rewrite rules, per-extension/MIME cache policy, fixed source headers, precompressed `.br`/`.gz` sidecars, forced-download extensions, Linux inside-root symlink policy and bounded FastCGI/PHP-FPM execution. PHP-FPM configuration supports Unix/loopback-TCP endpoint syntax, Authorization forwarding control, streaming body/header/stderr limits, trusted custom FastCGI parameters and validated `PHP_VALUE` overrides. Organize these settings into General, Routing, .htaccess, MIME, Cache & headers, Delivery, PHP-FPM and Security tabs using the same compact sticky modal-tab pattern as the Vhost editor.
- Fix repeated directory-listing refreshes, keep index-before-listing behavior per directory, and expose vhost-wide Web Server request/active/error/EWMA/traffic statistics.
- Split **Settings -> Logging** into Outputs, JSON format and Error log subsections in the same in-card sub-tab layout as Cache and accept route/cache/transform effective fields in custom JSON mappings.
- Add bounded per-vhost **Traffic** analytics with top countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes plus donut charts for the main dimensions. User-Agent capture is enabled by default; country capture/GeoIP lookup is explicit and disabled by default unless a country ACL/rate-limit already requires GeoIP.
- Keep Web Service lists stable across fast dashboard refreshes and return the normal customizable `403` page when a directory has neither an index nor directory listing.
- Add a bounded migration-oriented `.htaccess` compatibility layer with common rewrite/front-controller, index/listing, MIME, header, Expires and PHP `AddHandler` support; compile files on Web Service Apply, fail closed on unsupported access/handler directives, and never expose `.ht*` control files.
- Add one-shot Web Service presets for Static/SPA/PHP and common CMS/framework deployments (WordPress, Drupal, Laravel, Symfony, Joomla, PrestaShop, Downloads) plus optional hardening for high-confidence attack probes/sensitive files and response fingerprint headers.
- Add automatic RSS relief without vhost reloads: periodically ask glibc to return already-free pages and trim only idle HOT cache objects above a configurable waterline, while keeping active objects and bounded upstream keep-alive pools intact.
- Add an authenticated **Docs Reader** at `/docs` for bundled project Markdown, with the OpenAPI/Swagger interface kept in a separate **API** tab.
See [Web Server](docs/WEB_SERVER.md) for configuration and security details, [documentation index](docs/README.md) for the current documentation set, and [0.25 specification audit](docs/V0.25.0_AUDIT.md) for point-by-point release status. Open follow-up work is tracked separately in [TODO](docs/TODO.md).
## Documentation
- `/docs` - authenticated project documentation Reader plus the API/OpenAPI tab.
- [docs/README.md](docs/README.md) - canonical documentation index.
- [docs/WEB_SERVER.md](docs/WEB_SERVER.md) - Web Server configuration, HTTP behavior and filesystem security.
- [docs/PHP_FPM.md](docs/PHP_FPM.md) - implemented FastCGI/PHP-FPM integration, safety model and runtime requirements.
- [docs/V0.25.0_AUDIT.md](docs/V0.25.0_AUDIT.md) - mapping of the 0.25 specification to implementation and release gates.
- [docs/TEST_REPORT.md](docs/TEST_REPORT.md) - verification results and environment limitations.
- [docs/TODO.md](docs/TODO.md) - unresolved follow-up only.
## Release history
Historical user/operator-visible changes are maintained in [CHANGELOG.md](CHANGELOG.md). Detailed historical implementation notes are retained in [docs/CHANGELOG_TECHNICAL_ARCHIVE.md](docs/CHANGELOG_TECHNICAL_ARCHIVE.md), and completed roadmap milestones are retained in [docs/ROADMAP_HISTORY.md](docs/ROADMAP_HISTORY.md).
## Core capabilities and references
Managed certificates imported into the library renew automatically unless disabled. Initial issuance/import remains explicit and staging-first; imported PEM alone is not auto-managed. See [renewal and recovery](docs/RENEWAL.md).
Read [installation and update](docs/INSTALL.md), [host access and locations](docs/VHOST_ACCESS.md),
[migration](docs/MIGRATION.md), [NPM migration](docs/NPM_MIGRATION.md), [ACME providers](docs/ACME_PROVIDERS.md),
@@ -550,9 +66,9 @@ The bootstrap installs the compiler/build dependencies and Rust, clones this rep
builds the locked release. With no argument it runs in `auto` mode: a host without a managed
RustProxy installation is installed, while an existing `/opt/rustproxy/install.json` triggers
the safe `update.sh` path with backup, health check and rollback. First install starts HTTP on
`0.0.0.0:80`, HTTPS on `0.0.0.0:443` and the administration panel on plain HTTP
`0.0.0.0:9090` with the explicit `--allow-remote-admin` gate. Updates preserve the saved listener and
service settings. Restrict TCP/9090 with a firewall/private network.
`0.0.0.0:80`, HTTPS on `0.0.0.0:443` and keeps the administration panel on loopback HTTP
`127.0.0.1:9090`. Updates preserve the saved listener and service settings. Use an SSH tunnel for
initial remote access, then enable Administration HTTPS before exposing a non-loopback admin bind.
```bash
# automatic: install on a new host, update an existing managed installation
@@ -588,7 +104,7 @@ CARGO_BUILD_JOBS=1 CARGO_PROFILE_RELEASE_LTO=false \
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked
```
The 0.22.1 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
The 0.25.0 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
updates only this package's own version entry. This packaging environment has no Cargo, so the
dependency graph was not re-resolved here. On the compiler-enabled deployment host, run the
locked check/test/release gates below and retain the verified lockfile. `dev.sh` can generate a
@@ -805,17 +321,18 @@ language JSON files survive the update; shipped files replace their old names,
whose previous bytes remain in the backup. Unknown custom source edits are not
merged. Do not overlay individual source files onto an old tree.
RustProxy 0.13.2 advances SQLite to schema version 3 by adding the non-secret
`certificate_renewals` observation table; configuration-document fields still use defaults
when omitted. Once a 0.13.2 database/document is saved, an older binary may reject the
newer schema or unknown fields. Roll back
using the pre-upgrade data backup as well as the old source, not just the binary.
RustProxy 0.25.0 keeps the existing SQLite schema version 7. Web Services and vhost/location
source selection are stored in the normal revisioned configuration document, so no separate
database migration is required; omitted source fields still default to Reverse Proxy. Once a
0.25.0 configuration containing the new fields is saved, an older binary may reject unknown
configuration fields. Roll back using the pre-upgrade data backup as well as the old source,
not just the binary.
## Documentation and checks
[documentation index](docs/README.md), [API](docs/API.md), [architecture](docs/ARCHITECTURE.md),
[security](docs/SECURITY.md), [transport](docs/TRANSPORT.md),
[vhosts and pools](docs/VHOSTS.md), [settings](docs/SETTINGS.md), [cache](docs/CACHE.md),
[vhosts and pools](docs/VHOSTS.md), [Web Server](docs/WEB_SERVER.md), [settings](docs/SETTINGS.md), [cache](docs/CACHE.md),
[roadmap](ROADMAP.md), [changelog](CHANGELOG.md), [verification](docs/TEST_REPORT.md).
```bash
@@ -825,7 +342,7 @@ python3 scripts/release_smoke.py
# Runs those checks first, then the Rust suite when Cargo is available:
bash dev.sh test
# Source-only package, with no Git checkout required:
python3 make_zip.py /tmp/RustProxy-0.22.1.zip
python3 make_zip.py /tmp/RustProxy-0.25.0.zip
```
## New management and test-origin guide