RustProxy 0.31.8
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 and Cache.
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.8 Stored Logs sorting, consistent built-in status pages and scoped memory optimizations (Rust/Cargo and live testing required).
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.31.8
- Test organization: merge 28 mechanically numbered Rust test fragments into seven coherent
tests.rssuites. Test-only files are exempt from the 500-line production-module limit; no test cases or runtime behavior are intentionally changed. See test report. - 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.mdpreflight 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 (includingcurrent) 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 and configuration.
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 and test report.
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,pathor any supported parsed field across the bounded matching scan before pagination. - Add a default-enabled Consolidate rotated logs per vhost switch. Active
vhost.jsonland matchingvhost.jsonl.*.gzrotations 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 and test report.
- Make
/logsusable 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_originon the administration panel only behind a trusted reverse proxy. The optionaladministration.public_originpins the browser-facing HTTPS origin and allows a boundedX-Forwarded-Proto: https, httpchain when the immediate proxy peer is trusted. Without a pin, ambiguous forwarded-proto values still return HTTP 403. - Set only
administration.public_origin, for examplehttps://panel.example.test, in Settings → Administration. Its DNS hostname is automatically included in the panel Host allowlist; it does not need to be repeated inallowed_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 duplicateX-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 and test report.
- 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 callscargo 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, 5 or 10 seconds); fallback status/log polling is active only after SSE failure. Full configuration and system diagnostics are not serialized on every live event.
-
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-infowhen Overview or the relevant Settings section needs them. The previous full/api/statusresponse remains supported, while?view=liveprovides 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.
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 existingsysinfoRust library. Version display reads boundedpyvenv.cfgand Python.dist-info/METADATAfiles 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 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.
-
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_VALUEandPHP_ADMIN_VALUEsyntax, 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. -
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::unfoldpanic 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_INFOdispatch for existing scripts such as Roundcube 1.7/static.php/skins/...: when PATH_INFO is enabled, invoke the script beforetry_filescan fall back to/index.php. - Keep FastCGI
SCRIPT_FILENAME,SCRIPT_NAME,PATH_INFO,REQUEST_URIand 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_HOSTfor 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
internalCustom location without an HTTP redirect. Supported bounded statuses are403/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/barsecurely resolves the existingindex.phpscript, keepsSCRIPT_FILENAMEon that file and sends/foo/barasPATH_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.
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
Rotationsdiagnostics 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=denysupport private CIDRs or selected countries as intended. - Document the sibling
migrate_npm_core.pyandmigrate_npm_api.pymodules required byscripts/migration/migrate_npm.py, and fix the container example to mount the dedicatedscripts/migrationdirectory. - Detect the Linux runtime environment in Process diagnostics. LXC reports
Linux / LXCand 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
selectcontrols 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.
- 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_byandsniare 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=valuefields 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 and docs/CHANGELOG_TECHNICAL_ARCHIVE.md. Current verification status is maintained in docs/TEST_REPORT.md.
Documentation
/docs- authenticated project documentation Reader plus the API/OpenAPI tab.- docs/README.md - canonical documentation index.
- docs/WEB_SERVER.md - Web Server configuration, HTTP behavior and filesystem security.
- docs/FILE_LOGS.md - stored-log explorer, protocol-error records, bounds and filesystem security.
- docs/PHP_FPM.md - implemented FastCGI/PHP-FPM integration, safety model and runtime requirements.
- docs/TEST_REPORT.md - verification results and environment limitations.
- docs/TODO.md - unresolved follow-up only.
Release history
Historical user/operator-visible changes are maintained in CHANGELOG.md. Detailed historical implementation notes are retained in docs/CHANGELOG_TECHNICAL_ARCHIVE.md, and completed roadmap milestones are retained in 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.
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.
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.
# 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
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.
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 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 and
cache diagnostics.
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:
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. 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.
.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/migrationare coupled to application/build/deployment behavior;tools/checks,tools/dev,tools/audit,tools/legacyare auxiliary tools and are not needed by the running proxy;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, API, architecture, security, transport, vhosts and pools, Web Server, settings, cache, roadmap, changelog, verification.
# Rust-independent checks:
python3 tools/checks/check_source.py
python3 tools/checks/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.28.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.