RustProxy 0.24.9
Independent Rust reverse proxy with a dashboard, SQLite configuration, streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhosts and backend pools.
0.24.9 release source.
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 one upstream 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.
Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners.
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
logrotaterotation. - 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_pressureinstead 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::Errorso 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,PUTandPATCHare represented as a known zero-length body instead of being emitted asTransfer-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-Lengthbodies and HTTP/2 upstreams are left unchanged. - Add focused regressions for bodyless HTTP/3
DELETE, non-emptyDELETE, 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_bytesenforcement 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.rsfile 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/enabledchange. - Keep the existing managed
MALLOC_ARENA_MAX=2, transform allocation reductions and boundedmalloc_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=2in the managed systemd service while keeping/etc/rustproxy/environmentavailable 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 throttledmalloc_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
http2values 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/Aplaceholders 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::Networksas the primary API and merge insystemstatas a library-level supplement/fallback, including targets where the primary API has no inventory; the implementation does not shell out tonetstat/sysctlor reintroduce per-OS network parsers. - Fix the portable system-uptime build error by using the duration API exposed by
systemstatand remove the stale H2Futureimport 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:
systemstatfor portable host metrics,sysinfo::Networksfor network inventory/counters, andmetrics-processfor process metrics.systemstatremains the library-level network supplement/fallback wheresysinfohas no native inventory or returns only a partial view. Unsupported values remain null instead of being synthesized. - Preserve Linux
/procand 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-diralways wins. - Move Logging from the primary navigation into Settings -> Logging and keep
/loggingas 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 and verification report.
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(0disables it) anddrain_timeout_secondssettings, 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_statsplatform backends. Linux keeps the existing/proc/cgroup field names, units and semantics; FreeBSD/OpenBSD/NetBSD use nativesysctl/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 and verification report.
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
Hostto the configured backend authority, alignOriginto that backend scheme + authority, and tolerate legacy101 Switching Protocolsframing while retaining strictSec-WebSocket-Acceptand 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 and verification report.
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 --livelogswhen 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 and verification report.
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-KeyplusAuthorization: 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.pemorrust-proxy tls reloaddirectly 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 IDprints 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: h2con cleartext listeners that already enableh2c, while preserving the existing HTTP/2 prior-knowledge path. The initiating body-free H1 request is reconstructed as HTTP/2 stream 1 after101 Switching Protocols; malformed upgrades are rejected before switching. - Add authenticated certificate hot reload through
POST /api/certificates/reloadandrust-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 loopbackPOST /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 and verification report.
What changed in 0.22.2
- Add replay-safe bounded backend failover retry for empty
GET,HEADandOPTIONSexchanges, with per-vhost retry policy, passive-health integration, logs and Prometheus counters. - Send ordinary requests to explicit
protocol=http2backends as HTTP/2 and retain a real Hyper h2c prior-knowledge upstream regression. - Add per-backend
max_concurrent_requestswith a bounded capacity wait (queue_timeout_ms), immediate/timeout503rejection, 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 and verification report.
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: h2cis 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, andtunnel.killaudit 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 and verification report.
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, requestmax-stale, age-aware requestmax-age=N, and correct shared-cachemust-revalidate/proxy-revalidatesemantics while retainings-maxageprecedence. - 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, canonicalAccept-Encodinghandling 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-Statusdiagnostic. - 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
/transformrefreshable 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 formerX-Rust-Proxy-Backend-Timespelling as an untrusted upstream lookalike. - Split the former monolithic
src/cache.rsinto a responsibility-basedsrc/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 and verification report.
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/sin 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::Contexton 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 inputtext-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
/configurationto/settings?tab=manual-configand 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/8and::1on 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/sinstead 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-shellPATHthrough/etc/profile.d/rustproxy-path.shon 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
valuepayload and accepting thepagessection 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/CHDIRfailures 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=falsefully bypass X.509 certificate authentication/parsing callbacks used by webpki, restoring compatibility with legacy appliance certificates that fail withUnsupportedCertVersionwhile 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
Serverresponse-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.jsonlfallback 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-adminbut 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_*andrust_proxy_docker_backend_*series instead of appearing underrust_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-Revisionresponse-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-passwordand 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 nativerustproxypackage: hardened systemd service, dedicatedrustproxyuser,/var/lib/rustproxyand/var/log/rustproxy, daily three-daygzip -9log rotation, package/repository build scripts and repository layout suitable forhttps://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.jsonwith 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 runningplaceholder strictlyno-storeand 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_sessioncookie is still stripped for ordinary upstreams, but is preserved for a tightly guarded HTTPS self-admin route that directly targets the configured admin listener, hasaccept_local_listener_risk=true, and uses a hostname listed inadministration.allowed_hosts. - Harden RFC 9220 WebSocket setup: RustProxy now completes the backend HTTP/1.1
OnUpgradebefore returning downstream HTTP/3 success, avoiding a200followed 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_trimon 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
:80and HTTPS:443listeners 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-Backendexposes the selected member ID andX-RustProxy-Backend-Timeexposes 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.
- Add
nagios/checks for admin API RTT, backend availability, backend latency and dropped-work counters. See Nagios / Icinga checks. - Move
Server-Timingand 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=bf9b5489are 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/
localhostaccess remains tied to the real administration port and stays available. TrustedX-Forwarded-Host/X-Forwarded-Protoare 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 downstream200, 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.19with 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.jsonmetadata store is present; certificate state remains in the current SQLite/PEM paths, while the separate historicalcerts/renewals.jsonimporter 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_shutdownis 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.jsonobservations 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
/configurationbrowser 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_riskswitch. Together withallow_private=truewhere required, it can intentionally proxy to a local RustProxy listener such as127.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_verifyis 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_hostsmetadata 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,/tlsand 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_verifywas omitted; 0.13.0 intentionally changes that default to off. The debug-origin preset already wrote an explicittls_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
Varyselects representation variants. Unrelated request headers, frontend scheme and the selected load-balanced backend member no longer fragment the cache. - Treat
GETandHEADas 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-Agecontinuity. 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-ForandX-Real-IPwhile 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.12already present inCargo.lock, and stopdev.shfrom regenerating a valid application lockfile on every run. - Make the managed systemd service writable at
/var/log/rustproxyso the JSONL file sink works withProtectSystem=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
:authorityvalue exposed by Hyper through the request URI instead of requiring a legacyHostfield that browsers commonly omit on H2. - Keep HTTP/1.x strict single-Host handling and reject absolute-form targets; on H2/H3, reject conflicting
Hostand:authorityvalues rather than silently choosing one. - Add regression tests for H2 authority handling and the real administration
/healthzroute so HTTPS administration works without forcing HTTP/1.1. - Add per-vhost Force SSL directly below frontend selection. Plain HTTP receives a
308to 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_forcedto RustProxyforce_sslduring 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.tlsand 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--applybefore 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_EPOCHsupport 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 repeatedcurlGETs 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/rustproxyand keeps administration loopback by default. Docker discovery uses the separatedocker-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-Sincerequests can be answered as local conditional HITs, including304 Not Modified. - Request
no-cache,max-agefreshness constraints,min-freshand legacyPragma: no-cacheuse validator-based backend revalidation when a safe stored validator exists; backend304refreshes metadata and reuses the cached body. - Request
no-storeremains a hard BYPASS. ResponseCache-Control: no-cachemay be stored when it has a usable validator, but is validated before every reuse; responseno-store/privateremain uncacheable. cache.max_object_bytesnow permits values up to 1 GiB (still bounded bycache.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_storeand 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-dband 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
offnow 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-storeandVary: Cookiestill forbid shared storage. - Cache
Agenow 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 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.
Read installation and update, host access and locations, migration, NPM migration, ACME providers, Prometheus, cache diagnosis, HTTP/3 scope, TCP/UDP streams and container deployment. Cloudflare Tunnel remains deferred. Docker discovery is available through the standalone agent; see Docker discovery. Examples are disposable full configurations: applying one replaces, not merges, an existing document.
Requirements and first build
Debian 13+ one-line 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 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.
# 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:
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:
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
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.
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 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:
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:
--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 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, 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.
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 remains on cache hits. Optional X-Cache-Resident-Age tracks RustProxy residency and now survives revalidation/tier movement.
Purge is authenticated, CSRF-protected, audited and invalidates both tiers plus older
fills. See cache behavior and limits and
cache diagnostics.
Response compression is streamed and negotiated with Accept-Encoding; enabled algorithms are gzip, Brotli, Zstandard and deflate. Privacy-sensitive, ranged, upgraded, pre-encoded and no-transform responses are excluded. Strong ETags are weakened after transformation, and obsolete content digests are removed. Server policy is applied after generic response rules. Protected framing/identity headers 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:
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:
{
"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.
Updating an installed source tree
Read 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:
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. scripts/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.
.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.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.
Documentation and checks
documentation index, API, architecture, security, transport, vhosts and pools, settings, cache, roadmap, changelog, verification.
# Rust-independent checks:
python3 scripts/check_source.py
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
New management and test-origin guide
See MANAGEMENT.md for the certificate staging workflow,
page/status behavior and logs; 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.
# 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.