# RustProxy 0.33.3 ## 0.33.3 sidebar appearance follow-up - Main navigation takes active/hover backgrounds and selection colors from the selected **interface theme**, not the chart color palette. Dark and ultra-dark use theme brand tones; light and cream blend theme brand/text for contrast. Switching the chart palette no longer changes sidebar or mobile-menu highlighting. - Sidebar navigation and the mobile menu follow the existing Appearance → Corner rounding setting. Changes take effect live with the current preferences; no additional JavaScript, API changes or preference migrations are required. ## 0.33.3: resizable Overview dashboard and free card placement - **Visual layout editor fix:** **Arrange Overview cards** uses uniformly sized, readable preview tiles (three columns on desktop, two on tablets, one on phones), not the 12-column canvas used by the actual Overview. Its `2/12` through `12/12` width controls still resize the real dashboard cards. Toolbars and hidden-card actions wrap cleanly without horizontal modal scroll; dragging, hiding, Save/Cancel and factory reset work as before. - Fixed time-series SVG viewport scaling after widening cards. All Overview line plots (numeric sparklines, full-width charts and diagnostic/network interface charts) now span their available width while keeping their vertical sizing and stroke thickness; donut charts remain circular. No new status polling is required. - In **Unlock layout** or **Arrange cards visually**, use − / + to change a card's width in the 12-column dashboard grid. Available widths are 2, 3, 4, 6 and 12 columns, restricted by card type for readability. **3 columns fits four graphs in one row** on a desktop canvas wider than 1080px. Even the smallest number/sparkline cards can be expanded to 4 columns (twice their original width) and moved to the very top, beside regular charts. - The first manual move or resize enables a freely ordered layout, with no enforced separation between numbers, small charts, wide charts or panels. Responsive widths clamp to six/two columns on smaller canvases; dense grid packing reduces empty gaps without changing chart sampling or polling. - Card sizes are saved with the account's existing Overview preferences in nullable `dashboard_widget_sizes`; **null retains 0.33.2 group ordering** for older saved layouts, while `{}` enables free order with normal widths. Save, cancel, factory reset and modal preview include dimensions. Existing per-account layouts, factory visibility and 600-sample default are preserved. No SQLite migration or extra status fetches are needed. Runtime Rust acceptance remains required. ## 0.33.2: unified progressbar appearance - Cache HOT/COLD object, RAM and disk occupancy bars now use the same selected chart palette (`--chart-accent`) as Overview meters, instead of fixed green. Changing Appearance → Chart style updates every bar immediately, including native `` controls. The neutral track retains theme contrast. - Progressbar rounding follows Appearance → Corner rounding (default, square, subtle, rounded and extra) across Cache, Overview, WWW and traffic ranking bars. Both the track and its fill follow the same radius. No metrics, APIs, polling behavior, dashboards or saved preferences are changed. - The **System Load → RAM used / total** meter uses the same custom track/fill as other Overview cards (including the chart palette and corner radius), instead of browser-specific native `` rendering. Its original 5px height and status-based used/total percentage are unchanged. Missing total RAM does not produce an invented percentage. ## 0.33.1: factory Overview preset and live layout preview - `src/admin/web/dashboard-defaults.json` defines the factory Overview card order, visibility, density and initial 600-sample history. Both the Rust preference defaults and authenticated JavaScript use this same file. New accounts without stored preferences use the full preset; **Reset to default** restores card order/visibility, not density or browser-local sample history. Existing saved layouts and browser-persisted sample choices are preserved. Future registry additions remain opt-in. - An unlocked inline layout is now authoritative during live backend/Stream updates and unrelated preference refreshes. Showing/hiding those cards takes effect immediately and stays stable until **Save and lock** or **Cancel**. Cancel restores the saved layout. No extra polling, storage migrations or production request-path changes are introduced. **0.31.0 panel/cache additions:** browser-negotiated Zstd/Brotli/gzip for HTML, JS and CSS (Settings → Administration); optional HTTP BAN/PURGE restricted to explicit IP/CIDR allowlist (Settings → Cache, disabled by default); System information Refresh button beside the API badge. See [Settings](docs/SETTINGS.md) and [Cache](docs/CACHE.md). 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.31.9 Certificate API management: inspect and edit credential settings without exposing/rotating the current token, or regenerate one existing token with one-time display. Rust/Cargo and live testing required.** ## 0.33.0: Web Server / PHP-FPM observability - **Fixed dashboard startup:** initialize the shared Overview history selector before any bundled top-level change listener. This prevents `onChange` startup errors and allows the authenticated panel to load. The History selector supports 60/120/300/600 samples, temporary edits and browser-persistent choices, in the header row beside the connection indicator (Overview only), independently of Cache/Transform, without additional status polling. - **Compilation cleanup:** restrict `record_web` visibility to the Web Server module, matching its `ResponseKind` argument and removing the `private_interfaces` diagnostic without changing request accounting. - **Compact donut layout:** move HIT/MISS totals beside the rings/legends rather than above them, preserving standard card-row heights and responsive behavior. - **Twelve opt-in WWW widgets** in the existing Overview layout registry: HTTP status split, static/PHP/other, PHP permit capacity, HTTP methods, recent 5xx percentage, PHP requests/s, requests/s, response-header latency, FastCGI failures, emitted-body byte rates, status-class rates, and top services. **Every new widget starts hidden** for both new accounts and upgrades from older saved layouts. Existing cards remain as configured. - **Web Server per-service live details:** expandable metrics in existing service cards, including RPS, 5xx, header latency, PHP concurrency permits, static versus PHP classification, and body bytes. The main live SSE/status snapshot is reused; no new API polling, SQL schema or per-request untrusted labels. - **Prometheus exporter:** bounded per-Web-Service response-kind/method/status, body byte and downstream compression counters, plus active headers, PHP concurrency limit/use/available gauges and classified FastCGI failures. Response byte counts are sampled from produced body frames **before** final downstream compression (not wire throughput). Response latency is time to headers (not complete delivery). PHP capacity is RustProxy's semaphore, **not** the actual PHP-FPM worker pool. - **Grafana:** retain the existing operations dashboard and extend it with Web Server, PHP-FPM, per-service breakdown and WWW/PHP correlation rows, all filterable by configured `web_service` IDs. ## 0.32.8: Overview metric visualizations - HOT cache RAM occupancy, COLD write-queue RAM occupancy and COLD disk occupancy appear as compact progress bars with used/limit details on the Overview. COLD cache objects live on disk; queue RAM and disk storage have separate budgets. Without a configured budget, the card shows bytes and an indeterminate meter rather than an invented percentage. - The main cache HIT ratio has a small HIT/MISS donut with counts and legend. The optional recent-window cache ratio uses the same format; bounded file-descriptor, HTTP protocol-share and backend-capacity widgets use progress bars. - Transformation and compression activity use two full-width, four-series live charts like the existing HTTP protocol mix. They show sampled per-second counts with named series; compression charts count gzip, Brotli, Zstd and deflate responses (not uncompressed ones). - These changes use existing status/SSE data without extra polling, API routes, database migrations or altered appearance presets. Existing account-specific Overview ordering/visibility preferences remain in effect; newly added cards are visible by default in factory layouts. Runtime integration testing remains required. ## 0.32.8: Overview action layout - The Overview heading stays left-aligned while the refresh, arrangement and layout-lock actions flow to the right; small screens wrap buttons without squeezing them into three equal columns. - The inline layout actions and visual editor keep their existing IDs and behavior while sharing the standard button styles (including Compact mode). ## 0.32.7 development follow-up: Appearance and H2 diagnostics - Overview **Refresh now**, **Arrange Overview**, **Unlock layout**, and Appearance **Visual Overview editor** / **Show all cards** use the common button sizing, including the global **Compact** preset on mobile. - Dashboard density is more distinguishable in metric tile spacing/numbers, chart heights and non-table panel padding/headers. The grid gutters, visibility/order preferences, refresh cadence and proxy routes remain unchanged. - A terminal request failure tied to a recently confirmed `GOAWAY(NO_ERROR)` is only traced at `TRACE` (not `DEBUG`) as a duplicate upstream diagnostic. It still returns 502 and appears in the access diagnostics; unrelated `Canceled -> connection closed` failures remain genuine errors. No blanket suppression by error string. ## What changed in 0.32.7 - **H2 upstream recovery:** gracefully drained upstream H2 connections sending `GOAWAY(NO_ERROR)` no longer poison Passive Health. Retire the affected Hyper pool generation and retry **once**, only for empty, replay-safe GET/HEAD/OPTIONS without WebSocket/administration tunneling. Non-replay-safe requests are not resent and can still receive 502 if the peer closes their connection. - **Passive Health:** collapse bursts of I/O failures within 250 ms into one failure observation; when active checks are enabled, consecutive successful probes can reopen a passively quarantined backend. Passive-only monitoring uses a bounded cooldown before a half-open traffic attempt. Keep the I/O error checkbox enabled to count unrelated, genuine I/O failures. - **Error log:** `WARN` when a backend is first removed from traffic, including backend ID, health source, failure reason, timestamp/description of the first error in that failure streak and the triggering error. Requires enabling the existing Error log sink (Settings -> Logging); when disabled, WARN goes to stderr/journald. Access logs still show individual 502s and subsequent 503s. - **Acceptance:** Rust compile/test and live negotiated H2/GOAWAY testing on staging are required before production installation. - **Appearance Dashboard layout ** Overview cards now use a full-width horizontal strip instead of a long list in the right half of Settings. Navigate sideways with the arrow buttons, toggle card visibility or reorder in place, or select **Show all cards** to expand to a full grid. The existing visual editor and saved per-account preferences are unchanged. - **Rate-chart pause recovery:** share one counter continuity policy across Cache HIT/MISS/BYPASS, Transform, HTTP Overview/protocols, optional wide/small charts, backend and Stream/Vhost traffic charts. After tab hide/pagehide (including BFCache) or a delayed refresh, keep plotted history, use the first reading as a new baseline, and resume rate points on the next normal interval. Full-width Overview, WWW and Web Server charts keep their drawn lines continuous by not appending the unavailable first rate sample; the current rate displays "-" until a valid interval is measured. A genuine measured zero still appears as 0/s. Cache and Transform intervals and the separate System information interval remain configurable; no additional polling. - **Development fixes :** keep Network diagnostics chart DOM stable across live refreshes, preventing repeated row/SVG replacement during scrolling. Network-interface chart history advances at the Overview live-status cadence using the latest sampled rates; fetching system data still follows the independent System information interval in Settings. Current CPU/RSS and per-interface RX/TX chart points now come from the existing background OS sampler through compact SSE/fallback data, every **3 s** by default (saved **2 s** settings remain valid), while Process details still follow the configured System information refresh. On mobile the Network interface chart list no longer traps touch scrolling in a nested scroll area. Origin protocol badges use exactly the same rounding as adjacent pills for all corner presets, without changing their color. Repair CSS descendant selector transformation and protect admin responses with `Cache-Control: no-transform`. Real iOS 27 scrolling remains unverified. - **Mobile Overview:** display two metric tiles per row on phone-width canvases, including 320-430px layouts and the initial pre-script paint. Keep horizontal overflow disabled, allow vertical touch scrolling and avoid unnecessary DOM reparenting/scroll anchoring during Dashboard preference refreshes. - **Global corner presets:** apply the selected Appearance shape consistently to vhost cards, status badges, entity cards and secondary panels as well as the existing metric and content cards. Keep the square-style draft dock unchanged. - **Vhosts backend HTTP badges:** show the configured upstream mode alongside the last HTTP/1.1 or HTTP/2 version actually returned by a real upstream proxy request for each origin, in the same lower badge row as the Vhost policy indicators (retaining the original observed/unknown badge colors). `AUTO → ?` means there is no response from the past five minutes; never guess a negotiation result or run an extra probe. The authenticated status payload includes last observation timestamp and counters per upstream client; the active connection may vary across requests. - **Tests:** Chromium simulated-mobile layout/scroll and shape presets, JavaScript live-status protocol badges and Rust response-version recorder test. The actual Rust build, iOS Safari interaction and end-to-end negotiated ALPN verification remain pending on a deployment host. ## Previously in 0.32.5 - **ACL editor startup hotfix:** fix the JavaScript `i18n` initialization order that could prevent the entire administration UI from loading. This does not change stored configuration or DNS ACL behavior. - **Dynamic DNS/DDNS ACL allow rules:** reusable ACL profiles, host policies, inline vhost/location ACLs, and Docker ACL assignments now accept `allow office.example.ddns.net` in place of a static client IP/CIDR. Existing IP, CIDR and country-based controls retain their previous precedence. - DNS answers (A and AAAA) are refreshed every **60 seconds**, with up to **128 distinct hostnames**, **32 unique addresses per hostname**, **8 parallel lookups** and a **4-second timeout**. A failed/empty/invalid resolution is removed from the allowlist (fail closed); successful entries expire within 180 seconds if refresh tasks stall. Initial access is denied until the first successful lookup. No DNS lookup or locks on the proxy request path. - The ACL profile editor now offers an IP/CIDR vs DNS/DDNS selector and explains the allow-only semantics. Existing JSON documents keep the `network` string format; no database migration, extra public route or backend resolver behavior change. Name resolution follows the machine's DNS configuration. - DNS names are **allow-only**: dynamic deny rules are rejected because a DNS outage could otherwise silently remove a security deny. Hostnames must be ASCII FQDNs (punycode for IDNs, no wildcards, URL or ports). - **Security note:** allowing a DDNS hostname delegates address authorization to whoever controls its DNS records. Use trusted domains and keep a default-deny ACL profile; old IPs may remain allowed until the next DNS refresh. - Rust/Cargo compilation and real DNS/address-rotation testing are **pending** before production deployment. ## Previously in 0.32.4 - **Follow-up build correction:** a retry request now passes a cloned URI to the HTTP request builder, retaining the original for backend-specific HTTP/2 `:authority` selection. This resolves Rust `E0382` (borrow after move) in `src/proxy/types.rs`. Neither retry policy nor backend dialing changes. Rust compilation is still required on a host with Cargo. - **Tighter, consistent Overview gutters:** the aligned Dashboard uses 4px gaps at normal UI density, 3px at dense and 12px at comfortable, in both axes. This applies between small tiles *and* between tiles and large panels. The more-specific dashboard-density CSS rules no longer override the grid gutter. Widget sizes, responsive rows and saved layouts are unchanged. - **Preserve Host for every upstream protocol.** `http1`, `auto`, compatible `http2` and strict `h2` accept `preserve_host: true` without forced UI downgrades. For HTTP/2, the outgoing HTTP authority follows the chosen Host; network address validation/DNS/TCP continue to use the configured backend URL. HTTP/2 ALPN and H2C retain their previous protocol/retry semantics, and legacy WebSocket Upgrade stays isolated. - **Separated HTTP authority from transport identity.** The existing TLS server-name setting still controls SNI and certificate identity independently of the visitor Host. No extra DNS queries, forced HTTP/1.1 fallback, protocol probing or request replay are introduced. For a verified certificate issued to a DNS name, specify `tls_server_name` and private CA as appropriate. - **Less restrictive HTTPS-by-IP warning.** The H1 diagnostic preset remains an explicit *optional* troubleshooting action, not a validation requirement for Auto/H2, pools or Preserve Host. Warn only when verifying HTTPS-by-IP without an explicit certificate DNS name (IP-SAN certificates are also possible). - **Overview spacing:** remove the leftover outer margin of the shared grid so the transition from metric tiles to large charts uses the same density-aware gutter as every other row, without altering saved layouts or card sizes. - No database/configuration migration or new privileges. **Rust compilation, runtime protocol acceptance against real Angie and benchmarks are still required before production rollout.** ## Previously in 0.32.3 - **Consistently sized Overview rows:** the dashboard now uses ordinary CSS Grid for both default and customized layouts. Six numeric tiles, three standard live charts, two optional wide charts and three diagnostic panels form separate, equal-height rows with the original density-controlled gaps. Blocks cannot float into unfinished rows of another size or acquire arbitrary heights. Ordering and Hide/Show remain editable **inside each size group**; existing saved widget IDs, visibility, preference API, chart data and reset/default behavior stay compatible. CSS Grid automatically resizes whole rows when live content grows, without pixel offsets, layout timers or extra polling. - **Layout and shape polish:** all 62 blocks remain movable, hideable, recoverable and resettable using existing account preferences. The X Hide control now matches the rounding of the arrow buttons for all five global corner presets; the RustProxy logo keeps its established outline and is excluded from global corner changes. No new metric polling, backend settings, API routes or version changes. - **62 optional/standard blocks:** six more miniature history cards and seven new full-width multi-series charts. The new views cover requests/s, H1/H3 shares, cache misses, backend activity, protocol traffic rates, CPU, RAM, cache behavior, open connections, backend availability and latency. All 13 additions are hidden by default, consume the existing snapshot and have bounded histories; no extra backend polling. Buttons remain right-aligned, with the badge before them. - **Backend upstream protocols:** four explicit, backward-compatible choices: HTTP/1.1 (`http1`, default), Auto (`auto`: HTTPS ALPN H2/H1, cleartext H1), HTTP/2 compatible (`http2`: HTTPS ALPN H2/H1, cleartext h2c) and H2 only (`h2`: HTTPS requires H2, cleartext h2c). No post-failure request replay, extra retry loop or changes to WebSocket semantics. - **Whole-Overview arrangement:** the same visual editor now manages all 62 independent blocks: the previous 30 metric cards, 12 optional time-series cards and seven full-width panels (live traffic, system, connections, cache, process, network and backend table). A responsive, row-aligned grid allows free ordering/hiding of every block without sacrificing the symmetrical factory layout. **Default view** previews the factory layout without writing it; **Reset layout** requests confirmation and restores only Dashboard order/visibility in one preference PUT. Existing saved layout and unrelated account settings remain unchanged. - **More opt-in charts:** CPU, RSS, file descriptors, open connections, WebSocket tunnels, TLS failures/s, request errors/s, recent cache HIT percentage, cache HOT RAM, incoming HTTP/2 share, mean response latency and unhealthy backend count. All are optional and hidden initially; 30-sample history uses the existing status updates and never creates network calls. Ratios and rates require genuine counter deltas; missing observations remain unavailable, not fabricated zeros. - **Overview Cards registry:** source of truth for widget IDs, translations, selectors, defaults and data-source metadata is `src/admin/web/dashboard-widgets.json`. Both server-side preference validation and the authenticated dashboard JavaScript use this registry. Existing order and opt-ins are preserved; stale unknown widget IDs no longer invalidate an entire saved preference document. - **Optional HTTP backend cards:** fourteen opt-in Overview tiles: origin health, in-flight requests, errors/s, health-probe RTT, byte rates, configured upstream modes, request-rate trend, concurrency-capacity utilization, HTTP 5xx, timeouts, DNS/TCP/TLS/I/O errors, retry attempts, queue pressure and Hyper client-pool rotations. All reuse the existing status stream; all fourteen are hidden by default, including upgraded accounts. Configured protocol modes are not negotiated ALPN results. - **No protocol migration or behavior regression for saved origins:** unchanged `protocol: "http2"` HTTPS origins retain their 0.32.2 H1 TLS fallback. The new strict mode must be selected explicitly as `protocol: "h2"`. The Origin editor labels ALPN/H2C transport behaviors, and HTTP/1.1 WebSocket Upgrade continues using its separate client. The OpenAPI Dashboard preferences schema now matches all 49 registered blocks. - **Two optional appearance themes:** **Ultra dark** uses an AMOLED-style near-black canvas and restrained mint highlights; **Warm cream** uses a muted ivory, low-glare palette. Both are selectable in Settings -> Appearance, persisted per administrator via the existing preferences API, available on the login screen after a cached choice, and preserve the original Dark/Light options and dark default. - **Direct block hiding and restoring:** when Overview is unlocked, each numeric tile, chart, diagnostic panel and table has an accessible **× Hide from Dashboard** button. This changes only the current layout draft; the collapsible **Hidden blocks** shelf restores any block immediately. **Save and lock** persists order/visibility once; **Cancel** reverts both. Hidden blocks also remain available in the visual editor. No measurement, registry or server data is deleted. - **Direct, lockable Dashboard arrangement:** choose **Unlock layout** on Overview, drag the handles on actual number tiles, charts, diagnostics panels or the backend table, or use the arrow buttons. **Save and lock** saves once; **Cancel changes** restores the previous order. Moving to another panel discards unsaved edits. No status re-polling or cloning of live charts is necessary. The modal editor remains available for enabling hidden blocks. - **Labeled block types:** all 49 entries have explicit registry metadata for **Number**, **Number + chart**, **Chart**, **Diagnostics panel** or **Table**. Appearance settings and the arrangement modal show the type, and the modal filters hidden blocks by type. Existing selections and defaults are unchanged. - **Visual Overview layout editor:** use **Arrange cards visually** on Overview or **Visual layout editor** in Settings -> Appearance -> Dashboard layout. Drag previews of metrics or large panels to reorder; Show/Hide controls and keyboard arrows are available. Save commits both lists in one account-preference update; Cancel leaves the layout unchanged. Existing Appearance controls still work. - **Connection-level ALPN reuse:** H1/H2 is negotiated only when opening a TLS connection, not on every HTTP request. The existing per-backend Hyper keep-alive/pool and bounded generation recycling (default 25,000 requests or 3,600 seconds) reuse negotiated connections and permit renegotiation when new connections open. No shared protocol-decision cache or extra probes were added: DNS and multi-origin backends may have peers with different H2 support. Explicit H1, H2C and H2-only, and WebSocket isolation keep their existing behavior. - **Regression coverage:** add local TLS peers for H2/H1 ALPN, H2-required failures, cleartext Auto, protocol serialization, and WebSocket isolation; add registry/preference regressions. Existing pooling, health probes, HTTP/3/QUIC and WebSocket transport behavior are unchanged. - **Verification limit:** pre-Cargo checks are runnable here, but Rust 1.99+, real-peer Rust tests, process benchmarks and production acceptance must be executed on a Rust-enabled host; see [test report](docs/TEST_REPORT.md). ## Previously in 0.32.2 - **Web Server cache revalidation:** browser refresh (`Cache-Control: no-cache` or `max-age=0`), stale objects and freshness-constrained requests now use stored origin `ETag` / `Last-Modified` validators. An unchanged local static resource returns `304` to RustProxy; it reuses the cached body and increases `X-Cache-Hits` rather than resetting it to a new MISS. - **Correct conditional delivery:** retain the client's original validators for downstream `304` decisions (or serve a body on an unconditional refresh). HEAD, single byte ranges, transformed-response headers and `Vary` isolation are retained. If the local resource changes, a successful response replaces the previous representation; an uncacheable 304 discards the shared copy. - Reverse Proxy caching, frontend routing, PHP-FPM, configuration/storage schemas and the administration API remain unchanged. Rust/Cargo and browser-based runtime acceptance are required; see [verification report](docs/TEST_REPORT.md). ## Previously in 0.32.1 - **Overview readability at 90% UI scale:** compare the supplied 0.31.9 source with 0.32.0, remove the latter's forced desktop card heights and restore content-sized rows. The six-column desktop layout and visible chart legends remain intact. Increase compact Dashboard headings (10 → 11px), values (22 → 25px), secondary text (8.5 → 10px) and the Payload breakdown (9 → 10px). - **Consistent tile spacing:** Overview now uses `--ui-gap`, the same density-aware spacing variable as other Dashboard sections, instead of its own fixed 10/8/6px spacing in normal/compact/ultra Dashboard modes. UI scale (including 90%) affects all gaps equally. - **Appearance hints without overflow-causing tooltips:** Dashboard layout Stream card descriptions now use native, localized browser tooltips and accessible button descriptions instead of absolute-positioned custom bubbles. The settings grid fits narrower containers and obsolete tooltip CSS has been removed. - Preserve Dashboard visibility/order preferences, density choices, responsive column breakpoints and opt-in Stream cards. No runtime, API, SQLite, proxy routing or language-pack changes. The Rust-independent `./dev.sh test` checks passed, then stopped with code 127 because Cargo is unavailable; **Cargo/build and authenticated-browser validation remain open** until executed on a supported runtime. ## Previously in 0.32.0 **Dashboard follow-up:** saved opt-in cards show on Overview even without active Streams (neutral no-data state). Appearance card-setting explanations remain on hover/focus; Overview metrics and legends are permanently visible inside the original six-column desktop grid, with taller tiles and no hover popovers. Stream editor explains the detailed-metrics inheritance and omits the redundant enable hint. `scripts/start_stream_backends.sh`, `scripts/test_stream_tcp.py` and `scripts/test_stream_udp.py` provide runnable mock peers and separate black-box tests. See [STREAMS.md](docs/STREAMS.md). - TCP and UDP Stream hosts support optional pools of up to 32 IP:port backends with weighted Round Robin and weighted Least Connections/Sessions, stable backend IDs, session caps, enabled/drain flags and per-session backend affinity (including UDP). - Optional bounded TCP Connect checks with rise/fall thresholds, and explicit UDP probes with exact response matching. UDP connect without a verified response is **Unverified**, not Healthy. Health checks are canceled on listener shutdown and globally bounded to 16 concurrent probes. - Existing per-Stream counters, status snapshot, Prometheus `include_streams` and RX/TX charts are retained. Opt-in backend detail counters and health observations use bounded config IDs only. - **Settings → Appearance → Dashboard layout** adds Stream overview, traffic, sessions and backend-health cards. These use the existing preference persistence, layout, status updates and SSE/polling; all new cards are hidden by default for existing and fresh accounts. No UI action restarts the proxy. - Old single-`upstream` configs remain valid, with an implicit backend `primary`. Backend pool edits still follow the existing Stream restart-required lifecycle. See [Streams](docs/STREAMS.md). - **Release acceptance remains open** until Cargo check/tests and live TCP/UDP/health checks are exercised on a Rust toolchain host. ## Layer-4 streams Raw TCP/UDP forwarding has its own **Streams** page in the primary navigation, alongside **Vhosts**, **Redirects** and **404 hosts**. Streams use the same card/modal workflow as vhosts, but each stream owns a dedicated Layer-4 listener and an optional backend pool and intentionally bypasses HTTP ACL/cache/header/compression logic. The page exposes live per-stream connections/sessions, rejects, errors, transferred bytes and RX/TX rate charts. Listener changes require a restart. See [TCP/UDP streams](docs/STREAMS.md). Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners. ## Previously in 0.31.9 - **Settings → Certificate API:** view the saved non-secret configuration of any Key ID, including comment, allowed certificate IDs, reload/deploy permission and creation/last-use timestamps. Current bearer tokens cannot be retrieved. - **Edit settings:** change a credential's comment, certificate allowlist and deploy permission without replacing its bearer token, Key ID, creation timestamp or last-use timestamp. Existing automation can continue with the current secret. - **Regenerate token:** replace only the selected credential's token, keep its settings, immediately invalidate the old secret and display the new token once. New per-Key-ID endpoints: `GET` and `PATCH /api/certificate-api/{key_id}`, `POST /api/certificate-api/{key_id}/regenerate`. Administrator session and CSRF are required for writes; external automation bearer tokens cannot call the management endpoints. - No SQLite migration or public proxy change. Existing `PUT /api/certificate-api` creation/manual rotation, revocation and token grants remain compatible. Verify with Rust 1.99+ before production use. ## Previously in 0.31.8 - **Test organization:** merge 28 mechanically numbered Rust test fragments into seven coherent `tests.rs` suites. Test-only files are exempt from the 500-line production-module limit; no test cases or runtime behavior are intentionally changed. See [test report](docs/TEST_REPORT.md). - **Stored Logs:** click a desktop column heading to sort ascending/descending (including discovered nested JSON columns). Sorting applies to the entire bounded server-side matching scan **before pagination**, with missing values last. Direction and selected sort column persist per administrator. Existing filters, mobile cards, and repeated-value analysis are unchanged. - **Built-in HTML responses:** add missing styled pages for 200, 400, 408, 410, 413, 500 and 502. Any other built-in HTTP status uses the same compact dark appearance as the established 401/403/404/429/503/504 templates. Administrators' custom HTML remains authoritative, and 204/205/304 remain bodyless. - **GeoIP:** freeze loaded CSV arrays to exactly sized boxed slices; pack IPv6 range addresses in network byte order (34 bytes versus 48 bytes per record) without changing lookup semantics. Expected decrease in retained GeoIP allocations is workload-dependent, approximately 17 MiB for the reported 293,569 IPv4 and 284,256 IPv6 records; verify actual RSS separately. - **Cache fills:** avoid a duplicate body allocation when a transformed response supplies a single uniquely owned frame with known, tightly sized capacity. Preserve the existing bounded Vec-based streaming/fallback path and charge the shared backing capacity to HOT. This targets temporary peak allocations, not a guaranteed reduction of steady-state RSS. - **Docker VHosts:** display a neutral waiting state while the first agent observation is pending after restart, then the result from background discovery. Opening Docker VHosts reads the latest cached status even with per-page Live view off; first-result synchronization stops afterward. A configured TLS fingerprint no longer falsely signals a verified connection. Agent polling and security remain unchanged. - No settings/SQLite schema migration or change to the HOT limit. **Runtime acceptance gate remains open** until Cargo build/tests, browser, H1/H2/H3 and real-process resource tests pass. ## Previously in 0.31.7 - **Source-package cleanup:** old per-version audits and implementation reports may be omitted; preflight still requires active sources and docs embedded in the panel Reader. This fixes the removed `docs/V0.25.5_AUDIT.md` preflight error without restoring obsolete files. - **Settings → Rules & headers:** the global User-Agent blocklist, global custom header editor and client response settings now share a Cache-style tabbed page (three persistent sub-tabs). Settings → Security keeps sessions/password and host access policies. - **Vhosts → Traffic policy:** optional User-Agent-specific per-client-IP request limits. First matching case-insensitive substring or `*` wildcard rule overrides the default/country rate for that request, even when ordinary throttling is disabled. Each vhost, UA rule and IP has independent bounded fixed-window accounting. Up to 64 rules per vhost; patterns are validated and the feature is opt-in. - **Revision history:** show changed leaf fields rather than object-sized JSON previews, including stable IDs for array members. Full before/after JSON is available through a separate comparison dialog. Restore behavior unchanged. - **Listeners:** space apart HTTP/2 and HTTP/3 tuning shortcuts. **ACL profiles:** “Attached to” is initially collapsed but expandable. - **`update.sh`:** retain exactly two installed binary release directories (including `current`) and three private pre-update backups. Correct the previous mtime-sort path deletion bug; old releases were only printed, not actually deleted. After a successful update, optionally purge only incremental Cargo state unused for 30+ days, never fingerprint, dependency, build-script or compiled executable artifacts. A source-tree upgrade retains its own backups and target directory. - **Graceful managed update:** trace marker → systemd stop → forced best-effort HOT→COLD handoff when COLD is enabled; record completion, even when zero items were demoted. Existing update flush works regardless of `cold_on_shutdown`; no persisted schema or cold format change. - **Compatibility:** retains all 0.31.6 H3/iPhone diagnostic fixes, 0.31.5 mobile Logs and protocol-independent cache behavior. SQLite schema 9 unchanged. Rust/Cargo and live reload/update verification remain mandatory. See [test report](docs/TEST_REPORT.md) and [configuration](docs/SETTINGS.md). ## Previously in 0.31.6 - HTTP/3 full-navigation GET/HEAD receive-stream handling, client cancellation classification and diagnostic events. Keep logo behavior unchanged. See [HTTP/3](docs/HTTP3.md) and [test report](docs/TEST_REPORT.md). ## Previously in 0.31.5 - Add bounded **User-Agent blocking** globally under Settings → Security and per vhost under Vhosts → Security. Matching is case-insensitive; plain text matches a substring and `*` is a wildcard. Global and per-vhost rules are cumulative and run before opening an upstream. - Make Traffic table/chart values directly copyable, including User-Agent, IP, host/path and other displayed dimensions, to speed up blocklist creation and investigation. - Add **Advanced parser · repeated values** in Stored Logs. It counts repeated values for `user_agent`, `client_ip`, `host`, `path` or any supported parsed field across the bounded matching scan before pagination. - Add a default-enabled **Consolidate rotated logs per vhost** switch. Active `vhost.jsonl` and matching `vhost.jsonl.*.gz` rotations are queried as one logical vhost source while retaining individual source IDs internally. - Preserve SQLite schema 9 and existing saved configurations through serde defaults. See [Stored Logs](docs/FILE_LOGS.md) and [test report](docs/TEST_REPORT.md). - Make `/logs` usable on phones with expandable log cards, full parsed-field details and no global horizontal scrolling; dynamic columns remain available. - Treat H3 peer-cancelled pre-header requests (e.g. F5 navigation) as stream cancellations, not fabricated HTTP 400 results. This corrects error reporting and avoids redundant internal response resets; it does not yet prove the reported mobile white-screen symptom resolved. - Keep both memory and cold cache across per-vhost H2/H3 switches; changing frontend protocols alone does not invalidate cached representations. - Keep optional Administration **public panel HTTPS origin** for the trusted-proxy Origin/CSRF security context; **additional DNS hostnames** are a separate Host allowlist, not its replacement. - **Release gate remains open:** Rust/Cargo compilation and real proxy/browser acceptance are still required before production deployment. ## Previously in 0.31.4 - Fix intermittent `auth.invalid_origin` on the **administration panel only** behind a trusted reverse proxy. The optional `administration.public_origin` pins the browser-facing HTTPS origin and allows a bounded `X-Forwarded-Proto: https, http` chain when the immediate proxy peer is trusted. Without a pin, ambiguous forwarded-proto values still return HTTP 403. - Set **only** `administration.public_origin`, for example `https://panel.example.test`, in Settings → Administration. Its DNS hostname is automatically included in the panel Host allowlist; it does **not** need to be repeated in `allowed_hosts`. - The advanced **Additional allowed DNS hostnames** section remains optional. Older configurations with a duplicate pinned hostname still load, and editing/saving omits that duplicate while preserving independent entries. Removing or changing the pinned URL never silently keeps the previous hostname implicitly allowed. - Keep strict checks for foreign `Origin`, mismatched or duplicate `X-Forwarded-Host`, cross-site requests, CSRF and untrusted proxies. The narrow opt-in self-admin session-cookie path may use the derived hostname only under its existing local-listener-risk conditions. Public proxy traffic and SQLite schema 9 are unchanged. - Restart RustProxy after modifying the setting. See [Administration HTTPS](docs/SETTINGS.md) and [test report](docs/TEST_REPORT.md). - **Release gate remains open:** Rust/Cargo compilation, resolved dependency lockfile and real mobile/reverse-proxy acceptance are still required before production deployment. ## Previously in 0.31.3 - Correct mobile tab/BFCache recovery: share in-flight session validation across resume events and defer SSE/polling until verification succeeds. A failed check keeps a visible retry UI instead of reloading the page, and 401 still requires a fresh login. - Preserve the one-time initial Origin reload guard until **full** panel initialization succeeds. Authenticated dashboard navigation rejected for invalid Origin now returns a visible 403 HTML explanation rather than raw JSON; API requests retain JSON errors and the same Origin/Sec-Fetch-Site authorization policy. - Log bounded, credential-redacted Origin mismatch diagnostics (HTTP method, path, public host/scheme, fetch site and trusted forwarding metadata). No cookies, authorization headers, query strings or session tokens are logged. - New deterministic UI tests cover simultaneous visibility/BFCache events, session errors, manual recovery, stale session epochs and repeated transitions. No configuration or database migration; SQLite schema 9 and proxy traffic remain unchanged. - **Release gate remains open:** Rust/Cargo were unavailable in the validation environment, and the inherited 0.31.2 Cargo.lock still requires a real `cargo update`/build on Rust 1.99+. Reproduce mobile behavior in Safari/Chrome through the actual reverse proxy before deploying to production. ## Previously in 0.31.2 - Refresh Rust dependencies to current stable API families, including SQLx 0.9, Rand 0.10, Argon2 0.6, rcgen 0.14, Tower HTTP 0.7, Brotli 9 and Sysinfo 0.39. Retain SQLite schema 9, serialized settings, TLS/QUIC behavior and administration contracts. - Raise the minimum compiler version to Rust 1.99 for current dependency requirements, including Docker and RouterOS build images. - **Release gate open:** the updated dependency graph must be resolved with Cargo; the bundled lockfile is a prior-resolution snapshot and must be refreshed and tested before release. The source package is not production-verified. - **Complete the dependency upgrade on a Rust 1.99+ build host** with `bash scripts/resolve_dependencies_0312.sh` (registry and the pinned Swagger UI asset must be reachable, or supply an audited local archive). This calls `cargo update`, verifies the refreshed lockfile and runs formatting, clippy, build and tests. Review the lockfile diff and fix any Rust compiler errors before publishing. ## Previously in 0.31.1 - Improve mobile panel startup via an ordered JavaScript resource, versioned URLs and retry of temporary config failures. ## Earlier panel improvements - Improved mobile panel loading behind reverse proxies: one ordered JavaScript resource, versioned assets and retry of temporary configuration errors. - **Panel startup/mobile follow-up:** replace the former white loading state with a RustProxy spinner, an automatic delayed reload suggestion and an error screen with reload link. Paint the shell before waiting for preferences/configuration/initial status; the header's **Refresh now** action sits beside the Overview title without adding a row. Negotiate Zstd/Brotli/gzip for fixed panel HTML and assets, with one-time encoding per resource; preserve public login and identity clients. - Refresh Overview through a shared, authenticated SSE channel with per-administrator live pacing (1, 2, 3, 5 or 10 seconds; default 3); fallback status/log polling is active only after SSE failure. Detailed system diagnostics remain in the separately scheduled API; live status carries a small cached CPU/RSS/network chart snapshot. - **Settings → Appearance → Data refresh** now stores per-account Live enable/disable and independent Traffic, Cache and System information intervals. Manual mode (`0`) and the global Live switch disable automatic requests while preserving manual refresh, charts, filters and pagination. - Poll only the current Traffic/Cache view, and fetch system diagnostics independently from `/api/system-info` when Overview or the relevant Settings section needs them. The previous full `/api/status` response remains supported, while `?view=live` provides compact fallback. - Centralize dashboard polling with cancellation/in-flight guards, hidden-tab pause and logout cleanup; retain SQLite schema 9, previous preferences, proxy traffic and the existing authentication model. - Rust compilation and live wire/performance acceptance remain required on an equipped target; see [verification report](docs/TEST_REPORT.md). ## Previously in 0.30.1 - Match H1/H2/H3 legend markers to the corresponding protocol-chart line colors across chart palettes. - Keep **About** focused on the product, author, license and source/package links. Move Python/ACME diagnostics out of the About dialog. - Add **Settings -> System information** (`/settings?tab=system-info`), showing OS release/kernel/architecture where available, CPU, RAM, uptime, process metrics, ACME interpreter/pip/Certbot versions where discoverable from local metadata, ACME mode/state, and data paths. OS/kernel details come from the existing `sysinfo` Rust library. Version display reads bounded `pyvenv.cfg` and Python `.dist-info/METADATA` files at ACME initialization; it does not execute diagnostic commands. Some system-installed tools lack these metadata files, so their versions will be shown as unavailable rather than guessed. Operational ACME checks and certificate issuance still run Python/Certbot as required. - The authenticated status API exposes the extra read-only runtime fields; SQLite schema 9, Cold Cache format 3 and existing configurations are unchanged. Real Rust compilation and live integration verification are still required. ## Previously in 0.30.0 - Edit individual active health-check policies in **Vhosts → Health**. The backend selector lists only members with monitoring enabled in **Backends**. Choose a member and optionally customize its TCP/HTTP mode, path, Host, interval, timeout, thresholds and expected status range. Other backends retain their unsaved edits; disabling monitoring hides its editor but preserves the saved override for future re-enablement. No API or SQLite schema changes. - Improve sustained-memory handling: reclaim selective PURGE-generation bookkeeping, avoid unnecessary analytics-label allocations, reuse serialized access JSON across JSONL/Logstash/Loki, and avoid duplicate directory listing vectors/HTML buffers. Stored Logs discovery retains at most 256 per-vhost and 64 rotated-gzip candidates. See [memory stress verification](docs/MEMORY_STRESS.md) for the audit and real-world RSS/load test procedure; source-only checks cannot rule out runtime leaks. - The previous 0.29.7 improvements remain included. SQLite schema 9 and Cold Cache format 3 are unchanged. ## Previously in 0.29.7 - Configure active/passive monitoring per backend independently from backend enablement and balanced-pool eligibility. Optional per-member active TCP/HTTP health-check overrides inherit the vhost's HTTP Host when omitted. An unmonitored internal 404 backend remains routable but is no longer probed or passively ejected. - Add global and per-vhost **HIT-only cache diagnostics**. Suppress X-Cache, X-Cache-Hits, X-Cache-Reason and Cache-Status on MISS/BYPASS, while retaining diagnostic headers on actual HIT. The separately configured Via header still applies; internal metrics are unaffected. - Detect and warn about Web Services sharing the same PHP-FPM endpoint with different PHP_VALUE or PHP_ADMIN_VALUE settings. Shared PHP-FPM worker processes can retain dynamic ini settings between requests (including open_basedir), so WordPress/Roundcube must use distinct PHP-FPM pools/sockets when their policy differs. See [PHP-FPM isolation](docs/PHP_FPM_ISOLATION.md). - Add configuration/Rust source regressions for per-backend monitor overrides, HIT-only cache policy and cache revision stability. Existing persisted settings load with their prior defaults; SQLite schema 9 and Cold Cache format 3 remain unchanged. - Cargo and live PHP-FPM tests remain required before production deployment. - Expand per-service and shared-profile PHP-FPM editor help: field-by-field examples, FastCGI `NAME = value`, `PHP_VALUE` and `PHP_ADMIN_VALUE` syntax, and dedicated WordPress/Roundcube pool guidance. Fix checkboxes/labels and add explanatory info tooltips for PHP execution, PATH_INFO and Authorization forwarding. See [PHP-FPM settings](docs/PHP_FPM.md). - Add opt-in **vhost origin-error interception** (Vhosts → Pages) with selected 400/404/5xx statuses. RustProxy replaces application HTML with a configured vhost/global page or a built-in page; the application's HTTP error status is always preserved, final internal fallbacks have precedence, and intercepted responses are `no-store`. Origin responses remain unchanged when interception is disabled, even if a global RustProxy error page exists. ## Previously in 0.29.6 - Fix native Web Server/PHP-FPM response compression across HTTP/1.1, HTTP/2 and HTTP/3 by fusing the FastCGI response stream; prevent a `futures-util::stream::unfold` panic after EOF. - When **Error file** is enabled, write warnings, errors, PHP-FPM stderr and worker panic diagnostics to the error file instead of duplicating them in systemd. When disabled, use the console. If the file cannot be written, fall back to console diagnostics. - Add EOF, gzip and error-log routing regressions; actual Rust/Cargo build and Roundcube runtime verification are still required. ## Previously in 0.29.5 - Fix PHP-FPM `PATH_INFO` dispatch for existing scripts such as Roundcube 1.7 `/static.php/skins/...`: when PATH_INFO is enabled, invoke the script before `try_files` can fall back to `/index.php`. - Keep FastCGI `SCRIPT_FILENAME`, `SCRIPT_NAME`, `PATH_INFO`, `REQUEST_URI` and the query string accurate, and check access rules on the resolved PHP script path. - Add mock FastCGI regression tests proving that Roundcube static assets reach `static.php`; opt-out (`path_info: false`) retains the previous fallback behavior. - No database migration or saved Web Service configuration changes. Rust compiler/runtime verification is still required before production deployment. ## Previously in 0.29.4 - Reuse named PHP-FPM profiles across Web Services, or keep per-service PHP-FPM settings; edit profiles in the expandable Web Server modal. - Open the same PHP-FPM profile manager from the **PHP-FPM profiles** button beside **New Web Service** on the Web Server page. - Run vhost RustProxy cache and enabled response transformations for Web Server filesystem/PHP sources with normal response privacy protections. - Preserve the original request Host in FastCGI `HTTP_HOST` for WordPress, including HTTP/2/HTTP/3 authority-only requests. - Added regression tests; the Rust compiler/runtime gate is still required before production deployment. ## Previously in 0.29.3 - Fix internal error fallback for empty GET/HEAD requests over HTTP/2 or HTTP/3 with unknown body-length hints by safely checking if the body stream is empty; nonempty and unbounded bodies remain protected from unsafe replay. - Preserve the final status, headers and HTML returned by the internal fallback location, including its own 404 page, instead of replacing it with RustProxy's global error page. Warn when a named internal target cannot be found. - Add Rust regression tests for empty H2/H3 GET/HEAD, unknown-length request bodies and response precedence. These Rust tests require a Cargo-enabled environment before production deployment. ## Previously in 0.29.2 - Add Nginx-style **internal error fallbacks** for the vhost source and Custom locations. Configured upstream/Web Server statuses can internally hand the original method, URI, query string and request context to an `internal` Custom location without an HTTP redirect. Supported bounded statuses are `403/404/500/502/503/504`; configuration cycles are rejected and runtime dispatch has a depth limit. - Execute error fallback before an intercepted response is finalized or cached. The target location re-enters the normal vhost/location pipeline, including ACL, headers, compression, cache policy and response processing. Request bodies are replayed only when safely bounded and replayable; otherwise the original error is retained. - The main Web Server source ignores backend health/unavailability; Custom Locations configured for Reverse Proxy continue to use their backend pool. Error-fallback-specific Prometheus counters have been removed. - Add streaming **multipart byte-range** responses for requests such as `Range: bytes=0-99,200-299`, with a maximum of 16 ranges and identity representation for multipart responses. - Add opt-in PHP-FPM **PATH_INFO** splitting. With `path_info: true`, `/index.php/foo/bar` securely resolves the existing `index.php` script, keeps `SCRIPT_FILENAME` on that file and sends `/foo/bar` as `PATH_INFO`. 0.30.0 keeps SQLite schema 9 and Cold Cache format 3. Existing configurations remain loadable; new optional health and diagnostic fields receive backward-compatible defaults. Historical details are in [CHANGELOG.md](CHANGELOG.md). ### Historical 0.26.7 release notes - Show explicit HOT and COLD cache occupancy progress on `/cache`, including object-count and byte/disk limits from Cache settings plus percentage usage. - Preserve compatible upstream client pools across unrelated active-snapshot rebuilds so generation age, request count and `Rotations` diagnostics do not restart at zero unless the backend connection policy actually changes. - Keep age-based backend rotation in the maintenance loop and retain request-count rotation; compatible snapshot reuse now makes the existing counters observable over long-running processes. - Refresh container documentation and ship the OCI image with one pinned Certbot environment containing all RustProxy-supported DNS plugins: Cloudflare, OVH and RFC2136. - Review current installation/container/cache/backend lifecycle documentation for stale version or behavior statements. - Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.6 requires no data migration. 0.26.7 retains the 0.26.6 access-policy and administration fixes below. ### Retained 0.26.6 release notes - Keep backend diagnostics visible-column selection, sort key and sort direction synchronized with the account-scoped administrator preferences whenever preferences are loaded or updated. - Clear the ACME certificate-creation form after the issuance job finishes successfully, so successful certificates do not leave stale values while failed jobs keep the non-secret form values available for correction. - Compose explicit IP allows and **Allow only** countries as alternatives inside one ACL policy scope. Explicit IP denies and blocked countries still win, and profile/vhost/location scopes remain cumulative. This makes `default=deny` support private CIDRs **or** selected countries as intended. - Document the sibling `migrate_npm_core.py` and `migrate_npm_api.py` modules required by `scripts/migration/migrate_npm.py`, and fix the container example to mount the dedicated `scripts/migration` directory. - Detect the Linux runtime environment in Process diagnostics. LXC reports `Linux / LXC` and overrides system uptime with PID 1 age plus load average from the container-visible `/proc/loadavg`; VM/host/Docker and other Linux environments keep the existing host statistics path. - Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.5 requires no data migration. 0.26.6 retains the 0.26.5 interface-scaling and listener-navigation fixes below. ### Retained 0.26.5 release notes - Keep compact toolbar `select` controls on the same scaled box model as neighboring inputs, including Stored Logs, Backends, Docker, vhost-style lists and Settings filters. Form-control dimensions consume the interface-scale field variables consistently. - Make **Streams -> Add TCP/UDP listener** navigate to **Settings -> Listeners** instead of opening a new Stream configuration dialog. - Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.4 requires no data migration. ### Retained 0.26.4 release notes - Extend session-only editor drafts to **404 hosts**, preserving the complete unfinished form state when another editor is opened or the dialog is minimized. - In **Settings -> Appearance**, the Overview list shows clean card names and visibility/reorder actions without type badges; the draggable visual editor still identifies numeric cards, charts, tables and diagnostic panels. Appearance is the first Settings tab on a new browser, then the last active tab is remembered; explicit links such as `/settings?tab=cache` always win. - Independently of Dark, Light, Ultra Dark and Cream, administrators can choose **Corner rounding** (Original, Square, Subtle, Rounded or Extra rounded). Original matches the established geometry in every theme and is the default for existing accounts. Ultra Dark preserves the original coral/soft-green logo mark while keeping its near-black background. - Complete the Polish translation for **Settings -> Appearance -> Button style** and keep the button-size preference independent from global interface scale. - Keep search/filter inputs in compact toolbars no taller than the active button style, including Backends, vhost-style lists, Docker, Logs and Settings search controls. - Reuse the vhost Enabled control presentation in 404 hosts, Redirects and Streams so modal enable/disable state is visually consistent. - Replace the tall Overview-card checkbox list in Appearance with a compact responsive tile grid; each tile toggles visibility and retains reorder controls. - Run time-based upstream-client pool recycling from backend maintenance as well as request dispatch, so an idle backend rotates after its configured age instead of remaining on generation 0 until the next request. - Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.3 requires no data migration. ### Retained 0.26.3 release notes - Make interface scaling truly global: the 70-125% setting now scales the authenticated dashboard, navigation, dialogs, overlays, draft dock and other top-level administration UI consistently. Form fields receive an additional proportional size adjustment so inputs/selects/textarea do not remain visually oversized at low scale or undersized at high scale. - Tighten the Overview metric cards so wide dashboards fit more telemetry with less empty vertical space. - Expand chart presentation presets to Default, Soft, Technical, High contrast, Neon, Monochrome, Warm and Cool. Presets now alter palette, surface treatment, grid character, line weight and chart contrast instead of changing only stroke shape. - Restyle the bottom-right draft dock as a square-corner panel that follows the existing RustProxy card/navigation language instead of using a rounded glass/floating treatment. - Let the draft dock collapse to one bar and show the age of every suspended draft. - Add Settings search across translated section labels and settings content, per-section Appearance resets, and a full Appearance reset. - Add visual palette buttons for all chart presets, independent table/log density, independent dashboard density, and an Ultra compact option for both data tables/logs and Overview cards. - Add a per-user Button style selector: **Normal** keeps the refreshed buttons and **Compact** restores the smaller source-style button sizing independently from interface scale. The selection now applies consistently to generated vhost actions and tab buttons inside dialogs. - Let administrators hide/show and reorder the Overview telemetry cards from Appearance without changing metric collection. - Keep all new appearance choices account-scoped in the existing SQLite administrator-preferences document; schema 8 and the saved proxy configuration format remain unchanged. 0.26.3 includes the 0.26.2 administration workflow improvements below: - Add session-only editor drafts for Web Server, Vhosts, Redirects and Streams. Closing an edited form minimizes it into a bottom-right draft dock, while opening another item starts a clean independent editor. - Add **Settings -> Appearance**. Theme, language, interface scale, 12/24-hour time display and chart style are account-scoped preferences stored in SQLite; the scale slider now spans 70-125%. - Apply time-format preferences to dashboard timestamps and compact expanded Stored Logs details to reduce scrolling on large records. - Merge the Stored Logs and Live Logs top-bar actions into one **Logs** menu. - Replace the Stored Logs filter row with an optional log-source selector, one query field and page-size control. Search accepts Kibana-style field clauses such as `req: GET AND !country: Poland`, quoted values, wildcards and numeric comparisons. - Parse JSON/JSONL records into dynamic selectable columns discovered from returned fields instead of maintaining fixed protocol-specific columns. `matched_by` and `sni` are no longer hard-coded table columns, but remain available when present in a record. - Parse the built-in RAW error-log format into timestamp, level, target, message and detected `key=value` fields while retaining the original raw line. - Expand selected records as parsed field/value rows with optional raw JSON, and move the column picker to the upper-right edge of the result table. - Remove the Configured files inventory while keeping an optional source selector; the explorer searches all bounded configured log sources by default and narrows to one selected source when requested. - Replace backend sort text (`A-Z` / `Z-A`) with direction arrows (`↑` / `↓`). - Keep SQLite schema 8 and the saved proxy configuration format unchanged; upgrading from 0.26.1 requires no data migration. Historical release information remains in [CHANGELOG.md](CHANGELOG.md) and [docs/CHANGELOG_TECHNICAL_ARCHIVE.md](docs/CHANGELOG_TECHNICAL_ARCHIVE.md). Current verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.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/FILE_LOGS.md](docs/FILE_LOGS.md) - stored-log explorer, protocol-error records, bounds and filesystem security. - [docs/PHP_FPM.md](docs/PHP_FPM.md) - implemented FastCGI/PHP-FPM integration, safety model and runtime requirements. - [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), [Prometheus](docs/PROMETHEUS.md), [cache diagnosis](docs/CACHE_DIAGNOSTICS.md), [HTTP/3 scope](docs/HTTP3.md), [TCP/UDP streams](docs/STREAMS.md) and [container deployment](docs/CONTAINER.md). Cloudflare Tunnel remains deferred. Docker discovery is available through the standalone agent; see [Docker discovery](docs/DOCKER_DISCOVERY.md). Examples are disposable full configurations: applying one replaces, not merges, an existing document. ## Installation and source build ### Official package repositories The preferred installation/update path is the project-maintained package repositories: - **DEB/RPM packages:** `https://rustproxy.linuxiarz.pl/` - **OPNsense plugin:** `https://rustproxy-opn.linuxiarz.pl/` Use the repository instructions appropriate for the target operating system. Package/service installs do not need a packaging-time GeoIP download: the proxy starts an enabled-by-default background updater after its listeners bind, performs the first verified refresh immediately, and then checks again every 24 hours unless changed in **Settings -> GeoIP updates**. Building on Debian is kept as an optional source/development path rather than the primary installation method. The production CLI default data directory is `/var/lib/rustproxy`. `dev.sh` explicitly overrides it to the repository-local `./data` directory for development commands. ### Optional: Debian 13+ one-line source install/update The bootstrap installs the compiler/build dependencies and Rust, clones this repository and 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 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 wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash # explicit update wget -qO- https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/install-debian13.sh | bash -s -- update ``` Manual build prerequisites used by that bootstrap: ```bash apt install -y build-essential gcc git ca-certificates python3 pkg-config wget sudo python3-certbot-dns-rfc2136 python3-certbot-dns-cloudflare wget -qO- --https-only --secure-protocol=TLSv1_2 https://sh.rustup.rs | sh ``` Rust stable (declared minimum 1.88), Cargo, C compiler/linker, Bash and Python 3.10+. Linux is the primary deployment target; macOS/WSL2 need normal native build tools. Detailed OS diagnostics currently use Linux procfs and cgroup v2. Unsupported measurements remain null/N/A. The first build needs access to the Rust toolchain and crate registry. `dev.sh` never installs system software or runs sudo. Rustls handles runtime TLS; zstd's native dependency still needs a C build toolchain. The Debian bootstrap intentionally builds with one Cargo job, LTO disabled and `codegen-units=8`. This avoids `rustc` being killed by the OOM killer on small VPSes while leaving the repository's normal release profile unchanged. For a manual low-memory build use: ```bash CARGO_BUILD_JOBS=1 CARGO_PROFILE_RELEASE_LTO=false \ CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked ``` Package-build metadata remains outside this source tree and is maintained with the official package repositories above. The 0.28.1 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 lockfile only when one is genuinely absent; it does not replace normal locked verification. ```bash cd RustProxy bash dev.sh doctor bash dev.sh check bash dev.sh test bash dev.sh ``` | Service | Development default | |---|---| | Default HTTP | `http://127.0.0.1:8080` | | Default HTTPS | `https://localhost:8443` | | Administration (default) | `http://127.0.0.1:9090`; HTTPS/remote bind is opt-in in Settings | | Optional protocol fixture | `127.0.0.1:9000`, only with `RUST_PROXY_DEMO=1` | In a second terminal, print the one-time setup capability and use the browser, or initialize an administrator locally: ```bash bash dev.sh admin setup-token # Alternative: interactive account creation, no default credentials. bash dev.sh admin init ``` There is no default username/password. Normal startup serves a neutral informational page for an unconfigured address and does not seed sample vhosts. The self-signed bootstrap certificate is retained under `data/certs` and is not publicly trusted. Assign intended certificates explicitly. Public frontend TLS does not implicitly expose the separate administration listener. Administration remains loopback HTTP by default; enable its own HTTPS setting before choosing a remote bind. Existing databases are never reset by this default. Use the protocol fixture only explicitly when running the documented test suites; `RUST_PROXY_DEMO=1 bash dev.sh` seeds a new disposable database. The separate `bash dev.sh mock` helper remains available for cache/backend testing. For a system service, build as an ordinary user and follow the complete procedure in [INSTALL.md](docs/INSTALL.md): ```bash bash dev.sh release bash install.sh --plan --binary target/release/rust-proxy sudo bash install.sh --binary target/release/rust-proxy # A subsequent release: sudo bash update.sh --binary target/release/rust-proxy ``` Copy `.env.example` to `.env` for startup defaults; it is trusted shell code. `RUST_PROXY_DEMO=0` disables the demo. `RUST_PROXY_TLS=0` removes the startup TLS default used when bootstrapping listeners. The release checker reads its compile-time defaults from repository-root `UPDATE_CHECK.toml`, which is embedded in the final binary. It checks the configured `Cargo.toml` URL immediately on startup and then every 3600 seconds by default. A failed request is ignored until the next interval; it never blocks startup or proxy traffic and it never installs updates. On Unix-like systems the checker keeps its bundled public roots and also imports certificates from `SSL_CERT_FILE`, `CURL_CA_BUNDLE` and common Linux/BSD CA bundles, including the FreeBSD/OPNsense `ca_root_nss` path. It follows at most five credential-free HTTP(S) redirects and never downgrades an HTTPS check to HTTP. Failed checks stay invisible in the dashboard, preserving the existing footer behavior, but are emitted as application `ERROR` events so the optional error-file sink can capture them. Operators may override the embedded values with global CLI options or equivalent environment variables: ```text --update-repository-url RUST_PROXY_UPDATE_REPOSITORY_URL --update-version-url RUST_PROXY_UPDATE_VERSION_URL --update-check-interval-secs RUST_PROXY_UPDATE_CHECK_INTERVAL_SECS ``` Set the interval to `0` to disable automatic checks. Debian/systemd installs may place the environment overrides in `/etc/rustproxy/environment`; source/development runs may use the normal process environment. Persisted frontend sockets live only in `listeners.endpoints` and are edited under Settings -> Listeners. Listener address/TLS/H2/H3 capability changes need a process restart; vhost H2/H3 switches only narrow those capabilities and routing/pool policies otherwise use validated hot publication. ## Private vhosts and backend pools Use **Settings -> Listeners** to configure frontend sockets, then use **Vhosts** to select those named listeners and configure backend members. `examples/vhosts-private.json` binds its named listener only to `127.0.0.2` and uses two explicit loopback origins. Replace these with addresses assigned to your machine and your real services. `examples/vhosts-balanced.json` shows an opt-in public 80/443 deployment; do not apply it unintentionally. A private vhost is selected by hostname **and the accepted socket's actual local IP, port and TLS state**. Sending its Host/X-Forwarded-* values to a different IP does not select it. A shared wildcard socket may accept TCP at multiple addresses, but each vhost keeps its original routing constraints. IP binding is not a firewall or authentication: NAT/another proxy can still forward traffic to that private IP. Keep network restrictions and application authentication. New health-checked members remain in `checking` until the configured successes make them eligible. No healthy member means 503; a healthy backup may be selected. HTTP checks measure time to response headers, not whole-body throughput. Affinity cookies bypass shared cache; they contain only an opaque routing token and are not login sessions. Existing cookie sessions may finish on a draining healthy member. The keepalive controls are connection reuse, **not Keepalived/VRRP**. Save pool/routing/security changes live. New/removed sockets and TLS ALPN changes need a process restart; active vs desired endpoints are visible in Settings/API. Old top-level routes are converted once into vhosts during validated startup/import. There is no separate legacy routing UI or dispatcher; path-to-origin ownership is retained. Read the migration guide before updating an existing database. See [VHOSTS.md](docs/VHOSTS.md) for algorithms, defaults, bounds, caveats and the complete configuration contract. ## Standard ports without running as root Settings -> Listeners accepts multiple named endpoints and socket addresses such as `0.0.0.0:80`, `0.0.0.0:443`, `[::]:443` and custom ports. Presets change only the port: they do not silently replace a loopback interface with a public one. The admin listener is independent of these controls and stays loopback by default. In Settings -> Administration, enabling HTTPS permits a persisted non-loopback bind using either the application-managed certificate or a selected certificate. Plain remote HTTP remains available only with the explicit `--allow-remote-admin` startup flag. Linux low-port binding can require `CAP_NET_BIND_SERVICE`. Use a dedicated service account and the example in [deploy/README.md](deploy/README.md), not a root-run application. Port conflicts and OS permissions cannot be proved by merely saving configuration; bind failures are reported on restart. See [settings, defaults and rollback](docs/SETTINGS.md). ## Cache and response controls The shared cache is enabled by default. Normal fresh `200 GET` and cacheable HEAD requests use `s-maxage`, `max-age` or `Expires`; a configurable default TTL applies only to explicit `public` responses without an origin freshness lifetime and defaults to zero. GET/HEAD share the same frontend scheme + Host + exact URL object, response `Vary` selects representation variants, and unrelated request headers or the selected backend-pool member do not fragment that object. Since 0.19.1 HTTP and HTTPS use distinct primary cache identities so scheme-dependent origin responses cannot cross protocols. Non-GET/HEAD methods pass without globally purging unrelated cached objects. Cookies (except the configured static-asset exception), authorization, ranges, `If-Match`/`If-Unmodified-Since`, private/no-store responses, Set-Cookie, `Vary: *`, streaming events and failed/incomplete bodies are not reused. `If-None-Match` and `If-Modified-Since` can be answered from a fresh cache entry as local conditional HITs. Request `no-cache`/freshness constraints revalidate a stored validator instead of blanket-bypassing the cache. Response `no-cache` with a usable validator may be retained, but must validate before every reuse. Request/response `no-store` remains a hard exclusion. Default cache memory limits are 256 MiB HOT allocated/charged data, 16 MiB per object, 64 MiB transient RAM, a 32 MiB COLD writer queue, 4096 HOT entries and eight fill permits. The panel also offers memory-aware conservative/recommended/performance presets derived from the lower of detected host RAM and a finite cgroup memory limit; automatic presets are disabled below 256 MiB effective RAM. `max_object_bytes` remains an independent per-object ceiling and cannot exceed the global HOT budget. If it is configured above the transient budget, the panel warns that objects near that size will pass through uncached because a fill cannot reserve enough bounded transient RAM. Optional cold cache defaults to disabled; when enabled it uses a bounded disk path under the private data directory and asynchronously demotes LRU/idle hot objects. Cold objects survive process restart for the same configuration revision and are promoted to RAM on a fresh hit. Large fill buffers grow incrementally and consume multiple permits. Actual process RSS also includes in-flight responses, compression buffers and runtime allocations. HIT/MISS/BYPASS, hit count and standardized RFC 9211 `Cache-Status` diagnostics are independently optional; required `Age` advances on ordinary cache hits even when the origin does not send `Age`. A successful origin `304 Not Modified` starts a new freshness-age calculation, so the next `Age` may legitimately be `0`; optional `X-Cache-Resident-Age` tracks RustProxy residency across revalidation and tier movement. Purge is authenticated, CSRF-protected, audited and invalidates both tiers plus older fills. See [cache behavior and limits](docs/CACHE.md) and [cache diagnostics](docs/CACHE_DIAGNOSTICS.md). Response compression is streamed and negotiated with `Accept-Encoding`; zstd, Brotli and gzip default ON while deflate defaults OFF, and equal client quality uses `zstd -> br -> gzip -> deflate` server preference. The selected algorithm is reported in `Content-Encoding` with `Vary: Accept-Encoding`. Existing `Content-Encoding`, ranges, SSE, upgrades and `no-transform` are passed through without recompression. Cookie, Authorization, Set-Cookie, private and no-store headers do not by themselves disable dynamic compression. Ordinary vhosts and Web Server services may inherit/enable/disable compression and individual codecs. Docker publications expose a single Compression on/off switch and always use the globally enabled codec set; explicitly disabling a configurable scope hides/disables its codec selectors in the dashboard while preserving their saved values. Strong ETags are weakened after transformation, and obsolete content digests are removed. Server policy is applied after generic response rules. Protected framing/identity headers and cache-owned `Age` cannot be edited through generic rules. With the separate demo enabled, `/cache-demo` returns an explicitly public 30-second object. Enable cache and X-Cache in Settings, then issue this twice without cookies: ```bash curl -i -H 'Host: localhost' http://127.0.0.1:8080/cache-demo ``` The first eligible request is MISS, then HIT while fresh. The origin timestamp stays unchanged on HIT. Unlike proxy/system measurements, this endpoint is explicitly demo content. The reserved admin cookie is removed before eligibility; application cookies still trigger privacy bypass. Use anonymous curl requests to check cache behavior. ## Adding a language Create `langs/de_DE.json` with metadata and string translations, then rebuild and restart. No JavaScript language switch or registry edits are needed: ```json { "meta": { "locale": "de-DE", "name": "German", "native_name": "Deutsch", "direction": "ltr" }, "translations": { "settings": "Einstellungen", "overview": "Ubersicht" } } ``` Missing keys fall back to `en_US.json`. Translation strings are rendered as text, not HTML; locale and direction metadata also control formatting/RTL. The two bundled languages are English and Polish. New packs are compile-time assets, not untrusted runtime plugins. See [langs/README.md](langs/README.md). ## Updating an installed source tree Read [MIGRATION.md](docs/MIGRATION.md). Back up actual data/certificates, stop the old server and extract this archive into a separate, non-nested directory. From the new source directory: ```bash rust-proxy --data-dir /actual/RustProxy/data backup create \ --output /private/rustproxy-before-upgrade.rpb bash upgrade.sh /actual/RustProxy --stopped # Also pass --data-dir /actual/private/data when it is external. cd /actual/RustProxy bash dev.sh test bash dev.sh ``` The supported operator backup is the password-encrypted `rust-proxy backup create` command. `tools/legacy/backup.py` is retained only as an offline release-test helper and must not be used as a Secret Store backup. See [Secret Store and encrypted backup/restore](docs/SECRET_STORE_BACKUP.md). `.env`, data, unmanaged files and previous managed sources are preserved. Extra 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.25.3 upgrades SQLite to schema version 8 by adding retained manual-configuration history. Existing schema-7 data is migrated automatically; the current configuration is seeded as the first retained history row and future successful saves keep the newest 512 revisions. Vhost/location method and access-policy fields are additive and default to disabled/inherited behavior when omitted. Once a 0.25.3 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. ## Source helper layout `script` responsibilities are intentionally separated: - `scripts/runtime`, `scripts/build`, `scripts/deploy`, `scripts/migration` are coupled to application/build/deployment behavior; - `tools/dev`, `tools/audit`, `tools/legacy` are optional operator/development helpers; the removed `tools/checks` suite is not shipped; - `integrations/` contains external platform helpers such as OPNsense ACME and RouterOS OCI tooling. See `scripts/README.md`, `tools/README.md` and `integrations/README.md`. ## 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), [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 # Source preflight without Rust: ./dev.sh doctor # Cargo validation and the Rust test suite (Rust required): ./dev.sh check ./dev.sh test # Source-only package, with no Git checkout required: python3 make_zip.py /tmp/RustProxy-0.33.0.zip ``` ## New management and test-origin guide See [MANAGEMENT.md](docs/MANAGEMENT.md) for the certificate staging workflow, page/status behavior and logs; [MOCK_SERVER.md](docs/MOCK_SERVER.md) provides a ready-to-use cache/health test setup. The example `examples/mock-vhost.json` is a complete minimal document for a fresh test installation, not a merge patch. ## Authentication and mock development In **Vhosts -> Authentication**, enable Tinyauth and supply its base URL (or the complete `/api/auth/nginx` endpoint) and public login URL. Private verifiers need the explicit private-network permission; optionally constrain allowed networks. Default identity headers are Remote-User and Remote-Email. No embedded provider password or disabled TLS verification is required. Do not protect the login host with itself. See INTEGRATIONS_040.md for exact status/redirect behavior and limits. ```bash # Separate terminals, after building the real proxy on a toolchain-enabled host: bash dev.sh mock --port 9001 --name origin-a --ttl 30 bash dev.sh mock-auth --port 9300 ``` The fake-auth server accepts the intentionally insecure cookie `mock_auth=allow`; it is a loopback-only development peer, never an authentication product. ### Docker vhosts operational controls Docker vhosts now publish/unpublish immediately per service. Each Docker agent has a configurable inventory polling interval, while the optional Live view refreshes cached runtime state only. Docker-backed applications can use ACL profiles/inline ACLs and per-vhost proxy connect/header/read/send timeouts, matching the ordinary vhost proxy controls. ## Dashboard layout export (0.33.1) To share a preferred Overview arrangement for a future factory preset, open the authenticated Overview and run this in the browser developer console (no privileged database access): ```javascript (async () => { const response = await fetch('/api/preferences', { credentials: 'same-origin' }); if (!response.ok) throw new Error(`Preferences HTTP ${response.status}`); const prefs = await response.json(); const exportData = { dashboard_widgets: prefs.dashboard_widgets, dashboard_hidden_widgets: prefs.dashboard_hidden_widgets, dashboard_density: prefs.dashboard_density, overview_samples: localStorage.getItem('rustproxy.overview.liveChartSamples') }; console.log(JSON.stringify(exportData, null, 2)); })(); ``` Copy the JSON shown in Console using the browser's selection or context menu. Do not export the full preferences response or session cookies. This is an export for review, not an automatic factory-default change; existing account layouts remain unchanged. The original Cache HIT donut shows accumulated cache counters; the optional recent Cache HIT chart displays interval-delta counters. They intentionally measure different windows and can produce different percentages.