From d168ee2afa8a1749e4969ffbe8643763f690d8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Mon, 5 Oct 2026 12:22:41 +0200 Subject: [PATCH] v0.25.7 --- AGENTS.md | 2 +- CHANGELOG.md | 9 + Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 21 +- ROADMAP.md | 12 + SHA256SUMS | 95 +- debian/README.md | 2 +- debian/build-package.sh | 2 +- debian/changelog | 8 + dev.sh | 4 +- docker-agent/model.go | 2 +- docs/API_ACCESS.md | 2 +- docs/INSTALL.md | 2 +- docs/MIGRATION.md | 4 + docs/PROMETHEUS.md | 18 +- docs/TEST_REPORT.md | 102 +- grafana/README.md | 8 +- grafana/rustproxy-overview.json | 478 +++- langs/en_US.json | 3941 +++++++++++++------------- langs/pl_pl.json | 3941 +++++++++++++------------- make_zip.py | 2 +- scripts/check_source.py | 41 +- scripts/deploy_core.py | 2 +- scripts/docs_check.py | 15 +- scripts/preflight.py | 4 +- scripts/release_smoke.py | 25 +- scripts/rust_module_contracts.py | 2 +- scripts/swagger_assets.py | 2 +- scripts/upgrade.py | 6 +- scripts/web_server_contracts.py | 2 +- src/admin/documentation.rs | 452 +-- src/admin/documentation/documents.rs | 452 +++ src/admin/openapi.json | 72 +- src/admin/session.rs | 57 + src/admin/tests/part_04.rs | 36 +- src/admin/web/app/core.js | 2 +- src/admin/web/app/settings.js | 2 +- src/admin/web/index.html | 109 +- src/admin/web/style.css | 198 +- src/admin/web/vhosts/editor.js | 6 +- src/admin/web/vhosts/render.js | 97 +- src/logging/format.rs | 1 - src/main/bootstrap.rs | 2 +- src/main/tasks.rs | 2 +- src/prometheus/vhosts_backends.rs | 36 + src/web_server/fastcgi/protocol.rs | 2 +- src/web_server/response/file.rs | 2 +- src/web_server/tests/part_02.rs | 2 +- 49 files changed, 5608 insertions(+), 4680 deletions(-) create mode 100644 src/admin/documentation/documents.rs diff --git a/AGENTS.md b/AGENTS.md index e89787b..0e41f2d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ Read README.md, ROADMAP.md and docs/TEST_REPORT.md before making changes. The project name is RustProxy; the Cargo package/binary remains `rust-proxy` for -compatibility. Current source version: 0.25.6. +compatibility. Current source version: 0.25.7. ## Delivery diff --git a/CHANGELOG.md b/CHANGELOG.md index e953cd8..b32fba0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ > test-only changes and packaging implementation notes were moved to > [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md). +## 0.25.7 + +- Add one-click vhost enable/disable actions and make the vhost editor Enabled control clearly stand out with an explicit state indicator. +- Add search, sorting and selectable columns to the main Backends diagnostics table; visible columns and sort order are saved in the existing account-scoped administration preferences. +- Theme dashboard scrollbars for dark and light modes. +- Add ordinary/Docker Prometheus metrics for backend retry attempts/successes and upstream-client generation, generation request count, generation age and rotations. +- Add Grafana panels for ordinary and Docker backend client lifecycle, retries and rotations. +- Keep SQLite schema 8 and the existing configuration format; no migration is required from 0.25.6. + ## 0.25.6 - Show upstream Hyper client generation, request budget progress, generation age and rotation count in the live **Backends** diagnostics table, sourced from the same `/api/events` status snapshots as the existing backend metrics. diff --git a/Cargo.lock b/Cargo.lock index 26d9a10..831c66f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1688,7 +1688,7 @@ dependencies = [ [[package]] name = "rust-proxy" -version = "0.25.6" +version = "0.25.7" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index dc16342..09e3e42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-proxy" -version = "0.25.6" +version = "0.25.7" edition = "2021" rust-version = "1.88" description = "RustProxy - independent reverse proxy with local administration" diff --git a/README.md b/README.md index b70c4c8..b8410ff 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# RustProxy 0.25.6 +# RustProxy 0.25.7 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.25.6 release source.** +**0.25.7 release source.** ## Layer-4 streams @@ -11,13 +11,16 @@ Raw TCP/UDP forwarding has its own **Streams** page in the primary navigation, a Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners. -## What changed in 0.25.6 +## What changed in 0.25.7 -- Show backend Hyper client generation, generation request count, generation age and total rotations directly in the live **Backends** diagnostics table. The table consumes the same status snapshots delivered by `/api/events`, so these fields refresh alongside Active/Requests/Errors/Latency/Traffic without a second polling path. -- Keep the 0.25.5 bounded backend-client behavior: each backend client generation is recycled after 25,000 requests or one hour by default, with a 128 KiB upstream HTTP/1 adaptive read-buffer ceiling. All three limits remain configurable per vhost/backend and recycling does not reload the vhost or purge cache. -- Keep SQLite schema 8 and the existing configuration format; upgrading from 0.25.5 requires no data migration. +- Add a one-click enable/disable action to every vhost card while keeping the existing revision/CSRF protected save path. +- Make the main **Backends** diagnostics table searchable and sortable, with visible columns and sort order saved in the existing account-scoped administration preferences. These view preferences do not modify proxy configuration. +- Style dashboard scrollbars with the active dark/light theme. +- Export the previously missing backend retry and upstream-client lifecycle metrics to Prometheus for ordinary and Docker-discovered backends, and add matching Grafana lifecycle/retry panels. +- Make the vhost editor's **Enabled** control visually distinct, with an explicit state badge and traffic-impact hint. +- Keep SQLite schema 8 and the existing configuration format; upgrading from 0.25.6 requires no data migration. -The detailed 0.25.5 implementation audit remains available as historical baseline evidence. Current 0.25.6 verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.md). +The detailed 0.25.5 implementation audit remains available as historical baseline evidence. Current 0.25.7 verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.md). ## Documentation @@ -94,7 +97,7 @@ CARGO_BUILD_JOBS=1 CARGO_PROFILE_RELEASE_LTO=false \ CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked ``` -The 0.25.6 source archive preserves the resolved `Cargo.lock` supplied with the source tree and +The 0.25.7 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 @@ -333,7 +336,7 @@ python3 scripts/release_smoke.py # Runs those checks first, then the Rust suite when Cargo is available: bash dev.sh test # Source-only package, with no Git checkout required: -python3 make_zip.py /tmp/RustProxy-0.25.6.zip +python3 make_zip.py /tmp/RustProxy-0.25.7.zip ``` ## New management and test-origin guide diff --git a/ROADMAP.md b/ROADMAP.md index 25da961..9373215 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,17 @@ # RustProxy roadmap +## 0.25.7 - Vhost operations and backend observability + +Current direction: 0.25.6 -> 0.25.7 + +- [x] Add a fast vhost enable/disable action to the vhost cards using the existing revisioned save path. +- [x] Add backend-table search, sorting and account-scoped persisted column visibility preferences to the main dashboard. +- [x] Style scrollbars for dark and light dashboard themes. +- [x] Export retry and upstream-client lifecycle metrics for ordinary and Docker backends. +- [x] Add Grafana panels for backend client generation, age, retry activity and rotations. +- [x] Make the vhost editor Enabled control visually distinct from ordinary settings. +- [ ] Run compiler-enabled `cargo fmt --all`, `cargo check --locked --all-targets` and `cargo test --locked --all-targets` on a Rust release host. + ## 0.25.6 - Backend memory diagnostics visibility Current direction: 0.25.5 -> 0.25.6 diff --git a/SHA256SUMS b/SHA256SUMS index ac3d51b..0c323f0 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -1,19 +1,19 @@ 61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore 4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example 9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore -95ac5b696f463eb9b491564a2658f9e9db56d0beb629eea47c0ec0dc81e361e5 AGENTS.md -d9515bebfa7df5c0862e4fb1667017dc6d81c5e82e7383c55d9220a10e152372 CHANGELOG.md -22fb853ffef79b5f72f2b1c2818acae81b89511fdd5e2509b41c64883694a06a Cargo.lock -0a3790234bfadfcb178e26629be392d164ca0c86a7268ca9b12dd2713643819f Cargo.toml +160a7e43d9d963bfa93d0331e56fe039d39e2a4312199634bf3449611207eeb0 AGENTS.md +bc6f9cf316f77dbd4b4b7f79f02a1a77df86ddd97eb7e9f044403e9e425e75ff CHANGELOG.md +d07ad8d8f03ea00e9902b9b07eca1d91f3c8b683e169496c2fbc3ee7af908260 Cargo.lock +99b597e30f1aa5989dd553680f8de1f69663a04ea4f80663f19200f4d23d80d2 Cargo.toml d6d22ba63f4bc3d16a13012ecaabff8a156be57c824d2f20f66976502fb27d1f Dockerfile -a160ca8048f170a45da6abe57f886ee6e5416057ff158f5cbb12259b78b6adc8 README.md -3930c03cc27a1c441d976733b10783b6e36d037d691f75e5e7b569998ad8cd10 ROADMAP.md +45e033e8c9f53d919235463f77e3a3585b00f8bfaf196050e34b160d84def69d README.md +0fa8f954b10cc8c4a9452b821ece5a5841c5cf8c1581e27df091b5ce7e73300e ROADMAP.md da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml 928ba6a504bc431ae100c6e587861e5088b28822d2cb19da5d437b39d26c864a build.rs -a28b771e57632b7268a2e43bbf0447df564de522d1cacdc7cdf9aec766f653e7 debian/README.md -e322e6b0412b42f906e1a554ddcf2427d2f71d6fb0fa7e999ecc590131662154 debian/build-package.sh +f505c829f5256f5bf14320eed034c049b4e4dd568ae2918fd8ea238051759793 debian/README.md +33e38a974560d7f832b467a9223664e1fc26627259656927cbbcd7053441303c debian/build-package.sh 0763a4bd8b429f7922b23a7276ff694f3a751b83fb127f6ad7ec654e5e507ecd debian/build-repository.sh -d6d6d3a1a1f350e8930974cb06b3abf712a0144e25589ff578ee589ee0685dd9 debian/changelog +037ac5c953ddbb32bcd4f295f0fd259d0f64e003fa9830c9d4fe50afc552958c debian/changelog c90457b19b1b2f7998d3db59a656d215eb0fab23769197405960457b66d95cf7 debian/control dff2ecb9c14623416981f444bc6df1c4e2bf55d330260f36a312d8d42245400f debian/rules c537d54fd92a9b97c5f6e6ec63bc1276cda324513e2946b341b2193f63b62e6a debian/rustproxy.environment @@ -24,7 +24,7 @@ cb0db03a2c1b06fa04a11f7690755a0ca90b17f19ed8fdb228810f505c48c78a debian/rustpro e8e18df40bcd69d6aa404282679186d9b8256ac63a5b4e80d7f081e8a0095a2e debian/source/format 385ac7970fa94f043d0bcf04a91184e6e2c807587b85e55517ed064bb4bddba6 deploy/README.md 7b7fdf383bbaea4f37b5c120e98a24e9a075fba56ae7838a31a5152c7edcde02 deploy/rustproxy.service -18fb60f5f784389223ed7199e665d7033d51095fab2a3b13382401eec7ff5e7f dev.sh +e7d57772dab81cfcb9546a213d7cfad91a8aa381a08e13d25b2c64f0ae046d94 dev.sh 5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md 7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go 5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example @@ -33,14 +33,14 @@ bf687a851374d8f1fa59d050f3f76532f7c12f16a6daa7d3c36102c2d9a8ec9c docker-agent/d 9d77c90767fa929ee8338734d72ce83284d3d965673270f62cb2b1613d587a33 docker-agent/install.sh b68234472bec5cedd67c7cfe1de7d8806a965dfd4101f944aa6320132f18c14e docker-agent/main.go 3d4051a1f805d145df3877476e4b87773e74be8e123045065955a5133afdc68c docker-agent/main_test.go -7fd09ce19c86cf778eda55fc7b5943d70f650c656ffe0fc54f8e15a932a76578 docker-agent/model.go +9df430e38907d04ec62b47f7ed4d0bc06f43199103737050938b8a79bf86c398 docker-agent/model.go e52b31d0abf65ae3034f6cb367cca113633014ce8d1d799ad4dd5624d2c7b8bb docker-agent/network.go 634790f35ff4627df2a78cec2ed371f6e9ec9df00afb386075595fc7f3ed72eb docker-agent/rustproxy-docker-agent.service 5220d669171ec3ad65f50e0bc8de5178dadaa4904def8e1a4f61002aa9e9a55b docker-agent/server.go 802a30b793a6ae6a5046489612a23659f33d25e41d0794551381db202daac904 docs/ACME_PROVIDERS.md ec15163f5f51c9212003b7edd1fc380321311c2496fbaa9b45c838281b9af475 docs/ACME_RFC2136.md d699f2261a0d7854e49e9b8bae44fa37008a7d2f6340a73cdc37e840722ea211 docs/API.md -8e2b592bfb631ace744a3e0c75e1a4f1d94164b6bce3fd6faf05a3d954edfd9a docs/API_ACCESS.md +7a30b06c88701d1b689e0d402e716400e9e8c4a0cb350e8f8fe4210e165d29c0 docs/API_ACCESS.md 0f7f159ad5b4b5277f80c19f3c47f4e7823ea439ef02e5913e1391f1b34d129f docs/ARCHITECTURE.md cd2597465af031cdb47db802f8ad6d3af34ef9e79f679df906a7b84220ea3260 docs/CACHE.md 9cb338ed07ac1f92ad491e2099a7e3af63e66262417b1fef24d98c6a791d13fa docs/CACHE_DIAGNOSTICS.md @@ -50,17 +50,17 @@ db5534427ff0f004940fd6960906d3eaa75347a110e6322827c51c5d63f20adb docs/CONTAINER 7db65a96f696aff1d7f74e2041cfc6ecdf437b1412ece90cee26da1ceff4cf7e docs/DOCKER_DISCOVERY.md 9a882f07945b207d032936feb843f29467e4654f8255fa0104d988a54987f982 docs/ERROR_LOGGING.md df6ecd4a50796640243676ad4b3a87789f6e5d20cbebea6255e92fbfff1c7131 docs/HTTP3.md -4c27c3d7a7fca41fb325fcec5d86a883174eb4a3d11d5d6ac68912f9e8a17775 docs/INSTALL.md +8cd4109e62ec7106c64e77bb426933d5517b1e04b52574a9bdb21bd6e1884495 docs/INSTALL.md 3b5c31c805e5aee0dc2100b81246a9b631b5abb996faa598ae94f87ba39305f3 docs/INTEGRATIONS_040.md b640a87349e125d1cce1b93caed06aeee09ef5acd0824d0ca1472757b696d477 docs/LIVE_LOGS.md 7c35c4cdbe7bbb81d94f3bf6aeb22b8a866af3e7f0d62bbedc299e4d6f264e0d docs/MANAGEMENT.md -87608e2bd72a9fbeb611371064748ce33b4f21d7bc807af93c486fa53c5da244 docs/MIGRATION.md +397afd77e47be6b29b3acf3ee027e52a5ded5733789a998f2eb14073666984f3 docs/MIGRATION.md 5f090a190000c6badab2a74e5d4968e70c34de43b59c1452f5b05503b5c5c18a docs/MOCK_AUTH.md 1f85fac0e06e432ef6f744f0b5f9c1b7a27a1e9e1ad30dc1a218eab96b1caffe docs/MOCK_SERVER.md e7516646dfb107d6240370f4e7460b1189f2eb21f398740381d5d102847bbfe6 docs/NOT_FOUND_HOSTS.md 3da047768f32064c5ef0ad7a4c73c4b14930fe7317c54f5650f426af9f484593 docs/NPM_MIGRATION.md 712cb1cbf84515384b081fd2929e86e40af7c10f65bc69919b78b7b3e2fd12b5 docs/PHP_FPM.md -d3e3bff7e447356127814a9704706ec11eb94068eb6dc744eb614923dfe742b1 docs/PROMETHEUS.md +d27aebd13c71900df076a53e8ea77e3646565d1872085a59c4158de2df385e63 docs/PROMETHEUS.md 0832608a28022bec27b82a6c4abfbfeac7c4bdbe84572e8b3a430cee8d76efa2 docs/README.md 6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md 0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md @@ -71,7 +71,7 @@ a699fd663bfbf001525f22f0fbacdf03a58c5e825232d8d144e51cbb8b1008b2 docs/SECURITY. 620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md a2be253670072567459010b79f64df6093ccf9614aa249bdaa98917a83caeb31 docs/SETTINGS.md 3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md -71dbb8a13872ac9c1c5af5c63ffa44571e6d31bf4ae1ee6803c3373d1d8b1171 docs/TEST_REPORT.md +93e822855eea1d4c8d76f8e1fbbb3e3a143e6aab24ccd650b3b641921310e124 docs/TEST_REPORT.md cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md 8ee6187a5460ca45643b7fd789e27bffd264449e3a92ff70e9359edee011bbbb docs/TRANSFORM.md a1e9c6d38d21067d1ce7115ca3395ae8ff1f6a4c40fb0ebf00a6940ef79df439 docs/TRANSPORT.md @@ -113,14 +113,14 @@ b26833cb4251f9390a44192ecc827ff7f052fd19016a5ccf7498c94503ab4ce3 examples/mock- 5a8f3a8a054abc89c6e78896b9fe2f903212199a24dc3d2d2bcbd0696a31bcde examples/transport.json d242de9614fbb52933b4accd32f4715ca94107abe4a3b1d7e088362b07a6ba60 examples/vhosts-balanced.json af2bdb1343a8141069e94ccd2c7f92574ad848437e2f9fdb5c7576a9a18ef4a5 examples/vhosts-private.json -05f196d7f6d52083b6eaad3b432305fbd70c4cef541f85355a275d4804dc879d grafana/README.md -dfe6b4a94349af6091e25a2b2635bbdce9143aa452c90efbcc10de1081a4ed15 grafana/rustproxy-overview.json +93164163bb24981267fb67942c1f3a1b92534fa69c09ff0e5b3fd96c083ddf17 grafana/README.md +2ff0048e598edacfd569f24bdc8b577b5c1cf49c8f20322acea4e981ce1849cb grafana/rustproxy-overview.json 30763fc61c38992a44bc24ad6932b88fd3b322724fce799db1f17f9a747eb59a install-debian13.sh 858b39fa6886b71d20690bf369e76580922364b3cc7f0cf6ba9b040df9cd76e3 install.sh 29cada0936762f26495064d1524a668262ed729b21f20aebddc8b6e5cfea363b langs/README.md -70c1c370d906fa958293f9e4b5df7751f49104be115a40bdc0d5d4c479b5ca70 langs/en_US.json -c469574e18e8abc8ec66806d03ab53499371e6c7ca3aa318aebc7b171ab8efb4 langs/pl_pl.json -b650fd27159eab69c0fd4b27c541019a5ba48fcac120ad90a1195af2bcad1b23 make_zip.py +b1b2d9b5ba3037989f9e0ddfc75acd5b8aff6f27f1b33dc985425dc96add9057 langs/en_US.json +ca41421c7a40f066319b806b52f7004ce1736cfe6ab959b81ab773d3bb50d921 langs/pl_pl.json +268f53cc66c33e93217f4e8e143d9e74b979c095c9a53513b7d0337ca502818f make_zip.py e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql 20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql 5c62da30fa9db594a4d656c77ae676d3c388072b6a85f91170ec7d911d7cde43 migrations/0004_admin_preferences.sql @@ -139,11 +139,11 @@ edb6ee1445b01cd6f3a74a3a607f39fb107d411b49df028d2e0f4679e093de31 scripts/acme_p e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/acme_rfc2136.py 7e524285bfa2e3dbde0391257660635b039f23b0b3807e9510df663f757a5ad8 scripts/admin_audit.py 20e83f8b6347b819d1d1ea3de5c691c36f0816954a4210b0d3f39557fefe1931 scripts/backup.py -d0ca0435b4c3ab5bf62ec80b30f9b3c7d5e618cc39e62fa8c524c47570471d20 scripts/check_source.py +0c73dbd46f19b519ad6dde9e97a0b11841c84473f9285c6d03b2138e95817f86 scripts/check_source.py 187ee92c8029cdd59e89b4447cf4d170e856017a2091ceb85ae7c22dd1a79c72 scripts/deploy.py -381592aa62cc720b2f4aa559f885013027c5ac63d66c4562e688b753f854e818 scripts/deploy_core.py +fa03e74191206c0629024405b75cf0bec25d73477fd54e60571f8f793a63b7b7 scripts/deploy_core.py f014472588e889488976970dbaa95a8745b6907516aa81a7cca21d0f81eaaad3 scripts/deploy_runtime.py -90bd9eee430f67f75f96b2d25f98cc4efb9f3ae065484d32f975dcf19e6ea9bc scripts/docs_check.py +33f5ada91e81dd509738145a1256e7282e7c0ead1c937459da70ad5b59d739a7 scripts/docs_check.py 6facb2d65bfab234f09855097d12da8f72669a38ebceb4b1cbd03ab42b8d2469 scripts/langs_check.py 2e35b7c78887fd56f83ca9017caa168630963a9f47da71dfc53b1a8f9ad436c2 scripts/memory_contracts.py 2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migrate_npm.py @@ -153,24 +153,24 @@ d1418f8e574a7390fd45a2aa879bdf5720b773162d65e295ab0350506aa5220a scripts/mock_a 2d3ff92300b09ce9cecbbaaa9309b4d33160fa4b2291c9952b784e8cfb599ab5 scripts/mock_server.py 2d4c859aae5ba357a6d30024c8487ae8f59f01b192711f13f9c2f8fee0f48b50 scripts/os-acme-client/README.md c73b814a42bb4ff703441dbd177ee625055eeb115f9b5bb0c2150aede573a159 scripts/os-acme-client/opnsense-rustproxy-cert-deploy.sh -2e57cd5e40162f019e670e1526dade23892139a069c5db8fe04d20385a7aa315 scripts/preflight.py -bcf91eaaf6709709f21936a3040a048bbadc434db569823659731780c9b5dcd2 scripts/release_smoke.py +93eb03e1d26fd6dae3dc798b7284aa939c0c4a57270af3851a44eb2f0c0a7bf0 scripts/preflight.py +96a4ed125d21ebc38c280dccd13db437e942d4e3656de9f5decc6a96c469080b scripts/release_smoke.py 45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 scripts/routeros-oci-build/.env.routeros.example 3b48cff8506e5a6ae7d3876f47721f5de7d63e2e02264a78cf5b6ddd52d9fbc6 scripts/routeros-oci-build/Dockerfile.routeros 7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e scripts/routeros-oci-build/Dockerfile.routeros.dockerignore 68c076ef4537a047a7c390c534dbadd90e00cf495931c6d739f1c28b6b4dc7df scripts/routeros-oci-build/README.md d53b2ae7315ac143bd17d6327611a39e7c23666408bb95e39da2ca8517322ccb scripts/routeros-oci-build/build-routeros-oci.sh 3f267cafa16006e5456ade78ee2d5fae02cc7ce747839523068ffd8d7c98798a scripts/routeros-oci-build/docker-entrypoint.sh -4aca6fa11cd0b88b3b0d1527d2cf6132c94ce1405e69ff057ca1c9e48a5479ac scripts/rust_module_contracts.py +d36a5f5532f7d458b4e8249acf0fdf733b3c9531e9a590ea8d1b1dddec8fa7ef scripts/rust_module_contracts.py ecfe0bb21a7549225a19b0846bb6de8c99cbfbbf5a706d33cf84db2c7146abed scripts/rust_source.py 1c83054336b3508d7ad72cd259f039394682642439877fe69639c0b76be09154 scripts/security_contracts.py 295b6f2625b1875950ea3eecccd142f49be327afdd00c92641286e6de530ec51 scripts/security_dependency_contracts.py a65010f828194885ffc7f0f733937957f28e6049cd978bec1380a2b8bfbd0113 scripts/source_module_contracts.py -cdde3a77767dd6f9694fa4b6a9c322dabe1b461585bc2cb12ebed8a9afcc1a6c scripts/swagger_assets.py +a7a66a0f81216ce576e2b2a73e0d1eeeab0491f799b25105236767b40f6de88b scripts/swagger_assets.py 102b23de19a88a8e60de392fb83aefd3dfb33e90cc97ed1690d9f3d4a33d8866 scripts/test_compression.py -f6630becaaae2ca443817b2e16bb8b4940d5b06ab5eaa19d2db720e6344fa282 scripts/upgrade.py +2e81ff452d94b053f3c242edca26b6a5d04cde2b12982da5b757d9120035fe62 scripts/upgrade.py 43db35e7264b0345592172f2d1f6a6e4919fc4cbde2a9ff787acd7fff1d031d6 scripts/web_assets.py -0cdbedc07475d5c11f53361db7f8da4f2310594c704fcc214904f7a02ba083f4 scripts/web_server_contracts.py +769b6d92bde5457564937e03549b4f479315032540195b784ee19f8245f1ff94 scripts/web_server_contracts.py b8ce3e8fd08865015ce312fae9c0457612af18d6ef4513a6281b9e3212f8d458 scripts/web_service_ui_test.mjs d8e2b51c39252dbb4305512fa9b1ef508ec610968aed316b10514fd160298762 src/acl.rs 4e3be1ea1be0a81529c7c9021fb9bb77c24e5044acd54094972745443ad2c26a src/acl/tests.rs @@ -182,28 +182,29 @@ b9e57db4bd80ef37564dfc533a96897d8a494671d53acea9fb4bf28d23ba370d src/acme/provi 7acbaf34e7b953b753ab074893e47b5024f0cd756dc4c7a1074067dd936c2e8e src/acme/tests.rs 55ef7ceb44c25c7a8ddcbfd5e0d4b647526f9bdcde901ee08db5314e4d055b39 src/admin/access.rs 85f00f8157e83a152cc531f4cfecd0b1472ce269be9c8eb1ac17ad0693748b42 src/admin/certificates.rs -95d05aa0cef117161d4cd688f154b19aa8a99768273ae1f6a5566a919f97630d src/admin/documentation.rs +1de4c7c116eeab2452ccccbaba3f2b7b63c6eb1c1e146ab870d19c5a5ca16f80 src/admin/documentation.rs +ea4b58f7e46189e0b16606f197ee89f7587b569764470a6b92d37daef67e3afe src/admin/documentation/documents.rs 67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs beb8be241e4f1a8cea7b6c4e02b42f0359fb1fff10ab5ce2c70ccd0e63a554b0 src/admin/logging_api.rs 468b6062cb806ef489bc107f69d4725dbf9c08d7e18d15b4482ae0f309c15d2f src/admin/mod.rs -20edad7e3c31deea6ab40bf9bf8e44639118f90319dcd95935fa8620d12cf1a7 src/admin/openapi.json +6187fcb99a16c0b457e798d7f285bf687f3c164e8719e3d80a570a2e19d501c7 src/admin/openapi.json a53309daf118381031122ca70764f7a2f92adc44af3fc91df5f946e6856f76ae src/admin/operations.rs b4fa393b780b2676b5d72e0f90cd7290292f424b8062d4b5983e722d6ca72c32 src/admin/public.rs ea95e3d74729d652ce467c626a73e433060a195afa31dba5da1fc7ca935678ea src/admin/router.rs -2672f363659bda3402b12cfaae0878d62750238f965635c7e16d430642aef312 src/admin/session.rs +9e2981f9c96140bd6d9ca54e0d03b51b0783360e534a13e3b5cd1bec8c9440fd src/admin/session.rs f7938b202919a49fd2ff86ecdf09efadae12e0ffc0a4246a72a76218db11aa88 src/admin/status.rs cadd7dca29b9aad8c77c7bc23dd249ea37a15adfa4d636a8ef00273a91ce35dc src/admin/tail.rs 9bed1f93a8ef7bea4478b26bc825aacc8825ca70cf26c993fe78ac784aab2526 src/admin/tests.rs 5df98246c46135a176b4b8b705c92fd328719e82eb7342f088256abb976d5ae7 src/admin/tests/part_01.rs b8866db46f8be4f3f5bcceb5d84d32fe482f65d534b65cc75b4b3e33dba576c0 src/admin/tests/part_02.rs b31d594499d7f8164c14b66dd77971b9985cefd99bd4d3686f9ea26e11e5a59c src/admin/tests/part_03.rs -02046813070ae7311612592fefec5432582b74b9a9b897c06ee46f363e7fa434 src/admin/tests/part_04.rs +252456477d13c0652a488731c11173649c4816cf67f151cd881f138f1cac2edc src/admin/tests/part_04.rs 5f0062abc42a3b81c79088dc0824ab4c81a22c6ea765e77d2527d07d13bffd58 src/admin/tests/part_05.rs 23c55f23deeec844a9abc2289440c9e0583aaeb72416fc5f3632a43a864c0efd src/admin/web/acme.js 78e7d54d6536cd600dcbe66f0fc06ec109e121dfee1e57f3ca6e61cc6ae04a6a src/admin/web/app/config-history.js -22252759b3bbdacf887616d6c06113cc3f690884ffe958e7cfbd28bfb2d6805f src/admin/web/app/core.js +bf987a7652ebe054d02188fce32de3d797254b4740ea818985d5b76013fa3111 src/admin/web/app/core.js 19abc332a1009bcb087fe4ebb58d458739b27480ab50715b03d07fd408302942 src/admin/web/app/runtime.js -6dd5e2de7873c812e331546eee00380ec8529b70b9e7321d6ea14642eba80673 src/admin/web/app/settings.js +342b5e6401c2d23d680ff86dcc937b29f5673cd42e578c6a57127a6ab7609f2a src/admin/web/app/settings.js d0be71555de13f732fd6ee44438a0110eb08c91e78bbc1aa36a1a84182780210 src/admin/web/cache-panel.js 50d1ebcbaf4d0b2968da23bb943fc3f67131c5d32df3f61d23ff37aad9da5b81 src/admin/web/demo.html 3b84a7a08f9f68e2c78fed4523b594c31a251addc5480a69c5f6949908230539 src/admin/web/docker.js @@ -218,7 +219,7 @@ f7d0955ab18c15e04369204e789f341d2e832f927c1ff20a3b2b9e35e7898f00 src/admin/web/ e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/error_504.html 0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg dee3b113907f77138cdf919efdfb097e45b889cff3893bfc6f02ed998643bbae src/admin/web/host404.js -fa46ced03d335eb1b1e855f51fcbbcdeb52b7bfb955ce78f0e56322978bc895d src/admin/web/index.html +f3a946a33a2006a1e175c9c9a3621c51f46ad055d95c19324e5aa21c9711ef13 src/admin/web/index.html 24db88842707f764064657712d3660c6ac129fbfb47d188c0903925cf8244ce5 src/admin/web/integrations.js cdab0c11a28deebdf401c0453fbc76b675e9e643722106fb20e812bb9648ccde src/admin/web/login-keys.json a253d202dc9a147f2add34c64e0f35c38fdc7f667f9908933ce5f959b1a92a2e src/admin/web/login.html @@ -227,12 +228,12 @@ e41619e5cb0ba01a3d287748f28eb38bbe7641f9bedade252d286c18e619c400 src/admin/web/ 22318f39f7bb1ae98e65737d3c2ad9e63065b8e94ad59bed560c0e80d3a46949 src/admin/web/redirects.js 668f5162fa9f8bbe2fefce4115644a6469e01aa7defc9c7f760c28afd8e2afc7 src/admin/web/settings.js 1a30affd6a717095a1763998a5850a79ae0f86b7b694806f2aba2b880735dd1a src/admin/web/streams.js -702848ca4331fc68a53aa7df0622c0ca66f8cbb01abe598418754931dbee4360 src/admin/web/style.css +59eda800b0eadf4ca452bc9c9b1b669394973d96716afbc92ef8e3122b54fcc5 src/admin/web/style.css 47e98065281c04b4c185d53df4ed0cb12fabc716e52143e6ae3c3c25db62126a src/admin/web/traffic-panel.js d818580e61bbb70da1f758b9231c0667639cd947d875a55adc21dcf9ed1319c2 src/admin/web/transform-panel.js ac79a0f5471f110850bf5ceaaee9a3903bb92fb2edc10e969d8fda81f66571c0 src/admin/web/vhosts/core.js -c6fa43f90c7f3783b1dee7413a4d3333cef9f9453e74e3d5c85e7051369465bc src/admin/web/vhosts/editor.js -1457a049cd5d266995462bd9cad1b63530c469ecd4b8b80cc9d1e1b6ab4485ed src/admin/web/vhosts/render.js +d4938e0bf8cf41f79e9b49cf9b5cf2c8340668e792b73d5350cb1872e7ef1edf src/admin/web/vhosts/editor.js +c815bcf24a75608669232fe5ff447d0b755de586093addca3758aae739f9febc src/admin/web/vhosts/render.js 0de35a0671f3ac8fed62260d63ae43d04efce4947428ebdb9254cff0295295f9 src/admin/web/web-server.js 98c00d99822f9be54fc58afb6d4b577901712effd2c5eddce014312681864625 src/auth/files.rs b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs @@ -329,17 +330,17 @@ e40171e72327bc4350ba95cedacde2f3c9148c26a5a232d9f790f4449f20a685 src/geoip/test 68bc11160bc5275a904e48af8698b37433096fb6d592364d8281d59bb9e2b3f4 src/http3/tests.rs 3dab8fac75263120e48ee869ad55a3e2ccc2a19fc9f6d6a6fe055657ec55b1e3 src/lib.rs 6946917d57fb589bdba639fef2cec1d256fac0c8bfde92adffef2b31c3b3e08c src/logging.rs -4ef787e9c180f0ac6ba5781711becd0b08d7517520fc03e21248e442d8fe2901 src/logging/format.rs +1bff8b45d825ec29b44cda4b98b4c9d2e3ad14ff69252e5eb469ecce6e8514a9 src/logging/format.rs 147825d3c6dbb4c794c18897703741aa6b60bbfa3dbae0e30b6f770e2a8672ba src/logging/model.rs 348db1112a6067b06f4620ae75d2fc57d275852fef995b52649a6112b8c6589c src/logging/runtime.rs 6a07c1eeb6914b863ba7581444486029ca0c7465d2427f251bd1143cbba49448 src/logging/tests.rs 3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs 46732ed6d9cf2a33031624f941b8318d2676fb1b6bb5142e96820301f9fa1ac4 src/main/admin_runtime.rs -f31da9bff5455db1c0c793116f2cee209022555b9f3d804ef9f1662a1ae05e83 src/main/bootstrap.rs +b3d9ff6e92d3e6c8d54c7476200cacbc69d378e873e10d53ce306ac7132187ea src/main/bootstrap.rs 5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs 4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs 0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs -42784b7f4ff85f942d4dd3cee13a2182c20a0683f0d572eae137305398e7c928 src/main/tasks.rs +c601a96213abeff45dc879ee5a1e107ff60c1f1d657c505f770a81e7e7e4fb25 src/main/tasks.rs 49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs 201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs 49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs @@ -354,7 +355,7 @@ ff1c502ed1ce8d5de9ba7685253a6b70793ca9824b75fba58bae8aa6c4c11b84 src/prometheus d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus/model.rs 064b2be7fed2f6acf526b1cce070c1bb1b943d36f08fa50bbfcbdf3cf1c9318c src/prometheus/tests.rs 028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs -cbfb888199cc64c080230a729a00d57c0c56381d50ba45f3ae368e13d761d81f src/prometheus/vhosts_backends.rs +e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus/vhosts_backends.rs 6fc307286ab24b259237d34c6207dd325b375e1e896f824c66c9805a97bb981f src/proxy/body.rs 16b9d4db3b20b2ab14c47ac14fcd18d3d8ca77c3ad9a1f37866ebfa60f379862 src/proxy/body/tests.rs 00e50a914511754266b4eae2626244587174bfa71fff91509c530bcde7f0d397 src/proxy/cache_helpers.rs @@ -446,7 +447,7 @@ f0479524d66bfee7a6eed5eea03601630ba82064fb944902deb9166f90fe17cf src/vhost/vali 9c1c8d6eedecb95eadbfb23c3caea562f6f7a995606ef988f25b58c2d03bcdd5 src/web_server/config/model.rs 6191f4d541476c4a3ae296e7dd28bdb9f8a123fc509b47619f6f44519c44d278 src/web_server/config/validation.rs 86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs -a7039c5e1c9ec46807f26f50effd89fa1c7cb1d0f92e6b8c8f7bc348aa1e7979 src/web_server/fastcgi/protocol.rs +a490ec8fc283efe9c91e8e8ffd00926133444f51a9d2390aab63c5db234e85be src/web_server/fastcgi/protocol.rs 134c4998f6a0aa27e121af1ae3355b7e335488b2ae867ac0a934c58b4eb77191 src/web_server/fastcgi/response.rs 8186363315bd998919c6c783e6f7501528f257a5c0da77c5d60f423e8670db5e src/web_server/filesystem.rs 0aafd7f37c4fe784b047646e4ce5ddcb5fe821231a41ed0a9f519529385288a8 src/web_server/htaccess.rs @@ -456,14 +457,14 @@ a7039c5e1c9ec46807f26f50effd89fa1c7cb1d0f92e6b8c8f7bc348aa1e7979 src/web_server 80f946570c14c8915fd21bfdb1a84dfb6a14c633ab6060acb828fab4c7c21daa src/web_server/mod.rs 67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs c5cb561b0f276e8082f904b9446fa5885f6b3c0608f25ea2ef425061e9f7f6b4 src/web_server/response.rs -622dcb6005b6226709ee407279b72acd41dce7278f49d3f39cc9ae11423d7748 src/web_server/response/file.rs +9988a784cb025c63c230389da138deab40fae2716aaa85c4dfeec909bdc1adf1 src/web_server/response/file.rs 9aa68251a5f549f4ce3b1bda88d4abb9efc629caf444989381b4117c9488e37b src/web_server/response/headers.rs 2268a6aeed2f565f9791af33e1cd21c56c228c8873b031725b39a6c57184f2d1 src/web_server/routing.rs 400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs 3e0b4e92600a7d5abcec92efed532b3a01e0781cb4f2681daac6d6ae13b0a6e9 src/web_server/serve.rs cf86c4692080723bbdf8f4105e1abfae33d7fcf020d2ad9e13ebae3943bd0cbe src/web_server/tests.rs c62752fe2fa6b74ddc9d94d36f8d191376b1575b15d21fc434c5a5da4c932692 src/web_server/tests/part_01.rs -743789497958281203b136057d4bc711b6d1d0c167d2fc1ebbfc5c1d6507a618 src/web_server/tests/part_02.rs +5ac754a25cc0009015d5937522224195a695abda9e1f4e121d824b22f729dbff src/web_server/tests/part_02.rs e54f44f6ca1ed2c41e620de9195d32c4f8bb6936c3881745316a07160f87b4fa src/web_server/tests/part_03.rs f00743af2cf4a5952caef7a1dcf68e7817b5599a252a9973e1c22045517c0b0e tests/fixtures/argon2id.json 1725c10331745dc04a07675784d385260da7b14567b8dba3cbae5e891eb5dadf tests/http2.rs diff --git a/debian/README.md b/debian/README.md index d274622..4bf2785 100644 --- a/debian/README.md +++ b/debian/README.md @@ -1,6 +1,6 @@ # Debian packaging -This directory builds the `rustproxy` binary package for RustProxy 0.25.6. +This directory builds the `rustproxy` binary package for RustProxy 0.25.7. The package installs: - `/usr/bin/rust-proxy` diff --git a/debian/build-package.sh b/debian/build-package.sh index c2fe5d0..415067c 100755 --- a/debian/build-package.sh +++ b/debian/build-package.sh @@ -21,6 +21,6 @@ cargo fetch --locked dpkg-buildpackage -us -uc -b mkdir -p dist -find .. -maxdepth 1 -type f \( -name 'rustproxy_0.25.6_*.deb' -o -name 'rustproxy_0.25.6_*.changes' -o -name 'rustproxy_0.25.6_*.buildinfo' \) \ +find .. -maxdepth 1 -type f \( -name 'rustproxy_0.25.7_*.deb' -o -name 'rustproxy_0.25.7_*.changes' -o -name 'rustproxy_0.25.7_*.buildinfo' \) \ -exec cp -f {} dist/ \; echo "Packages copied to $ROOT/dist" diff --git a/debian/changelog b/debian/changelog index ea4601d..e4cc51f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +rustproxy (0.25.7) stable; urgency=medium + + * Add fast vhost enable/disable controls and improve the vhost Enabled editor control. + * Add backend-table search, sorting and selectable columns plus themed scrollbars. + * Export missing backend retry/client-lifecycle Prometheus metrics and extend Grafana. + + -- RustProxy Maintainers Mon, 05 Oct 2026 11:42:00 +0200 + rustproxy (0.25.6) stable; urgency=medium * Show upstream client generation, generation requests/age and rotations in the live Backends diagnostics table. diff --git a/dev.sh b/dev.sh index 8022f5f..1624544 100755 --- a/dev.sh +++ b/dev.sh @@ -18,7 +18,7 @@ if [[ $# -gt 0 ]]; then shift; fi case "$mode" in help|-h|--help) cat <<'HELP' -RustProxy 0.25.6 +RustProxy 0.25.7 ./dev.sh Build and start proxy + local panel ./dev.sh run [serve flags] Same, with extra server options ./dev.sh admin setup-token Generate/print a one-time setup capability before first login @@ -139,7 +139,7 @@ if [[ "$mode" == "test" ]]; then printf 'Checking all Rust targets before tests...\n' >&2 cargo check --locked --all-targets fi -printf 'Building RustProxy 0.25.6...\n' >&2 +printf 'Building RustProxy 0.25.7...\n' >&2 cargo build --locked BIN="$CARGO_TARGET_DIR/debug/rust-proxy" case "$mode" in diff --git a/docker-agent/model.go b/docker-agent/model.go index 6809992..aeea54d 100644 --- a/docker-agent/model.go +++ b/docker-agent/model.go @@ -1,6 +1,6 @@ package main -const version = "0.25.6" +const version = "0.25.7" type config struct { Listen string diff --git a/docs/API_ACCESS.md b/docs/API_ACCESS.md index 909f356..28528b3 100644 --- a/docs/API_ACCESS.md +++ b/docs/API_ACCESS.md @@ -1,4 +1,4 @@ -# Administration API access - 0.25.6 +# Administration API access - 0.25.7 ## Sign-in boundary diff --git a/docs/INSTALL.md b/docs/INSTALL.md index ebdedf0..d5971b6 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -1,4 +1,4 @@ -# Installing and updating RustProxy 0.25.6 +# Installing and updating RustProxy 0.25.7 The scripts prepare a Linux/systemd installation. This source archive is **not a verified production build**: Rust/Cargo, real CA operations, live systemd startup diff --git a/docs/MIGRATION.md b/docs/MIGRATION.md index 4a37691..5492a28 100644 --- a/docs/MIGRATION.md +++ b/docs/MIGRATION.md @@ -1,5 +1,9 @@ # Deployment and configuration migration history +## 0.25.6 -> 0.25.7 + +There is no SQLite schema or saved-configuration migration. Version 0.25.7 reuses the existing `admin_preferences` document to persist backend-table visible columns and sort order per administrator account; search text remains transient. It also adds vhost enable/disable UI actions, themed scrollbars and additional Prometheus/Grafana observability. Existing vhost `enabled` values and backend configuration remain unchanged until an administrator explicitly uses the new action. + ## 0.25.5 -> 0.25.6 There is no SQLite schema or saved-configuration migration. Version 0.25.6 adds the already-exposed upstream client generation/rotation diagnostics to the live Backends table and keeps the 0.25.5 backend client recycling defaults unchanged. diff --git a/docs/PROMETHEUS.md b/docs/PROMETHEUS.md index 47f1582..7e3be25 100644 --- a/docs/PROMETHEUS.md +++ b/docs/PROMETHEUS.md @@ -56,7 +56,7 @@ Only `GET` on the exact configured path without a query string is accepted. A wrong path is `404`, wrong method `405`, disallowed peer `403`, invalid/missing required bearer `401`, and exporter concurrency exhaustion `429`. -## Coverage audit in 0.19.1 +## Coverage audit in 0.25.7 The exporter represents all scalar fields currently sampled by `diagnostics::View` when available. The per-interface `network_interfaces` list added in 0.18.6 is intentionally dashboard-only so kernel-created interface names cannot create an uncontrolled Prometheus label set. RustProxy also exports the bounded operational data already available from traffic metrics, cache, vhosts, backend pools, streams, logging, GeoIP and ACME renewal observations. @@ -72,8 +72,8 @@ The exporter represents all scalar fields currently sampled by `diagnostics::Vie | Traffic analytics | independent live collector (`include_traffic`): capture-state gauges, per-vhost request/error/body-byte/duration totals; approximate bounded top countries; fixed User-Agent families; fixed HTTP method families; status classes; cache outcomes; serving source (`web_server`, `reverse_proxy`, `local_response`, `unresolved`); and currently configured route IDs | | Built-in Web Server | configured Web Service count/info, PHP and directory-listing flags, vhost/route source metadata, plus actual request traffic through the shared vhost counters and Traffic serving-source metrics | | Redirect/404 hosts | desired enable state, domain/rule counts and local-response status | -| Backends | pool readiness/policy info, bounded backend status, health/drain/backup, active work and configured request-concurrency/queue limits, requests/errors/bytes, weight, separate active/passive failure state, active/passive successes and health-failure totals, unconditional HTTP-5xx/timeout/connect/I/O/slow-response observation counters, DNS/TLS/header-timeout/read-timeout/send-timeout diagnostics, capacity rejection/queue-timeout counters, plus `passive_http_5xx_total`, `passive_timeouts_total`, `passive_connect_errors_total`, `passive_io_errors_total` and `passive_slow_total` aliases, health transitions, last status, current/EWMA latency, last-probe/failure/ejection/recovery timestamps, traffic rate, and retry attempt/success totals for ordinary vhosts | -| Docker vhosts | separate `rust_proxy_docker_vhost_*` and `rust_proxy_docker_backend_*` families: configured agents/assignments/domains, vhost traffic/status/duration plus backend readiness, health, requests/errors/bytes, latency/EWMA, separate active/passive failure state, unconditional observation counters and matching passive-health aliases, transitions and probe results | +| Backends | pool readiness/policy info, bounded backend status, health/drain/backup, active work and configured request-concurrency/queue limits, requests/errors/bytes, weight, separate active/passive failure state, active/passive successes and health-failure totals, unconditional HTTP-5xx/timeout/connect/I/O/slow-response observation counters, DNS/TLS/header-timeout/read-timeout/send-timeout diagnostics, capacity rejection/queue-timeout counters, retry attempt/success totals, upstream-client generation/current-generation requests/generation age/rotation totals, plus `passive_http_5xx_total`, `passive_timeouts_total`, `passive_connect_errors_total`, `passive_io_errors_total` and `passive_slow_total` aliases, health transitions, last status, current/EWMA latency, last-probe/failure/ejection/recovery timestamps and traffic rate for ordinary vhosts | +| Docker vhosts | separate `rust_proxy_docker_vhost_*` and `rust_proxy_docker_backend_*` families: configured agents/assignments/domains, vhost traffic/status/duration plus backend readiness, health, requests/errors/bytes, latency/EWMA, separate active/passive failure state, unconditional observation counters and matching passive-health aliases, retry attempt/success totals, upstream-client generation/current-generation requests/generation age/rotation totals, transitions and probe results | | Streams | desired enable state, active/session/reject/error counters, bytes/packets and max connections | | Logging | structured sink queue capacity, sent/error/drop counters plus the global live-log contention drop counter | | TLS/ACME | configured certificate count, auto-renew flag, bounded issuer metadata, latest ACME job state, renewal check/expiry timestamps, failure count and status | @@ -157,6 +157,18 @@ rust_proxy_docker_backend_up rust_proxy_docker_backend_ewma_latency_seconds ``` +Backend client lifecycle and retry diagnostics: + +```promql +rust_proxy_backend_upstream_client_generation_requests +rust_proxy_backend_upstream_client_generation_age_seconds +rate(rust_proxy_backend_upstream_client_rotations_total[5m]) +rate(rust_proxy_backend_retry_attempts_total[5m]) +rate(rust_proxy_backend_retry_successes_total[5m]) +``` + +The same fields are exported for Docker-discovered backends under the `rust_proxy_docker_backend_*` prefix. + Certificate expiry window: ```promql diff --git a/docs/TEST_REPORT.md b/docs/TEST_REPORT.md index 4b22957..7c45f98 100644 --- a/docs/TEST_REPORT.md +++ b/docs/TEST_REPORT.md @@ -1,78 +1,27 @@ -# Verification report - RustProxy 0.25.6 +# Verification report - RustProxy 0.25.7 ## Scope -RustProxy 0.25.6 is a patch release that keeps the bounded upstream-client memory controls from 0.25.5 and makes their runtime state visible in the main Backends diagnostics table. Each row now shows client generation, requests in the current generation, generation age and total rotations. Those values come from the same backend-pool status object delivered through `/api/events` and `/api/status`, so the dashboard refreshes them with the existing live diagnostics path. The defaults remain 25,000 requests, 3,600 seconds and a 131,072-byte upstream HTTP/1 adaptive read-buffer ceiling. Recycling remains local to the backend client and does not reload the vhost or purge cache. SQLite remains schema 8 and no saved-configuration migration is introduced. +RustProxy 0.25.7 is a patch release focused on vhost operations and backend observability. Vhost cards now expose a direct revision-protected enable/disable action, the main Backends diagnostics table supports account-scoped persisted sort/column visibility preferences plus transient search, and the vhost editor gives the Enabled setting a distinct state treatment. Dashboard scrollbars follow the active theme. Prometheus now exports backend retry attempt/success counters and upstream-client generation, generation-request, generation-age and rotation metrics for both ordinary and Docker-discovered backends; the bundled Grafana dashboard adds matching lifecycle/retry panels. SQLite remains schema 8 and no saved-configuration migration is introduced. -## Source contracts reviewed - -- Revision History now uses the shared dashboard dialog rule with square corners; the dedicated history dialog retains only layout dimensions/overflow and no longer duplicates color, background, border, shadow or backdrop appearance declarations. Calendar/diff sub-panels no longer add local rounded corners. -- Dashboard widths up to 850 px now hide the main section list behind an accessible `aria-expanded` Menu control. Opening shows a two-column section grid; selecting a section, pressing Escape or clicking outside closes it. Desktop navigation keeps the existing sidebar behavior. -- The authenticated top bar exposes an About dialog with author Mateusz Griszczynski, an Open Source notice and the canonical Git repository link; the documentation action is labeled Documentation. The About dialog uses the same square-corner modal styling and adds no new server route. -- Cloudflare client-IP mode still requires the direct transport peer to match the built-in Cloudflare edge CIDRs. After a successful verified `CF-Connecting-IP` override, one valid two-letter `CF-IPCountry` value is normalized and preferred for country policy/logging/Traffic; missing, duplicate, malformed and `XX` values fall back to local GeoIP of the verified effective client IP. -- Prometheus `include_traffic` defaults on and exports bounded per-vhost Traffic totals, country top values, fixed User-Agent families, fixed method families, status classes, cache outcomes, serving source and configured route IDs. Raw effective client IPs, raw request paths and full User-Agent strings remain excluded from exporter labels. -- Traffic serving source is recorded as one fixed value (`web_server`, `reverse_proxy`, `local_response`, `unresolved`) and the exporter adds configured Web Service inventory plus vhost/route source metadata. This makes pure Web Server traffic explicit while preserving the existing shared vhost request/status/byte/duration counters. -- The bundled Grafana dashboard adds a Traffic vhost variable and panels for Web Server request rate, queue drops, countries, User-Agent families, source rates, methods, status classes, cache outcomes, capture-state gauges and configured-route traffic. -- Vhost and location `method_policy` values validate and normalize HTTP methods; host and selected-location policies are cumulative and deny with 405 before upstream work. Allow-list denial includes `Allow`. -- Custom locations can select an `acl_profile_id` and add inline IP ACL plus country access policy. Profile and inline rules are compiled with the route and checked before authentication/backend selection; a location cannot weaken a vhost denial. -- Every observed exchange receives a fresh 64-hex SHA-256 `request_id`, overwrites inbound `X-Request-ID` before forwarding, and reuses the same value for diagnostics/logging. Custom header rules continue to protect `X-Request-ID`. -- SQLite schema 8 stores revision/time/actor/document in bounded `configuration_history`; successful CAS writes record history transactionally and retain the newest 512 revisions. The session-protected `/api/config/history` API supports metadata listing and one-revision detail with the previous retained document. -- `POST /api/config/history/restore` accepts an older retained revision plus the currently observed `expected_revision`. It rejects stale or non-older targets, reloads the retained document and passes it through the same startup-lock, certificate-removal, compile, cache-invalidation, persistence and hot-publish path as a normal configuration update. -- Restore persistence uses the existing storage CAS and appends the restored document as the next monotonic revision. The same transaction records `config.restore` with `source_revision= revision=`; the selected historical row is never overwritten. -- The Manual config history UI groups retained revisions by month/day, lists revisions for a selected day and renders a bounded recursive path-level before/after diff using text-only DOM operations. An older selected revision exposes a confirmation-gated restore action; success refreshes the active envelope and history. -- `Config.web_services` is a separate persisted collection; vhost/location `source` defaults to Reverse Proxy for old documents and Web Server stores only `web_service_id`. -- Full configuration compilation validates Web Service IDs, absolute/existing document roots, index names, duplicate IDs and every active Web Service reference. A pure static vhost does not require a backend pool; mixed Web Server and Reverse Proxy locations do. -- Web Server dispatch occurs after normal frontend routing, ACL and Basic/Tinyauth authorization and before backend selection/DNS/cache/upstream work. Static responses continue through the existing custom error-page, response-header/security, compression and transport pipeline. -- Static files use streamed Tokio file bodies with explicit lengths rather than whole-file buffering. -- Files support metadata-based ETag/Last-Modified, If-None-Match/If-Modified-Since, one Range/If-Range and 304/206/416 behavior. -- Directory requests redirect to a slash path, then search the optional ordered index list (which may be empty), then optionally render an HTML-escaped and URL-encoded RustProxy-styled listing without exposing filesystem paths. -- Root directory listing opens a fresh directory file description per request rather than a `dup` sharing the persistent root descriptor offset; a regression test requests the same listing twice. Nested directories independently apply index lookup first and listing fallback only when no index exists. Generated listings send `Cache-Control: no-store`. -- A directory with no matching index and directory listing disabled returns the built-in generic 403 page (or the configured vhost/global 403 replacement in the outer response pass), not a Web Server implementation-detail string. HEAD keeps an empty body. -- Web Services support up to 64 normalized MIME overrides, a validated fallback MIME header and an optional validated default `Cache-Control` header. Static files remain backed by the filesystem/OS page cache; existing vhost/location response-header rules run later and can override the source-level cache policy. -- Web Services additionally support ordered `ext:`/`mime:` Cache-Control rules, validated fixed response headers, ordered `try_files`, regex internal/redirect rewrites, precompressed `.br`/`.gz` sidecars and attachment extensions. Protected framing/transport headers cannot be overridden by the source header map. -- Optional `.htaccess` compatibility compiles a bounded root/subdirectory set at Web Service Apply time rather than parsing per request. It supports common RewriteRule/RewriteCond front controllers, DirectoryIndex/Indexes, AddType, Header, Expires, PHP AddHandler and simple Require all granted/denied. Unsupported access/handler scopes fail closed, `.ht*` control files are never served, and PHP AddHandler requires PHP-FPM. -- Web Service presets are UI-only generators: they populate ordinary configuration fields and do not persist a hidden CMS mode. ID/name/document root and PHP-FPM endpoint/tuning remain operator-owned. Optional hardening is persisted explicitly and defaults off for compatibility. -- `block_common_attacks` rejects TRACE/CONNECT/TRACK, sensitive dot/control/backup paths and a bounded set of high-confidence exploit probes; it also suppresses FastCGI `HTTP_PROXY` derivation from the inbound `Proxy` header. It does not claim generic WAF/SQLi/XSS filtering. -- `strip_unnecessary_headers` removes common source/PHP fingerprint headers after Web Service and `.htaccess` response handling while leaving the later vhost/location response-header pipeline authoritative. -- Optional PHP handling executes configured extensions through a bounded FastCGI connector over Unix socket or loopback TCP. PHP concurrency uses a fixed semaphore without an unbounded wait queue, request/response bodies use bounded streaming, and connection failure cannot fall back to serving PHP source. Advanced configuration adds Authorization forwarding control, a streaming request-body ceiling, bounded CGI response headers/stderr, trusted custom FastCGI parameters and validated `PHP_VALUE` overrides that cannot replace core CGI/HTTP fields or `PHP_ADMIN_VALUE`. -- Web Service symlink policy defaults to `deny`/`O_NOFOLLOW`; Linux-only `inside_root` verifies opened descriptors through `/proc/self/fd` against the canonical root. PHP-FPM is intentionally limited to `deny` because the external worker reopens `SCRIPT_FILENAME`. -- Routing rejects malformed/ambiguous encoded paths before filesystem lookup. Unix filesystem lookup walks from an opened root descriptor; `deny` uses `openat` + `O_NOFOLLOW`, while Linux-only `inside_root` verifies every opened descriptor against the canonical root. PHP-FPM requires `deny`. The secure Web Server compile path remains Unix-only. -- No second URL router, custom-error subsystem or object cache was introduced. Reverse Proxy remains the default source for existing configuration. -- Dashboard CRUD, source selectors, English/Polish strings and OpenAPI schemas expose the new model. -- Web Service index files are optional (0..16). An empty list skips index lookup, allowing directory-listing-only services without synthetic index names. -- Generated directory listings use a self-contained RustProxy panel-style layout (matching palette/typography, responsive light/dark treatment and RustProxy footer) while preserving HTML escaping, URL encoding and filesystem-path secrecy. -- Pure Web Server vhosts no longer present backend diagnostics as though an origin pool existed; their Backends summary identifies `Web Server`, while mixed static/proxy vhosts retain backend diagnostics. -- Status payloads expose fixed-cardinality per-vhost metrics independently of backend pools. The Vhosts dashboard uses those counters for Web Server-only request/active/error values, EWMA latency and byte-rate traffic while retaining backend health details for reverse-proxy sources. -- Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout. `route`, `cache_effective_enabled` and `transform_effective_enabled` are accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields. -- Structured logging exposes `user_agent` and `country`. User-Agent capture defaults on; country capture defaults off. Country resolution is skipped unless capture or an existing country ACL/rate-limit needs it; verified Cloudflare mode prefers trusted `CF-IPCountry`, otherwise local GeoIP is used. -- The authenticated Traffic workspace uses a bounded 2048-sample non-blocking queue, at most 64 vhost buckets and 32-entry approximate top tables for countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes. It never writes per-request analytics to SQLite. The Traffic UI is split into Overview, Clients, Requests and Delivery sub-tabs. Countries/methods/status/cache use donut summaries; User-Agent, effective client IP, path, route and request/response byte volume use bounded horizontal bar charts from the same in-memory TOP state. -- Sustained-traffic memory maintenance calls `malloc_trim(0)` every 60 seconds on Linux/glibc to release already-free allocator pages and trims HOT objects only when above the configured waterline and idle past the configured age. Backend Hyper clients additionally recycle their connection-pool generation after 25,000 requests or 3,600 seconds by default; both triggers are configurable/disableable per vhost, and HTTP/1 upstream adaptive read buffers default to a 128 KiB ceiling. Recycling does not publish a new vhost snapshot or purge cache. -- The live Backends table renders `upstream_client_generation`, `upstream_client_generation_requests`, `upstream_client_generation_age_seconds` and `upstream_client_rotations_total` in the same row as Active/Requests/Errors/Latency/Traffic. `app/core.js` feeds the table from the existing `/api/events` `snapshot.status` payload, so the new fields do not introduce another polling loop or control-plane query. -- Cache compatibility currently includes vhost configuration, so a cache-affecting vhost save can purge cache during snapshot publication; replacing the compiled snapshot also retires its upstream clients after outstanding references drain. These mechanisms explain why a manual vhost save can visibly reduce RSS without implying that reloads are required for steady-state operation. -- The Web Server list now uses the same vhost card/detail-cell visual structure as the Vhosts list. Reverse Proxy vhost creation reports a dedicated “at least one backend” validation error instead of the generic paths/ACL/headers JSON error. -- Web Service cards use only the shared `el(...)` DOM helper; a regression contract rejects the previous undefined `text(...)` call that aborted list rendering. Authenticated-shell startup now verifies `/api/auth/session` first and never reveals the legacy embedded sign-in form for non-authentication JavaScript/API failures, preventing F5 from falsely presenting the user as logged out. -- The Web Server UI module performs a catch-up render when it registers after `app.js`; this closes the race where a very fast `/api/config` response could finish before `web-server.js` existed and leave the Web Service list blank until a later render. -- The Web Service editor now builds its configuration tabs with the same `vh-tabs` + `quiet` button pattern and active/ARIA state handling as the Vhost editor; the source contract also checks this shared modal-tab pattern and invalid-field navigation switches to the owning tab. -- Static dispatch clones only `Method`, `HeaderMap` and `Uri` before awaiting the filesystem source; it does not hold `&Request` across an await, keeping the Axum 0.8 fallback handler future `Send`. This addresses the reported `Handler<_, _>` / E0277 failure at `.fallback(forward)`. -- `/docs` is an authenticated documentation surface with a Markdown Reader, searchable embedded docs bundle and a separate API/OpenAPI tab. Reader Markdown files are direct `include_str!` compiler inputs and no longer depend on a generated `OUT_DIR/docs-content.json`, preventing clean/incremental builds from failing on a missing documentation artifact. -- Documentation cleanup keeps README and the active ROADMAP current-only; operator release history, developer-level changelog history and completed roadmap milestones are separated into CHANGELOG/audit/archive documents. +Backend-table visible columns and sort order are presentation-only fields in the existing account-scoped `admin_preferences` document; search text is not persisted and none of these view settings alter RustProxy configuration. The quick vhost action changes only the selected vhost `enabled` flag through the same `saveSection("vhosts", ...)` revision/CSRF path as other vhost edits. Existing backend client recycling defaults remain unchanged. ## Implemented automated coverage -Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. Upstream tests cover request-budget client generation recycling and disabled recycling; balancing tests cover the new keepalive defaults and validation bounds. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases. +Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. Upstream tests cover request-budget client generation recycling and disabled recycling; balancing tests cover the new keepalive defaults and validation bounds. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover account-scoped/CSRF-protected view preferences including legacy preference defaults, backend-table columns/sort persistence and invalid-column rejection, plus restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases. Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging. -During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.6 tree remains a release-host gate. +During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.7 tree remains a release-host gate. ### Modular source-tree verification -- The new upstream client implementation is split into `src/upstream/client.rs` with test bodies in `src/upstream/client_tests.rs`; both stay below the 500-line module limit, and `src/upstream.rs` remains below that limit after moving client construction out. -- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational deploy/NPM-migration Python modules remain within their source-size contracts. -- `python3 scripts/rust_module_contracts.py` is BLOCKED by a pre-existing source-tree issue in the supplied 0.25.5 baseline archive: `src/admin/documentation.rs` is 554 lines while the contract limit is 500. The same failure reproduces on the unmodified 0.25.5 baseline archive. -- `python3 scripts/docs_check.py` is also BLOCKED by a pre-existing supplied-archive issue: the Reader does not embed `docs/ACME_PROVIDERS.md`. This also reproduces on the unmodified input archive. -- Rust unit-test bodies added for this change are isolated in a test include file; the implementation module contains only the guarded include declaration. -- Cargo parsing/type checking remains a release-host requirement because this workspace has no Rust toolchain. +- `src/admin/documentation.rs` was split so the embedded Reader document catalog lives in `src/admin/documentation/documents.rs`; both files now stay below the 500-line Rust module limit without changing Reader behavior. +- The Rust module contract now recognizes the existing `*_tests.rs` naming convention, and the documentation contract validates embedded documents independently of `include_str!` line wrapping. +- `python3 scripts/rust_module_contracts.py`: PASS. +- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational Python modules remain within their source-size contracts. +- `python3 scripts/docs_check.py`: PASS. The documentation index, authenticated Reader/API split and local Markdown links are consistent. +- Cargo parsing/type checking remains a release-host requirement because this workspace has no Rust/Cargo toolchain. ## Verification status in this workspace @@ -80,26 +29,23 @@ During the prior 0.25.4 compiler gate, an external build exposed one module-priv |---|---| | `python3 scripts/langs_check.py` | PASS | | `node --check src/admin/web/vhosts/render.js` | PASS | -| Backend live-table source contract | PASS: four client-generation diagnostics are rendered from backend member status fields | -| `python3 scripts/memory_contracts.py` | PASS, including upstream generation-recycle/buffer-cap source contracts | +| `node --check src/admin/web/vhosts/editor.js` | PASS | +| 0.25.7 vhost/dashboard source contracts | PASS: quick enable/disable, backend search/sort/column controls, account-scoped backend table preferences, themed scrollbars and distinct Enabled editor control are present | +| 0.25.7 Prometheus/Grafana source contracts | PASS: retry/client-lifecycle families exist for ordinary and Docker backends and matching dashboard queries are present | +| `python3 scripts/memory_contracts.py` | PASS | | `python3 scripts/web_server_contracts.py` | PASS | | `python3 scripts/security_contracts.py` | PASS | | `python3 scripts/security_dependency_contracts.py` | PASS | | `python3 scripts/source_module_contracts.py` | PASS | -| `node --check src/admin/web/vhosts/editor.js` | PASS | +| `python3 scripts/rust_module_contracts.py` | PASS | +| `python3 scripts/docs_check.py` | PASS | | `node scripts/web_service_ui_test.mjs` | PASS | -| OpenAPI/language JSON parse | PASS | +| OpenAPI/language/Grafana JSON parse | PASS | | `go test ./...` in `docker-agent` | PASS | -| SQL migration/backup smoke (`release_smoke.sql_and_backup_smoke`) | PASS | -| Stopped-source upgrade smoke (`release_smoke.upgrade_smoke`) | PASS | -| `python3 scripts/rust_module_contracts.py` | BLOCKED by pre-existing `src/admin/documentation.rs` 554-line baseline failure | -| `python3 scripts/docs_check.py` | BLOCKED by pre-existing missing `docs/ACME_PROVIDERS.md` Reader embed | -| `python3 scripts/check_source.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate | -| `python3 scripts/release_smoke.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate; its SQL/upgrade smoke functions pass when run directly | -| `./dev.sh test` | BLOCKED at the same pre-existing Rust module-size gate before reaching Cargo | -| `cargo fmt --all` / `./dev.sh fmt` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace | -| `cargo check --locked --all-targets` / `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace | -| `cargo test --locked --all-targets` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace | -| Live sustained HTTPS/HTTP/1.1 RSS acceptance | release-host acceptance gate; verify RSS plateau and `upstream_client_rotations_total` under representative traffic | +| `python3 scripts/check_source.py` | PASS; explicitly reports Rust parsing/types/runtime not verified | +| `python3 scripts/release_smoke.py` | PASS, including SQLite/backup/upgrade, Debian/Grafana and reproducible source-archive contracts | +| `./dev.sh test` | Static/security/UI/smoke gates PASS; exits 127 when it reaches Rust because Cargo is unavailable | +| `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace | +| `cargo fmt --all`, `cargo check --locked --all-targets`, `cargo test --locked --all-targets` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace | -The new source-level memory bounds and UI/config contracts pass the available targeted checks. Compiler-enabled and sustained-traffic runtime acceptance remain required before production release; two unrelated static gates are already failing in the supplied 0.25.5 baseline as described above. +All Rust-independent release gates available in this workspace pass. Compiler formatting, parsing, type checking, linking and Rust unit/integration tests still require a Rust-enabled release host before treating the archive as compiler-verified production output. diff --git a/grafana/README.md b/grafana/README.md index 4591fed..5c3b5dd 100644 --- a/grafana/README.md +++ b/grafana/README.md @@ -2,13 +2,13 @@ `rustproxy-overview.json` is a provisioning/import dashboard for the dedicated RustProxy Prometheus exporter. It covers global traffic, status classes, vhost -latency, backend health/latency, a dedicated Docker-vhost section, hot/cold/transient -cache memory, Linux process and cgroup diagnostics, HTTP/2/HTTP/3/TLS/WebSocket +latency, backend health/latency, upstream-client generation/retry/rotation diagnostics, +a dedicated Docker-vhost section, hot/cold/transient cache memory, Linux process and cgroup diagnostics, HTTP/2/HTTP/3/TLS/WebSocket counters, Layer-4 streams, structured-log sink health, configuration inventory and bounded Traffic analytics. The **Docker vhosts** row uses only the dedicated `rust_proxy_docker_*` metric families and includes configured/enabled counts, request/error rates, p95 exchange -latency, backend health/EWMA latency/active work, traffic and probe age. Dashboard +latency, backend health/EWMA latency/active work, traffic, probe age and upstream-client lifecycle/retry panels. Dashboard variables **Docker agent** and **Docker service** filter only this section, which keeps multi-agent installations readable without changing the ordinary vhost panels. @@ -19,7 +19,7 @@ classes, cache outcomes, capture-state gauges and configured-route traffic. Raw are intentionally absent from Prometheus labels. Import the JSON in Grafana and select a Prometheus datasource when prompted. The -dashboard expects RustProxy 0.25.6 metric names and a scrape interval around 15s. +dashboard expects RustProxy 0.25.7 metric names and a scrape interval around 15s. Collectors can be disabled in RustProxy settings; panels for disabled collectors will simply show no series. diff --git a/grafana/rustproxy-overview.json b/grafana/rustproxy-overview.json index 333d22c..7bcf17d 100644 --- a/grafana/rustproxy-overview.json +++ b/grafana/rustproxy-overview.json @@ -670,6 +670,174 @@ } ] }, + { + "id": 83, + "type": "timeseries", + "title": "Backend client generation", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 35 + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "rust_proxy_backend_upstream_client_generation", + "legendFormat": "{{vhost}} / {{backend}} generation", + "range": true + }, + { + "refId": "B", + "expr": "rust_proxy_backend_upstream_client_generation_requests", + "legendFormat": "{{vhost}} / {{backend}} requests", + "range": true + } + ], + "description": "Current reusable upstream-client generation and the requests served by that generation." + }, + { + "id": 84, + "type": "timeseries", + "title": "Backend client generation age", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 35 + }, + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "rust_proxy_backend_upstream_client_generation_age_seconds", + "legendFormat": "{{vhost}} / {{backend}}", + "range": true + } + ], + "description": "Age of the currently active reusable upstream-client generation." + }, + { + "id": 85, + "type": "timeseries", + "title": "Backend retries and rotations", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 35 + }, + "fieldConfig": { + "defaults": { + "unit": "ops", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "sum by (vhost,backend) (rate(rust_proxy_backend_retry_attempts_total[$__rate_interval]))", + "legendFormat": "{{vhost}} / {{backend}} retry attempts", + "range": true + }, + { + "refId": "B", + "expr": "sum by (vhost,backend) (rate(rust_proxy_backend_retry_successes_total[$__rate_interval]))", + "legendFormat": "{{vhost}} / {{backend}} retry successes", + "range": true + }, + { + "refId": "C", + "expr": "sum by (vhost,backend) (rate(rust_proxy_backend_upstream_client_rotations_total[$__rate_interval]))", + "legendFormat": "{{vhost}} / {{backend}} client rotations", + "range": true + } + ], + "description": "Backend retry attempts/successes and reusable upstream-client rotations per second." + }, { "id": 58, "type": "row", @@ -679,7 +847,7 @@ "h": 1, "w": 24, "x": 0, - "y": 35 + "y": 42 }, "panels": [] }, @@ -695,7 +863,7 @@ "h": 5, "w": 6, "x": 0, - "y": 36 + "y": 43 }, "fieldConfig": { "defaults": { @@ -739,7 +907,7 @@ "h": 5, "w": 6, "x": 6, - "y": 36 + "y": 43 }, "fieldConfig": { "defaults": { @@ -783,7 +951,7 @@ "h": 5, "w": 6, "x": 12, - "y": 36 + "y": 43 }, "fieldConfig": { "defaults": { @@ -827,7 +995,7 @@ "h": 5, "w": 6, "x": 18, - "y": 36 + "y": 43 }, "fieldConfig": { "defaults": { @@ -871,7 +1039,7 @@ "h": 7, "w": 8, "x": 0, - "y": 41 + "y": 48 }, "fieldConfig": { "defaults": { @@ -920,7 +1088,7 @@ "h": 7, "w": 8, "x": 8, - "y": 41 + "y": 48 }, "fieldConfig": { "defaults": { @@ -975,7 +1143,7 @@ "h": 7, "w": 8, "x": 16, - "y": 41 + "y": 48 }, "fieldConfig": { "defaults": { @@ -1024,7 +1192,7 @@ "h": 7, "w": 8, "x": 0, - "y": 48 + "y": 55 }, "fieldConfig": { "defaults": { @@ -1073,7 +1241,7 @@ "h": 7, "w": 8, "x": 8, - "y": 48 + "y": 55 }, "fieldConfig": { "defaults": { @@ -1122,7 +1290,7 @@ "h": 7, "w": 8, "x": 16, - "y": 48 + "y": 55 }, "fieldConfig": { "defaults": { @@ -1171,7 +1339,7 @@ "h": 7, "w": 8, "x": 0, - "y": 55 + "y": 62 }, "fieldConfig": { "defaults": { @@ -1220,7 +1388,7 @@ "h": 7, "w": 8, "x": 8, - "y": 55 + "y": 62 }, "fieldConfig": { "defaults": { @@ -1275,7 +1443,7 @@ "h": 7, "w": 8, "x": 16, - "y": 55 + "y": 62 }, "fieldConfig": { "defaults": { @@ -1312,6 +1480,174 @@ } ] }, + { + "id": 86, + "type": "timeseries", + "title": "Docker client generation", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 69 + }, + "fieldConfig": { + "defaults": { + "unit": "short", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "rust_proxy_docker_backend_upstream_client_generation{agent=~\"$docker_agent\",service=~\"$docker_service\"}", + "legendFormat": "{{agent}} / {{service}} / {{backend}} generation", + "range": true + }, + { + "refId": "B", + "expr": "rust_proxy_docker_backend_upstream_client_generation_requests{agent=~\"$docker_agent\",service=~\"$docker_service\"}", + "legendFormat": "{{agent}} / {{service}} / {{backend}} requests", + "range": true + } + ], + "description": "Current reusable upstream-client generation and requests for Docker-discovered backends." + }, + { + "id": 87, + "type": "timeseries", + "title": "Docker client generation age", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 69 + }, + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "rust_proxy_docker_backend_upstream_client_generation_age_seconds{agent=~\"$docker_agent\",service=~\"$docker_service\"}", + "legendFormat": "{{agent}} / {{service}} / {{backend}}", + "range": true + } + ], + "description": "Age of the active reusable upstream-client generation for Docker-discovered backends." + }, + { + "id": 88, + "type": "timeseries", + "title": "Docker retries and rotations", + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 69 + }, + "fieldConfig": { + "defaults": { + "unit": "ops", + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "lineWidth": 1, + "fillOpacity": 10, + "showPoints": "never", + "spanNulls": false, + "axisPlacement": "auto" + } + }, + "overrides": [] + }, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "calcs": [] + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "refId": "A", + "expr": "sum by (agent,service,backend) (rate(rust_proxy_docker_backend_retry_attempts_total{agent=~\"$docker_agent\",service=~\"$docker_service\"}[$__rate_interval]))", + "legendFormat": "{{agent}} / {{service}} / {{backend}} retry attempts", + "range": true + }, + { + "refId": "B", + "expr": "sum by (agent,service,backend) (rate(rust_proxy_docker_backend_retry_successes_total{agent=~\"$docker_agent\",service=~\"$docker_service\"}[$__rate_interval]))", + "legendFormat": "{{agent}} / {{service}} / {{backend}} retry successes", + "range": true + }, + { + "refId": "C", + "expr": "sum by (agent,service,backend) (rate(rust_proxy_docker_backend_upstream_client_rotations_total{agent=~\"$docker_agent\",service=~\"$docker_service\"}[$__rate_interval]))", + "legendFormat": "{{agent}} / {{service}} / {{backend}} client rotations", + "range": true + } + ], + "description": "Retry attempts/successes and reusable upstream-client rotations for Docker-discovered backends." + }, { "id": 16, "type": "row", @@ -1321,7 +1657,7 @@ "h": 1, "w": 24, "x": 0, - "y": 62 + "y": 76 }, "panels": [] }, @@ -1337,7 +1673,7 @@ "h": 5, "w": 6, "x": 0, - "y": 63 + "y": 77 }, "fieldConfig": { "defaults": { @@ -1381,7 +1717,7 @@ "h": 5, "w": 6, "x": 6, - "y": 63 + "y": 77 }, "fieldConfig": { "defaults": { @@ -1425,7 +1761,7 @@ "h": 5, "w": 6, "x": 12, - "y": 63 + "y": 77 }, "fieldConfig": { "defaults": { @@ -1469,7 +1805,7 @@ "h": 5, "w": 6, "x": 18, - "y": 63 + "y": 77 }, "fieldConfig": { "defaults": { @@ -1513,7 +1849,7 @@ "h": 7, "w": 12, "x": 0, - "y": 68 + "y": 82 }, "fieldConfig": { "defaults": { @@ -1580,7 +1916,7 @@ "h": 7, "w": 12, "x": 12, - "y": 68 + "y": 82 }, "fieldConfig": { "defaults": { @@ -1647,7 +1983,7 @@ "h": 7, "w": 12, "x": 0, - "y": 75 + "y": 89 }, "fieldConfig": { "defaults": { @@ -1720,7 +2056,7 @@ "h": 7, "w": 12, "x": 12, - "y": 75 + "y": 89 }, "fieldConfig": { "defaults": { @@ -1766,7 +2102,7 @@ "h": 1, "w": 24, "x": 0, - "y": 82 + "y": 96 }, "panels": [] }, @@ -1782,7 +2118,7 @@ "h": 8, "w": 12, "x": 0, - "y": 83 + "y": 97 }, "fieldConfig": { "defaults": { @@ -1861,7 +2197,7 @@ "h": 8, "w": 12, "x": 12, - "y": 83 + "y": 97 }, "fieldConfig": { "defaults": { @@ -1916,7 +2252,7 @@ "h": 7, "w": 8, "x": 0, - "y": 91 + "y": 105 }, "fieldConfig": { "defaults": { @@ -1971,7 +2307,7 @@ "h": 7, "w": 8, "x": 8, - "y": 91 + "y": 105 }, "fieldConfig": { "defaults": { @@ -2032,7 +2368,7 @@ "h": 7, "w": 8, "x": 16, - "y": 91 + "y": 105 }, "fieldConfig": { "defaults": { @@ -2087,7 +2423,7 @@ "h": 7, "w": 12, "x": 0, - "y": 98 + "y": 112 }, "fieldConfig": { "defaults": { @@ -2142,7 +2478,7 @@ "h": 7, "w": 12, "x": 12, - "y": 98 + "y": 112 }, "fieldConfig": { "defaults": { @@ -2194,7 +2530,7 @@ "h": 1, "w": 24, "x": 0, - "y": 105 + "y": 119 }, "panels": [] }, @@ -2210,7 +2546,7 @@ "h": 7, "w": 8, "x": 0, - "y": 106 + "y": 120 }, "fieldConfig": { "defaults": { @@ -2271,7 +2607,7 @@ "h": 7, "w": 8, "x": 8, - "y": 106 + "y": 120 }, "fieldConfig": { "defaults": { @@ -2326,7 +2662,7 @@ "h": 7, "w": 8, "x": 16, - "y": 106 + "y": 120 }, "fieldConfig": { "defaults": { @@ -2381,7 +2717,7 @@ "h": 7, "w": 12, "x": 0, - "y": 113 + "y": 127 }, "fieldConfig": { "defaults": { @@ -2448,7 +2784,7 @@ "h": 7, "w": 12, "x": 12, - "y": 113 + "y": 127 }, "fieldConfig": { "defaults": { @@ -2512,7 +2848,7 @@ "h": 1, "w": 24, "x": 0, - "y": 120 + "y": 134 }, "panels": [] }, @@ -2528,7 +2864,7 @@ "h": 7, "w": 12, "x": 0, - "y": 121 + "y": 135 }, "fieldConfig": { "defaults": { @@ -2589,7 +2925,7 @@ "h": 7, "w": 12, "x": 12, - "y": 121 + "y": 135 }, "fieldConfig": { "defaults": { @@ -2644,7 +2980,7 @@ "h": 7, "w": 12, "x": 0, - "y": 128 + "y": 142 }, "fieldConfig": { "defaults": { @@ -2705,7 +3041,7 @@ "h": 7, "w": 12, "x": 12, - "y": 128 + "y": 142 }, "fieldConfig": { "defaults": { @@ -2763,7 +3099,7 @@ "h": 1, "w": 24, "x": 0, - "y": 135 + "y": 149 }, "panels": [] }, @@ -2779,7 +3115,7 @@ "h": 7, "w": 12, "x": 0, - "y": 136 + "y": 150 }, "fieldConfig": { "defaults": { @@ -2864,7 +3200,7 @@ "h": 7, "w": 12, "x": 12, - "y": 136 + "y": 150 }, "fieldConfig": { "defaults": { @@ -2910,7 +3246,7 @@ "h": 1, "w": 24, "x": 0, - "y": 143 + "y": 157 }, "panels": [] }, @@ -2952,7 +3288,7 @@ "h": 7, "w": 12, "x": 0, - "y": 144 + "y": 158 }, "description": "Seconds until the observed certificate notAfter timestamp.", "targets": [ @@ -3002,7 +3338,7 @@ "h": 7, "w": 6, "x": 12, - "y": 144 + "y": 158 }, "targets": [ { @@ -3025,7 +3361,7 @@ "h": 7, "w": 6, "x": 18, - "y": 144 + "y": 158 }, "fieldConfig": { "defaults": { @@ -3063,7 +3399,7 @@ "h": 1, "w": 24, "x": 0, - "y": 151 + "y": 165 }, "id": 51, "panels": [], @@ -3133,7 +3469,7 @@ "h": 7, "w": 8, "x": 0, - "y": 152 + "y": 166 }, "id": 52, "options": { @@ -3229,7 +3565,7 @@ "h": 7, "w": 8, "x": 8, - "y": 152 + "y": 166 }, "id": 53, "options": { @@ -3336,7 +3672,7 @@ "h": 7, "w": 8, "x": 16, - "y": 152 + "y": 166 }, "id": 54, "options": { @@ -3375,7 +3711,7 @@ "h": 1, "w": 24, "x": 0, - "y": 159 + "y": 173 }, "id": 55, "panels": [], @@ -3445,7 +3781,7 @@ "h": 7, "w": 12, "x": 0, - "y": 160 + "y": 174 }, "id": 56, "options": { @@ -3552,7 +3888,7 @@ "h": 7, "w": 12, "x": 12, - "y": 160 + "y": 174 }, "id": 57, "options": { @@ -3605,7 +3941,7 @@ "h": 1, "w": 24, "x": 0, - "y": 167 + "y": 181 }, "panels": [] }, @@ -3621,7 +3957,7 @@ "h": 7, "w": 6, "x": 0, - "y": 168 + "y": 182 }, "fieldConfig": { "defaults": { @@ -3665,7 +4001,7 @@ "h": 7, "w": 6, "x": 6, - "y": 168 + "y": 182 }, "fieldConfig": { "defaults": { @@ -3709,7 +4045,7 @@ "h": 7, "w": 6, "x": 12, - "y": 168 + "y": 182 }, "fieldConfig": { "defaults": { @@ -3754,7 +4090,7 @@ "h": 7, "w": 6, "x": 18, - "y": 168 + "y": 182 }, "fieldConfig": { "defaults": { @@ -3799,7 +4135,7 @@ "h": 7, "w": 12, "x": 0, - "y": 175 + "y": 189 }, "fieldConfig": { "defaults": { @@ -3848,7 +4184,7 @@ "h": 7, "w": 12, "x": 12, - "y": 175 + "y": 189 }, "fieldConfig": { "defaults": { @@ -3897,7 +4233,7 @@ "h": 7, "w": 12, "x": 0, - "y": 182 + "y": 196 }, "fieldConfig": { "defaults": { @@ -3946,7 +4282,7 @@ "h": 7, "w": 12, "x": 12, - "y": 182 + "y": 196 }, "fieldConfig": { "defaults": { @@ -3995,7 +4331,7 @@ "h": 5, "w": 12, "x": 0, - "y": 189 + "y": 203 }, "fieldConfig": { "defaults": { @@ -4050,7 +4386,7 @@ "h": 5, "w": 12, "x": 12, - "y": 189 + "y": 203 }, "fieldConfig": { "defaults": { @@ -4193,9 +4529,9 @@ }, "timepicker": {}, "timezone": "browser", - "title": "RustProxy 0.25.6 - Operations", + "title": "RustProxy 0.25.7 - Operations", "uid": "rustproxy-0170", - "version": 4, + "version": 5, "weekStart": "", - "description": "RustProxy 0.25.6 operations dashboard including bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic." -} \ No newline at end of file + "description": "RustProxy 0.25.7 operations dashboard including backend client lifecycle/retry diagnostics, bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic." +} diff --git a/langs/en_US.json b/langs/en_US.json index 7565c14..ba1d8a4 100644 --- a/langs/en_US.json +++ b/langs/en_US.json @@ -1,1967 +1,1978 @@ { - "meta": { - "locale": "en-US", - "name": "English", - "native_name": "English", - "direction": "ltr" - }, - "translations": { - "overview": "Overview", - "mainMenu": "Menu", - "routing": "Legacy routes", - "configuration": "Configuration", - "manualConfig": "Manual config", - "runtime": "RUNTIME", - "localOnly": "ADMINISTRATION", - "logout": "Sign out", - "firstSlice": "INDEPENDENT CORE / EXPLICIT ACCESS", - "loginTitle": "Administration", - "unlock": "Unlock administration", - "tokenHelp": "Run this command in a second terminal and paste the token below.", - "token": "Local access token", - "connect": "Connect to proxy", - "tokenNote": "Administration defaults to loopback HTTP. Enable Administration HTTPS before using a non-loopback bind.", - "requests": "Requests", - "activeExchanges": "Active exchanges", - "bodyLifetime": "Full body lifetime", - "bandwidth": "Payload transferred", - "bothDirections": "Both directions", - "errors": "Errors", - "errorDescription": "5xx / body / cancelled", - "liveTraffic": "LIVE TRAFFIC", - "liveTransformed": "Transformed", - "requestsPerSecond": "Requests per second", - "live": "LIVE", - "lastMinute": "Recent samples / resets on reload", - "coreState": "CORE STATE", - "configurationRevision": "Applied revision", - "backends": "Backends", - "routes": "Routes", - "connections": "Open connections", - "uptime": "Uptime", - "activity": "ACTIVITY", - "accessLog": "Access log", - "boundedLog": "Last 50 / retained ring 4096", - "time": "Time", - "request": "Request", - "status": "Status", - "duration": "Duration", - "outcome": "Outcome", - "noTraffic": "No traffic yet. Open the proxy to make your first request.", - "reload": "Reload configuration", - "addBackend": "Add / edit backend", - "backendUrl": "Backend origin (HTTP / HTTPS, IP / DNS)", - "allowPrivate": "Explicitly allow private / loopback IP", - "preserveHost": "Preserve original Host header", - "saveBackend": "Save backend", - "clear": "Clear", - "addRoute": "Add / edit route", - "hostnames": "Hostnames and aliases, comma-separated", - "pathPrefix": "Path prefix (not stripped)", - "backend": "Backend", - "enabled": "Enabled", - "saveRoute": "Save route", - "rawConfig": "Configuration document", - "export": "Export JSON", - "configHelp": "A valid save is applied atomically. Invalid or stale changes leave the running configuration untouched.", - "apply": "Validate, save and apply", - "noRestart": "Routing and response policies apply live; listener changes require restart.", - "roadmapHelp": "Release details and planned features are documented in ROADMAP.md.", - "overviewTitle": "Traffic, in focus.", - "overviewDescription": "Traffic, cache and operating-system measurements in one compact dashboard.", - "routingTitle": "Connect the right dots.", - "routingDescription": "Existing backend/route format remains supported. New deployments can use one vhost with its own frontend and pool.", - "configurationTitle": "One source of truth.", - "configurationDescription": "One canonical configuration: vhosts, listeners and shared policies.", - "connected": "CONNECTED TO LOCAL CORE", - "disconnected": "CORE NOT REACHABLE", - "edit": "Edit", - "remove": "Delete", - "privateAllowed": "PRIVATE IP APPROVED", - "configured": "CONFIGURED / NOT PROBED", - "disabled": "DISABLED", - "emptyBackends": "No backends configured. Add an explicit HTTP or HTTPS origin.", - "emptyRoutes": "No routes configured. Unknown hosts return 404.", - "saving": "Saving…", - "unsavedChanges": "Unsaved changes", - "saved": "Configuration applied.", - "confirmDelete": "Delete this item? The change takes effect immediately.", - "confirmTitle": "Confirm action", - "confirmationLabel": "CONFIRMATION", - "warningLabel": "WARNING", - "continueAction": "Continue", - "cancelAction": "Cancel", - "discardAction": "Discard changes", - "errorContext": "{area}: {message}", - "stale": "Configuration changed elsewhere. Reload before saving.", - "busy": "A save is already in progress.", - "loginError": "Sign-in failed.", - "fresh": "Configuration reloaded.", - "locked": "Signed out. The session was revoked.", - "backendUsed": "This backend is referenced by a route. Delete or change the route first.", - "renaming": "IDs cannot be renamed in this form. Use the JSON editor to update references atomically.", - "complete": "complete", - "cancelled": "cancelled", - "body_error": "body error", - "proxy_or_upstream_error": "proxy/upstream error", - "security": "Security", - "sessionNote": "Local HTTP administration. Passwords use Argon2id and session cookies are HttpOnly. Do not expose the panel publicly.", - "setupHelp": "Create the first administrator using a one-time capability from the local terminal.", - "setupToken": "One-time setup token", - "username": "Username", - "password": "Password", - "confirmPassword": "Confirm password", - "setupTitle": "Create your administrator", - "signIn": "Sign in", - "createAndSignIn": "Create account and sign in", - "securityTitle": "Access stays deliberate.", - "securityDescription": "One administrator. Revocable sessions. Explicit host and route access policies.", - "manualBackends": "MANUAL BACKENDS", - "routePolicies": "Access policy and custom headers", - "useRouteAcl": "Enable route ACL", - "aclDefault": "Default action", - "allow": "Allow", - "deny": "Deny", - "aclRules": "One rule per line: allow/deny followed by CIDR", - "aclHelp": "Use IPv4/IPv6 CIDRs, e.g. 192.168.1.0/24 or 10.0.0.5/32. Deny wins. An allowed IP must still authenticate; a location cannot bypass the host ACL.", - "routeHeaders": "Request / response headers (JSON)", - "headersHelp": "Operations: set, append, remove. Transport, body encoding and client-identity headers are protected.", - "currentSession": "CURRENT SESSION", - "recoveryHelp": "Lost access? Run rust-proxy admin reset-password locally. Existing sessions will be revoked.", - "revokeAll": "Sign out all sessions", - "changePassword": "Change password", - "currentPassword": "Current password", - "newPassword": "New password (12-128 UTF-8 bytes)", - "savePassword": "Change and sign out", - "hostPolicies": "Host access policies", - "editHostPolicy": "Add / replace host policy", - "savePolicy": "Apply host policy", - "auditRetention": "SQLITE / LAST 100 / RETAINED 10,000", - "audit": "Administration audit", - "reloadAudit": "Reload", - "actor": "Actor", - "action": "Action", - "detail": "Detail", - "noAudit": "No audit entries.", - "noPolicies": "No host ACLs. Route ACLs may still restrict access.", - "expires": "Absolute session expiry: ", - "passwordChanged": "Password changed. All sessions were revoked. Sign in again.", - "passwordMismatch": "The passwords do not match.", - "ruleSyntax": "Use one rule per line, for example: allow 127.0.0.1/32", - "confirmRevoke": "Sign out every administrator session, including this one?", - "streamLive": "SSE live", - "streamFallback": "Polling fallback", - "auth.required": "Your session expired or was revoked. Sign in again.", - "auth.invalid_credentials": "Incorrect username or password.", - "auth.password_policy": "The password must contain 12-128 UTF-8 bytes and no line breaks.", - "auth.invalid_username": "Use 3-64 letters, digits, dots, dashes or underscores.", - "auth.invalid_setup_token": "The setup token is invalid. Read it from the local terminal.", - "auth.already_initialized": "An administrator already exists. Sign in.", - "auth.rate_limited": "Too many attempts. Retry after 60 seconds or use local password recovery.", - "auth.busy": "Password workers are busy. Retry shortly.", - "auth.csrf": "Request protection failed. Reload the page and retry.", - "auth.invalid_host": "Use the configured administration address and allowed hostname.", - "auth.invalid_origin": "Cross-origin administration is blocked.", - "auth.credentials_changed": "Credentials changed concurrently. Sign in again.", - "auth.unavailable": "Administration storage is temporarily unavailable.", - "events.too_many_viewers": "Live viewer limit reached; polling is available.", - "protocol": "Upstream protocol", - "protocolHelp": "HTTP/2 and auto use the backend authority. Preserve Host is available with HTTP/1.1 only. RFC 8441 can use an explicit HTTP/2 upstream; other WebSocket transports bridge through HTTP/1.1.", - "addressAllowlist": "Optional address allowlist (CIDR, one per line)", - "caPem": "Additional trusted CA / certificate (PEM, optional)", - "backendTlsHelp": "TLS encryption remains available, but certificate/hostname verification is off unless enabled explicitly. Private addresses still need explicit approval, including DNS answers.", - "advancedTransport": "Transport and trust", - "tls": "Certificates", - "tlsTitle": "Encrypted, deliberately.", - "tlsDescription": "Exact SNI names. Private local certificate files. Apply bindings without restarting.", - "certificateBindings": "Certificate bindings", - "addCertificate": "Add certificate", - "certificateId": "Certificate ID", - "certificateFile": "Certificate filename", - "privateKeyFile": "Private key filename", - "defaultCertificate": "Use as the default certificate", - "saveCertificate": "Apply certificate", - "reloadCertificates": "Reload certificate files", - "certificateHelp": "Upload a PEM pair, reference files already in data/certs, or deploy an externally issued certificate with `./dev.sh tls deploy --id ID --cert FULLCHAIN --key PRIVKEY`. Reload re-reads configured files without changing the configuration revision.", - "certificateHint": "External Certbot hook: ./dev.sh tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem", - "emptyCertificates": "No explicit SNI bindings. The generated default certificate is used while the TLS listener is enabled.", - "certificateSafety": "Certificates secure TLS connections, not routing. Assign a certificate to a vhost. Changes affect new handshakes.", - "wsActive": "WebSocket tunnels", - "h2Requests": "HTTP/2 requests", - "h2ActiveConnections": "Active H2 connections", - "tlsFailures": "TLS handshake errors", - "tlsListener": "TLS listener", - "notEnabled": "Disabled", - "websocket_closed": "WebSocket closed", - "defaultLabel": "DEFAULT", - "language": "Language", - "settings": "Settings", - "settingsTitle": "Configure your edge.", - "settingsDescription": "Switch between function tabs. Unsaved changes stay in their forms.", - "cacheHitRatio": "Cache hit ratio", - "processMemory": "Process memory", - "systemLoad": "SYSTEM LOAD", - "systemChart": "Recent system CPU usage", - "systemMemory": "System RAM", - "systemSwap": "System swap", - "systemUptime": "System uptime", - "loadAverage": "Load 1 / 5 / 15 min", - "cacheOverview": "RAM cache", - "cacheObjects": "Objects / memory", - "cacheEvictions": "Evicted / expired", - "processDiagnostics": "Process", - "platform": "Platform", - "processCpu": "CPU (100% = 1 core)", - "fileDescriptors": "File descriptors / limit", - "processThreads": "OS threads", - "processVirtualMemory": "Virtual memory / limit", - "processStartTime": "Process start", - "containerMemory": "cgroup RAM / limit", - "networkDiagnostics": "Network and responses", - "hostScope": "OS scope", - "networkRate": "RX / TX per second", - "meanLatency": "Mean exchange duration", - "filterLogs": "Filter host or path", - "filterResult": "Filter result", - "allResults": "All results", - "routeCache": "Route cache policy", - "inheritCache": "Inherit global policy", - "bypassCache": "Always bypass", - "listeners": "Listeners", - "httpConnections": "HTTP connections", - "httpConnectionsHelp": "Connection lifecycle and transport limits for HTTP/2 and HTTP/3.", - "http2Tab": "HTTP/2", - "http3Tab": "HTTP/3", - "http2Settings": "HTTP/2 connections", - "http2SettingsHelp": "HTTP/2 enablement is controlled per listener. Tune idle, maximum lifetime and graceful GOAWAY drain limits here.", - "http2IdleTimeout": "Idle timeout (seconds)", - "http2MaxLifetime": "Maximum connection lifetime (seconds, 0 = disabled)", - "http2DrainTimeout": "Drain timeout (seconds)", - "http2DrainHelp": "These limits apply to this listener. Idle timeout applies only to unused connections; maximum lifetime is absolute; drain bounds active streams after GOAWAY. Changes require restart.", - "http2Save": "Save HTTP/2 settings", - "http2NoEnabledListeners": "No listener has HTTP/2 enabled. Enable HTTP/2 or h2c in Settings > Listeners first.", - "http2ListenersDirty": "Save pending listener changes before editing HTTP/2 settings.", - "restartLabel": "RESTART", - "listenersHelp": "Named IP and port bindings. Changes require restart. The administration endpoint remains separate.", - "httpAddress": "HTTP bind address and port", - "httpsAddress": "HTTPS bind address and port", - "enableHttps": "Enable HTTPS listener", - "lowPortsHelp": "Privileged ports may need CAP_NET_BIND_SERVICE. Do not run the whole application as root.", - "saveListeners": "Save listeners", - "inheritListeners": "Use startup defaults", - "responseSettings": "Client response", - "hotApply": "LIVE APPLY", - "serverHeader": "Server header", - "serverPreserve": "Preserve origin value", - "serverHide": "Hide completely", - "serverCustom": "Replace / add custom value", - "serverValue": "Custom Server value", - "compression": "Streaming compression", - "compressionMin": "Minimum response size (bytes)", - "compressionHelp": "Negotiates Accept-Encoding. Skips private responses, cookies, ranges, SSE and no-transform; existing compressed bodies are passed through.", - "saveResponse": "Apply response settings", - "cacheSettings": "Cache", - "enableCache": "Enable cache", - "cacheSafety": "Complete public-safe GET responses are cached. Authorization, cookies and private/no-store responses still bypass. One byte range can be served from a complete cached object; multipart/unsupported ranges pass through.", - "cacheMemory": "HOT allocated budget (MiB)", - "cacheObject": "Maximum object (KiB)", - "cacheEntries": "Maximum entries", - "cacheMaxTtl": "Maximum TTL (seconds)", - "cacheDefaultTtl": "Fallback TTL for public responses (0 = off)", - "bypassQuery": "Bypass URLs with a query string", - "cachePrefixes": "Bypass path prefixes, one per line", - "cacheAgeHelp": "Age is always sent on cache hits. Counters remain available even when diagnostic headers are hidden. Only cache-affecting configuration changes invalidate incompatible objects; managed software updates hand hot objects to cold storage when the cold tier is enabled.", - "saveCache": "Apply cache policy", - "purgeCache": "Purge all cache", - "customHeaders": "Global custom headers", - "globalHeadersHelp": "Request rules go to the backend; response rules go to the client. Route rules run after global rules. Server policy takes final precedence.", - "responseHeaders": "Response to client", - "requestHeaders": "Request to backend", - "addHeader": "Add header rule", - "saveHeaders": "Apply header rules", - "unavailable": "N/A", - "threads": "threads", - "realSample": "Measured", - "noKnownLimit": "unknown / unlimited", - "unlimited": "unlimited", - "restartPending": "Saved listener changes are pending. Restart RustProxy to apply them.", - "activeListeners": "Currently active", - "headerLimit": "At most 32 rules per direction.", - "headerOperation": "Operation", - "header_set": "Set", - "header_append": "Append", - "header_remove": "Remove", - "headerName": "Header name", - "headerValue": "Header value", - "confirmInherit": "Restore listener defaults from startup flags and environment on the next restart?", - "confirmPurge": "Purge every cached object and cancel all pending cache fills?", - "cachePurged": "Cache purged; removed entries", - "logsDropped": "dropped", - "updateAvailable": "New version", - "vhosts": "Vhosts", - "vhostsTitle": "Virtual hosts & backends", - "vhostsDescription": "Manage hostnames, frontend bindings, backends and per-host policies.", - "vhHealthTitle": "Backends", - "vhManage": "Manage vhosts", - "vhHealthHint": "Live state: leases cover the entire exchange; traffic is an EWMA of payload bytes.", - "vhHealthEmpty": "No backend diagnostics yet.", - "vhVhost": "Vhost", - "vhActive": "Active", - "vhRequests": "Requests", - "vhErrors": "Errors", - "vhLatency": "Latency (EWMA)", - "vhTraffic": "Traffic/s", - "vhClientGeneration": "Client gen.", - "vhGenerationRequests": "Gen. requests", - "vhGenerationAge": "Gen. age", - "vhClientRotations": "Rotations", - "vhIntro": "Each vhost owns its bound IPs, paths and backends. Unlisted addresses cannot reach it. Listener changes require restart.", - "vhList": "Virtual hosts", - "vhSearch": "Search vhosts", - "vhSearchPlaceholder": "Search hostname, vhost or backend", - "vhSearchEmpty": "No vhosts match this search.", - "vhNew": "New vhost", - "vhMigrate": "Migrate a legacy route group", - "vhImport": "Load into editor", - "vhMigrationHint": "Migration is saved atomically. Routes sharing one host and one backend are grouped; ambiguous host ownership is rejected.", - "vhEditor": "Vhost configuration", - "vhReset": "Discard changes", - "vhSafetyHint": "Private IP binding is not authentication. Keep firewall/ACL rules. HSTS preload is opt-in; affinity cookies are not login sessions.", - "vhId": "Vhost ID", - "vhHosts": "Hostnames", - "vhEnabled": "Enabled", - "vhFrontends": "Frontends / bound addresses", - "vhAddFrontend": "Add frontend", - "vhAddress": "IP:port (IPv6: [address]:port)", - "vhTls": "TLS enabled", - "vhHttp2": "Prefer HTTP/2 over TLS; retain HTTP/1.1", - "vhBackendPool": "Backends", - "vhAddBackend": "Add backend", - "vhMemberId": "Backend ID", - "vhUrl": "Origin URL", - "vhWeight": "Weight", - "vhBackup": "Backup only", - "vhDrain": "Drain new sessions", - "vhPrivate": "Allow private origin IP", - "vhPreserveHost": "Preserve client Host (HTTP/1.1 only)", - "vhProtocol": "Origin protocol", - "vhProtocolHttp1": "HTTP/1.1", - "vhProtocolAuto": "TLS ALPN: HTTP/2 + HTTP/1.1", - "vhProtocolHttp2": "HTTP/2 (TLS: with HTTP/1.1 fallback; plaintext: h2c)", - "vhAddressAllowlist": "Origin IP/CIDR allowlist (optional)", - "vhTlsServerName": "TLS server name / SNI (optional)", - "vhTlsVerify": "Verify backend certificate and hostname", - "vhTlsVerifyHelp": "Disabled when omitted. Enable it when RustProxy must validate the backend certificate chain and identity. If verification fails, set TLS server name to a DNS name present in the certificate and/or add the private CA PEM. Do not use an IP address as SNI.", - "vhCa": "Additional trusted CA (PEM, optional)", - "vhBalancing": "Balancing & connection reuse", - "vhAlgorithm": "Algorithm", - "vhRoundRobin": "Smooth weighted round-robin", - "vhLeastConnections": "Weighted least active exchanges", - "vhLeastTraffic": "Weighted least traffic (EWMA)", - "vhAdaptive": "Adaptive: activity + latency + traffic", - "vhIpHash": "Client IP hash", - "vhSlowStart": "Recovery slow-start (seconds)", - "vhRetryMax": "Failover retries", - "vhRetryConnect": "Retry connection failures", - "vhRetryTimeouts": "Retry response-header timeouts", - "vhRetryStatuses": "Retry HTTP statuses", - "vhRetryHelp": "Retries are limited to body-free GET, HEAD and OPTIONS requests, use a different healthy backend and never replay WebSocket or write requests.", - "vhKeepalive": "Reuse upstream connections (keepalive)", - "vhIdleTimeout": "Idle pool timeout (seconds)", - "vhMaxIdle": "Max idle connections / origin", - "vhTcpKeepalive": "TCP / HTTP/2 keepalive interval (seconds)", - "vhHealth": "Backend health", - "vhHealthMode": "Check type", - "vhOff": "Off", - "vhTcp": "TCP connect", - "vhHttp": "HTTP status + response time", - "vhHealthPath": "HTTP check path", - "vhHealthHost": "HTTP Host override (optional)", - "vhInterval": "Interval (ms)", - "vhTimeout": "Timeout (ms)", - "vhSlow": "Slow threshold (ms; 0 = off)", - "vhFall": "Failures before down", - "vhRise": "Successes before recovery", - "vhStatusMin": "Minimum HTTP status", - "vhStatusMax": "Maximum HTTP status", - "vhHealthNote": "HTTP probes use HTTP/1.1 and measure time to headers, not body duration. Use TCP for h2c-only services. New backends wait for successful probes. Active health is independent from passive health.", - "vhPassiveHealth": "Passive Backend Health", - "vhPassiveEnabled": "Allow normal request failures to mark a backend unhealthy", - "vhPassiveHelp": "Off by default. Errors are still logged and counted, but normal user traffic cannot change backend health until this is explicitly enabled.", - "vhPassiveConnect": "Count connection errors", - "vhPassiveTimeouts": "Count timeouts", - "vhPassiveIo": "Count body/read/write I/O errors", - "vhPassive5xx": "Count HTTP 5xx responses", - "vhPassiveSlow": "Count slow responses", - "vhPassiveFall": "Passive failures before down (empty = active fall)", - "vhPassiveRise": "Passive successes before recovery (empty = active rise)", - "vhPassiveWarning": "Enabling HTTP 5xx or slow-response failures can quarantine the whole backend after repeated errors from a single endpoint.", - "vhSticky": "Sticky sessions", - "vhStickyMode": "Affinity mode", - "vhCookie": "Opaque proxy cookie", - "vhCookieName": "Cookie name (empty = per-vhost default)", - "vhCookieTtl": "Cookie lifetime (seconds)", - "vhStickyNote": "Cookie affinity bypasses shared cache. Drain preserves existing cookie sessions. IP affinity uses the verified client IP under the configured trusted-proxy policy.", - "vhSecurity": "Security", - "vhHsts": "Enable HSTS (TLS responses only)", - "vhHstsAge": "HSTS max-age (seconds)", - "vhHstsSub": "HSTS includeSubDomains", - "vhHstsPreload": "HSTS preload (explicit opt-in)", - "vhNosniff": "X-Content-Type-Options: nosniff", - "vhFrame": "X-Frame-Options", - "vhPreserve": "Preserve origin value", - "vhDeny": "DENY", - "vhSameorigin": "SAMEORIGIN", - "vhReferrer": "Referrer-Policy (optional)", - "vhCsp": "Content-Security-Policy (optional)", - "vhPermissions": "Permissions-Policy (optional)", - "vhAdvanced": "Advanced: paths, ACL and custom headers", - "vhPaths": "Paths (JSON; optional backend_id pins a path to a single pool member)", - "vhAcl": "Vhost ACL (JSON or null)", - "vhHeaders": "Request / response header rules (JSON)", - "vhEmpty": "No vhosts yet. Existing routes continue to work.", - "vhUnsaved": "Discard unsaved vhost changes?", - "vhDelete": "Remove this vhost? Bound sockets are closed after restart.", - "vhConflict": "That vhost ID already exists.", - "vhRowLimit": "The maximum number of rows has been reached.", - "vhMigrationAmbiguous": "Hostnames overlap other legacy routes. Resolve ownership in JSON before migration.", - "vhMigrationPending": "Legacy migration will be committed with this save.", - "vhMigrationNone": "Select a legacy route", - "vhJsonInvalid": "Invalid JSON or data type in paths, ACL or headers.", - "vhUp": "Up", - "vhDown": "Down", - "vhChecking": "Checking", - "vhDraining": "Draining", - "vhDisabled": "Disabled", - "vhHealthDisabled": "Checks off", - "vhHealthUnknown": "Unknown", - "vhNewLabel": "NEW", - "vhEditLabel": "EDIT", - "vhFrontendNote": "Use an IP assigned to this machine. A wildcard accepts every IP in its address family; host routing still checks the local destination. TLS certificates are configured in the TLS tab.", - "close": "Close", - "inherit": "Inherit", - "liveLogs": "Live logs", - "logVhost": "Filter by vhost", - "logAllVhosts": "All vhosts", - "logAllMethods": "All methods", - "logPause": "Pause", - "logPaused": "PAUSED", - "logResume": "Resume", - "logPin": "Dock", - "logUndock": "Open as modal", - "logColumns": "Columns", - "logColumnsRequired": "At least one Live Logs column must remain visible.", - "logLoadHistory": "Increase buffer", - "logHistoryLoaded": "Live buffer increased to {count} retained entries.", - "logHost": "Host", - "logBufferHint": "Live view starts with the latest 256 completed exchanges. Increase buffer to seed it with retained history and keep accumulating live entries up to 4096 until the log window is closed. Export includes the currently filtered rows.", - "settingsSecurityHint": "Accounts and ACLs are global. SSL, HSTS, headers and cache are also configured inside each vhost.", - "theme": "Theme", - "themeDark": "Dark", - "themeLight": "Light", - "density": "Interface density", - "densityCompact": "Compact", - "densityDense": "Dense", - "densityComfortable": "Comfortable", - "globalPages": "Default responses", - "pagesHelp": "Pages for direct IP, unknown hosts and errors. An empty status selector preserves the original status. Static pages do not contact the upstream.", - "pageInherit": "Default / inherited", - "pageWelcome": "Congratulations page", - "pageEmpty": "Empty response", - "pageHtml": "Custom HTML", - "pageStatus": "Response status", - "pageOriginalStatus": "Original status", - "pageHtmlSource": "HTML source", - "pageUploadHtml": "Optional HTML file (32 KiB maximum)", - "pageTooLarge": "HTML must not exceed 32 KiB in UTF-8.", - "customErrorPages": "Custom error pages", - "pageStaticHost": "Static / maintenance host", - "pageMissingPath": "Unmatched path", - "pageDirectIp": "Direct IP access", - "pageUnknownHost": "Unknown hostname", - "pagesSafetyHint": "HTML is public content, not an admin template. ACLs still run first. Explicit HTTP 200 for an error masks its status to clients and monitoring. Total configuration size is limited.", - "vhDetailsTab": "Details", - "vhSsl": "SSL certificates", - "vhCertificate": "Named certificate", - "vhCertificateDefault": "Global SNI / default certificate", - "vhCertificateFile": "Certificate / full chain (PEM)", - "vhPrivateKeyFile": "Private key (PEM)", - "vhUploadCertificate": "Upload and validate pair", - "vhSelectCertificateFiles": "Choose both a certificate and private key file.", - "vhCertificateTooLarge": "Each PEM file is limited to 128 KiB.", - "vhCertificateNeedsHosts": "Enter vhost domain names in Details first.", - "vhCertificateStaged": "Pair verified and staged. Save this vhost to activate its certificate.", - "vhCertificateUploadHint": "Optional upload verifies key match and domain coverage. Private keys are stored in private files, never returned by the API. Save the vhost to activate the selection. Uploads do not save other changes. Listener changes require restart.", - "vhCache": "Cache", - "vhCacheTtl": "Maximum TTL (seconds, blank inherits)", - "vhCacheDefault": "Public default TTL (blank inherits)", - "vhCacheObject": "Object limit (KiB, blank inherits)", - "cacheEnabled": "Enable cache", - "cacheBypassQuery": "Bypass query strings", - "cacheStatusHeader": "Expose X-Cache", - "cacheHitsHeader": "Expose X-Cache-Hits", - "cacheRfcHeader": "Expose Cache-Status", - "cacheBypassPrefixes": "Bypass path prefixes", - "vhCacheCustomPrefixes": "Override inherited bypass paths", - "vhCacheHint": "Per-host policy can enable caching independently of the global default. All vhosts share global RAM and entry ceilings. Cookie affinity, private responses and authorization still bypass cache.", - "vhPurgeCache": "Purge host cache", - "vhPurgeConfirm": "Purge only this vhost cache? In-progress fills for this host will also be invalidated.", - "vhPages": "Error pages", - "vhHeadersOrder": "Order: global rules, vhost rules, path rules, then security/Server policy. Advanced JSON remains available.", - "vhNewHealthHint": "Save the vhost to start observing its backend health.", - "listenerAdd": "Add listener", - "listenerMigrate": "Convert defaults to named listeners", - "listenerScopeHint": "Internal / public is a label, not a firewall. New listeners do not expose legacy routes unless explicitly selected.", - "listenerLimit": "Maximum 64 named listeners.", - "listenerEndpoint": "Listener", - "listenerName": "Display name", - "listenerScope": "Label", - "listenerInternal": "Internal", - "listenerPublic": "Public", - "listenerLegacy": "Allow legacy routes", - "listenerInUse": "Listener is assigned to vhosts", - "listenerDuplicate": "Listener IDs must be unique.", - "listenerChooseHint": "Select named listeners configured in Settings > Listeners. A disabled listener grants no access.", - "listenerMissing": "Missing listener", - "http3Settings": "HTTP/3 / QUIC", - "http3SettingsHelp": "HTTP/3 enablement is controlled in Settings > Listeners. Tune advertisement, connection and stream limits here.", - "http3NoTlsListeners": "No TLS listeners are configured. Add and save a TLS listener first.", - "http3NoEnabledListeners": "No TLS listener has HTTP/3 enabled. Enable HTTP/3 in Settings > Listeners first.", - "http3ListenersDirty": "Save pending listener changes before editing HTTP/3 settings.", - "http3Save": "Save HTTP/3 settings", - "h2Configure": "Configure HTTP/2 limits", - "h3Enable": "Enable HTTP/3 over QUIC (UDP)", - "h3Configure": "Configure HTTP/3 limits", - "h3Limits": "HTTP/3 limits and advertisement", - "h3_alt_svc_max_age": "Alt-Svc lifetime (s)", - "h3_max_concurrent_connections": "Connections per listener", - "h3_max_concurrent_bidistream": "Bidirectional streams per connection", - "h3_max_concurrent_unistream": "Unidirectional streams per connection", - "h3_max_idle_timeout": "QUIC idle timeout (s; 0 = unlimited)", - "h3Help": "HTTP/3 requires TLS. Keep TCP plus the same UDP port available; HTTP/1.1 and HTTP/2 remain. Zero disables the local QUIC idle timeout. Changes require restart.", - "h3TuningHelp": "These limits apply only when HTTP/3 is enabled for this TLS listener. Changes require restart.", - "h3Requests": "HTTP/3 requests", - "certImport": "Import certificate", - "certImportSave": "Import and save in library", - "certLibraryHint": "Upload fullchain/certificate and private key in PEM. Save once, then assign the certificate to one or more vhosts.", - "certCheckDomains": "Domains to verify (comma-separated)", - "certAcmeLater": "Issued certificates are imported into the library and assigned per vhost.", - "certAdvanced": "Existing files / advanced", - "certLegacyNames": "Legacy SNI names (optional; prefer per-vhost assignment)", - "certAssigned": "Assigned vhosts", - "certUnassigned": "Not assigned", - "certInUse": "Certificate is in use. Reassign vhosts and change the default before removal.", - "certDuplicate": "This certificate ID exists. Use a new ID for safe rotation.", - "certManage": "Manage certificate library", - "certSelectHint": "Select an imported certificate. Uploads and rotation are in the Certificates tab. Assignments are validated against vhost names.", - "vhTinyauth": "Authentication and IP access", - "vhTabAuth": "Authentication", - "taEnable": "Enable Tinyauth protection", - "taUrl": "Tinyauth URL / verification endpoint", - "taLogin": "Public login URL", - "taRedirectForbidden": "Accept same-origin provider redirects for 403", - "taConnect": "Connect timeout (s)", - "taTimeout": "Total verification timeout (s)", - "taRequestHeaders": "Client headers sent to Tinyauth", - "taResponseHeaders": "Verified identity headers sent to application", - "taHelp": "An origin URL adds /api/auth/nginx automatically. Verification is body-free and runs before cache and WebSocket upgrades. Protected responses use private, no-store. Configure Tinyauth to trust the actual RustProxy IP.", - "vhResponsePolicy": "Response identity and diagnostics", - "vhInherit": "Inherit global settings", - "diagnosticHeaders": "Diagnostic response headers", - "diagInherit": "Inherit diagnostic headers", - "diagRequestId": "Expose X-Request-ID", - "hideMockOrigin": "Hide X-Mock-Origin", - "diagHelp": "X-Request-ID is opt-in. Other upstream response headers are controlled with ordinary response-header rules.", - "forwardingSettings": "Client identity / forwarding", - "forwardingHelp": "By default, client-supplied forwarding headers are discarded. Add only immediate proxies you control. Trusted chains are evaluated right-to-left, stopping at the first untrusted address.", - "forwardingCanonical": "RustProxy generates Forwarded, X-Forwarded-For, X-Real-IP, X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port and X-Forwarded-URI. Socket destination never comes from a header.", - "trustedProxies": "Trusted proxy CIDRs (one per line; /32 for one IPv4, /128 for one IPv6)", - "trustForwardedProto": "Trust X-Forwarded-Proto only from trusted proxies", - "listenerId": "Listener ID", - "cache": "Cache", - "cacheTitle": "Cache, explained.", - "cacheDescription": "Objects, domain effectiveness and precise decisions.", - "cacheRefresh": "Refresh", - "cacheLive": "Live (3 s)", - "cachePurgeScope": "Purge selected scope", - "cacheObjectCount": "Resident objects", - "cacheSaved": "Body bytes served from RAM", - "cacheCounterScope": "Domain counters since configuration revision", - "cacheDomains": "Domains and effectiveness", - "cacheScopeHint": "Memory limits, fills and evictions are global. Domain counters reset on configuration publication; purging objects does not reset counters.", - "cacheDomain": "Domain", - "cacheReasons": "Decision counters", - "cacheNoDomains": "No cache decisions yet. Send traffic to a configured host.", - "cacheObjectList": "Stored objects", - "cachePrevious": "Previous", - "cacheNext": "Next", - "cacheObjectHint": "Most recently used first. Click Target or Cache key / tags to copy the full value. Bodies and request headers are not exposed.", - "cachePath": "Path", - "cacheBodySize": "Body", - "cacheAge": "Age", - "cacheTtlRemaining": "Remaining TTL", - "cacheNoObjects": "No fresh objects in this scope. Inspect the decision counters above.", - "cacheLegacy": "Unassigned", - "cacheGlobalLimit": "Global limit", - "cacheFills": "Active fills (global)", - "cacheRejected": "Rejected fills (global)", - "cacheUpdated": "Updated", - "acmeTitle": "Let's Encrypt / ACME", - "acmeHelp": "Issue an ACME certificate, add it to the library, then assign it to a vhost. Automatic renewal starts after import.", - "acmeEmail": "ACME contact email", - "acmeDomains": "DNS names, comma-separated (wildcards only with DNS-01)", - "acmeEnvironment": "CA environment", - "acmeStaging": "Staging - not browser-trusted", - "acmeProduction": "Production", - "acmeDnsServer": "DNS update server IP", - "acmeDnsPort": "DNS update port", - "acmeKeyName": "TSIG key name", - "acmeSecret": "TSIG secret (base64)", - "acmeAlgorithm": "TSIG algorithm", - "acmePropagation": "DNS propagation wait (seconds)", - "acmeSignQuery": "Sign SOA discovery query", - "acmeTos": "I accept the Let's Encrypt subscriber agreement and authorize domain validation.", - "acmeConfirmProduction": "I confirm production issuance (CA rate limits apply).", - "acmeIssue": "Request certificate", - "acmeIdle": "No issuance job in this process.", - "acmeImport": "Add issued certificate to library", - "acmeRenewalHint": "Initial issuance/import remains explicit. Managed certificate profiles are then checked automatically while RustProxy is running; saved renewal status is restored from SQLite after restart.", - "acmeReplace": "Replace the existing library certificate? Current vhost assignments will be retained and revalidated.", - "acmeImported": "Certificate saved. Assign it in the vhost SSL tab.", - "certFuture": "Managed automatic renewal is available for supported ACME providers; saved renewal observations are persisted in SQLite.", - "cacheReason_cache_hit": "Fresh object reused", - "cacheReason_cache_miss": "No matching fresh object", - "cacheReason_cache_disabled": "Cache disabled", - "cacheReason_route_disabled": "Route bypass", - "cacheReason_request_cookie": "Application cookie", - "cacheReason_request_authorization": "Authorization header", - "cacheReason_request_cache_control": "Client cache directive / hard refresh", - "cacheReason_request_pragma": "Client Pragma", - "cacheReason_request_method": "Method other than GET", - "cacheReason_request_body": "Nonempty request body", - "cacheReason_request_range": "Range request", - "cacheReason_request_conditional": "Conditional request", - "cacheReason_request_upgrade": "Protocol upgrade", - "cacheReason_query_excluded": "Query excluded", - "cacheReason_path_excluded": "Path excluded", - "cacheReason_request_cache_control_invalid": "Invalid request cache directives", - "cacheReason_response_status": "Non-200 response", - "cacheReason_response_set_cookie": "Origin Set-Cookie", - "cacheReason_response_cache_control": "Origin privacy/cache directive", - "cacheReason_response_cache_control_invalid": "Invalid origin cache directives", - "cacheReason_response_vary": "Uncacheable Vary", - "cacheReason_response_range": "Partial response", - "cacheReason_response_trailers": "Response trailers", - "cacheReason_response_ttl_size_or_metadata": "TTL, size or metadata rejected", - "cacheReason_response_headers_policy": "Response rule prevents storage", - "cacheReason_configuration_changed": "Configuration changed", - "cacheReason_not_proxy_response": "Local page / rejected request", - "cacheReason_tinyauth": "Tinyauth protected content", - "cacheReason_sticky_cookie": "Sticky-session cookie mode", - "acme.working": "Certificate request is running.", - "acme.ready_to_import": "Certificate validated; ready to add to the library.", - "acme.certbot_not_installed": "Certbot is not installed or is not in the service PATH. Install Certbot and certbot-dns-rfc2136.", - "acme.certbot_failed_check_private_log": "Certbot failed. Check the private ACME logs; the exact path is shown with the failed operation.", - "acme.production_confirmation": "Explicit production confirmation is required.", - "acme.consent_required": "Accept the subscriber agreement and confirm the selected CA environment.", - "acme.provider_timeout": "Certificate provider deadline exceeded. Check the Certbot log path shown with the failed operation before retrying.", - "acme.invalid_key_secret": "TSIG secret must be valid base64 (16-512 decoded bytes).", - "acme.job_busy": "Another certificate request is already running.", - "acme.cancelled": "Certificate job cancelled on shutdown.", - "acme.certificate_validation_failed": "Issued certificate/key or domain coverage validation failed. Nothing was activated.", - "acme.invalid_request": "ACME: invalid request.", - "acme.unknown_field": "ACME: unknown field.", - "acme.invalid_id": "ACME: invalid id.", - "acme.invalid_email": "ACME: invalid email.", - "acme.invalid_domains": "ACME: invalid domains.", - "acme.invalid_domain": "ACME: invalid domain.", - "acme.dns_names_only": "ACME: dns names only.", - "acme.invalid_environment": "ACME: invalid environment.", - "acme.tos_required": "ACME: tos required.", - "acme.invalid_dns_server": "ACME: invalid dns server.", - "acme.invalid_limits": "ACME: invalid limits.", - "acme.invalid_key_algorithm": "ACME: invalid key algorithm.", - "acme.invalid_sign_query": "ACME: invalid sign query.", - "acme.unsafe_directory": "ACME: unsafe directory.", - "acme.unsafe_output_path": "ACME: unsafe output path.", - "acme.invalid_pem_size": "ACME: invalid pem size.", - "acme.invalid_pem": "ACME: invalid pem.", - "acme.profile_limit": "ACME: profile limit.", - "acme.profile_busy": "ACME: profile busy.", - "acme.staging_limit": "ACME: staging limit.", - "acme.request_too_large": "ACME: request too large.", - "acme.local_io_or_json_error": "ACME: local io or json error.", - "acme.no_certificate_directory": "ACME: no certificate directory.", - "acme.python_not_available": "ACME: python not available.", - "acme.worker_io": "ACME: worker io.", - "acme.invalid_worker_response": "ACME: invalid worker response.", - "acme.worker_failed": "ACME: worker failed.", - "acme.validation_worker_failed": "ACME: validation worker failed.", - "cacheResidentLabel": "Cache memory", - "certificateFuture": "ACME providers: HTTP-01, Cloudflare, OVH and RFC2136. Renewal is manual.", - "prometheusTitle": "Prometheus", - "prometheusHelp": "A dedicated read-only HTTP listener, separate from admin sessions. Binding, enabling or changing the token variable requires a restart; CIDRs, path and collectors apply live.", - "prometheusEnable": "Enable the scrape endpoint", - "prometheusListen": "Exporter bind IP and port", - "prometheusPath": "Metrics path", - "prometheusCidrs": "Allowed scraper IPs (CIDR, one per line)", - "prometheusTokenEnv": "Environment variable holding the bearer token (optional on loopback)", - "prometheusTokenHelp": "Enter a variable NAME, not the secret. Set its value to a random 32+ character token in the service environment. Non-loopback binding requires it. This endpoint is HTTP: use a private network or a TLS tunnel. The Prometheus credential file must contain the same token.", - "prometheusCollectors": "Metric groups", - "prometheusPreview": "Preview current metrics", - "prometheusPreviewFailed": "Could not fetch metrics", - "prometheusActive": "Active endpoint", - "prometheusDisabled": "Exporter disabled. Authenticated preview remains available.", - "certificateProvider": "Certificate source / validation method", - "providerHttp01": "Let's Encrypt - domain validation (HTTP-01)", - "providerCloudflare": "Let's Encrypt - Cloudflare API (DNS-01)", - "providerOvh": "Let's Encrypt - OVH API (DNS-01)", - "providerRfc2136": "Let's Encrypt - RFC2136 / TSIG (DNS-01)", - "providerImport": "Import certificate and private key (PEM)", - "providerExisting": "Existing server files (advanced)", - "providerHint_http01": "Requires Certbot. Every domain must resolve to this proxy and be reachable on public TCP port 80. RustProxy serves the challenge without stopping HTTP traffic. Wildcards need DNS-01. Staging certificates are not browser-trusted; automatic renewal is not installed.", - "providerHint_cloudflare": "Requires Certbot + certbot-dns-cloudflare. Use a restricted API token with Zone:DNS:Edit for the necessary zones only. Supports wildcard certificates. Secrets stay in private server files.", - "providerHint_ovh": "Requires Certbot + certbot-dns-ovh. Supply application key, application secret and consumer key authorized for the required DNS zones. Supports wildcard certificates.", - "providerHint_rfc2136": "Requires Certbot + certbot-dns-rfc2136 and a DNS server accepting signed RFC2136 updates. Limit the TSIG key to the required challenge records.", - "providerHint_import": "Upload a matching PEM/fullchain and private key. Save in the library, then assign the certificate in a vhost SSL tab.", - "providerHint_existing": "Advanced: only existing private files inside the configured certificate directory. Never put private key contents in JSON.", - "acmeCfToken": "Cloudflare API token", - "acmeOvhEndpoint": "OVH API region", - "acmeOvhApplicationKey": "OVH application key", - "acmeOvhApplicationSecret": "OVH application secret", - "acmeOvhConsumerKey": "OVH consumer key", - "acme.invalid_provider": "Select a supported certificate provider.", - "acme.invalid_api_credential": "API credential is missing or has invalid characters.", - "acme.invalid_ovh_endpoint": "Select OVH Europe or Canada.", - "acme.http01_no_wildcard": "HTTP-01 cannot issue wildcard names. Select a DNS-01 provider.", - "acme.http01_listener_required": "HTTP-01 needs an active plaintext HTTP listener reachable on public port 80.", - "cacheScopeLegacy": "Unassigned / old scope", - "certificateLibrary": "Certificates", - "certificateWorkspaceHelp": "Manage installed certificates, automatic renewal, and generation/import in separate views.", - "certificateTabInstalled": "Installed", - "certificateTabRenewal": "Renewal", - "certificateTabGenerate": "Generate", - "certificateInstalledTitle": "Installed certificates", - "certificateInstalledHelp": "Certificates available to vhosts, redirects, 404 hosts, and the administration listener.", - "certificateGenerateTitle": "Generate and import", - "certificateGenerateHelp": "Choose Let's Encrypt/ACME issuance, PEM upload, or existing files from RustProxy's private certificate directory.", - "certificateOperationStatus": "Latest ACME operation", - "certificateNoRenewalOperation": "No renewal operation in this process.", - "certificateStateIdle": "Idle", - "certificateStateRunning": "Running", - "certificateStateReady": "Ready", - "certificateStateComplete": "Complete", - "certificateStateFailed": "Failed", - "certbotLogs": "Certbot logs", - "systemDiagnostics": "System / process", - "vhWebsockets": "WebSocket support", - "vhLocations": "Custom locations", - "locationPath": "Location prefix", - "locationPool": "Vhost backends", - "locationMissing": "Missing backend", - "locationLimit": "A host supports up to 64 locations.", - "locationAccess": "Location access control", - "locationHeaders": "Location headers", - "locationAddBackend": "Add dedicated backend", - "locationAdd": "Add location", - "locationHelp": "The longest matching prefix wins. The original path and query are retained. Select a backend from this host or add a dedicated backend. Host authentication and ACL always apply.", - "aclUse": "Enable IP access list", - "aclAllow": "Allow", - "aclNetwork": "IP network (CIDR)", - "aclAction": "Action", - "aclAdd": "Add IP rule", - "authMode": "Authentication", - "authNone": "None", - "authTinyauth": "Tinyauth", - "authBasic": "HTTP Basic Auth", - "basicRealm": "Realm (login prompt)", - "basicRequireTls": "Require HTTPS for Basic Auth", - "basicForward": "Forward verified Authorization to backend", - "basicPassword": "Password (12-128 bytes)", - "basicKeepPassword": "Leave empty to keep the password", - "basicHashSaved": "Password set", - "basicHashRequired": "Set a password for each user.", - "basicAddUser": "Add user", - "basicHelp": "Only Argon2id hashes are stored. Verified credentials are removed from upstream requests unless forwarding is enabled. Enable forwarding only to a trusted HTTPS backend or an isolated network. Protected hosts bypass shared cache.", - "basic.too_many_users": "At most 64 users per host.", - "basic.invalid_username": "Invalid username.", - "basic.duplicate_username": "Duplicate username.", - "basic.unsupported_hash": "Use an Argon2id password hash generated by RustProxy.", - "basic.invalid_hash": "Invalid password hash.", - "basic.invalid_realm": "Invalid login realm.", - "basic.users_required": "Basic Auth requires at least one user.", - "basic.busy": "Password workers are busy; try again.", - "renewalTitle": "Automatic renewal", - "renewalHelp": "Managed ACME certificates are checked about every 12 hours while RustProxy is running. Certbot decides when renewal is due. Validated replacements are deployed without restarting listeners. Keep provider credentials and HTTP-01 port 80 available.", - "renewalNone": "No managed ACME certificates in the library.", - "renewalEnabled": "Automatic renewal enabled", - "renewalDisabled": "Automatic renewal disabled", - "renewalEnable": "Enable automatic renewal", - "renewalDisable": "Disable automatic renewal", - "renewalNow": "Check now", - "renewalDryRun": "Validate renewal (dry run)", - "renewalLast": "Last check", - "renewalNext": "Next check", - "renewalExpires": "Valid until", - "acme.renewing": "Checking certificate renewal", - "acme.renewed": "Certificate renewed and deployed", - "acme.not_due": "Certificate does not need renewal yet", - "acme.renewal_test_ok": "Renewal validation passed; active certificate unchanged", - "acme.renewal_profile_missing": "Saved renewal profile is missing or unreadable. Restore the private ACME profile.", - "acme.configuration_changed": "Certificate configuration changed during renewal; nothing deployed.", - "acme.deployment_failed": "Renewed certificate failed configuration validation; previous certificate remains active.", - "acme.not_managed": "Only managed ACME certificates can be renewed automatically.", - "acme.certificate_not_found": "Certificate no longer exists.", - "acme.renewal_disabled": "Automatic renewal is disabled.", - "acme.openssl_not_installed": "OpenSSL is required to inspect certificate validity.", - "cacheReason_basic_auth": "HTTP Basic authentication", - "locationPoolEligible": "Include in the default load-balancing pool", - "locationId": "Location ID", - "vhIpAccess": "Vhost IP access list", - "apiDocs": "Documentation", - "auth.invalid_request": "Invalid request. Check the supplied fields.", - "locationProxyHeaders": "Proxy request headers (to backend)", - "locationResponseHeaders": "Response headers (to client)", - "locationHeadersHelp": "Set replaces a header, append adds a value, remove deletes it. Applied after global and vhost rules, only for this location. Values are literal (no nginx variables). Transport and verified identity headers stay system-managed.", - "headersAdvancedJson": "Advanced header rules (JSON)", - "headersInvalid": "Invalid header rule. Check name, operation and value.", - "headersProtected": "Transport and proxy identity headers cannot be overridden here. Use forwarding, authentication or response settings.", - "docsTitle": "Documentation", - "docsSession": "Uses your administrator session. API writes require CSRF protection.", - "docsSignIn": "Sign in to view documentation", - "docsPanel": "Back to panel", - "docsWrites": "Enable write operations", - "docsWriteConfirm": "This sends a real change to RustProxy. Continue?", - "docsExpired": "Session ended. Sign in again.", - "docsError": "Documentation could not be loaded.", - "docsAccount": "Signed in as", - "docsReadOnly": "Read-only execution by default. SSE streams and login/setup are not executed here.", - "docsLogout": "Sign out", - "authPrivateNote": "Access is restricted to authorized administrators.", - "advanced": "Advanced", - "docsLicenses": "Swagger UI licenses", - "vhTrafficPolicy": "Traffic policy", - "vhHttp3Enabled": "Enable HTTP/3 for this vhost", - "vhCloudflareClientIp": "Use verified Cloudflare client IP", - "vhTimingHeaders": "Expose Server-Timing diagnostics", - "vhRateEnabled": "Enable per-client IP rate limit", - "vhRateRequests": "Requests per window", - "vhRateWindow": "Window (seconds)", - "vhRateBurst": "Burst allowance", - "vhCountryMode": "Country access policy", - "vhCountryBlock": "Block listed countries", - "vhCountryAllow": "Allow only listed countries", - "vhCountryList": "Countries (ISO 3166-1 alpha-2)", - "vhCountryPolicyHelp": "Country rules use the installed GeoIP database. Allow-only mode fails closed when a client country cannot be resolved.", - "vhCountry": "Country", - "vhAddCountryRate": "Add country rate limit", - "vhCountryRateLimit": "At most 64 country-specific rate limits are allowed.", - "vhRateHelp": "Country-specific limits override the base per-IP limit. Exceeded limits return 429; denied countries return 403.", - "vhHealthOffWarning": "Active backend probes are disabled. Passive Backend Health is configured separately and remains off unless explicitly enabled.", - "vhFrontendSelectionOnly": "Select named listeners for this vhost. Listener IP addresses, ports and H2/H3 capabilities are configured only in Settings > Listeners.", - "vhForceSsl": "Force SSL (redirect HTTP to HTTPS)", - "vhForceSslHelp": "Plain HTTP requests for this vhost receive a 308 redirect to HTTPS while preserving path and query. Select at least one plain HTTP listener and at least one TLS listener. If several TLS ports are selected, port 443 is used; otherwise the TLS target port must be unambiguous.", - "vhForceSslNeedsTls": "Force SSL requires at least one enabled TLS listener for this vhost.", - "vhForceSslPortConflict": "Force SSL cannot choose the HTTPS redirect target because selected TLS listeners use multiple non-standard ports. Select one TLS port or include port 443.", - "vhForwardClientIp": "Forward client IP to backend", - "vhForwardClientIpHelp": "Keep enabled for normal reverse-proxy behavior. Disable to withhold Forwarded, X-Forwarded-For and X-Real-IP from the application while RustProxy, ACLs, rate limits and Tinyauth still use the real client IP.", - "vhClientIpHidden": "Client IP hidden from backend", - "listenerMigrateInline": "Existing vhost listener (will migrate)", - "vhDebugOriginPreset": "Apply recommended preset", - "vhDebugOriginTlsWarning": "This preset keeps backend TLS certificate verification disabled. The connection is encrypted, but CA and hostname identity are not checked. Continue?", - "vhOriginPresetHelp": "Debug origin defaults for new backend rows: HTTPS by IP, default LB pool ON, private origin ON, HTTP/1.1, Preserve client Host ON and TLS verification OFF. Re-enable TLS verification whenever the origin certificate can be validated.", - "vhDebugOriginMismatch": "This HTTPS-by-IP origin does not match the debug forwarding preset (pool ON, private origin ON, HTTP/1.1, preserve Host ON, TLS verification OFF). If you enable verification, set TLS server name to the certificate DNS name and add its private CA when needed. Continue with the current values?", - "vhCacheStaticCookie": "Ignore request cookies for selected static file extensions", - "vhCacheStaticCustom": "Use a custom static extension list", - "vhCacheStaticExtensions": "Static extensions (one per line, without dot)", - "vhCacheStaticHelp": "Inherit the global policy or override it for this vhost. Ignore Cookie only for files whose bytes do not depend on the session; Set-Cookie, private/no-store and Vary: Cookie still block shared storage.", - "cacheStaticTitle": "Static asset cache boost", - "cacheStaticCookie": "Ignore request cookies for static files", - "cacheStaticExtensions": "Global static extensions (one per line, without dot)", - "cacheStaticHelp": "Enable this only for files whose bytes do not depend on the session. Request Cookie then does not affect the shared cache key for these extensions; responses with Set-Cookie, private/no-store or Vary: Cookie are still never stored.", - "vhHttp2Enabled": "Enable HTTP/2 for this vhost", - "vhFrontendProtocolsHelp": "H2 and H3 are per-vhost opt-outs. A switch is available only when at least one selected listener has that protocol enabled in Settings > Listeners.", - "administration": "Administration", - "administrationActiveHttp": "Active HTTP administration", - "administrationActiveHttps": "Active HTTPS administration", - "administrationCertificate": "Certificate", - "administrationGeneratedCertificate": "Application-generated default certificate", - "administrationHelp": "HTTPS allows the administration listener to bind beyond loopback. Plain HTTP on the HTTPS port is redirected automatically. Listener and certificate changes take effect after restart.", - "administrationHosts": "Allowed DNS hostnames (optional strict allowlist)", - "administrationHttps": "Enable HTTPS for administration", - "administrationListen": "Listen address", - "cacheOverhead": "Overhead", - "cacheResidentAge": "X-Cache-Resident-Age", - "controlPlane": "CONTROL PLANE", - "logging": "Logging", - "loggingTitle": "Structured access logging", - "loggingTabOutputs": "Outputs", - "loggingTabFormat": "JSON format", - "loggingTabErrors": "Error log", - "loggingDescription": "Write configurable JSON access logs to a file, Logstash or Loki.", - "loggingHelp": "Live log viewing stays in memory. External sinks use a bounded background queue and do not block request I/O.", - "loggingFile": "JSON file", - "loggingPath": "File path", - "loggingAddress": "TCP address", - "loggingTokenEnv": "Bearer token environment variable", - "loggingLabels": "Labels (JSON object)", - "loggingFormat": "Configurable JSON format", - "loggingFormatHelp": "Map output names to source fields. Leave mapping empty for the complete standard entry.", - "loggingFields": "Field mapping (JSON object)", - "loggingStatic": "Static fields (JSON object)", - "loggingJsonInvalid": "Logging JSON fields must contain valid JSON objects.", - "loggingQueue": "Sink queue", - "loggingDropped": "dropped", - "loggingSent": "sent", - "loggingCapacity": "capacity", - "errorLogTitle": "Error file", - "errorLogPath": "Error log path", - "errorLogFormat": "Format", - "tls12": "TLS 1.2", - "tls13": "TLS 1.3", - "tlsPolicy": "TLS policy", - "tlsPolicyHelp": "This is the global TLS policy inherited by every TLS host in the application. Per-vhost policy may only narrow it. HTTP/3 requires TLS 1.3.", - "tlsCiphers": "Cipher suites (one per line; empty = rustls defaults)", - "tlsAvailableCiphers": "Available cipher suites", - "tlsPolicyVersionRequired": "Enable at least one TLS version.", - "vhTlsOverride": "Override global TLS policy", - "vhTlsOverrideHelp": "Use only when this vhost needs different TLS versions or cipher suites. Empty cipher list keeps rustls defaults.", - "vhTlsHttp3Conflict": "HTTP/3 uses the global TLS policy. Disable HTTP/3 on this vhost before using a different TLS override.", - "vhListeners": "Listeners", - "vhProtocols": "Protocols", - "loggingMode": "JSON / ASYNC / BOUNDED", - "loggingPushUrl": "Push URL", - "cacheHotObjects": "Hot objects", - "cacheHotMemory": "Hot memory", - "cacheColdObjects": "Cold objects", - "cacheColdDisk": "Cold disk", - "cacheTierMoves": "Tier moves", - "cacheColdHits": "cold hits", - "cacheTier": "Tier", - "cacheStorage": "Memory / disk", - "cacheColdTitle": "Persistent cold cache", - "cacheColdEnable": "Enable persistent disk tier", - "cacheColdHelp": "Choose what is moved from hot RAM to persistent disk. Cold hits are read asynchronously and promoted back to RAM. Metadata is readable JSON; bodies are raw .body files.", - "cacheColdPath": "Cold path (inside data directory)", - "cacheColdBytes": "Cold disk budget (MiB)", - "cacheColdEntries": "Cold object limit", - "cacheColdAfter": "Demote after idle seconds", - "cacheHot": "Hot", - "cacheCold": "Cold", - "cacheReason_request_no_cache": "Client no-cache / hard reload requires validation", - "cacheReason_request_max_age": "Client max-age requires validation", - "cacheReason_request_min_fresh": "Client min-fresh requires validation", - "cacheReason_request_pragma_no_cache": "Client Pragma no-cache / legacy hard reload", - "cacheReason_cache_revalidated": "Stored object validated by origin", - "cacheReason_cache_conditional_hit": "Fresh object satisfied a conditional request", - "cacheReason_request_no_store": "Client no-store bypass", - "cacheReason_request_precondition": "Client precondition requires origin", - "loggingPreset": "Format preset", - "loggingPresetCustom": "Custom", - "loggingPresetStandard": "RustProxy standard", - "loggingPresetNginx": "Nginx-style JSON", - "loggingPresetEcs": "ECS-style field names", - "loggingPresetMinimal": "Minimal", - "loggingBuilder": "Visual field builder", - "loggingBuilderOpen": "Configure fields", - "loggingAdvancedJson": "Advanced JSON mapping", - "loggingBuilderHelp": "Select source fields and optionally rename their JSON keys. Applying the visual editor normalizes each source field to at most one output key; use advanced JSON for duplicate aliases.", - "loggingSourceField": "Source field", - "loggingOutputField": "Output JSON key", - "loggingPreview": "Preview", - "loggingOutputRequired": "Every enabled log field needs an output JSON key.", - "loggingOutputDuplicate": "Output JSON keys must be unique.", - "aclProfiles": "ACL profiles", - "acl-profiles": "ACL profiles", - "acl-profilesTitle": "Reusable ACL profiles", - "acl-profilesDescription": "Define reusable IP and country access rules, then attach them to one or more virtual hosts.", - "aclProfilesIntro": "Reusable access profiles can be attached to multiple vhosts. Per-vhost ACL and country rules remain active and are enforced together with the profile.", - "aclProfilesReusable": "REUSABLE POLICY", - "aclProfileNew": "New profile", - "aclProfileEdit": "Editing profile", - "aclProfileEditor": "Profile configuration", - "aclProfileId": "Profile ID", - "aclProfileName": "Display name", - "aclProfileIpEnabled": "Enable IP ACL", - "aclProfileRules": "IP rules — one “allow|deny CIDR” per line", - "aclProfileCombineHelp": "Profile and vhost rules are restrictive: a request must pass both policies.", - "aclProfileIpRulesShort": "IP rules", - "aclProfileIpOff": "IP ACL disabled", - "aclProfileCountriesOff": "Country filtering disabled", - "aclProfileAttached": "Attached to", - "aclProfileInUse": "Profile is attached to vhosts", - "aclProfilesEmpty": "No reusable ACL profiles yet.", - "aclProfileCountryInvalid": "Country codes must use two-letter ISO codes.", - "aclProfileDuplicate": "An ACL profile with this ID already exists.", - "vhAclProfile": "ACL profile", - "vhAclProfileNone": "No reusable profile", - "vhAclProfileHelp": "Optional reusable profile. Inline vhost ACL and country rules below are still enforced in addition to the profile.", - "vhHostAdd": "Add hostname", - "vhHostsHelp": "Press Enter or comma to add a hostname. Wildcards are supported only as a leading *. (for example *.example.com). Exact hosts take priority over wildcard matches.", - "vhHostInvalid": "Invalid hostname or wildcard pattern.", - "vhHostRequired": "Add at least one hostname.", - "vhLifetimeChart": "Lifetime request rate", - "vhReqPerSecond": "req/s", - "vhPeak": "peak", - "listenerAddresses": "Bind addresses", - "listenerAddressesInvalid": "Provide 1–16 unique listener addresses.", - "listenerAddressesExplicit": "When a listener uses multiple addresses, select explicit IPs; 0.0.0.0 and :: are not allowed.", - "ruleSyntaxLine": "Invalid ACL rule on line", - "vhForceSslNeedsHttp": "Force SSL needs at least one selected plain HTTP (non-TLS) listener. A listener named “HTTP” may still be configured as TLS in Settings > Listeners.", - "aclProfileRuleBuilder": "IP rules", - "aclProfileBulkRules": "Paste / import rules", - "aclProfileBulkHelp": "Paste one “allow|deny CIDR” rule per line. Invisible Unicode spacing is normalized during import and errors identify the exact line.", - "aclProfileImportRules": "Import rules", - "aclProfileRulesImported": "ACL rules imported into the visual editor.", - "streamHosts": "Stream hosts", - "streamsHelp": "Raw TCP/UDP forwarding on dedicated ports. Stream traffic bypasses HTTP vhosts, ACL, cache, headers and compression.", - "streamAdd": "Add stream host", - "saveStreams": "Save stream hosts", - "streamRestartHelp": "Changing a stream listener requires a RustProxy restart.", - "streamRestartPending": "Saved stream changes are pending. Restart RustProxy to apply them.", - "streamActive": "Currently active streams", - "streamNone": "No stream hosts active", - "streamEndpoint": "Stream endpoint", - "streamId": "Stream ID", - "streamName": "Display name", - "streamProtocol": "Protocol", - "streamListen": "Listen address", - "streamUpstream": "Upstream address", - "streamConnectTimeout": "TCP connect timeout (seconds)", - "streamIdleTimeout": "Idle/session timeout (seconds)", - "streamMaxConnections": "Max connections/sessions", - "streamTcp": "TCP", - "streamUdp": "UDP", - "streamLimit": "At most 128 stream hosts are supported.", - "streamDuplicate": "Stream host IDs must be unique.", - "streams": "Streams", - "streamsTitle": "TCP / UDP streams", - "streamsDescription": "Manage raw Layer-4 listeners, upstreams and live traffic telemetry.", - "streamsPageIntro": "TCP/UDP streams are independent Layer-4 proxies. Each stream owns a dedicated listener and upstream and bypasses the HTTP vhost, ACL and cache stack.", - "streamLayer4": "LAYER 4 / TCP + UDP", - "streamList": "Streams", - "streamSearch": "Search streams", - "streamSearchPlaceholder": "ID, name, listener or upstream…", - "streamSearchEmpty": "No streams match this search.", - "streamEmpty": "No TCP/UDP streams yet. Add a listener to start forwarding Layer-4 traffic.", - "streamNew": "New stream", - "streamAddListener": "Add TCP/UDP listener", - "streamEditor": "Stream configuration", - "streamEditLabel": "EDITING", - "streamNewLabel": "NEW", - "streamDetailsTab": "Details", - "streamNetworkTab": "Listener & upstream", - "streamLimitsTab": "Limits", - "streamNetwork": "Listener & upstream", - "streamLimits": "Connection / session limits", - "streamDedicatedListenerHelp": "A stream listener is created together with the stream and is separate from HTTP/HTTPS listeners.", - "streamLimitsHelp": "Limits apply to concurrent TCP connections or per-client UDP sessions. TCP connect timeout is not used by UDP.", - "streamListenAdd": "Add listen address", - "streamListenHelp": "Enter one IP:port listener address and press Enter. Listener changes become active after RustProxy restarts.", - "streamListenInvalid": "The listener address must be one IP:port value without spaces or commas.", - "streamListenRequired": "Add a listener address.", - "streamDelete": "Delete this stream? The active listener remains until RustProxy restarts.", - "streamPendingRestart": "Pending restart", - "streamRunning": "Running", - "streamActiveSessions": "Active connections / sessions", - "streamSessionsTotal": "Connections / sessions", - "streamErrors": "Errors", - "streamRejected": "Rejected", - "streamTransferred": "Transferred", - "streamTrafficChart": "Live traffic rate", - "streamClientToUpstream": "client → upstream", - "streamUpstreamToClient": "upstream → client", - "streamNoLiveMetrics": "No live metrics until this stream is active after restart.", - "streamIdleShort": "Idle timeout", - "listenerAddressAdd": "Add bind address", - "listenerAddressesHelp": "Press Enter or comma to add a bind address. Multiple addresses use the same listener policy; wildcard 0.0.0.0/:: cannot be mixed with explicit addresses.", - "cacheColdOnIdle": "Move old/idle objects to cold storage", - "cacheColdOnLru": "Move hot LRU evictions to cold storage", - "cacheColdOnShutdown": "Flush hot cache to cold storage during graceful shutdown", - "certificateCovers": "Certificate domains", - "certificateCoverageUnknown": "Domain data (DNS SAN) is unavailable. Reload certificate files or import the certificate again.", - "certificateDetails": "Certificate details", - "certificateFiles": "Certificate / key files", - "redirects": "Redirects", - "redirectsTitle": "Redirect with intent.", - "redirectsDescription": "Local redirect hosts with explicit match, target, status, path and query behavior.", - "redirectsPageIntro": "Redirect hosts answer locally without opening an upstream connection. Rules can match scheme and path, then redirect to a URL, another host or a path.", - "redirectLayer": "HTTP REDIRECTION", - "redirectList": "Redirect hosts", - "redirectSearch": "Search redirects", - "redirectSearchPlaceholder": "ID, hostname, target…", - "redirectNew": "New redirect", - "redirectEmpty": "No redirect hosts configured.", - "redirectSearchEmpty": "No redirects match this search.", - "redirectEditor": "Redirect configuration", - "redirectId": "Redirect ID", - "redirectName": "Display name", - "redirectHosts": "Source hostnames", - "redirectFrontend": "FRONTEND", - "redirectListeners": "Listeners", - "redirectBehavior": "BEHAVIOR", - "redirectRules": "Rules", - "redirectAddRule": "Add rule", - "redirectRulesHelp": "Longest matching path wins. 307/308 preserve the request method; 301/302/303 may change it in clients.", - "redirectSafetyHint": "Redirect hosts do not contact a backend. Global host ACLs still apply. Avoid self-referential rules that can create browser redirect loops.", - "redirectRule": "Rule", - "redirectRuleId": "Rule ID", - "redirectSourceScheme": "Incoming scheme", - "redirectSchemeAny": "HTTP or HTTPS", - "redirectSchemeHttp": "HTTP", - "redirectSchemeHttps": "HTTPS", - "redirectSchemePreserve": "Preserve incoming scheme", - "redirectMatchType": "Path match", - "redirectMatchPrefix": "Prefix", - "redirectMatchExact": "Exact", - "redirectSourcePath": "Source path", - "redirectTargetType": "Target type", - "redirectTargetUrl": "Absolute URL", - "redirectTargetHost": "Host / application", - "redirectTargetPath": "Path on the same host", - "redirectTarget": "Target", - "redirectTargetScheme": "Target scheme", - "redirectPathMode": "Path handling", - "redirectPathAppend": "Append full source path", - "redirectPathStrip": "Strip matched prefix and append remainder", - "redirectPathReplace": "Use configured target path only", - "redirectQueryMode": "Query handling", - "redirectQueryPreserve": "Preserve source query", - "redirectQueryDrop": "Drop source query", - "redirectStatus": "HTTP status", - "redirect301": "301 Moved Permanently", - "redirect302": "302 Found", - "redirect303": "303 See Other", - "redirect307": "307 Temporary Redirect (preserve method)", - "redirect308": "308 Permanent Redirect (preserve method)", - "redirectCacheSeconds": "Browser/shared cache max-age (seconds; 0 = no-store)", - "redirectHostsRequired": "Add at least one source hostname.", - "redirectListenersRequired": "Select at least one listener.", - "redirectRulesRequired": "Add at least one redirect rule.", - "redirectDuplicate": "A redirect with this ID already exists.", - "redirectUnsaved": "Discard unsaved redirect changes?", - "redirectNewLabel": "NEW", - "administrationSessionDays": "Administrator session lifetime (days)", - "administrationSessionDaysHelp": "Browser sessions use an absolute 7–30 day lifetime. Changing this value applies immediately; password changes and “revoke all sessions” still invalidate sessions at once.", - "vhLocalListenerRisk": "Allow local RustProxy listener as backend (risk)", - "vhLocalListenerRiskHelp": "Shown when the backend URL directly targets the configured or active RustProxy administration listener. localhost, 127.0.0.1 and ::1 are treated as equivalent loopback forms on the same administration port. Enabling it can expose the control plane or create a proxy loop; private/loopback targets still require “Allow private origin IP”.", - "vhLocalListenerRiskConfirm": "This can route requests into a local RustProxy listener, including the administration port, and may create a loop or expose the control plane. Accept this risk?", - "cacheResidentHistory": "Resident RAM history", - "networkHistory": "RX / TX history", - "responseLatencyHistory": "Response time history", - "sourceIp": "Source IP", - "cacheColdOnAge": "Move objects to cold storage after a maximum hot-tier age", - "cacheColdMaxHot": "Maximum hot-tier age (seconds)", - "cacheColdPolicyHelp": "Idle time measures how long an object has not been used. Hot-tier age measures continuous residency in RAM even if the object is still requested. LRU pressure and graceful-shutdown handoff are independent policies.", - "documentation": "Documentation", - "locationPathPattern": "Path / regex pattern", - "locationMatchType": "Match type", - "locationMatchPrefix": "Prefix", - "locationMatchPriority": "Priority prefix (^~)", - "locationMatchExact": "Exact path (=)", - "locationMatchRegex": "Regex (~)", - "locationMatchRegexI": "Regex, case-insensitive (~*)", - "locationMatch_prefix": "prefix", - "locationMatch_prefix_priority": "priority prefix", - "locationMatch_exact": "exact", - "locationMatch_regex": "regex", - "locationMatch_regex_insensitive": "regex i", - "locationAction": "Action", - "locationProxyAction": "Proxy to backend", - "locationReturnAction": "Custom response (return)", - "locationProxyShort": "proxy", - "locationReturnShort": "local response", - "locationHandling": "Request handling", - "locationRewriteMode": "Backend path rewrite", - "locationRewritePreserve": "Keep original path", - "locationRewriteStrip": "Strip matched prefix", - "locationRewriteReplace": "Replace matched prefix", - "locationRewriteRegex": "Regex replacement", - "locationRewriteValue": "Replacement path / expression", - "locationRewriteHelp": "Query parameters are preserved. Prefix rewrites operate on the normalized routing path. Regex replacement supports Rust regex captures such as $1. Rewritten paths are validated before forwarding.", - "locationResponseStatus": "Response status", - "locationResponseType": "Content-Type", - "locationResponseBody": "Response body", - "headersVisualBuilder": "Visual configurator", - "locationDocsTitle": "Custom locations documentation", - "headersDocsTitle": "Header rules documentation", - "locationDocsIntro": "Custom locations are evaluated inside the selected vhost after host authentication and ACL. They never bypass vhost security.", - "locationDocsPrefix": "Prefix: matches a complete path segment prefix. The longest prefix wins. Priority prefix behaves like nginx ^~ and prevents regex locations from taking precedence.", - "locationDocsExact": "Exact: matches only the exact normalized path, like nginx location = /path.", - "locationDocsRegex": "Regex: first matching regex wins after exact/priority-prefix processing. Case-sensitive and case-insensitive modes are supported. Rust regex syntax is used; look-around/backreferences in the pattern are intentionally unsupported.", - "locationDocsReturn": "Custom response: answer locally with a chosen HTTP status, Content-Type and body without opening a backend connection. Location response-header rules still apply.", - "locationDocsRewrite": "Backend path rewrite: keep the original target, strip/replace a matched prefix, or use regex capture replacement. The original query string is preserved.", - "locationDocsAccess": "Per-location IP ACL, cache override and request/response header rules are composed with the vhost policy. A location cannot disable host authentication or host ACL.", - "locationDocsLimits": "Up to 64 locations per vhost. Regexes and response bodies are bounded; transport, forwarding identity and WebSocket protocol headers remain system-managed.", - "headersDocsIntro": "Header rules are applied in order: global → vhost → matching location. Use the visual configurator for normal changes; JSON remains an advanced escape hatch.", - "headersDocsSet": "Set: replace all existing values of a header with the configured literal value.", - "headersDocsAppend": "Append: add another value without deleting existing values.", - "headersDocsRemove": "Remove: delete the header before forwarding or before sending the response.", - "headersDocsProtected": "Protected transport/identity headers (Host, Connection, Content-Length, Forwarded/X-Forwarded-*, WebSocket proof headers and similar) cannot be overridden here.", - "headersDocsOrder": "Values are literal; nginx variables are not interpreted. Request rules run before canonical forwarding metadata is applied, and response rules run before final RustProxy security/diagnostic policy.", - "cacheColdPolicyTitle": "Hot → cold policy", - "headerRule": "Header rule", - "headerRulesEmpty": "No rules yet. Add a rule below.", - "headerRuleHelp": "Choose Set, Append or Remove. Transport, forwarding identity and WebSocket protocol headers remain protected.", - "locationPreviewTitle": "Effective behavior preview", - "locationPreviewMatch": "Matching", - "locationPreviewHandling": "Handling", - "locationPreviewRewrite": "Backend path", - "locationPreviewCache": "Cache", - "locationPreviewAccess": "Access", - "locationPreviewHeaders": "Header rules", - "locationPreviewDisabled": "This location is disabled and will not match requests.", - "locationPreviewBackendSkipped": "backend is not contacted", - "locationPreviewVhostAcl": "Vhost authentication and ACL only", - "locationPreviewCustomAcl": "Vhost policy + location ACL", - "locationPreviewRequestRules": "request", - "locationPreviewResponseRules": "response", - "locationPreviewQueryPreserved": "query string is preserved", - "locationDocsMatchHeading": "1. Matching and precedence", - "locationDocsActionHeading": "2. Proxy, rewrite and local response", - "locationDocsPolicyHeading": "3. Access, cache and headers", - "locationDocsExamplesHeading": "Common examples", - "locationDocsExampleExact": "Health endpoint: Exact (=) /health + Custom response 200 answers locally without a backend connection.", - "locationDocsExampleStatic": "Static assets: Priority prefix (^~) /static/ keeps regex locations from overriding it; cache can be enabled for this location.", - "locationDocsExampleRegex": "Versioned API: Regex (~) ^/api/v[0-9]+/ can select a backend and use regex replacement groups such as $1.", - "cacheOutcomeHistory": "HIT / MISS / BYPASS activity", - "cacheHotMemoryHistory": "HOT RAM usage / limit", - "cacheTransientMemoryHistory": "Transient RAM usage / limit", - "cacheColdStorageHistory": "COLD storage usage / limit", - "processCpuHistory": "Process CPU history", - "processRssHistory": "Process RSS history", - "cacheMemoryBreakdown": "Hot / transient cache RAM", - "cacheTransientBreakdown": "Fill / cold queue / cold I/O", - "cacheColdStorageUsage": "COLD storage / budget", - "cacheColdStorageObjects": "objects", - "cacheTransientMemory": "Transient cache RAM", - "cacheTransientShort": "TOTAL", - "cacheFillShort": "fill", - "cacheQueueShort": "cold queue", - "cacheIoShort": "cold I/O", - "processRssTotal": "RSS total", - "memoryCacheHot": "HOT cache RAM / limit", - "memoryCacheTransient": "Cache transient RAM / limit", - "memoryTransform": "Transform reserved RAM / budget", - "memoryTransformInflight": "Active transforms / limit", - "memoryNonCacheRss": "Non-cache process RSS", - "transformMemoryUsage": "Transform RAM reservation", - "transformConcurrencyUsage": "Active transform slots", - "transformBudgetShort": "budget", - "processRssAnon": "Anonymous RSS", - "processRssFile": "File-backed / shared RSS", - "processDataSwap": "Data address space / swap", - "memoryAccountingHint": "RSS is the real process footprint. HOT/transient cache values are RustProxy-accounted allocations; transform memory is a conservative active reservation. Non-cache RSS is RSS minus accounted cache and includes transforms, connections, TLS, logging, Tokio/runtime state, allocator overhead and other buffers, so these rows are not all additive.", - "memoryAccountingInfo": "Memory accounting information", - "logTransport": "Transport", - "logWebSocket": "WebSocket", - "logUpstreamError": "Upstream error", - "listenerDefaultPortsHint": "New vhosts automatically select the standard HTTP :80 listener when it is available.", - "vhBackendDiagnostics": "Backend diagnostics", - "vhBackendHeader": "Expose selected backend (X-RustProxy-Backend)", - "vhBackendTimingHeader": "Expose backend response time (X-RustProxy-Backend-Time)", - "vhBackendDiagnosticsHelp": "Opt-in response headers. Backend time measures origin request-to-response-headers latency; responses served without contacting an origin do not report a backend.", - "authModeHelp": "Choose one authentication provider. The IP access list below is independent and can be combined with either provider.", - "taAdvanced": "Advanced Tinyauth settings", - "notfound": "404 hosts", - "notfoundTitle": "404 hosts, under control.", - "notfoundDescription": "Reserve domains that should answer locally with a status, placeholder or custom HTML.", - "notfoundPageIntro": "404 hosts reserve selected domains and answer locally without contacting a backend. They can use the same listeners and certificates as vhosts.", - "notfoundLayer": "LOCAL RESPONSE", - "notfoundList": "404 hosts", - "notfoundSearch": "Search 404 hosts", - "notfoundSearchPlaceholder": "ID, name or hostname…", - "notfoundNew": "New 404 host", - "notfoundEditor": "404 host configuration", - "notfoundId": "Host ID", - "notfoundName": "Display name", - "notfoundFrontend": "FRONTEND", - "notfoundBehavior": "RESPONSE", - "notfoundResponse": "Local response", - "notfoundMode": "Response type", - "notfoundModeWelcome": "RustProxy placeholder", - "notfoundModeEmpty": "Status only / empty", - "notfoundModeHtml": "Custom HTML", - "notfoundStatus": "HTTP status", - "notfoundHtml": "Custom HTML", - "notfoundResponseHelp": "The host never opens an upstream connection. The built-in placeholder is no-store and intentionally omits optional RustProxy diagnostic/server headers.", - "notfoundHosts": "Hostnames", - "notfoundNewLabel": "NEW", - "notfoundHostsRequired": "Add at least one hostname.", - "notfoundListenersRequired": "Select at least one listener.", - "notfoundHtmlRequired": "Custom HTML cannot be blank.", - "notfound204Empty": "HTTP 204, 205 and 304 responses must use Empty mode.", - "notfoundDuplicate": "A 404 host with this ID already exists.", - "notfoundUnsaved": "Discard unsaved 404 host changes?", - "notfoundEmpty": "No 404 hosts configured.", - "notfoundSearchEmpty": "No 404 hosts match the search.", - "prometheusTrustedNoToken": "Allow token-free reads from trusted CIDRs", - "prometheusTrustedNoTokenHelp": "Clients still must match Allowed client CIDRs. Enable only on a private, trusted monitoring network; forwarded headers are never trusted for this check.", - "docker-vhosts": "Docker vhosts", - "docker-vhostsTitle": "Docker services, named.", - "docker-vhostsDescription": "Discover published Docker ports and map services to base-domain names, custom domains and aliases without copying observed state into SQLite.", - "dockerVhosts": "Docker vhosts", - "dockerVhostsIntro": "Published TCP ports discovered by configured Docker agents. Map each service to a short name under the agent base domain or to any FQDN, add aliases, choose the Docker host IP, and inspect or tune live backend health.", - "dockerDiscovery": "DOCKER DISCOVERY", - "dockerRefresh": "Refresh agents", - "dockerAgentsSettings": "Docker agents settings", - "dockerAgents": "Docker agents", - "dockerDesiredState": "DESIRED STATE / SQLITE", - "dockerAgentsHelp": "Configure one agent per Docker host. HTTPS with a persistent self-signed certificate is the agent default; paste its SHA-256 fingerprint to pin it. Each agent keeps its own base domain and optional default backend IP.", - "dockerAgentAdd": "Add Docker agent", - "dockerAgentsSave": "Save and connect agents", - "dockerAgent": "DOCKER AGENT", - "dockerAgentNew": "New agent", - "dockerAgentId": "Agent ID", - "dockerAgentName": "Display name", - "dockerAgentEndpoint": "Agent endpoint", - "dockerAgentToken": "Bearer token", - "dockerBaseDomain": "Base domain", - "dockerTargetOverride": "Target IP override", - "dockerTargetAuto": "automatic", - "dockerListeners": "Listeners", - "dockerListenersRequired": "Select at least one listener for the Docker agent.", - "dockerNoAgents": "No Docker agents configured.", - "dockerNoAgentsConfigured": "Configure a Docker agent in Settings first.", - "dockerPublish": "Publish", - "dockerPreserveHost": "Preserve Host", - "dockerServiceMissing": "Not present in the latest inventory", - "dockerConnected": "CONNECTED", - "dockerError": "ERROR", - "dockerWaiting": "WAITING", - "dockerAgentDisabled": "This Docker agent is disabled.", - "dockerNoObservation": "No observation yet. Refresh the agents.", - "dockerHost": "Docker host", - "dockerDetectedIp": "Detected IP", - "dockerEffectiveIp": "Routing IP", - "dockerNoPublishedPorts": "No published TCP ports were reported.", - "dockerAssignmentsSave": "Save Docker vhosts", - "dockerDefaultTarget": "Default backend IP", - "dockerDetectedIps": "Detected host IPs", - "dockerHostname": "Hostname", - "dockerHostnameHelp": "Short names use {domain}; a full FQDN uses its own domain.", - "dockerAliases": "Aliases", - "dockerAliasAdd": "Add alias", - "dockerAliasesHelp": "Add aliases with Enter or comma. Short names use the agent base domain; full FQDNs are kept as entered.", - "dockerBackendIp": "Backend host IP", - "dockerBackendIpAuto": "Auto / agent default", - "dockerBackendScheme": "Backend protocol", - "dockerBindingIp": "Docker binding", - "dockerAgentDefaultIp": "agent default", - "dockerAgentEndpointHelp": "Use https:// for the default agent setup. Plain HTTP is supported only for compatibility and is visibly marked insecure.", - "dockerTlsFingerprint": "TLS certificate SHA-256", - "dockerTlsFingerprintHelp": "For the default self-signed agent certificate, paste the fingerprint printed by install.sh or rustproxy-docker-agent --print-fingerprint. Leave empty only for a certificate trusted by a public CA.", - "dockerTlsPinned": "TLS PINNED", - "dockerTlsPublicCa": "TLS / PUBLIC CA", - "dockerTlsPlain": "PLAIN HTTP", - "dockerTlsPlainHelp": "The agent token and inventory are not protected by TLS on this endpoint.", - "dockerTlsPublicCaHelp": "Certificate chain and hostname are verified against the system/public CA roots.", - "dockerAgentConnectionFailed": "Agent connection failed", - "dockerAgentVersion": "Agent version", - "dockerLastChecked": "Last checked", - "dockerNeverChecked": "never", - "dockerJustNow": "just now", - "dockerSecondsAgo": "{seconds}s ago", - "dockerMinutesAgo": "{minutes}m ago", - "dockerBackendMissing": "SERVICE MISSING", - "dockerBackendNotActive": "NOT PUBLISHED", - "dockerBackendChecking": "CHECKING", - "dockerBackendHealthOff": "HEALTH OFF", - "dockerBackendUp": "UP", - "dockerBackendDown": "DOWN", - "dockerBackendDraining": "DRAINING", - "dockerBackendNoMetrics": "Runtime metrics appear after the dynamic backend is active.", - "dockerHealthCheck": "Backend health check", - "dockerHealthSummary": "Active TCP/HTTP probes; passive health is configured separately", - "dockerPassiveHealth": "Passive backend health", - "dockerPassiveHealthSummary": "Off by default; opt in to health decisions from normal requests", - "dockerHealthMode": "Mode", - "dockerHealthHttp": "HTTP", - "dockerHealthTcp": "TCP", - "dockerHealthOff": "Off", - "dockerHealthPath": "HTTP path", - "dockerHealthHost": "Health Host header", - "dockerHealthHostAuto": "backend host / automatic", - "dockerHealthInterval": "Interval (ms)", - "dockerHealthTimeout": "Timeout (ms)", - "dockerHealthSlow": "Slow threshold (ms)", - "dockerHealthFall": "Failures to mark down", - "dockerHealthRise": "Successes to mark up", - "dockerHealthStatusMin": "Min HTTP status", - "dockerHealthStatusMax": "Max HTTP status", - "dockerHealthLatency": "Latency", - "dockerHealthResult": "Last probe", - "dockerHealthRequests": "Requests", - "dockerHealthErrors": "Errors", - "dockerHealthActive": "Active", - "loggingPerVhost": "Separate file per vhost", - "loggingDirectory": "Per-vhost directory", - "loggingPerVhostHelp": "When enabled, each vhost writes to its own JSONL file. Unmatched traffic uses _unmatched.jsonl.", - "listenerStartupLocked": "This startup/systemd address cannot be changed or removed here. Other addresses and listener options remain editable.", - "administrationStartupLocked": "This address is fixed by the process startup/systemd configuration and cannot be changed here.", - "notfoundStatusInvalid": "Select a supported HTTP error status.", - "tlsEffectiveCiphers": "Currently effective cipher suites", - "certificateManaged": "ACME managed", - "certManagedReadOnly": "ACME-managed certificates are renewed automatically and cannot be edited as custom file certificates.", - "vhWebsocketTransport": "WebSocket transport", - "vhWebsocketHttp1": "HTTP/1.1 Upgrade (recommended)", - "vhWebsocketRfc9220": "RFC 9220 Extended CONNECT over HTTP/3", - "vhWebsocketTransportHelp": "Enable WebSocket with the separate switch, then choose the transport. H2/H3 modes use Extended CONNECT while HTTP/1.1 Upgrade remains the fallback.", - "dockerLiveView": "Live view", - "dockerPollInterval": "Agent poll interval (s)", - "dockerPollIntervalHelp": "How often RustProxy contacts this agent for Docker inventory. Live view only reads RustProxy memory.", - "dockerAgentPollEvery": "Agent poll interval", - "dockerSearch": "Search Docker vhosts", - "dockerSearchPlaceholder": "Search service, host, alias or agent...", - "dockerShowHidden": "Show Hidden", - "dockerHideHidden": "Hide Hidden", - "dockerHideVhost": "Hide from view", - "dockerUnhideVhost": "Show in view", - "dockerCertificate": "Frontend certificate", - "dockerCertificateHelp": "Certificate assigned to every generated vhost for this agent. Default uses normal TLS/SNI certificate selection.", - "dockerDefaultAcl": "Default ACL profile", - "dockerDefaultAclNone": "No default ACL profile", - "dockerDefaultAclHelp": "Inherited by generated Docker vhosts that do not select their own per-app ACL profile.", - "dockerApplyService": "Apply changes", - "dockerAccessControl": "Access control", - "dockerAclSummary": "Optional ACL profile and per-app IP rules", - "dockerAclProfile": "ACL profile", - "dockerAclProfileNone": "No ACL profile", - "dockerAclProfileInherit": "Agent default", - "dockerAclInline": "Use additional per-app ACL", - "dockerAclDefault": "Default ACL action", - "dockerAclRules": "IP/CIDR rules", - "dockerAclHelp": "One rule per line, for example allow 10.0.0.0/8. Profile and per-app ACL are both enforced.", - "dockerProxyTimeouts": "Proxy timeouts", - "dockerProxyTimeoutsHelp": "Explicit per-app limits: connect 10 s, response headers 120 s, upstream read 60 s and request send 60 s by default.", - "dockerHostnameRequired": "Hostname is required before publishing.", - "dockerForceSsl": "Redirect HTTP to HTTPS", - "dockerForceSslUnavailable": "Requires an active plain HTTP listener and one unambiguous TLS listener on this agent.", - "dockerWebsockets": "WebSockets", - "dockerCache": "Cache", - "vhProxyTimeouts": "Proxy timeouts", - "vhProxyConnectTimeout": "Proxy connect timeout (s)", - "vhProxyHeaderTimeout": "Proxy response header timeout (s)", - "vhProxyReadTimeout": "Proxy read timeout (s)", - "vhProxySendTimeout": "Proxy send timeout (s)", - "vhProxyTimeoutsHelp": "Defaults: connect 10 s, response headers 120 s, read 60 s and send 60 s. Read/send are idle-gap timeouts for streaming bodies.", - "notfoundModeBuiltin": "Application-style status page", - "pageBuiltin": "Built-in status page", - "vhOpenBrowser": "Open", - "securityPasswordHint": "Requires the current password and signs out all sessions.", - "securityAccessControl": "ACCESS CONTROL", - "securityPoliciesHint": "Keep the policy list visible; open the editor only when adding or changing a rule set.", - "securityPolicyEditorHint": "Hostname scope, default action and CIDR rules.", - "securityAuditOpen": "Administration audit", - "securityAuditHint": "Recent administration changes are loaded only when this window is opened.", - "dockerConfigureService": "Configure vhost", - "dockerAliasesShort": "aliases", - "dockerAgentDetails": "Agent details", - "dockerServices": "Services", - "dockerOpenApp": "Open app", - "networkInterfacesHistory": "Traffic by interface", - "networkInterfaceRate": "RX / TX", - "networkNoInterfaces": "No non-loopback network interfaces are available.", - "networkInterfacesCount": "{count} interfaces", - "logExpandBuffer": "Increase buffer", - "logExpandedBuffer": "Buffer 4096", - "logBufferExpanded": "Live buffer increased to {count} retained entries.", - "vhIdRenameHelp": "Changing the vhost ID starts a new metrics/log/cache identity and resets its live health/traffic history. Hostnames and configured backend IDs are unchanged.", - "vhIdRenameConfirm": "Change vhost ID from {old} to {new}? Live health/traffic history and metric/cache identity for this vhost will restart.", - "cacheDomainFilter": "Show", - "cacheDomainFilterAll": "All domains", - "cacheDomainFilterEnabled": "Cache enabled", - "cacheDomainFilterDisabled": "Cache disabled", - "cacheNoDomainsFiltered": "No domains match this filter.", - "cacheColdCleanup": "Clean cold cache", - "cacheColdCleanupHelp": "Runs asynchronously and uses the same eviction mechanism as automatic cold-cache GC.", - "cacheColdUnusedSeconds": "Unused for at least (seconds, optional)", - "cacheColdOldestCount": "Remove up to oldest objects", - "cacheColdHitsZero": "Only objects with hits = 0", - "cacheColdCleanupStart": "Start cleanup", - "cacheColdCleanupRunning": "Cold-cache cleanup is running…", - "cacheColdCleanupDone": "Removed {count} objects and freed {bytes}.", - "cacheColdCleanupFailed": "Cold-cache cleanup failed.", - "cacheColdCleanupInvalidJob": "Cold-cache cleanup did not return a job identifier.", - "cacheColdGcInterval": "Cold-cache GC interval (seconds)", - "cacheColdGcMaxDelete": "Maximum deletes per GC pass", - "transformSettings": "Static response transformation", - "transformEnable": "Enable transformation engine globally", - "transformHelp": "Transformation happens after upstream decoding and before cache storage and client compression. Each vhost must opt in separately.", - "transformJavascript": "JavaScript minification", - "transformCss": "CSS minification", - "transformHtml": "HTML minification", - "transformSvg": "SVG optimization", - "transformJson": "JSON compaction", - "transformExtensions": "Allowed file extensions, one per line", - "transformMaxBody": "Maximum transformable response (KiB)", - "transformResourcePresetTitle": "Resource preset", - "transformResourcePresetHelp": "Presets tune the temporary memory ceiling, maximum transformable response size and global concurrent transformation limit. Content types and extension allow-lists are left unchanged.", - "transformPresetConservative": "RAM saver", - "transformPresetRecommended": "Recommended", - "transformPresetPerformance": "Performance", - "transformPresetUber": "Uber performance", - "transformMemoryBudget": "Temporary transform memory budget (MiB)", - "transformMaxInflight": "Maximum concurrent transformations", - "transformMaxInflightShort": "concurrent", - "transformResourceCurrent": "Current limits", - "transformBudgetTooSmallWarning": "The memory budget is smaller than the worst-case temporary buffers for one maximum-size compressed response. Such responses can be skipped with memory_pressure.", - "transformBudgetHighWarning": "The transform memory ceiling is more than 50% of effective host/cgroup RAM:", - "transformSafety": "Cache-Control: no-transform is always respected. Transformed representations receive a new ETag and are cached before gzip, Brotli or zstd encoding.", - "saveTransform": "Apply transformation policy", - "vhTransform": "Transform", - "vhTransformEnable": "Enable transformations for this vhost", - "vhTransformExtensionsCustom": "Override global transform extensions", - "vhTransformHelp": "The global engine must also be enabled. Format selectors inherit the global policy unless explicitly enabled or disabled here.", - "dockerTransform": "Transform static responses", - "vhPassive5xxWarning": "Counting HTTP 5xx can quarantine the whole backend after repeated application errors from one endpoint.", - "vhPassiveSlowWarning": "Counting slow responses can quarantine the backend after repeated responses that are correct but exceed the slow-response threshold.", - "transform": "Transform", - "transformTitle": "Static response transformation.", - "transformDescription": "Runtime transformation effectiveness, savings, skips and cache reuse.", - "transformApplied": "Transformed responses", - "transformExamined": "Examined", - "transformCacheHits": "Transformed cache HITs", - "transformCacheHitsHelp": "Served without running the transformer again", - "transformSaved": "Bytes saved before compression", - "transformReduction": "Average reduction", - "transformReductionHelp": "For responses that changed representation", - "transformSkipped": "Skipped / fail-open", - "transformErrors": "Body / transport errors", - "transformAvgTime": "Avg time", - "transformByType": "Transformations by type", - "transformType": "Type", - "transformSkipReasons": "Skip / fail-open reasons", - "transformNoSkips": "No skipped transformations in this scope.", - "transformNoSkipsShort": "No skips", - "transformVhosts": "Vhost effectiveness", - "transformScopeHint": "Counters are in-memory runtime diagnostics. A transformed cache HIT does not execute the transformer again.", - "transformNoData": "No transform activity yet.", - "transformBadge": "transformed", - "cacheLiveChartTitle": "Live cache activity", - "cacheLiveChartHelp": "HIT / MISS / BYPASS per second for the selected scope", - "liveChartSamples": "Samples", - "transformLiveChartTitle": "Live transformation activity", - "transformLiveChartHelp": "Applied / cache HIT / skipped / errors per second for the selected scope", - "transformChartApplied": "Applied", - "transformChartCacheHits": "Cache HIT", - "transformChartSkipped": "Skipped", - "cacheInvalidationTitle": "Cache purge / ban", - "cacheInvalidationOperation": "Operation", - "cacheInvalidationSelector": "Selector", - "cacheInvalidationValue": "Value", - "cacheInvalidationHost": "Host (optional)", - "cacheBanTtl": "BAN TTL (seconds)", - "cacheInvalidationHelp": "The selected vhost limits the operation. Exact and prefix values include the query string. Regex and root-prefix / operations require an additional confirmation.", - "cacheRunInvalidation": "Run operation", - "cacheActiveBans": "Active BAN rules", - "cacheBanExpires": "Expires", - "cacheNoBans": "No active BAN rules.", - "cacheTarget": "Target", - "cacheKeyTags": "Cache key / tags", - "cachePurgeUrl": "Purge URL", - "cacheRemoveBan": "Remove BAN", - "cacheBanCreated": "BAN created", - "cacheConfirmPurgeUrl": "Purge this cached URL from RAM and cold storage?", - "cacheConfirmRemoveBan": "Remove this BAN rule?", - "cacheWideInvalidationConfirm": "This broad invalidation may affect many cached objects. Continue?", - "cacheCollapseWaiters": "waiting", - "cacheCollapsed": "collapsed", - "actions": "Actions", - "cacheCollapseTitle": "Request collapsing", - "cacheCollapseEnable": "Collapse concurrent fills for one cache key", - "cacheCollapseTimeout": "Follower wait timeout (ms)", - "cacheCollapseFallback": "Timeout fallback", - "cacheCollapseFallbackOrigin": "Origin", - "cacheCollapseFallbackStale": "Stale if available", - "cacheStaleErrorTitle": "Stale-if-error policy", - "cacheSieTimeout": "Timeout", - "cacheSieConnection": "Connection failure", - "cacheSieDns": "DNS failure", - "cacheSieTls": "TLS failure", - "cacheSieStatuses": "HTTP 5xx statuses eligible for stale fallback", - "cacheProactiveTitle": "Proactive refresh", - "cacheProactiveEnable": "Refresh sampled cached objects before expiry", - "cacheProactiveBefore": "Refresh before expiry (seconds)", - "cacheProactivePercent": "Sampled objects (%)", - "cacheProactiveInflight": "Maximum concurrent refreshes", - "cacheProactiveHelp": "Uses validator revalidation, deterministic sampling and a global concurrency cap to avoid refresh storms.", - "cacheInvalidationOpen": "Purge / Ban", - "cacheBanListOpen": "Active BANs", - "cacheBanRemoved": "BAN rule removed", - "tunnelsOpen": "Active tunnels", - "tunnelsTitle": "Active WebSocket / tunnels", - "tunnelsReload": "Reload", - "tunnelsEmpty": "No active tunnels.", - "tunnelId": "ID", - "tunnelClient": "Client", - "tunnelHost": "Host", - "tunnelUpstream": "Upstream", - "tunnelProtocol": "Protocol", - "tunnelDuration": "Duration", - "tunnelRx": "RX", - "tunnelTx": "TX", - "tunnelKill": "Kill", - "tunnelKilled": "Tunnel closed by administrator", - "tunnelKillConfirm": "Close this tunnel?", - "tunnelKillReason": "Close reason", - "tunnelKillReasonPlaceholder": "Administrative close", - "tunnelKillReasonDefault": "admin panel", - "listenerH2c": "h2c cleartext HTTP/2 (prior knowledge + HTTP/1.1 Upgrade)", - "vhWebsocketRfc8441": "RFC 8441 Extended CONNECT over HTTP/2", - "wsH1": "H1 Upgrade", - "wsH2Rfc8441": "H2 RFC 8441", - "wsH3Rfc9220": "H3 RFC 9220", - "wsEstablished": "Established", - "httpProtocolMix": "HTTP protocol mix", - "wsProtocolMix": "WebSocket protocol mix", - "vhWebsocketMode": "WebSocket transport", - "vhWebsocketDisabled": "Disabled", - "vhWebsocketH1": "HTTP/1.1 Upgrade", - "vhWebsocketH2Fallback": "HTTP/2 RFC 8441 + H1 fallback", - "vhWebsocketH3Fallback": "HTTP/3 RFC 9220 + H1 fallback", - "vhWebsocketH2H3Fallback": "HTTP/2 + HTTP/3 + H1 fallback", - "vhMaxConcurrentRequests": "Max concurrent requests", - "vhBackendQueueTimeout": "Capacity queue timeout (ms)", - "vhBackendCapacityHelp": "0 concurrent requests means unlimited. A queue timeout of 0 rejects immediately with HTTP 503 when the backend is at capacity.", - "vhLastFailure": "Last failure", - "vhLastRecovery": "Last recovery", - "certificateIssuerName": "Certificate issuer", - "certificateValidFrom": "Valid from", - "certificateDaysRemaining": "Days remaining", - "certificateExpired": "Certificate expired", - "certificateExpiresSoon": "Certificate expires soon", - "certificateRenewalStatus": "Renewal status", - "certificateRenewalError": "Last renewal error", - "vhActiveHealth": "Active health", - "vhPassiveFailures": "Passive failures", - "certificateAdminRestartRequired": "Administration TLS uses a startup-fixed listener; restart RustProxy to refresh that certificate.", - "cacheTabGeneral": "General", - "cacheTabResilience": "Resilience", - "cacheTabCold": "Cold cache", - "cacheTabDiagnostics": "Static & diagnostics", - "certificateApiTitle": "Certificate API", - "certificateApiHelp": "Create separate Key ID + Bearer Token credentials for certificate deploy/reload automation. Tokens cannot read configuration or use other administration APIs.", - "certificateApiKeyId": "Key ID", - "certificateApiToken": "Bearer token (optional custom value)", - "certificateApiTokenHelp": "Leave the field empty to generate a strong token. Each cleartext token is shown only once; RustProxy stores only its hash.", - "certificateApiRotate": "Generate / rotate token", - "certificateApiRevoke": "Revoke token", - "certificateApiOneTimeToken": "Copy this token now", - "certificateApiCurlHelp": "External automation sends the Key ID header and Bearer token to the certificate deploy/reload endpoints over HTTPS (or loopback HTTP).", - "certificateApiUnknown": "Loading certificate API status…", - "certificateApiConfigured": "Certificate API enabled", - "certificateApiDisabled": "Certificate API disabled", - "certificateApiLastUsed": "last used", - "certificateApiRotated": "Certificate API token created / rotated. Copy the token now.", - "certificateApiRevoked": "Certificate API token revoked.", - "certificateApiRevokeConfirm": "Revoke the external certificate API token? Certbot/API deployments using it will stop immediately.", - "certificate_api.invalid_token": "Invalid certificate API Key ID or Bearer Token.", - "certificate_api.https_required": "External certificate API tokens require HTTPS unless the request comes from loopback.", - "certificate_api.invalid_token_format": "Certificate API tokens must be 32–128 URL-safe characters.", - "certificate_api.invalid_key_id": "Invalid certificate API Key ID.", - "vhWebsocketLegacySupport": "Enable WebSocket legacy support", - "vhWebsocketLegacySupportHelp": "For older appliances and embedded servers. WebSocket handshakes use HTTP/1.1 upstream, Host and Origin are aligned to the configured backend authority, and legacy 101 response framing is tolerated. Ordinary HTTP traffic is unchanged.", - "vhWebsocketLegacyBadge": "WebSocket legacy", - "runtimeInformation": "Runtime information", - "runtimeInformationHelp": "Reported by the running RustProxy process and available only from the authenticated administrator status API.", - "runtimePlatform": "Platform", - "statisticsSource": "Statistics source", - "dataDirectory": "Data directory", - "databaseLocation": "Database", - "connectionActivity": "CONNECTION ACTIVITY", - "reloadCertificate": "Reload certificate", - "certificateApiComment": "Comment", - "certificateApiConfiguredCount": "Certificate API tokens: {count} / {max}", - "certificateApiNeverUsed": "never used", - "certificateApiRevokeAll": "Revoke all tokens", - "certificateApiRevokeOneConfirm": "Revoke Certificate API token {key}? Any automation using it will stop immediately.", - "certificateApiRevokeAllConfirm": "Revoke every Certificate API token? All external certificate automation using these tokens will stop immediately.", - "certificate_api.invalid_comment": "Certificate API comments must be at most 256 characters and contain no control characters.", - "certificate_api.limit_reached": "The Certificate API token limit has been reached.", - "certificate_api.not_found": "Certificate API token not found.", - "networkInterfacesVisibleCount": "{visible} / {total} interfaces", - "hideMetric": "Hide", - "showMetric": "Show", - "hiddenInterfaces": "Hidden interfaces", - "networkNoVisibleInterfaces": "All detected interfaces are hidden in this browser.", - "cacheMemorySizingTitle": "Memory sizing", - "cacheMemorySizingHelp": "Presets use effective memory available to RustProxy (host RAM capped by cgroup when present). They tune HOT, transient RAM, object size, entry count and the demotion queue; the COLD disk budget is left unchanged.", - "cachePresetConservative": "Conservative", - "cachePresetRecommended": "Recommended", - "cachePresetPerformance": "Performance", - "cachePresetSelected": "Selected", - "cachePresetCustom": "Custom", - "cacheColdPresetTitle": "COLD policy preset", - "cacheColdPresetHelp": "The recommended policy enables idle/LRU/shutdown demotion, sizes the COLD queue from transient RAM and uses conservative GC timings. Disk path, disk budget and object limit are left unchanged.", - "cacheTransientLimit": "Transient RAM budget (MiB)", - "cacheEvictionLimit": "LRU removals per admission", - "cacheColdQueueLimit": "COLD queue RAM budget (MiB)", - "cacheMemoryNotDetected": "Memory not detected", - "cacheMemoryPresetUnavailable": "Automatic presets require host or cgroup memory telemetry.", - "cacheMemoryCgroup": "Effective cgroup RAM", - "cacheMemoryDetected": "Detected RAM", - "cacheQueueOverTransientWarning": "COLD queue budget cannot exceed the transient RAM budget.", - "cacheMemoryHighWarning": "Warning: HOT + transient cache budgets are a large share of effective RAM:", - "cachePresetTransientShort": "transient", - "cachePresetObjectShort": "max object", - "cachePresetQueueShort": "COLD queue", - "cacheLogicalShort": "logical", - "cacheLimitShort": "limit", - "cacheMemoryPressureShort": "memory pressure", - "cacheNukeLimitShort": "LRU limit", - "cacheMemoryPresetTooSmall": "Automatic cache presets are disabled below 256 MiB of effective RAM; configure the cache manually if this is intentional.", - "cacheMemoryRecommendedFor": "Recommended for detected memory:", - "cacheMemoryHeadroomWarning": "Warning: the additional cache budget is large compared with currently available host/cgroup memory:", - "cacheObjectOverTransientWarning": "Maximum object exceeds the transient RAM budget; objects near that size will pass through instead of being cached.", - "vhCacheGlobalDisabled": "Global cache is disabled. This vhost cannot enable cache until the global cache is enabled.", - "responseLatencyInfo": "Response time information", - "responseLatencyHint": "The value is the cumulative mean duration of completed HTTP exchanges since process start. The chart shows successive samples of that mean; it is not a percentile or the latency of one request.", - "web-server": "Web Server", - "web-serverTitle": "Serve local files.", - "web-serverDescription": "Create reusable Web Services and attach them to vhosts or Custom locations.", - "webServer": "Web Server", - "webServerIntro": "Create reusable local Web Services here, then attach them to a vhost or Custom location.", - "webServiceList": "Web Services", - "webServiceSearch": "Search Web Services", - "webServiceSearchPlaceholder": "Search name, ID or document root", - "webServiceNew": "New Web Service", - "webServiceEditor": "Web Service configuration", - "webServiceTabGeneral": "General", - "webServiceTabRouting": "Routing", - "webServiceTabMime": "MIME", - "webServiceTabCacheHeaders": "Cache & headers", - "webServiceTabDelivery": "Delivery", - "webServiceTabPhp": "PHP-FPM", - "webServiceTabSecurity": "Security", - "webServiceId": "Service ID", - "webServiceName": "Name", - "webServiceRoot": "Document root", - "webServiceIndex": "Index files", - "webServiceDirectoryListing": "Directory listing", - "webServiceMimeOverrides": "MIME overrides", - "webServiceMimeBuiltin": "Built-in mappings", - "webServiceMimeHelp": "Optional extension-to-Content-Type overrides, one per line. Use: ext = media/type.", - "webServiceMimeInvalid": "MIME overrides must use one unique 'ext = media/type' entry per line.", - "webServiceDefaultMime": "Default MIME type", - "webServiceCacheControl": "Cache-Control", - "webServiceCacheRules": "Cache-Control rules", - "webServiceCacheRulesHelp": "Specific rules are evaluated in order before the default policy. Match ext:css or mime:image/.", - "webServiceCacheRulesInvalid": "Cache-Control rules must use matcher = value, for example ext:css = public, max-age=3600.", - "webServiceResponseHeaders": "Response headers", - "webServiceResponseHeadersHelp": "Fixed headers for this Web Service. Vhost/location response headers run later and can override them.", - "webServiceResponseHeadersInvalid": "Response headers must use one unique Header-Name = value entry per line.", - "webServiceCacheHelp": "Local files use filesystem/OS page cache. These settings control browser/proxy caching and do not create a second RustProxy object cache.", - "webServiceTryFiles": "try_files", - "webServiceTryFilesHelp": "One candidate per line. Supports $uri, $query_string and a final =404/other error status.", - "webServiceRewrites": "Rewrite rules", - "webServiceRewritesHelp": "One regex rule per line. Use pattern => /target for an internal rewrite or pattern => 301:/target for a redirect.", - "webServiceRewritesInvalid": "Rewrite rules must use pattern => /target or pattern => 301:/target (301/302/307/308).", - "webServicePrecompressed": "Serve precompressed sidecars", - "webServicePrecompressedBr": "Brotli (.br)", - "webServicePrecompressedGzip": "Gzip (.gz)", - "webServiceDownloadExtensions": "Download extensions", - "webServiceDownloadExtensionsHelp": "Files with these extensions receive Content-Disposition: attachment.", - "webServiceRangeHelp": "Static and precompressed representations keep validators, single-range requests, 206/416 and streaming delivery.", - "webServicePhpEnabled": "Enable PHP-FPM / FastCGI", - "webServicePhpEndpoint": "PHP-FPM endpoint", - "webServicePhpEndpointHelp": "Unix: unix:/run/php/php-fpm.sock. TCP: tcp:127.0.0.1:9000 or tcp:[::1]:9000. TCP is intentionally limited to loopback addresses.", - "webServicePhpExtensions": "PHP extensions", - "webServicePhpPassAuthorization": "Forward Authorization header", - "webServicePhpConnectTimeout": "Connect timeout (ms)", - "webServicePhpRequestTimeout": "Total FastCGI request timeout (ms)", - "webServicePhpConcurrency": "Max concurrent PHP requests", - "webServicePhpBodyLimit": "PHP request body limit (bytes, 0 = unlimited)", - "webServicePhpHeaderLimit": "Max FastCGI response header bytes", - "webServicePhpStderrLimit": "Max PHP-FPM stderr log bytes", - "webServicePhpCustomParams": "Custom FastCGI parameters", - "webServicePhpCustomParamsHelp": "One NAME = value entry per line. Static trusted values only; core CGI, HTTP_* and PHP_* control names are reserved.", - "webServicePhpCustomParamsInvalid": "Custom FastCGI parameters must use one unique NAME = value entry per line.", - "webServicePhpCustomDataTooLarge": "Custom FastCGI parameters and PHP INI overrides may use at most 128 KiB combined.", - "webServicePhpValues": "PHP INI overrides (PHP_VALUE)", - "webServicePhpValuesHelp": "One php.ini directive = value per line. RustProxy sends the validated set as PHP_VALUE; PHP_ADMIN_VALUE is never accepted here.", - "webServicePhpValuesInvalid": "PHP INI overrides must use one unique directive = value entry per line.", - "webServicePhpDocsButton": "FastCGI syntax and safety", - "webServicePhpDocsTitle": "PHP-FPM / FastCGI configuration", - "webServicePhpDocsIntro": "RustProxy connects directly to an existing PHP-FPM pool. Prefer a Unix socket on the same host. TCP is accepted only on loopback and is not a public/network FastCGI transport.", - "webServicePhpDocsEndpointTitle": "Endpoint syntax", - "webServicePhpDocsEndpoint": "For TCP, include the tcp: prefix, a literal loopback IP and port. Hostnames and non-loopback addresses are rejected. For Unix sockets, RustProxy must have permission to connect to the socket.", - "webServicePhpDocsCustomTitle": "Custom FastCGI parameters", - "webServicePhpDocsCustom": "Use one NAME = value entry per line. Names are normalized to uppercase and may contain A-Z, 0-9 and underscore. These are static trusted operator values. RustProxy rejects core CGI names, HTTP_* names, PHP_VALUE and PHP_ADMIN_VALUE so they cannot override request routing, script selection or HTTP-derived parameters.", - "webServicePhpDocsValuesTitle": "PHP INI overrides", - "webServicePhpDocsValues": "These lines are combined into the FastCGI PHP_VALUE parameter. PHP-FPM/PHP still decides which directives are changeable at this scope. Newlines/control characters are rejected and PHP_ADMIN_VALUE is intentionally unavailable.", - "webServicePhpDocsLimitsTitle": "Limits and headers", - "webServicePhpDocsLimits": "Request timeout covers the FastCGI exchange. The body limit is enforced while streaming and returns 413 when exceeded; 0 disables the RustProxy-side body limit. Response-header and stderr limits bound memory/diagnostic data. Up to 64 custom FastCGI parameters and 64 PHP INI overrides are accepted, with at most 128 KiB of combined custom data. Authorization forwarding can be disabled for applications that do not need HTTP_AUTHORIZATION.", - "webServicePhpDocsSecurity": "Do not put secrets in custom parameters or PHP_VALUE unless you accept storing them in normal Web Service configuration. Use a dedicated non-root PHP-FPM pool identity and keep PHP-FPM off public networks.", - "webServicePhpHelp": "RustProxy speaks FastCGI directly to a long-running PHP-FPM pool. PHP is not spawned per request and PHP source is never served when PHP handling is selected.", - "webServicePhpSymlinkConflict": "PHP-FPM currently requires the symlink policy to be Deny.", - "webServiceSymlinkPolicy": "Symlink policy", - "webServiceSymlinkDeny": "Deny", - "webServiceSymlinkInsideRoot": "Allow only inside document root (Linux)", - "webServiceSafety": "Document root is a strict filesystem boundary. The default denies symlinks. Linux can optionally follow only targets that resolve inside the root; PHP-FPM currently requires the deny policy.", - "webServiceSelect": "Select Web Service", - "webService": "Web Service", - "webServiceUsedBy": "Used by", - "webServiceUnused": "Not attached", - "webServiceEmpty": "No Web Services yet.", - "webServiceSearchEmpty": "No Web Services match this search.", - "webServiceInUse": "Web Service is still used by", - "webServiceDelete": "Delete this Web Service?", - "webServiceIndexRequired": "Index files are optional.", - "webServiceDuplicate": "A Web Service with this ID already exists.", - "webServiceRequired": "Select a Web Service.", - "sourceType": "Source type", - "sourceReverseProxy": "Reverse Proxy", - "sourceWebServer": "Web Server", - "sourceHelp": "The vhost stores only the source choice. Web Server settings remain in the selected reusable Web Service.", - "locationWebServerAction": "Web Server", - "locationWebServerShort": "Web Server", - "docsReader": "Reader", - "docsApi": "API", - "docsReaderSearch": "Search documentation", - "docsReaderSearchPlaceholder": "Search title or path", - "docsReaderEmpty": "No documentation matches this search.", - "docsCategoryProject": "Project", - "docsCategoryGuides": "Functional guides", - "docsCategoryTechnical": "Technical", - "docsCategoryAudits": "Audits and history", - "docsCategoryHistorical": "Historical", - "webServiceIndexHelp": "Optional. Leave empty to skip index lookup; with directory listing enabled, the file list is shown directly.", - "webServiceNoIndex": "No index files", - "vhBackendRequired": "Reverse Proxy requires at least one backend. Add a backend or change the source to Web Server.", - "vhListenerRequired": "Select at least one listener for this vhost.", - "traffic": "Traffic", - "trafficTitle": "Traffic, per vhost.", - "trafficDescription": "Bounded request analytics: countries, User-Agents, client IPs, paths, routes and protocol outcomes.", - "trafficSinceStart": "Since process start", - "trafficResponseBytes": "Response bytes", - "trafficRequestBytes": "Request bytes", - "trafficMeanLatency": "Mean latency", - "trafficDroppedSamples": "Dropped analytics samples", - "trafficBoundedLabel": "BOUNDED / ASYNC", - "trafficDimensionsTitle": "Traffic dimensions", - "trafficApproxHelp": "Top lists are approximate and bounded so high-cardinality traffic cannot grow proxy memory without limit.", - "trafficTopCountries": "Top countries", - "trafficTopUserAgents": "Top User-Agents", - "trafficTopClientIps": "Top client IPs", - "trafficClientIp": "Client IP", - "trafficTopPaths": "Top paths", - "trafficTopRoutes": "Top routes", - "trafficMethods": "Methods", - "trafficStatusClasses": "Status classes", - "trafficCacheOutcomes": "Cache outcomes", - "trafficValue": "Value", - "trafficOther": "Other", - "trafficNoCountryData": "Country collection is disabled or no GeoIP data is available.", - "trafficNoUserAgentData": "No User-Agent data collected.", - "trafficNoData": "No traffic data yet.", - "trafficUserAgentEnabled": "User-Agent collection enabled", - "trafficUserAgentDisabled": "User-Agent collection disabled", - "trafficCountryEnabled": "Country collection enabled", - "trafficCountryDisabled": "Country collection disabled", - "trafficCountryNoDb": "Country collection enabled, GeoIP database unavailable", - "trafficUpdated": "Updated", - "loggingCaptureTitle": "Captured request dimensions", - "loggingCaptureUserAgent": "Capture User-Agent", - "loggingCaptureCountry": "Capture country from GeoIP", - "loggingCaptureCountryHelp": "Country lookup is optional and disabled by default. Enable it only when country logs/statistics are needed; country ACL/rate-limit rules still resolve GeoIP when required.", - "cacheAutoTrimEnabled": "Automatically release idle HOT cache memory", - "cacheAutoTrimAfter": "Idle age before HOT trim (seconds)", - "cacheAutoTrimTarget": "HOT trim target (%)", - "cacheAutoTrimHelp": "When HOT memory is above the target, only entries idle for the configured age are removed in bounded passes. Active objects are not purged.", - "webServiceTabHtaccess": ".htaccess", - "webServiceHtaccessEnabled": "Enable .htaccess compatibility", - "webServiceHtaccessFilename": "Configuration file", - "webServiceHtaccessRecursive": "Scan subdirectories", - "webServiceHtaccessStrict": "Strict unsupported-directive mode", - "webServiceHtaccessDocs": "Compatibility documentation", - "webServiceHtaccessHelp": "RustProxy compiles a bounded Apache-compatible subset when the Web Service is applied. Files are not parsed on every request; apply the Web Service again after editing .htaccess on disk.", - "webServiceHtaccessDocsTitle": ".htaccess compatibility", - "webServiceHtaccessDocsIntro": "This is a migration-oriented compatibility layer, not a complete Apache runtime. Supported directives are compiled into RustProxy Web Server rules.", - "webServiceHtaccessDocsSupportedTitle": "Supported subset", - "webServiceHtaccessDocsRewriteTitle": "Rewrite compatibility", - "webServiceHtaccessDocsRewrite": "Rewrite conditions support REQUEST_FILENAME file tests (-f, -d, -s), REQUEST_URI, REQUEST_METHOD, QUERY_STRING, HTTP_HOST, HTTPS, DOCUMENT_ROOT, THE_REQUEST and HTTP headers. Flags: L, END, R, R=301/302/307/308, QSA, NC, F, OR. PT/NE are accepted as no-ops. E= is accepted as a compatibility no-op because request HTTP headers already reach PHP-FPM.", - "webServiceHtaccessDocsPhpTitle": "PHP-FPM", - "webServiceHtaccessDocsPhp": ".htaccess may add PHP extensions with AddHandler, but the PHP-FPM endpoint, timeouts and concurrency remain controlled by the Web Service PHP-FPM tab. Apache SetHandler proxy socket syntax is intentionally not accepted.", - "webServiceHtaccessDocsReloadTitle": "Loading and limits", - "webServiceHtaccessDocsReload": "Files are read and compiled on Validate, save and apply. RustProxy does not parse .htaccess per request. Re-apply after changing a file. The scan is bounded to 128 files, depth 16, 128 KiB per file and 1 MiB total.", - "webServiceHtaccessDocsUnsupportedTitle": "Not Apache-complete", - "webServiceHtaccessDocsUnsupported": "ErrorDocument, SetEnvIf, Redirect/RedirectMatch and FallbackResource are not implemented in this compatibility layer. General Files/FilesMatch, unsupported authentication/authorization directives, non-PHP handlers and SetHandler are rejected even when Strict mode is off because silently ignoring them could weaken access control or expose source. .htaccess/.htpasswd files are always blocked from HTTP delivery. Other unsupported non-security directives are logged and ignored unless Strict mode is enabled.", - "webServiceHtaccessDocsSecurity": "Vhost/location ACL, authentication, error pages and response rules still remain authoritative. .htaccess cannot escape the document root, select an arbitrary FastCGI socket or override protected framing headers.", - "webServicePresetTitle": "Configuration preset", - "webServicePreset": "Preset", - "webServicePresetCustom": "Custom", - "webServicePresetStatic": "Static site", - "webServicePresetSpa": "SPA", - "webServicePresetPhpGeneric": "PHP generic", - "webServicePresetDownloads": "Downloads / file repository", - "webServicePresetAction": "Preset action", - "webServicePresetApply": "Apply preset", - "webServicePresetHelp": "Presets fill normal Web Service settings and remain fully editable. Document root, service ID/name and PHP-FPM endpoint are not replaced.", - "webServicePresetChoose": "Choose a preset before applying it.", - "webServicePresetApplied": "Preset applied. Review the generated settings before saving.", - "webServicePresetHintStatic": "Static site: HTML indexes, precompressed sidecars and cache rules for CSS/JS/images/fonts.", - "webServicePresetHintSpa": "SPA: index.html fallback via try_files, precompressed assets and long-lived static asset caching.", - "webServicePresetHintPhpGeneric": "Generic PHP: PHP-FPM enabled, index.php first and only existing files/directories are served directly.", - "webServicePresetHintWordpress": "WordPress: PHP-FPM, index.php and front-controller routing. Keep document root on the WordPress public directory.", - "webServicePresetHintDrupal": "Drupal: PHP-FPM, index.php and front-controller routing with static asset caching.", - "webServicePresetHintLaravel": "Laravel: PHP-FPM and front-controller routing. Point document root at the application public/ directory.", - "webServicePresetHintSymfony": "Symfony: PHP-FPM and front-controller routing. Point document root at the application public/ directory.", - "webServicePresetHintJoomla": "Joomla: PHP-FPM, index.php and front-controller routing with static asset caching.", - "webServicePresetHintPrestashop": "PrestaShop: PHP-FPM, index.php and front-controller routing with static asset caching.", - "webServicePresetHintDownloads": "Downloads: directory listing enabled, Range-friendly static delivery and common archive/document extensions forced as attachments.", - "webServiceHardeningTitle": "Hardening", - "webServiceHardeningAttacks": "Block common attack probes", - "webServiceHardeningHeaders": "Strip unnecessary fingerprint headers", - "webServiceHardeningSecurityHelp": "Hardening switches are shown beside the preset selector on General. They remain independent settings after a preset is applied.", - "trafficTabOverview": "Overview", - "trafficTabClients": "Clients", - "trafficTabRequests": "Requests", - "trafficTabDelivery": "Delivery", - "trafficVolume": "Traffic volume", - "vhMethodMode": "HTTP method policy", - "vhMethodList": "HTTP methods (one per line)", - "vhMethodHelp": "Allow only listed methods or block listed methods for this vhost. The policy stacks with location rules.", - "locationAclProfile": "ACL profile", - "locationMethodMode": "HTTP method policy", - "locationMethodList": "HTTP methods (one per line)", - "locationMethodAllow": "Allow only", - "locationMethodBlock": "Block listed", - "locationMethodHelp": "The location policy stacks with the vhost method policy. Example: GET, HEAD and POST.", - "locationCountryMode": "Country access policy", - "locationCountryList": "Country codes (one per line)", - "locationCountryHelp": "Location country policy stacks with vhost/profile policy. GeoIP is resolved only when required.", - "configHistory": "Revision history", - "configHistoryRetention": "SQLITE / LAST 512 REVISIONS", - "configHistoryHelp": "Select a marked day to inspect retained configuration revisions and their changes. History retention starts with 0.25.3.", - "configHistoryChanges": "CHANGES", - "configHistorySelectDay": "Select a day.", - "configHistoryRevision": "Revision", - "configHistoryRevisionShort": "rev", - "configHistoryBefore": "Before", - "configHistoryAfter": "After", - "configHistoryBaseline": "This is the oldest retained baseline; no earlier revision is available for comparison.", - "configHistoryNoChanges": "No configuration differences were found.", - "configHistoryDiffLimit": "Diff truncated after 200 changed paths.", - "configHistoryMissing": "(not present)", - "configHistoryEntries": "revisions", - "configHistorySummary": "{count} retained revisions", - "configHistoryEmpty": "No retained revisions.", - "configHistoryLoading": "Loading revision history...", - "configHistoryFailed": "Could not load revision history.", - "configHistoryRestoreAction": "Restore revision", - "configHistoryRestoreConfirm": "Restore revision {revision}? It will be validated and saved as a new revision after current revision {current}. The existing history will be preserved.", - "configHistoryRestored": "Revision {revision} restored as new revision {new_revision}.", - "about": "About", - "aboutTitle": "About RustProxy", - "aboutAuthor": "Author", - "aboutLicense": "License", - "aboutLicenseValue": "Open Source", - "aboutOpenSourceText": "RustProxy is an open-source project. Its source code is publicly available for inspection, development and community contribution.", - "aboutRepository": "Source repository", - "vhPoolRecycleRequests": "Recycle upstream pool after requests (0 = off)", - "vhPoolRecycleSeconds": "Maximum upstream pool age (seconds, 0 = off)", - "vhHttp1MaxBuffer": "HTTP/1 upstream max read buffer (bytes)", - "vhPoolRecycleHelp": "Recycling replaces only the Hyper client generation for each backend; active exchanges continue normally. Defaults bound long-lived pool/TLS buffer retention without reloading the vhost or cache. Request recycling accepts 0 or 1000..10000000; age accepts 0 or 60..604800." - } + "meta": { + "locale": "en-US", + "name": "English", + "native_name": "English", + "direction": "ltr" + }, + "translations": { + "overview": "Overview", + "mainMenu": "Menu", + "routing": "Legacy routes", + "configuration": "Configuration", + "manualConfig": "Manual config", + "runtime": "RUNTIME", + "localOnly": "ADMINISTRATION", + "logout": "Sign out", + "firstSlice": "INDEPENDENT CORE / EXPLICIT ACCESS", + "loginTitle": "Administration", + "unlock": "Unlock administration", + "tokenHelp": "Run this command in a second terminal and paste the token below.", + "token": "Local access token", + "connect": "Connect to proxy", + "tokenNote": "Administration defaults to loopback HTTP. Enable Administration HTTPS before using a non-loopback bind.", + "requests": "Requests", + "activeExchanges": "Active exchanges", + "bodyLifetime": "Full body lifetime", + "bandwidth": "Payload transferred", + "bothDirections": "Both directions", + "errors": "Errors", + "errorDescription": "5xx / body / cancelled", + "liveTraffic": "LIVE TRAFFIC", + "liveTransformed": "Transformed", + "requestsPerSecond": "Requests per second", + "live": "LIVE", + "lastMinute": "Recent samples / resets on reload", + "coreState": "CORE STATE", + "configurationRevision": "Applied revision", + "backends": "Backends", + "routes": "Routes", + "connections": "Open connections", + "uptime": "Uptime", + "activity": "ACTIVITY", + "accessLog": "Access log", + "boundedLog": "Last 50 / retained ring 4096", + "time": "Time", + "request": "Request", + "status": "Status", + "duration": "Duration", + "outcome": "Outcome", + "noTraffic": "No traffic yet. Open the proxy to make your first request.", + "reload": "Reload configuration", + "addBackend": "Add / edit backend", + "backendUrl": "Backend origin (HTTP / HTTPS, IP / DNS)", + "allowPrivate": "Explicitly allow private / loopback IP", + "preserveHost": "Preserve original Host header", + "saveBackend": "Save backend", + "clear": "Clear", + "addRoute": "Add / edit route", + "hostnames": "Hostnames and aliases, comma-separated", + "pathPrefix": "Path prefix (not stripped)", + "backend": "Backend", + "enabled": "Enabled", + "saveRoute": "Save route", + "rawConfig": "Configuration document", + "export": "Export JSON", + "configHelp": "A valid save is applied atomically. Invalid or stale changes leave the running configuration untouched.", + "apply": "Validate, save and apply", + "noRestart": "Routing and response policies apply live; listener changes require restart.", + "roadmapHelp": "Release details and planned features are documented in ROADMAP.md.", + "overviewTitle": "Traffic, in focus.", + "overviewDescription": "Traffic, cache and operating-system measurements in one compact dashboard.", + "routingTitle": "Connect the right dots.", + "routingDescription": "Existing backend/route format remains supported. New deployments can use one vhost with its own frontend and pool.", + "configurationTitle": "One source of truth.", + "configurationDescription": "One canonical configuration: vhosts, listeners and shared policies.", + "connected": "CONNECTED TO LOCAL CORE", + "disconnected": "CORE NOT REACHABLE", + "edit": "Edit", + "remove": "Delete", + "privateAllowed": "PRIVATE IP APPROVED", + "configured": "CONFIGURED / NOT PROBED", + "disabled": "DISABLED", + "emptyBackends": "No backends configured. Add an explicit HTTP or HTTPS origin.", + "emptyRoutes": "No routes configured. Unknown hosts return 404.", + "saving": "Saving…", + "unsavedChanges": "Unsaved changes", + "saved": "Configuration applied.", + "confirmDelete": "Delete this item? The change takes effect immediately.", + "confirmTitle": "Confirm action", + "confirmationLabel": "CONFIRMATION", + "warningLabel": "WARNING", + "continueAction": "Continue", + "cancelAction": "Cancel", + "discardAction": "Discard changes", + "errorContext": "{area}: {message}", + "stale": "Configuration changed elsewhere. Reload before saving.", + "busy": "A save is already in progress.", + "loginError": "Sign-in failed.", + "fresh": "Configuration reloaded.", + "locked": "Signed out. The session was revoked.", + "backendUsed": "This backend is referenced by a route. Delete or change the route first.", + "renaming": "IDs cannot be renamed in this form. Use the JSON editor to update references atomically.", + "complete": "complete", + "cancelled": "cancelled", + "body_error": "body error", + "proxy_or_upstream_error": "proxy/upstream error", + "security": "Security", + "sessionNote": "Local HTTP administration. Passwords use Argon2id and session cookies are HttpOnly. Do not expose the panel publicly.", + "setupHelp": "Create the first administrator using a one-time capability from the local terminal.", + "setupToken": "One-time setup token", + "username": "Username", + "password": "Password", + "confirmPassword": "Confirm password", + "setupTitle": "Create your administrator", + "signIn": "Sign in", + "createAndSignIn": "Create account and sign in", + "securityTitle": "Access stays deliberate.", + "securityDescription": "One administrator. Revocable sessions. Explicit host and route access policies.", + "manualBackends": "MANUAL BACKENDS", + "routePolicies": "Access policy and custom headers", + "useRouteAcl": "Enable route ACL", + "aclDefault": "Default action", + "allow": "Allow", + "deny": "Deny", + "aclRules": "One rule per line: allow/deny followed by CIDR", + "aclHelp": "Use IPv4/IPv6 CIDRs, e.g. 192.168.1.0/24 or 10.0.0.5/32. Deny wins. An allowed IP must still authenticate; a location cannot bypass the host ACL.", + "routeHeaders": "Request / response headers (JSON)", + "headersHelp": "Operations: set, append, remove. Transport, body encoding and client-identity headers are protected.", + "currentSession": "CURRENT SESSION", + "recoveryHelp": "Lost access? Run rust-proxy admin reset-password locally. Existing sessions will be revoked.", + "revokeAll": "Sign out all sessions", + "changePassword": "Change password", + "currentPassword": "Current password", + "newPassword": "New password (12-128 UTF-8 bytes)", + "savePassword": "Change and sign out", + "hostPolicies": "Host access policies", + "editHostPolicy": "Add / replace host policy", + "savePolicy": "Apply host policy", + "auditRetention": "SQLITE / LAST 100 / RETAINED 10,000", + "audit": "Administration audit", + "reloadAudit": "Reload", + "actor": "Actor", + "action": "Action", + "detail": "Detail", + "noAudit": "No audit entries.", + "noPolicies": "No host ACLs. Route ACLs may still restrict access.", + "expires": "Absolute session expiry: ", + "passwordChanged": "Password changed. All sessions were revoked. Sign in again.", + "passwordMismatch": "The passwords do not match.", + "ruleSyntax": "Use one rule per line, for example: allow 127.0.0.1/32", + "confirmRevoke": "Sign out every administrator session, including this one?", + "streamLive": "SSE live", + "streamFallback": "Polling fallback", + "auth.required": "Your session expired or was revoked. Sign in again.", + "auth.invalid_credentials": "Incorrect username or password.", + "auth.password_policy": "The password must contain 12-128 UTF-8 bytes and no line breaks.", + "auth.invalid_username": "Use 3-64 letters, digits, dots, dashes or underscores.", + "auth.invalid_setup_token": "The setup token is invalid. Read it from the local terminal.", + "auth.already_initialized": "An administrator already exists. Sign in.", + "auth.rate_limited": "Too many attempts. Retry after 60 seconds or use local password recovery.", + "auth.busy": "Password workers are busy. Retry shortly.", + "auth.csrf": "Request protection failed. Reload the page and retry.", + "auth.invalid_host": "Use the configured administration address and allowed hostname.", + "auth.invalid_origin": "Cross-origin administration is blocked.", + "auth.credentials_changed": "Credentials changed concurrently. Sign in again.", + "auth.unavailable": "Administration storage is temporarily unavailable.", + "events.too_many_viewers": "Live viewer limit reached; polling is available.", + "protocol": "Upstream protocol", + "protocolHelp": "HTTP/2 and auto use the backend authority. Preserve Host is available with HTTP/1.1 only. RFC 8441 can use an explicit HTTP/2 upstream; other WebSocket transports bridge through HTTP/1.1.", + "addressAllowlist": "Optional address allowlist (CIDR, one per line)", + "caPem": "Additional trusted CA / certificate (PEM, optional)", + "backendTlsHelp": "TLS encryption remains available, but certificate/hostname verification is off unless enabled explicitly. Private addresses still need explicit approval, including DNS answers.", + "advancedTransport": "Transport and trust", + "tls": "Certificates", + "tlsTitle": "Encrypted, deliberately.", + "tlsDescription": "Exact SNI names. Private local certificate files. Apply bindings without restarting.", + "certificateBindings": "Certificate bindings", + "addCertificate": "Add certificate", + "certificateId": "Certificate ID", + "certificateFile": "Certificate filename", + "privateKeyFile": "Private key filename", + "defaultCertificate": "Use as the default certificate", + "saveCertificate": "Apply certificate", + "reloadCertificates": "Reload certificate files", + "certificateHelp": "Upload a PEM pair, reference files already in data/certs, or deploy an externally issued certificate with `./dev.sh tls deploy --id ID --cert FULLCHAIN --key PRIVKEY`. Reload re-reads configured files without changing the configuration revision.", + "certificateHint": "External Certbot hook: ./dev.sh tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem", + "emptyCertificates": "No explicit SNI bindings. The generated default certificate is used while the TLS listener is enabled.", + "certificateSafety": "Certificates secure TLS connections, not routing. Assign a certificate to a vhost. Changes affect new handshakes.", + "wsActive": "WebSocket tunnels", + "h2Requests": "HTTP/2 requests", + "h2ActiveConnections": "Active H2 connections", + "tlsFailures": "TLS handshake errors", + "tlsListener": "TLS listener", + "notEnabled": "Disabled", + "websocket_closed": "WebSocket closed", + "defaultLabel": "DEFAULT", + "language": "Language", + "settings": "Settings", + "settingsTitle": "Configure your edge.", + "settingsDescription": "Switch between function tabs. Unsaved changes stay in their forms.", + "cacheHitRatio": "Cache hit ratio", + "processMemory": "Process memory", + "systemLoad": "SYSTEM LOAD", + "systemChart": "Recent system CPU usage", + "systemMemory": "System RAM", + "systemSwap": "System swap", + "systemUptime": "System uptime", + "loadAverage": "Load 1 / 5 / 15 min", + "cacheOverview": "RAM cache", + "cacheObjects": "Objects / memory", + "cacheEvictions": "Evicted / expired", + "processDiagnostics": "Process", + "platform": "Platform", + "processCpu": "CPU (100% = 1 core)", + "fileDescriptors": "File descriptors / limit", + "processThreads": "OS threads", + "processVirtualMemory": "Virtual memory / limit", + "processStartTime": "Process start", + "containerMemory": "cgroup RAM / limit", + "networkDiagnostics": "Network and responses", + "hostScope": "OS scope", + "networkRate": "RX / TX per second", + "meanLatency": "Mean exchange duration", + "filterLogs": "Filter host or path", + "filterResult": "Filter result", + "allResults": "All results", + "routeCache": "Route cache policy", + "inheritCache": "Inherit global policy", + "bypassCache": "Always bypass", + "listeners": "Listeners", + "httpConnections": "HTTP connections", + "httpConnectionsHelp": "Connection lifecycle and transport limits for HTTP/2 and HTTP/3.", + "http2Tab": "HTTP/2", + "http3Tab": "HTTP/3", + "http2Settings": "HTTP/2 connections", + "http2SettingsHelp": "HTTP/2 enablement is controlled per listener. Tune idle, maximum lifetime and graceful GOAWAY drain limits here.", + "http2IdleTimeout": "Idle timeout (seconds)", + "http2MaxLifetime": "Maximum connection lifetime (seconds, 0 = disabled)", + "http2DrainTimeout": "Drain timeout (seconds)", + "http2DrainHelp": "These limits apply to this listener. Idle timeout applies only to unused connections; maximum lifetime is absolute; drain bounds active streams after GOAWAY. Changes require restart.", + "http2Save": "Save HTTP/2 settings", + "http2NoEnabledListeners": "No listener has HTTP/2 enabled. Enable HTTP/2 or h2c in Settings > Listeners first.", + "http2ListenersDirty": "Save pending listener changes before editing HTTP/2 settings.", + "restartLabel": "RESTART", + "listenersHelp": "Named IP and port bindings. Changes require restart. The administration endpoint remains separate.", + "httpAddress": "HTTP bind address and port", + "httpsAddress": "HTTPS bind address and port", + "enableHttps": "Enable HTTPS listener", + "lowPortsHelp": "Privileged ports may need CAP_NET_BIND_SERVICE. Do not run the whole application as root.", + "saveListeners": "Save listeners", + "inheritListeners": "Use startup defaults", + "responseSettings": "Client response", + "hotApply": "LIVE APPLY", + "serverHeader": "Server header", + "serverPreserve": "Preserve origin value", + "serverHide": "Hide completely", + "serverCustom": "Replace / add custom value", + "serverValue": "Custom Server value", + "compression": "Streaming compression", + "compressionMin": "Minimum response size (bytes)", + "compressionHelp": "Negotiates Accept-Encoding. Skips private responses, cookies, ranges, SSE and no-transform; existing compressed bodies are passed through.", + "saveResponse": "Apply response settings", + "cacheSettings": "Cache", + "enableCache": "Enable cache", + "cacheSafety": "Complete public-safe GET responses are cached. Authorization, cookies and private/no-store responses still bypass. One byte range can be served from a complete cached object; multipart/unsupported ranges pass through.", + "cacheMemory": "HOT allocated budget (MiB)", + "cacheObject": "Maximum object (KiB)", + "cacheEntries": "Maximum entries", + "cacheMaxTtl": "Maximum TTL (seconds)", + "cacheDefaultTtl": "Fallback TTL for public responses (0 = off)", + "bypassQuery": "Bypass URLs with a query string", + "cachePrefixes": "Bypass path prefixes, one per line", + "cacheAgeHelp": "Age is always sent on cache hits. Counters remain available even when diagnostic headers are hidden. Only cache-affecting configuration changes invalidate incompatible objects; managed software updates hand hot objects to cold storage when the cold tier is enabled.", + "saveCache": "Apply cache policy", + "purgeCache": "Purge all cache", + "customHeaders": "Global custom headers", + "globalHeadersHelp": "Request rules go to the backend; response rules go to the client. Route rules run after global rules. Server policy takes final precedence.", + "responseHeaders": "Response to client", + "requestHeaders": "Request to backend", + "addHeader": "Add header rule", + "saveHeaders": "Apply header rules", + "unavailable": "N/A", + "threads": "threads", + "realSample": "Measured", + "noKnownLimit": "unknown / unlimited", + "unlimited": "unlimited", + "restartPending": "Saved listener changes are pending. Restart RustProxy to apply them.", + "activeListeners": "Currently active", + "headerLimit": "At most 32 rules per direction.", + "headerOperation": "Operation", + "header_set": "Set", + "header_append": "Append", + "header_remove": "Remove", + "headerName": "Header name", + "headerValue": "Header value", + "confirmInherit": "Restore listener defaults from startup flags and environment on the next restart?", + "confirmPurge": "Purge every cached object and cancel all pending cache fills?", + "cachePurged": "Cache purged; removed entries", + "logsDropped": "dropped", + "updateAvailable": "New version", + "vhosts": "Vhosts", + "vhostsTitle": "Virtual hosts & backends", + "vhostsDescription": "Manage hostnames, frontend bindings, backends and per-host policies.", + "vhHealthTitle": "Backends", + "vhManage": "Manage vhosts", + "vhHealthHint": "Live state: leases cover the entire exchange; traffic is an EWMA of payload bytes.", + "vhHealthEmpty": "No backend diagnostics yet.", + "vhVhost": "Vhost", + "vhActive": "Active", + "vhRequests": "Requests", + "vhErrors": "Errors", + "vhLatency": "Latency (EWMA)", + "vhTraffic": "Traffic/s", + "vhClientGeneration": "Client gen.", + "vhGenerationRequests": "Gen. requests", + "vhGenerationAge": "Gen. age", + "vhClientRotations": "Rotations", + "vhIntro": "Each vhost owns its bound IPs, paths and backends. Unlisted addresses cannot reach it. Listener changes require restart.", + "vhList": "Virtual hosts", + "vhSearch": "Search vhosts", + "vhSearchPlaceholder": "Search hostname, vhost or backend", + "vhSearchEmpty": "No vhosts match this search.", + "vhNew": "New vhost", + "vhMigrate": "Migrate a legacy route group", + "vhImport": "Load into editor", + "vhMigrationHint": "Migration is saved atomically. Routes sharing one host and one backend are grouped; ambiguous host ownership is rejected.", + "vhEditor": "Vhost configuration", + "vhReset": "Discard changes", + "vhSafetyHint": "Private IP binding is not authentication. Keep firewall/ACL rules. HSTS preload is opt-in; affinity cookies are not login sessions.", + "vhId": "Vhost ID", + "vhHosts": "Hostnames", + "vhEnabled": "Enabled", + "vhFrontends": "Frontends / bound addresses", + "vhAddFrontend": "Add frontend", + "vhAddress": "IP:port (IPv6: [address]:port)", + "vhTls": "TLS enabled", + "vhHttp2": "Prefer HTTP/2 over TLS; retain HTTP/1.1", + "vhBackendPool": "Backends", + "vhAddBackend": "Add backend", + "vhMemberId": "Backend ID", + "vhUrl": "Origin URL", + "vhWeight": "Weight", + "vhBackup": "Backup only", + "vhDrain": "Drain new sessions", + "vhPrivate": "Allow private origin IP", + "vhPreserveHost": "Preserve client Host (HTTP/1.1 only)", + "vhProtocol": "Origin protocol", + "vhProtocolHttp1": "HTTP/1.1", + "vhProtocolAuto": "TLS ALPN: HTTP/2 + HTTP/1.1", + "vhProtocolHttp2": "HTTP/2 (TLS: with HTTP/1.1 fallback; plaintext: h2c)", + "vhAddressAllowlist": "Origin IP/CIDR allowlist (optional)", + "vhTlsServerName": "TLS server name / SNI (optional)", + "vhTlsVerify": "Verify backend certificate and hostname", + "vhTlsVerifyHelp": "Disabled when omitted. Enable it when RustProxy must validate the backend certificate chain and identity. If verification fails, set TLS server name to a DNS name present in the certificate and/or add the private CA PEM. Do not use an IP address as SNI.", + "vhCa": "Additional trusted CA (PEM, optional)", + "vhBalancing": "Balancing & connection reuse", + "vhAlgorithm": "Algorithm", + "vhRoundRobin": "Smooth weighted round-robin", + "vhLeastConnections": "Weighted least active exchanges", + "vhLeastTraffic": "Weighted least traffic (EWMA)", + "vhAdaptive": "Adaptive: activity + latency + traffic", + "vhIpHash": "Client IP hash", + "vhSlowStart": "Recovery slow-start (seconds)", + "vhRetryMax": "Failover retries", + "vhRetryConnect": "Retry connection failures", + "vhRetryTimeouts": "Retry response-header timeouts", + "vhRetryStatuses": "Retry HTTP statuses", + "vhRetryHelp": "Retries are limited to body-free GET, HEAD and OPTIONS requests, use a different healthy backend and never replay WebSocket or write requests.", + "vhKeepalive": "Reuse upstream connections (keepalive)", + "vhIdleTimeout": "Idle pool timeout (seconds)", + "vhMaxIdle": "Max idle connections / origin", + "vhTcpKeepalive": "TCP / HTTP/2 keepalive interval (seconds)", + "vhHealth": "Backend health", + "vhHealthMode": "Check type", + "vhOff": "Off", + "vhTcp": "TCP connect", + "vhHttp": "HTTP status + response time", + "vhHealthPath": "HTTP check path", + "vhHealthHost": "HTTP Host override (optional)", + "vhInterval": "Interval (ms)", + "vhTimeout": "Timeout (ms)", + "vhSlow": "Slow threshold (ms; 0 = off)", + "vhFall": "Failures before down", + "vhRise": "Successes before recovery", + "vhStatusMin": "Minimum HTTP status", + "vhStatusMax": "Maximum HTTP status", + "vhHealthNote": "HTTP probes use HTTP/1.1 and measure time to headers, not body duration. Use TCP for h2c-only services. New backends wait for successful probes. Active health is independent from passive health.", + "vhPassiveHealth": "Passive Backend Health", + "vhPassiveEnabled": "Allow normal request failures to mark a backend unhealthy", + "vhPassiveHelp": "Off by default. Errors are still logged and counted, but normal user traffic cannot change backend health until this is explicitly enabled.", + "vhPassiveConnect": "Count connection errors", + "vhPassiveTimeouts": "Count timeouts", + "vhPassiveIo": "Count body/read/write I/O errors", + "vhPassive5xx": "Count HTTP 5xx responses", + "vhPassiveSlow": "Count slow responses", + "vhPassiveFall": "Passive failures before down (empty = active fall)", + "vhPassiveRise": "Passive successes before recovery (empty = active rise)", + "vhPassiveWarning": "Enabling HTTP 5xx or slow-response failures can quarantine the whole backend after repeated errors from a single endpoint.", + "vhSticky": "Sticky sessions", + "vhStickyMode": "Affinity mode", + "vhCookie": "Opaque proxy cookie", + "vhCookieName": "Cookie name (empty = per-vhost default)", + "vhCookieTtl": "Cookie lifetime (seconds)", + "vhStickyNote": "Cookie affinity bypasses shared cache. Drain preserves existing cookie sessions. IP affinity uses the verified client IP under the configured trusted-proxy policy.", + "vhSecurity": "Security", + "vhHsts": "Enable HSTS (TLS responses only)", + "vhHstsAge": "HSTS max-age (seconds)", + "vhHstsSub": "HSTS includeSubDomains", + "vhHstsPreload": "HSTS preload (explicit opt-in)", + "vhNosniff": "X-Content-Type-Options: nosniff", + "vhFrame": "X-Frame-Options", + "vhPreserve": "Preserve origin value", + "vhDeny": "DENY", + "vhSameorigin": "SAMEORIGIN", + "vhReferrer": "Referrer-Policy (optional)", + "vhCsp": "Content-Security-Policy (optional)", + "vhPermissions": "Permissions-Policy (optional)", + "vhAdvanced": "Advanced: paths, ACL and custom headers", + "vhPaths": "Paths (JSON; optional backend_id pins a path to a single pool member)", + "vhAcl": "Vhost ACL (JSON or null)", + "vhHeaders": "Request / response header rules (JSON)", + "vhEmpty": "No vhosts yet. Existing routes continue to work.", + "vhUnsaved": "Discard unsaved vhost changes?", + "vhDelete": "Remove this vhost? Bound sockets are closed after restart.", + "vhConflict": "That vhost ID already exists.", + "vhRowLimit": "The maximum number of rows has been reached.", + "vhMigrationAmbiguous": "Hostnames overlap other legacy routes. Resolve ownership in JSON before migration.", + "vhMigrationPending": "Legacy migration will be committed with this save.", + "vhMigrationNone": "Select a legacy route", + "vhJsonInvalid": "Invalid JSON or data type in paths, ACL or headers.", + "vhUp": "Up", + "vhDown": "Down", + "vhChecking": "Checking", + "vhDraining": "Draining", + "vhDisabled": "Disabled", + "vhHealthDisabled": "Checks off", + "vhHealthUnknown": "Unknown", + "vhNewLabel": "NEW", + "vhEditLabel": "EDIT", + "vhFrontendNote": "Use an IP assigned to this machine. A wildcard accepts every IP in its address family; host routing still checks the local destination. TLS certificates are configured in the TLS tab.", + "close": "Close", + "inherit": "Inherit", + "liveLogs": "Live logs", + "logVhost": "Filter by vhost", + "logAllVhosts": "All vhosts", + "logAllMethods": "All methods", + "logPause": "Pause", + "logPaused": "PAUSED", + "logResume": "Resume", + "logPin": "Dock", + "logUndock": "Open as modal", + "logColumns": "Columns", + "logColumnsRequired": "At least one Live Logs column must remain visible.", + "logLoadHistory": "Increase buffer", + "logHistoryLoaded": "Live buffer increased to {count} retained entries.", + "logHost": "Host", + "logBufferHint": "Live view starts with the latest 256 completed exchanges. Increase buffer to seed it with retained history and keep accumulating live entries up to 4096 until the log window is closed. Export includes the currently filtered rows.", + "settingsSecurityHint": "Accounts and ACLs are global. SSL, HSTS, headers and cache are also configured inside each vhost.", + "theme": "Theme", + "themeDark": "Dark", + "themeLight": "Light", + "density": "Interface density", + "densityCompact": "Compact", + "densityDense": "Dense", + "densityComfortable": "Comfortable", + "globalPages": "Default responses", + "pagesHelp": "Pages for direct IP, unknown hosts and errors. An empty status selector preserves the original status. Static pages do not contact the upstream.", + "pageInherit": "Default / inherited", + "pageWelcome": "Congratulations page", + "pageEmpty": "Empty response", + "pageHtml": "Custom HTML", + "pageStatus": "Response status", + "pageOriginalStatus": "Original status", + "pageHtmlSource": "HTML source", + "pageUploadHtml": "Optional HTML file (32 KiB maximum)", + "pageTooLarge": "HTML must not exceed 32 KiB in UTF-8.", + "customErrorPages": "Custom error pages", + "pageStaticHost": "Static / maintenance host", + "pageMissingPath": "Unmatched path", + "pageDirectIp": "Direct IP access", + "pageUnknownHost": "Unknown hostname", + "pagesSafetyHint": "HTML is public content, not an admin template. ACLs still run first. Explicit HTTP 200 for an error masks its status to clients and monitoring. Total configuration size is limited.", + "vhDetailsTab": "Details", + "vhSsl": "SSL certificates", + "vhCertificate": "Named certificate", + "vhCertificateDefault": "Global SNI / default certificate", + "vhCertificateFile": "Certificate / full chain (PEM)", + "vhPrivateKeyFile": "Private key (PEM)", + "vhUploadCertificate": "Upload and validate pair", + "vhSelectCertificateFiles": "Choose both a certificate and private key file.", + "vhCertificateTooLarge": "Each PEM file is limited to 128 KiB.", + "vhCertificateNeedsHosts": "Enter vhost domain names in Details first.", + "vhCertificateStaged": "Pair verified and staged. Save this vhost to activate its certificate.", + "vhCertificateUploadHint": "Optional upload verifies key match and domain coverage. Private keys are stored in private files, never returned by the API. Save the vhost to activate the selection. Uploads do not save other changes. Listener changes require restart.", + "vhCache": "Cache", + "vhCacheTtl": "Maximum TTL (seconds, blank inherits)", + "vhCacheDefault": "Public default TTL (blank inherits)", + "vhCacheObject": "Object limit (KiB, blank inherits)", + "cacheEnabled": "Enable cache", + "cacheBypassQuery": "Bypass query strings", + "cacheStatusHeader": "Expose X-Cache", + "cacheHitsHeader": "Expose X-Cache-Hits", + "cacheRfcHeader": "Expose Cache-Status", + "cacheBypassPrefixes": "Bypass path prefixes", + "vhCacheCustomPrefixes": "Override inherited bypass paths", + "vhCacheHint": "Per-host policy can enable caching independently of the global default. All vhosts share global RAM and entry ceilings. Cookie affinity, private responses and authorization still bypass cache.", + "vhPurgeCache": "Purge host cache", + "vhPurgeConfirm": "Purge only this vhost cache? In-progress fills for this host will also be invalidated.", + "vhPages": "Error pages", + "vhHeadersOrder": "Order: global rules, vhost rules, path rules, then security/Server policy. Advanced JSON remains available.", + "vhNewHealthHint": "Save the vhost to start observing its backend health.", + "listenerAdd": "Add listener", + "listenerMigrate": "Convert defaults to named listeners", + "listenerScopeHint": "Internal / public is a label, not a firewall. New listeners do not expose legacy routes unless explicitly selected.", + "listenerLimit": "Maximum 64 named listeners.", + "listenerEndpoint": "Listener", + "listenerName": "Display name", + "listenerScope": "Label", + "listenerInternal": "Internal", + "listenerPublic": "Public", + "listenerLegacy": "Allow legacy routes", + "listenerInUse": "Listener is assigned to vhosts", + "listenerDuplicate": "Listener IDs must be unique.", + "listenerChooseHint": "Select named listeners configured in Settings > Listeners. A disabled listener grants no access.", + "listenerMissing": "Missing listener", + "http3Settings": "HTTP/3 / QUIC", + "http3SettingsHelp": "HTTP/3 enablement is controlled in Settings > Listeners. Tune advertisement, connection and stream limits here.", + "http3NoTlsListeners": "No TLS listeners are configured. Add and save a TLS listener first.", + "http3NoEnabledListeners": "No TLS listener has HTTP/3 enabled. Enable HTTP/3 in Settings > Listeners first.", + "http3ListenersDirty": "Save pending listener changes before editing HTTP/3 settings.", + "http3Save": "Save HTTP/3 settings", + "h2Configure": "Configure HTTP/2 limits", + "h3Enable": "Enable HTTP/3 over QUIC (UDP)", + "h3Configure": "Configure HTTP/3 limits", + "h3Limits": "HTTP/3 limits and advertisement", + "h3_alt_svc_max_age": "Alt-Svc lifetime (s)", + "h3_max_concurrent_connections": "Connections per listener", + "h3_max_concurrent_bidistream": "Bidirectional streams per connection", + "h3_max_concurrent_unistream": "Unidirectional streams per connection", + "h3_max_idle_timeout": "QUIC idle timeout (s; 0 = unlimited)", + "h3Help": "HTTP/3 requires TLS. Keep TCP plus the same UDP port available; HTTP/1.1 and HTTP/2 remain. Zero disables the local QUIC idle timeout. Changes require restart.", + "h3TuningHelp": "These limits apply only when HTTP/3 is enabled for this TLS listener. Changes require restart.", + "h3Requests": "HTTP/3 requests", + "certImport": "Import certificate", + "certImportSave": "Import and save in library", + "certLibraryHint": "Upload fullchain/certificate and private key in PEM. Save once, then assign the certificate to one or more vhosts.", + "certCheckDomains": "Domains to verify (comma-separated)", + "certAcmeLater": "Issued certificates are imported into the library and assigned per vhost.", + "certAdvanced": "Existing files / advanced", + "certLegacyNames": "Legacy SNI names (optional; prefer per-vhost assignment)", + "certAssigned": "Assigned vhosts", + "certUnassigned": "Not assigned", + "certInUse": "Certificate is in use. Reassign vhosts and change the default before removal.", + "certDuplicate": "This certificate ID exists. Use a new ID for safe rotation.", + "certManage": "Manage certificate library", + "certSelectHint": "Select an imported certificate. Uploads and rotation are in the Certificates tab. Assignments are validated against vhost names.", + "vhTinyauth": "Authentication and IP access", + "vhTabAuth": "Authentication", + "taEnable": "Enable Tinyauth protection", + "taUrl": "Tinyauth URL / verification endpoint", + "taLogin": "Public login URL", + "taRedirectForbidden": "Accept same-origin provider redirects for 403", + "taConnect": "Connect timeout (s)", + "taTimeout": "Total verification timeout (s)", + "taRequestHeaders": "Client headers sent to Tinyauth", + "taResponseHeaders": "Verified identity headers sent to application", + "taHelp": "An origin URL adds /api/auth/nginx automatically. Verification is body-free and runs before cache and WebSocket upgrades. Protected responses use private, no-store. Configure Tinyauth to trust the actual RustProxy IP.", + "vhResponsePolicy": "Response identity and diagnostics", + "vhInherit": "Inherit global settings", + "diagnosticHeaders": "Diagnostic response headers", + "diagInherit": "Inherit diagnostic headers", + "diagRequestId": "Expose X-Request-ID", + "hideMockOrigin": "Hide X-Mock-Origin", + "diagHelp": "X-Request-ID is opt-in. Other upstream response headers are controlled with ordinary response-header rules.", + "forwardingSettings": "Client identity / forwarding", + "forwardingHelp": "By default, client-supplied forwarding headers are discarded. Add only immediate proxies you control. Trusted chains are evaluated right-to-left, stopping at the first untrusted address.", + "forwardingCanonical": "RustProxy generates Forwarded, X-Forwarded-For, X-Real-IP, X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port and X-Forwarded-URI. Socket destination never comes from a header.", + "trustedProxies": "Trusted proxy CIDRs (one per line; /32 for one IPv4, /128 for one IPv6)", + "trustForwardedProto": "Trust X-Forwarded-Proto only from trusted proxies", + "listenerId": "Listener ID", + "cache": "Cache", + "cacheTitle": "Cache, explained.", + "cacheDescription": "Objects, domain effectiveness and precise decisions.", + "cacheRefresh": "Refresh", + "cacheLive": "Live (3 s)", + "cachePurgeScope": "Purge selected scope", + "cacheObjectCount": "Resident objects", + "cacheSaved": "Body bytes served from RAM", + "cacheCounterScope": "Domain counters since configuration revision", + "cacheDomains": "Domains and effectiveness", + "cacheScopeHint": "Memory limits, fills and evictions are global. Domain counters reset on configuration publication; purging objects does not reset counters.", + "cacheDomain": "Domain", + "cacheReasons": "Decision counters", + "cacheNoDomains": "No cache decisions yet. Send traffic to a configured host.", + "cacheObjectList": "Stored objects", + "cachePrevious": "Previous", + "cacheNext": "Next", + "cacheObjectHint": "Most recently used first. Click Target or Cache key / tags to copy the full value. Bodies and request headers are not exposed.", + "cachePath": "Path", + "cacheBodySize": "Body", + "cacheAge": "Age", + "cacheTtlRemaining": "Remaining TTL", + "cacheNoObjects": "No fresh objects in this scope. Inspect the decision counters above.", + "cacheLegacy": "Unassigned", + "cacheGlobalLimit": "Global limit", + "cacheFills": "Active fills (global)", + "cacheRejected": "Rejected fills (global)", + "cacheUpdated": "Updated", + "acmeTitle": "Let's Encrypt / ACME", + "acmeHelp": "Issue an ACME certificate, add it to the library, then assign it to a vhost. Automatic renewal starts after import.", + "acmeEmail": "ACME contact email", + "acmeDomains": "DNS names, comma-separated (wildcards only with DNS-01)", + "acmeEnvironment": "CA environment", + "acmeStaging": "Staging - not browser-trusted", + "acmeProduction": "Production", + "acmeDnsServer": "DNS update server IP", + "acmeDnsPort": "DNS update port", + "acmeKeyName": "TSIG key name", + "acmeSecret": "TSIG secret (base64)", + "acmeAlgorithm": "TSIG algorithm", + "acmePropagation": "DNS propagation wait (seconds)", + "acmeSignQuery": "Sign SOA discovery query", + "acmeTos": "I accept the Let's Encrypt subscriber agreement and authorize domain validation.", + "acmeConfirmProduction": "I confirm production issuance (CA rate limits apply).", + "acmeIssue": "Request certificate", + "acmeIdle": "No issuance job in this process.", + "acmeImport": "Add issued certificate to library", + "acmeRenewalHint": "Initial issuance/import remains explicit. Managed certificate profiles are then checked automatically while RustProxy is running; saved renewal status is restored from SQLite after restart.", + "acmeReplace": "Replace the existing library certificate? Current vhost assignments will be retained and revalidated.", + "acmeImported": "Certificate saved. Assign it in the vhost SSL tab.", + "certFuture": "Managed automatic renewal is available for supported ACME providers; saved renewal observations are persisted in SQLite.", + "cacheReason_cache_hit": "Fresh object reused", + "cacheReason_cache_miss": "No matching fresh object", + "cacheReason_cache_disabled": "Cache disabled", + "cacheReason_route_disabled": "Route bypass", + "cacheReason_request_cookie": "Application cookie", + "cacheReason_request_authorization": "Authorization header", + "cacheReason_request_cache_control": "Client cache directive / hard refresh", + "cacheReason_request_pragma": "Client Pragma", + "cacheReason_request_method": "Method other than GET", + "cacheReason_request_body": "Nonempty request body", + "cacheReason_request_range": "Range request", + "cacheReason_request_conditional": "Conditional request", + "cacheReason_request_upgrade": "Protocol upgrade", + "cacheReason_query_excluded": "Query excluded", + "cacheReason_path_excluded": "Path excluded", + "cacheReason_request_cache_control_invalid": "Invalid request cache directives", + "cacheReason_response_status": "Non-200 response", + "cacheReason_response_set_cookie": "Origin Set-Cookie", + "cacheReason_response_cache_control": "Origin privacy/cache directive", + "cacheReason_response_cache_control_invalid": "Invalid origin cache directives", + "cacheReason_response_vary": "Uncacheable Vary", + "cacheReason_response_range": "Partial response", + "cacheReason_response_trailers": "Response trailers", + "cacheReason_response_ttl_size_or_metadata": "TTL, size or metadata rejected", + "cacheReason_response_headers_policy": "Response rule prevents storage", + "cacheReason_configuration_changed": "Configuration changed", + "cacheReason_not_proxy_response": "Local page / rejected request", + "cacheReason_tinyauth": "Tinyauth protected content", + "cacheReason_sticky_cookie": "Sticky-session cookie mode", + "acme.working": "Certificate request is running.", + "acme.ready_to_import": "Certificate validated; ready to add to the library.", + "acme.certbot_not_installed": "Certbot is not installed or is not in the service PATH. Install Certbot and certbot-dns-rfc2136.", + "acme.certbot_failed_check_private_log": "Certbot failed. Check the private ACME logs; the exact path is shown with the failed operation.", + "acme.production_confirmation": "Explicit production confirmation is required.", + "acme.consent_required": "Accept the subscriber agreement and confirm the selected CA environment.", + "acme.provider_timeout": "Certificate provider deadline exceeded. Check the Certbot log path shown with the failed operation before retrying.", + "acme.invalid_key_secret": "TSIG secret must be valid base64 (16-512 decoded bytes).", + "acme.job_busy": "Another certificate request is already running.", + "acme.cancelled": "Certificate job cancelled on shutdown.", + "acme.certificate_validation_failed": "Issued certificate/key or domain coverage validation failed. Nothing was activated.", + "acme.invalid_request": "ACME: invalid request.", + "acme.unknown_field": "ACME: unknown field.", + "acme.invalid_id": "ACME: invalid id.", + "acme.invalid_email": "ACME: invalid email.", + "acme.invalid_domains": "ACME: invalid domains.", + "acme.invalid_domain": "ACME: invalid domain.", + "acme.dns_names_only": "ACME: dns names only.", + "acme.invalid_environment": "ACME: invalid environment.", + "acme.tos_required": "ACME: tos required.", + "acme.invalid_dns_server": "ACME: invalid dns server.", + "acme.invalid_limits": "ACME: invalid limits.", + "acme.invalid_key_algorithm": "ACME: invalid key algorithm.", + "acme.invalid_sign_query": "ACME: invalid sign query.", + "acme.unsafe_directory": "ACME: unsafe directory.", + "acme.unsafe_output_path": "ACME: unsafe output path.", + "acme.invalid_pem_size": "ACME: invalid pem size.", + "acme.invalid_pem": "ACME: invalid pem.", + "acme.profile_limit": "ACME: profile limit.", + "acme.profile_busy": "ACME: profile busy.", + "acme.staging_limit": "ACME: staging limit.", + "acme.request_too_large": "ACME: request too large.", + "acme.local_io_or_json_error": "ACME: local io or json error.", + "acme.no_certificate_directory": "ACME: no certificate directory.", + "acme.python_not_available": "ACME: python not available.", + "acme.worker_io": "ACME: worker io.", + "acme.invalid_worker_response": "ACME: invalid worker response.", + "acme.worker_failed": "ACME: worker failed.", + "acme.validation_worker_failed": "ACME: validation worker failed.", + "cacheResidentLabel": "Cache memory", + "certificateFuture": "ACME providers: HTTP-01, Cloudflare, OVH and RFC2136. Renewal is manual.", + "prometheusTitle": "Prometheus", + "prometheusHelp": "A dedicated read-only HTTP listener, separate from admin sessions. Binding, enabling or changing the token variable requires a restart; CIDRs, path and collectors apply live.", + "prometheusEnable": "Enable the scrape endpoint", + "prometheusListen": "Exporter bind IP and port", + "prometheusPath": "Metrics path", + "prometheusCidrs": "Allowed scraper IPs (CIDR, one per line)", + "prometheusTokenEnv": "Environment variable holding the bearer token (optional on loopback)", + "prometheusTokenHelp": "Enter a variable NAME, not the secret. Set its value to a random 32+ character token in the service environment. Non-loopback binding requires it. This endpoint is HTTP: use a private network or a TLS tunnel. The Prometheus credential file must contain the same token.", + "prometheusCollectors": "Metric groups", + "prometheusPreview": "Preview current metrics", + "prometheusPreviewFailed": "Could not fetch metrics", + "prometheusActive": "Active endpoint", + "prometheusDisabled": "Exporter disabled. Authenticated preview remains available.", + "certificateProvider": "Certificate source / validation method", + "providerHttp01": "Let's Encrypt - domain validation (HTTP-01)", + "providerCloudflare": "Let's Encrypt - Cloudflare API (DNS-01)", + "providerOvh": "Let's Encrypt - OVH API (DNS-01)", + "providerRfc2136": "Let's Encrypt - RFC2136 / TSIG (DNS-01)", + "providerImport": "Import certificate and private key (PEM)", + "providerExisting": "Existing server files (advanced)", + "providerHint_http01": "Requires Certbot. Every domain must resolve to this proxy and be reachable on public TCP port 80. RustProxy serves the challenge without stopping HTTP traffic. Wildcards need DNS-01. Staging certificates are not browser-trusted; automatic renewal is not installed.", + "providerHint_cloudflare": "Requires Certbot + certbot-dns-cloudflare. Use a restricted API token with Zone:DNS:Edit for the necessary zones only. Supports wildcard certificates. Secrets stay in private server files.", + "providerHint_ovh": "Requires Certbot + certbot-dns-ovh. Supply application key, application secret and consumer key authorized for the required DNS zones. Supports wildcard certificates.", + "providerHint_rfc2136": "Requires Certbot + certbot-dns-rfc2136 and a DNS server accepting signed RFC2136 updates. Limit the TSIG key to the required challenge records.", + "providerHint_import": "Upload a matching PEM/fullchain and private key. Save in the library, then assign the certificate in a vhost SSL tab.", + "providerHint_existing": "Advanced: only existing private files inside the configured certificate directory. Never put private key contents in JSON.", + "acmeCfToken": "Cloudflare API token", + "acmeOvhEndpoint": "OVH API region", + "acmeOvhApplicationKey": "OVH application key", + "acmeOvhApplicationSecret": "OVH application secret", + "acmeOvhConsumerKey": "OVH consumer key", + "acme.invalid_provider": "Select a supported certificate provider.", + "acme.invalid_api_credential": "API credential is missing or has invalid characters.", + "acme.invalid_ovh_endpoint": "Select OVH Europe or Canada.", + "acme.http01_no_wildcard": "HTTP-01 cannot issue wildcard names. Select a DNS-01 provider.", + "acme.http01_listener_required": "HTTP-01 needs an active plaintext HTTP listener reachable on public port 80.", + "cacheScopeLegacy": "Unassigned / old scope", + "certificateLibrary": "Certificates", + "certificateWorkspaceHelp": "Manage installed certificates, automatic renewal, and generation/import in separate views.", + "certificateTabInstalled": "Installed", + "certificateTabRenewal": "Renewal", + "certificateTabGenerate": "Generate", + "certificateInstalledTitle": "Installed certificates", + "certificateInstalledHelp": "Certificates available to vhosts, redirects, 404 hosts, and the administration listener.", + "certificateGenerateTitle": "Generate and import", + "certificateGenerateHelp": "Choose Let's Encrypt/ACME issuance, PEM upload, or existing files from RustProxy's private certificate directory.", + "certificateOperationStatus": "Latest ACME operation", + "certificateNoRenewalOperation": "No renewal operation in this process.", + "certificateStateIdle": "Idle", + "certificateStateRunning": "Running", + "certificateStateReady": "Ready", + "certificateStateComplete": "Complete", + "certificateStateFailed": "Failed", + "certbotLogs": "Certbot logs", + "systemDiagnostics": "System / process", + "vhWebsockets": "WebSocket support", + "vhLocations": "Custom locations", + "locationPath": "Location prefix", + "locationPool": "Vhost backends", + "locationMissing": "Missing backend", + "locationLimit": "A host supports up to 64 locations.", + "locationAccess": "Location access control", + "locationHeaders": "Location headers", + "locationAddBackend": "Add dedicated backend", + "locationAdd": "Add location", + "locationHelp": "The longest matching prefix wins. The original path and query are retained. Select a backend from this host or add a dedicated backend. Host authentication and ACL always apply.", + "aclUse": "Enable IP access list", + "aclAllow": "Allow", + "aclNetwork": "IP network (CIDR)", + "aclAction": "Action", + "aclAdd": "Add IP rule", + "authMode": "Authentication", + "authNone": "None", + "authTinyauth": "Tinyauth", + "authBasic": "HTTP Basic Auth", + "basicRealm": "Realm (login prompt)", + "basicRequireTls": "Require HTTPS for Basic Auth", + "basicForward": "Forward verified Authorization to backend", + "basicPassword": "Password (12-128 bytes)", + "basicKeepPassword": "Leave empty to keep the password", + "basicHashSaved": "Password set", + "basicHashRequired": "Set a password for each user.", + "basicAddUser": "Add user", + "basicHelp": "Only Argon2id hashes are stored. Verified credentials are removed from upstream requests unless forwarding is enabled. Enable forwarding only to a trusted HTTPS backend or an isolated network. Protected hosts bypass shared cache.", + "basic.too_many_users": "At most 64 users per host.", + "basic.invalid_username": "Invalid username.", + "basic.duplicate_username": "Duplicate username.", + "basic.unsupported_hash": "Use an Argon2id password hash generated by RustProxy.", + "basic.invalid_hash": "Invalid password hash.", + "basic.invalid_realm": "Invalid login realm.", + "basic.users_required": "Basic Auth requires at least one user.", + "basic.busy": "Password workers are busy; try again.", + "renewalTitle": "Automatic renewal", + "renewalHelp": "Managed ACME certificates are checked about every 12 hours while RustProxy is running. Certbot decides when renewal is due. Validated replacements are deployed without restarting listeners. Keep provider credentials and HTTP-01 port 80 available.", + "renewalNone": "No managed ACME certificates in the library.", + "renewalEnabled": "Automatic renewal enabled", + "renewalDisabled": "Automatic renewal disabled", + "renewalEnable": "Enable automatic renewal", + "renewalDisable": "Disable automatic renewal", + "renewalNow": "Check now", + "renewalDryRun": "Validate renewal (dry run)", + "renewalLast": "Last check", + "renewalNext": "Next check", + "renewalExpires": "Valid until", + "acme.renewing": "Checking certificate renewal", + "acme.renewed": "Certificate renewed and deployed", + "acme.not_due": "Certificate does not need renewal yet", + "acme.renewal_test_ok": "Renewal validation passed; active certificate unchanged", + "acme.renewal_profile_missing": "Saved renewal profile is missing or unreadable. Restore the private ACME profile.", + "acme.configuration_changed": "Certificate configuration changed during renewal; nothing deployed.", + "acme.deployment_failed": "Renewed certificate failed configuration validation; previous certificate remains active.", + "acme.not_managed": "Only managed ACME certificates can be renewed automatically.", + "acme.certificate_not_found": "Certificate no longer exists.", + "acme.renewal_disabled": "Automatic renewal is disabled.", + "acme.openssl_not_installed": "OpenSSL is required to inspect certificate validity.", + "cacheReason_basic_auth": "HTTP Basic authentication", + "locationPoolEligible": "Include in the default load-balancing pool", + "locationId": "Location ID", + "vhIpAccess": "Vhost IP access list", + "apiDocs": "Documentation", + "auth.invalid_request": "Invalid request. Check the supplied fields.", + "locationProxyHeaders": "Proxy request headers (to backend)", + "locationResponseHeaders": "Response headers (to client)", + "locationHeadersHelp": "Set replaces a header, append adds a value, remove deletes it. Applied after global and vhost rules, only for this location. Values are literal (no nginx variables). Transport and verified identity headers stay system-managed.", + "headersAdvancedJson": "Advanced header rules (JSON)", + "headersInvalid": "Invalid header rule. Check name, operation and value.", + "headersProtected": "Transport and proxy identity headers cannot be overridden here. Use forwarding, authentication or response settings.", + "docsTitle": "Documentation", + "docsSession": "Uses your administrator session. API writes require CSRF protection.", + "docsSignIn": "Sign in to view documentation", + "docsPanel": "Back to panel", + "docsWrites": "Enable write operations", + "docsWriteConfirm": "This sends a real change to RustProxy. Continue?", + "docsExpired": "Session ended. Sign in again.", + "docsError": "Documentation could not be loaded.", + "docsAccount": "Signed in as", + "docsReadOnly": "Read-only execution by default. SSE streams and login/setup are not executed here.", + "docsLogout": "Sign out", + "authPrivateNote": "Access is restricted to authorized administrators.", + "advanced": "Advanced", + "docsLicenses": "Swagger UI licenses", + "vhTrafficPolicy": "Traffic policy", + "vhHttp3Enabled": "Enable HTTP/3 for this vhost", + "vhCloudflareClientIp": "Use verified Cloudflare client IP", + "vhTimingHeaders": "Expose Server-Timing diagnostics", + "vhRateEnabled": "Enable per-client IP rate limit", + "vhRateRequests": "Requests per window", + "vhRateWindow": "Window (seconds)", + "vhRateBurst": "Burst allowance", + "vhCountryMode": "Country access policy", + "vhCountryBlock": "Block listed countries", + "vhCountryAllow": "Allow only listed countries", + "vhCountryList": "Countries (ISO 3166-1 alpha-2)", + "vhCountryPolicyHelp": "Country rules use the installed GeoIP database. Allow-only mode fails closed when a client country cannot be resolved.", + "vhCountry": "Country", + "vhAddCountryRate": "Add country rate limit", + "vhCountryRateLimit": "At most 64 country-specific rate limits are allowed.", + "vhRateHelp": "Country-specific limits override the base per-IP limit. Exceeded limits return 429; denied countries return 403.", + "vhHealthOffWarning": "Active backend probes are disabled. Passive Backend Health is configured separately and remains off unless explicitly enabled.", + "vhFrontendSelectionOnly": "Select named listeners for this vhost. Listener IP addresses, ports and H2/H3 capabilities are configured only in Settings > Listeners.", + "vhForceSsl": "Force SSL (redirect HTTP to HTTPS)", + "vhForceSslHelp": "Plain HTTP requests for this vhost receive a 308 redirect to HTTPS while preserving path and query. Select at least one plain HTTP listener and at least one TLS listener. If several TLS ports are selected, port 443 is used; otherwise the TLS target port must be unambiguous.", + "vhForceSslNeedsTls": "Force SSL requires at least one enabled TLS listener for this vhost.", + "vhForceSslPortConflict": "Force SSL cannot choose the HTTPS redirect target because selected TLS listeners use multiple non-standard ports. Select one TLS port or include port 443.", + "vhForwardClientIp": "Forward client IP to backend", + "vhForwardClientIpHelp": "Keep enabled for normal reverse-proxy behavior. Disable to withhold Forwarded, X-Forwarded-For and X-Real-IP from the application while RustProxy, ACLs, rate limits and Tinyauth still use the real client IP.", + "vhClientIpHidden": "Client IP hidden from backend", + "listenerMigrateInline": "Existing vhost listener (will migrate)", + "vhDebugOriginPreset": "Apply recommended preset", + "vhDebugOriginTlsWarning": "This preset keeps backend TLS certificate verification disabled. The connection is encrypted, but CA and hostname identity are not checked. Continue?", + "vhOriginPresetHelp": "Debug origin defaults for new backend rows: HTTPS by IP, default LB pool ON, private origin ON, HTTP/1.1, Preserve client Host ON and TLS verification OFF. Re-enable TLS verification whenever the origin certificate can be validated.", + "vhDebugOriginMismatch": "This HTTPS-by-IP origin does not match the debug forwarding preset (pool ON, private origin ON, HTTP/1.1, preserve Host ON, TLS verification OFF). If you enable verification, set TLS server name to the certificate DNS name and add its private CA when needed. Continue with the current values?", + "vhCacheStaticCookie": "Ignore request cookies for selected static file extensions", + "vhCacheStaticCustom": "Use a custom static extension list", + "vhCacheStaticExtensions": "Static extensions (one per line, without dot)", + "vhCacheStaticHelp": "Inherit the global policy or override it for this vhost. Ignore Cookie only for files whose bytes do not depend on the session; Set-Cookie, private/no-store and Vary: Cookie still block shared storage.", + "cacheStaticTitle": "Static asset cache boost", + "cacheStaticCookie": "Ignore request cookies for static files", + "cacheStaticExtensions": "Global static extensions (one per line, without dot)", + "cacheStaticHelp": "Enable this only for files whose bytes do not depend on the session. Request Cookie then does not affect the shared cache key for these extensions; responses with Set-Cookie, private/no-store or Vary: Cookie are still never stored.", + "vhHttp2Enabled": "Enable HTTP/2 for this vhost", + "vhFrontendProtocolsHelp": "H2 and H3 are per-vhost opt-outs. A switch is available only when at least one selected listener has that protocol enabled in Settings > Listeners.", + "administration": "Administration", + "administrationActiveHttp": "Active HTTP administration", + "administrationActiveHttps": "Active HTTPS administration", + "administrationCertificate": "Certificate", + "administrationGeneratedCertificate": "Application-generated default certificate", + "administrationHelp": "HTTPS allows the administration listener to bind beyond loopback. Plain HTTP on the HTTPS port is redirected automatically. Listener and certificate changes take effect after restart.", + "administrationHosts": "Allowed DNS hostnames (optional strict allowlist)", + "administrationHttps": "Enable HTTPS for administration", + "administrationListen": "Listen address", + "cacheOverhead": "Overhead", + "cacheResidentAge": "X-Cache-Resident-Age", + "controlPlane": "CONTROL PLANE", + "logging": "Logging", + "loggingTitle": "Structured access logging", + "loggingTabOutputs": "Outputs", + "loggingTabFormat": "JSON format", + "loggingTabErrors": "Error log", + "loggingDescription": "Write configurable JSON access logs to a file, Logstash or Loki.", + "loggingHelp": "Live log viewing stays in memory. External sinks use a bounded background queue and do not block request I/O.", + "loggingFile": "JSON file", + "loggingPath": "File path", + "loggingAddress": "TCP address", + "loggingTokenEnv": "Bearer token environment variable", + "loggingLabels": "Labels (JSON object)", + "loggingFormat": "Configurable JSON format", + "loggingFormatHelp": "Map output names to source fields. Leave mapping empty for the complete standard entry.", + "loggingFields": "Field mapping (JSON object)", + "loggingStatic": "Static fields (JSON object)", + "loggingJsonInvalid": "Logging JSON fields must contain valid JSON objects.", + "loggingQueue": "Sink queue", + "loggingDropped": "dropped", + "loggingSent": "sent", + "loggingCapacity": "capacity", + "errorLogTitle": "Error file", + "errorLogPath": "Error log path", + "errorLogFormat": "Format", + "tls12": "TLS 1.2", + "tls13": "TLS 1.3", + "tlsPolicy": "TLS policy", + "tlsPolicyHelp": "This is the global TLS policy inherited by every TLS host in the application. Per-vhost policy may only narrow it. HTTP/3 requires TLS 1.3.", + "tlsCiphers": "Cipher suites (one per line; empty = rustls defaults)", + "tlsAvailableCiphers": "Available cipher suites", + "tlsPolicyVersionRequired": "Enable at least one TLS version.", + "vhTlsOverride": "Override global TLS policy", + "vhTlsOverrideHelp": "Use only when this vhost needs different TLS versions or cipher suites. Empty cipher list keeps rustls defaults.", + "vhTlsHttp3Conflict": "HTTP/3 uses the global TLS policy. Disable HTTP/3 on this vhost before using a different TLS override.", + "vhListeners": "Listeners", + "vhProtocols": "Protocols", + "loggingMode": "JSON / ASYNC / BOUNDED", + "loggingPushUrl": "Push URL", + "cacheHotObjects": "Hot objects", + "cacheHotMemory": "Hot memory", + "cacheColdObjects": "Cold objects", + "cacheColdDisk": "Cold disk", + "cacheTierMoves": "Tier moves", + "cacheColdHits": "cold hits", + "cacheTier": "Tier", + "cacheStorage": "Memory / disk", + "cacheColdTitle": "Persistent cold cache", + "cacheColdEnable": "Enable persistent disk tier", + "cacheColdHelp": "Choose what is moved from hot RAM to persistent disk. Cold hits are read asynchronously and promoted back to RAM. Metadata is readable JSON; bodies are raw .body files.", + "cacheColdPath": "Cold path (inside data directory)", + "cacheColdBytes": "Cold disk budget (MiB)", + "cacheColdEntries": "Cold object limit", + "cacheColdAfter": "Demote after idle seconds", + "cacheHot": "Hot", + "cacheCold": "Cold", + "cacheReason_request_no_cache": "Client no-cache / hard reload requires validation", + "cacheReason_request_max_age": "Client max-age requires validation", + "cacheReason_request_min_fresh": "Client min-fresh requires validation", + "cacheReason_request_pragma_no_cache": "Client Pragma no-cache / legacy hard reload", + "cacheReason_cache_revalidated": "Stored object validated by origin", + "cacheReason_cache_conditional_hit": "Fresh object satisfied a conditional request", + "cacheReason_request_no_store": "Client no-store bypass", + "cacheReason_request_precondition": "Client precondition requires origin", + "loggingPreset": "Format preset", + "loggingPresetCustom": "Custom", + "loggingPresetStandard": "RustProxy standard", + "loggingPresetNginx": "Nginx-style JSON", + "loggingPresetEcs": "ECS-style field names", + "loggingPresetMinimal": "Minimal", + "loggingBuilder": "Visual field builder", + "loggingBuilderOpen": "Configure fields", + "loggingAdvancedJson": "Advanced JSON mapping", + "loggingBuilderHelp": "Select source fields and optionally rename their JSON keys. Applying the visual editor normalizes each source field to at most one output key; use advanced JSON for duplicate aliases.", + "loggingSourceField": "Source field", + "loggingOutputField": "Output JSON key", + "loggingPreview": "Preview", + "loggingOutputRequired": "Every enabled log field needs an output JSON key.", + "loggingOutputDuplicate": "Output JSON keys must be unique.", + "aclProfiles": "ACL profiles", + "acl-profiles": "ACL profiles", + "acl-profilesTitle": "Reusable ACL profiles", + "acl-profilesDescription": "Define reusable IP and country access rules, then attach them to one or more virtual hosts.", + "aclProfilesIntro": "Reusable access profiles can be attached to multiple vhosts. Per-vhost ACL and country rules remain active and are enforced together with the profile.", + "aclProfilesReusable": "REUSABLE POLICY", + "aclProfileNew": "New profile", + "aclProfileEdit": "Editing profile", + "aclProfileEditor": "Profile configuration", + "aclProfileId": "Profile ID", + "aclProfileName": "Display name", + "aclProfileIpEnabled": "Enable IP ACL", + "aclProfileRules": "IP rules — one “allow|deny CIDR” per line", + "aclProfileCombineHelp": "Profile and vhost rules are restrictive: a request must pass both policies.", + "aclProfileIpRulesShort": "IP rules", + "aclProfileIpOff": "IP ACL disabled", + "aclProfileCountriesOff": "Country filtering disabled", + "aclProfileAttached": "Attached to", + "aclProfileInUse": "Profile is attached to vhosts", + "aclProfilesEmpty": "No reusable ACL profiles yet.", + "aclProfileCountryInvalid": "Country codes must use two-letter ISO codes.", + "aclProfileDuplicate": "An ACL profile with this ID already exists.", + "vhAclProfile": "ACL profile", + "vhAclProfileNone": "No reusable profile", + "vhAclProfileHelp": "Optional reusable profile. Inline vhost ACL and country rules below are still enforced in addition to the profile.", + "vhHostAdd": "Add hostname", + "vhHostsHelp": "Press Enter or comma to add a hostname. Wildcards are supported only as a leading *. (for example *.example.com). Exact hosts take priority over wildcard matches.", + "vhHostInvalid": "Invalid hostname or wildcard pattern.", + "vhHostRequired": "Add at least one hostname.", + "vhLifetimeChart": "Lifetime request rate", + "vhReqPerSecond": "req/s", + "vhPeak": "peak", + "listenerAddresses": "Bind addresses", + "listenerAddressesInvalid": "Provide 1–16 unique listener addresses.", + "listenerAddressesExplicit": "When a listener uses multiple addresses, select explicit IPs; 0.0.0.0 and :: are not allowed.", + "ruleSyntaxLine": "Invalid ACL rule on line", + "vhForceSslNeedsHttp": "Force SSL needs at least one selected plain HTTP (non-TLS) listener. A listener named “HTTP” may still be configured as TLS in Settings > Listeners.", + "aclProfileRuleBuilder": "IP rules", + "aclProfileBulkRules": "Paste / import rules", + "aclProfileBulkHelp": "Paste one “allow|deny CIDR” rule per line. Invisible Unicode spacing is normalized during import and errors identify the exact line.", + "aclProfileImportRules": "Import rules", + "aclProfileRulesImported": "ACL rules imported into the visual editor.", + "streamHosts": "Stream hosts", + "streamsHelp": "Raw TCP/UDP forwarding on dedicated ports. Stream traffic bypasses HTTP vhosts, ACL, cache, headers and compression.", + "streamAdd": "Add stream host", + "saveStreams": "Save stream hosts", + "streamRestartHelp": "Changing a stream listener requires a RustProxy restart.", + "streamRestartPending": "Saved stream changes are pending. Restart RustProxy to apply them.", + "streamActive": "Currently active streams", + "streamNone": "No stream hosts active", + "streamEndpoint": "Stream endpoint", + "streamId": "Stream ID", + "streamName": "Display name", + "streamProtocol": "Protocol", + "streamListen": "Listen address", + "streamUpstream": "Upstream address", + "streamConnectTimeout": "TCP connect timeout (seconds)", + "streamIdleTimeout": "Idle/session timeout (seconds)", + "streamMaxConnections": "Max connections/sessions", + "streamTcp": "TCP", + "streamUdp": "UDP", + "streamLimit": "At most 128 stream hosts are supported.", + "streamDuplicate": "Stream host IDs must be unique.", + "streams": "Streams", + "streamsTitle": "TCP / UDP streams", + "streamsDescription": "Manage raw Layer-4 listeners, upstreams and live traffic telemetry.", + "streamsPageIntro": "TCP/UDP streams are independent Layer-4 proxies. Each stream owns a dedicated listener and upstream and bypasses the HTTP vhost, ACL and cache stack.", + "streamLayer4": "LAYER 4 / TCP + UDP", + "streamList": "Streams", + "streamSearch": "Search streams", + "streamSearchPlaceholder": "ID, name, listener or upstream…", + "streamSearchEmpty": "No streams match this search.", + "streamEmpty": "No TCP/UDP streams yet. Add a listener to start forwarding Layer-4 traffic.", + "streamNew": "New stream", + "streamAddListener": "Add TCP/UDP listener", + "streamEditor": "Stream configuration", + "streamEditLabel": "EDITING", + "streamNewLabel": "NEW", + "streamDetailsTab": "Details", + "streamNetworkTab": "Listener & upstream", + "streamLimitsTab": "Limits", + "streamNetwork": "Listener & upstream", + "streamLimits": "Connection / session limits", + "streamDedicatedListenerHelp": "A stream listener is created together with the stream and is separate from HTTP/HTTPS listeners.", + "streamLimitsHelp": "Limits apply to concurrent TCP connections or per-client UDP sessions. TCP connect timeout is not used by UDP.", + "streamListenAdd": "Add listen address", + "streamListenHelp": "Enter one IP:port listener address and press Enter. Listener changes become active after RustProxy restarts.", + "streamListenInvalid": "The listener address must be one IP:port value without spaces or commas.", + "streamListenRequired": "Add a listener address.", + "streamDelete": "Delete this stream? The active listener remains until RustProxy restarts.", + "streamPendingRestart": "Pending restart", + "streamRunning": "Running", + "streamActiveSessions": "Active connections / sessions", + "streamSessionsTotal": "Connections / sessions", + "streamErrors": "Errors", + "streamRejected": "Rejected", + "streamTransferred": "Transferred", + "streamTrafficChart": "Live traffic rate", + "streamClientToUpstream": "client → upstream", + "streamUpstreamToClient": "upstream → client", + "streamNoLiveMetrics": "No live metrics until this stream is active after restart.", + "streamIdleShort": "Idle timeout", + "listenerAddressAdd": "Add bind address", + "listenerAddressesHelp": "Press Enter or comma to add a bind address. Multiple addresses use the same listener policy; wildcard 0.0.0.0/:: cannot be mixed with explicit addresses.", + "cacheColdOnIdle": "Move old/idle objects to cold storage", + "cacheColdOnLru": "Move hot LRU evictions to cold storage", + "cacheColdOnShutdown": "Flush hot cache to cold storage during graceful shutdown", + "certificateCovers": "Certificate domains", + "certificateCoverageUnknown": "Domain data (DNS SAN) is unavailable. Reload certificate files or import the certificate again.", + "certificateDetails": "Certificate details", + "certificateFiles": "Certificate / key files", + "redirects": "Redirects", + "redirectsTitle": "Redirect with intent.", + "redirectsDescription": "Local redirect hosts with explicit match, target, status, path and query behavior.", + "redirectsPageIntro": "Redirect hosts answer locally without opening an upstream connection. Rules can match scheme and path, then redirect to a URL, another host or a path.", + "redirectLayer": "HTTP REDIRECTION", + "redirectList": "Redirect hosts", + "redirectSearch": "Search redirects", + "redirectSearchPlaceholder": "ID, hostname, target…", + "redirectNew": "New redirect", + "redirectEmpty": "No redirect hosts configured.", + "redirectSearchEmpty": "No redirects match this search.", + "redirectEditor": "Redirect configuration", + "redirectId": "Redirect ID", + "redirectName": "Display name", + "redirectHosts": "Source hostnames", + "redirectFrontend": "FRONTEND", + "redirectListeners": "Listeners", + "redirectBehavior": "BEHAVIOR", + "redirectRules": "Rules", + "redirectAddRule": "Add rule", + "redirectRulesHelp": "Longest matching path wins. 307/308 preserve the request method; 301/302/303 may change it in clients.", + "redirectSafetyHint": "Redirect hosts do not contact a backend. Global host ACLs still apply. Avoid self-referential rules that can create browser redirect loops.", + "redirectRule": "Rule", + "redirectRuleId": "Rule ID", + "redirectSourceScheme": "Incoming scheme", + "redirectSchemeAny": "HTTP or HTTPS", + "redirectSchemeHttp": "HTTP", + "redirectSchemeHttps": "HTTPS", + "redirectSchemePreserve": "Preserve incoming scheme", + "redirectMatchType": "Path match", + "redirectMatchPrefix": "Prefix", + "redirectMatchExact": "Exact", + "redirectSourcePath": "Source path", + "redirectTargetType": "Target type", + "redirectTargetUrl": "Absolute URL", + "redirectTargetHost": "Host / application", + "redirectTargetPath": "Path on the same host", + "redirectTarget": "Target", + "redirectTargetScheme": "Target scheme", + "redirectPathMode": "Path handling", + "redirectPathAppend": "Append full source path", + "redirectPathStrip": "Strip matched prefix and append remainder", + "redirectPathReplace": "Use configured target path only", + "redirectQueryMode": "Query handling", + "redirectQueryPreserve": "Preserve source query", + "redirectQueryDrop": "Drop source query", + "redirectStatus": "HTTP status", + "redirect301": "301 Moved Permanently", + "redirect302": "302 Found", + "redirect303": "303 See Other", + "redirect307": "307 Temporary Redirect (preserve method)", + "redirect308": "308 Permanent Redirect (preserve method)", + "redirectCacheSeconds": "Browser/shared cache max-age (seconds; 0 = no-store)", + "redirectHostsRequired": "Add at least one source hostname.", + "redirectListenersRequired": "Select at least one listener.", + "redirectRulesRequired": "Add at least one redirect rule.", + "redirectDuplicate": "A redirect with this ID already exists.", + "redirectUnsaved": "Discard unsaved redirect changes?", + "redirectNewLabel": "NEW", + "administrationSessionDays": "Administrator session lifetime (days)", + "administrationSessionDaysHelp": "Browser sessions use an absolute 7–30 day lifetime. Changing this value applies immediately; password changes and “revoke all sessions” still invalidate sessions at once.", + "vhLocalListenerRisk": "Allow local RustProxy listener as backend (risk)", + "vhLocalListenerRiskHelp": "Shown when the backend URL directly targets the configured or active RustProxy administration listener. localhost, 127.0.0.1 and ::1 are treated as equivalent loopback forms on the same administration port. Enabling it can expose the control plane or create a proxy loop; private/loopback targets still require “Allow private origin IP”.", + "vhLocalListenerRiskConfirm": "This can route requests into a local RustProxy listener, including the administration port, and may create a loop or expose the control plane. Accept this risk?", + "cacheResidentHistory": "Resident RAM history", + "networkHistory": "RX / TX history", + "responseLatencyHistory": "Response time history", + "sourceIp": "Source IP", + "cacheColdOnAge": "Move objects to cold storage after a maximum hot-tier age", + "cacheColdMaxHot": "Maximum hot-tier age (seconds)", + "cacheColdPolicyHelp": "Idle time measures how long an object has not been used. Hot-tier age measures continuous residency in RAM even if the object is still requested. LRU pressure and graceful-shutdown handoff are independent policies.", + "documentation": "Documentation", + "locationPathPattern": "Path / regex pattern", + "locationMatchType": "Match type", + "locationMatchPrefix": "Prefix", + "locationMatchPriority": "Priority prefix (^~)", + "locationMatchExact": "Exact path (=)", + "locationMatchRegex": "Regex (~)", + "locationMatchRegexI": "Regex, case-insensitive (~*)", + "locationMatch_prefix": "prefix", + "locationMatch_prefix_priority": "priority prefix", + "locationMatch_exact": "exact", + "locationMatch_regex": "regex", + "locationMatch_regex_insensitive": "regex i", + "locationAction": "Action", + "locationProxyAction": "Proxy to backend", + "locationReturnAction": "Custom response (return)", + "locationProxyShort": "proxy", + "locationReturnShort": "local response", + "locationHandling": "Request handling", + "locationRewriteMode": "Backend path rewrite", + "locationRewritePreserve": "Keep original path", + "locationRewriteStrip": "Strip matched prefix", + "locationRewriteReplace": "Replace matched prefix", + "locationRewriteRegex": "Regex replacement", + "locationRewriteValue": "Replacement path / expression", + "locationRewriteHelp": "Query parameters are preserved. Prefix rewrites operate on the normalized routing path. Regex replacement supports Rust regex captures such as $1. Rewritten paths are validated before forwarding.", + "locationResponseStatus": "Response status", + "locationResponseType": "Content-Type", + "locationResponseBody": "Response body", + "headersVisualBuilder": "Visual configurator", + "locationDocsTitle": "Custom locations documentation", + "headersDocsTitle": "Header rules documentation", + "locationDocsIntro": "Custom locations are evaluated inside the selected vhost after host authentication and ACL. They never bypass vhost security.", + "locationDocsPrefix": "Prefix: matches a complete path segment prefix. The longest prefix wins. Priority prefix behaves like nginx ^~ and prevents regex locations from taking precedence.", + "locationDocsExact": "Exact: matches only the exact normalized path, like nginx location = /path.", + "locationDocsRegex": "Regex: first matching regex wins after exact/priority-prefix processing. Case-sensitive and case-insensitive modes are supported. Rust regex syntax is used; look-around/backreferences in the pattern are intentionally unsupported.", + "locationDocsReturn": "Custom response: answer locally with a chosen HTTP status, Content-Type and body without opening a backend connection. Location response-header rules still apply.", + "locationDocsRewrite": "Backend path rewrite: keep the original target, strip/replace a matched prefix, or use regex capture replacement. The original query string is preserved.", + "locationDocsAccess": "Per-location IP ACL, cache override and request/response header rules are composed with the vhost policy. A location cannot disable host authentication or host ACL.", + "locationDocsLimits": "Up to 64 locations per vhost. Regexes and response bodies are bounded; transport, forwarding identity and WebSocket protocol headers remain system-managed.", + "headersDocsIntro": "Header rules are applied in order: global → vhost → matching location. Use the visual configurator for normal changes; JSON remains an advanced escape hatch.", + "headersDocsSet": "Set: replace all existing values of a header with the configured literal value.", + "headersDocsAppend": "Append: add another value without deleting existing values.", + "headersDocsRemove": "Remove: delete the header before forwarding or before sending the response.", + "headersDocsProtected": "Protected transport/identity headers (Host, Connection, Content-Length, Forwarded/X-Forwarded-*, WebSocket proof headers and similar) cannot be overridden here.", + "headersDocsOrder": "Values are literal; nginx variables are not interpreted. Request rules run before canonical forwarding metadata is applied, and response rules run before final RustProxy security/diagnostic policy.", + "cacheColdPolicyTitle": "Hot → cold policy", + "headerRule": "Header rule", + "headerRulesEmpty": "No rules yet. Add a rule below.", + "headerRuleHelp": "Choose Set, Append or Remove. Transport, forwarding identity and WebSocket protocol headers remain protected.", + "locationPreviewTitle": "Effective behavior preview", + "locationPreviewMatch": "Matching", + "locationPreviewHandling": "Handling", + "locationPreviewRewrite": "Backend path", + "locationPreviewCache": "Cache", + "locationPreviewAccess": "Access", + "locationPreviewHeaders": "Header rules", + "locationPreviewDisabled": "This location is disabled and will not match requests.", + "locationPreviewBackendSkipped": "backend is not contacted", + "locationPreviewVhostAcl": "Vhost authentication and ACL only", + "locationPreviewCustomAcl": "Vhost policy + location ACL", + "locationPreviewRequestRules": "request", + "locationPreviewResponseRules": "response", + "locationPreviewQueryPreserved": "query string is preserved", + "locationDocsMatchHeading": "1. Matching and precedence", + "locationDocsActionHeading": "2. Proxy, rewrite and local response", + "locationDocsPolicyHeading": "3. Access, cache and headers", + "locationDocsExamplesHeading": "Common examples", + "locationDocsExampleExact": "Health endpoint: Exact (=) /health + Custom response 200 answers locally without a backend connection.", + "locationDocsExampleStatic": "Static assets: Priority prefix (^~) /static/ keeps regex locations from overriding it; cache can be enabled for this location.", + "locationDocsExampleRegex": "Versioned API: Regex (~) ^/api/v[0-9]+/ can select a backend and use regex replacement groups such as $1.", + "cacheOutcomeHistory": "HIT / MISS / BYPASS activity", + "cacheHotMemoryHistory": "HOT RAM usage / limit", + "cacheTransientMemoryHistory": "Transient RAM usage / limit", + "cacheColdStorageHistory": "COLD storage usage / limit", + "processCpuHistory": "Process CPU history", + "processRssHistory": "Process RSS history", + "cacheMemoryBreakdown": "Hot / transient cache RAM", + "cacheTransientBreakdown": "Fill / cold queue / cold I/O", + "cacheColdStorageUsage": "COLD storage / budget", + "cacheColdStorageObjects": "objects", + "cacheTransientMemory": "Transient cache RAM", + "cacheTransientShort": "TOTAL", + "cacheFillShort": "fill", + "cacheQueueShort": "cold queue", + "cacheIoShort": "cold I/O", + "processRssTotal": "RSS total", + "memoryCacheHot": "HOT cache RAM / limit", + "memoryCacheTransient": "Cache transient RAM / limit", + "memoryTransform": "Transform reserved RAM / budget", + "memoryTransformInflight": "Active transforms / limit", + "memoryNonCacheRss": "Non-cache process RSS", + "transformMemoryUsage": "Transform RAM reservation", + "transformConcurrencyUsage": "Active transform slots", + "transformBudgetShort": "budget", + "processRssAnon": "Anonymous RSS", + "processRssFile": "File-backed / shared RSS", + "processDataSwap": "Data address space / swap", + "memoryAccountingHint": "RSS is the real process footprint. HOT/transient cache values are RustProxy-accounted allocations; transform memory is a conservative active reservation. Non-cache RSS is RSS minus accounted cache and includes transforms, connections, TLS, logging, Tokio/runtime state, allocator overhead and other buffers, so these rows are not all additive.", + "memoryAccountingInfo": "Memory accounting information", + "logTransport": "Transport", + "logWebSocket": "WebSocket", + "logUpstreamError": "Upstream error", + "listenerDefaultPortsHint": "New vhosts automatically select the standard HTTP :80 listener when it is available.", + "vhBackendDiagnostics": "Backend diagnostics", + "vhBackendHeader": "Expose selected backend (X-RustProxy-Backend)", + "vhBackendTimingHeader": "Expose backend response time (X-RustProxy-Backend-Time)", + "vhBackendDiagnosticsHelp": "Opt-in response headers. Backend time measures origin request-to-response-headers latency; responses served without contacting an origin do not report a backend.", + "authModeHelp": "Choose one authentication provider. The IP access list below is independent and can be combined with either provider.", + "taAdvanced": "Advanced Tinyauth settings", + "notfound": "404 hosts", + "notfoundTitle": "404 hosts, under control.", + "notfoundDescription": "Reserve domains that should answer locally with a status, placeholder or custom HTML.", + "notfoundPageIntro": "404 hosts reserve selected domains and answer locally without contacting a backend. They can use the same listeners and certificates as vhosts.", + "notfoundLayer": "LOCAL RESPONSE", + "notfoundList": "404 hosts", + "notfoundSearch": "Search 404 hosts", + "notfoundSearchPlaceholder": "ID, name or hostname…", + "notfoundNew": "New 404 host", + "notfoundEditor": "404 host configuration", + "notfoundId": "Host ID", + "notfoundName": "Display name", + "notfoundFrontend": "FRONTEND", + "notfoundBehavior": "RESPONSE", + "notfoundResponse": "Local response", + "notfoundMode": "Response type", + "notfoundModeWelcome": "RustProxy placeholder", + "notfoundModeEmpty": "Status only / empty", + "notfoundModeHtml": "Custom HTML", + "notfoundStatus": "HTTP status", + "notfoundHtml": "Custom HTML", + "notfoundResponseHelp": "The host never opens an upstream connection. The built-in placeholder is no-store and intentionally omits optional RustProxy diagnostic/server headers.", + "notfoundHosts": "Hostnames", + "notfoundNewLabel": "NEW", + "notfoundHostsRequired": "Add at least one hostname.", + "notfoundListenersRequired": "Select at least one listener.", + "notfoundHtmlRequired": "Custom HTML cannot be blank.", + "notfound204Empty": "HTTP 204, 205 and 304 responses must use Empty mode.", + "notfoundDuplicate": "A 404 host with this ID already exists.", + "notfoundUnsaved": "Discard unsaved 404 host changes?", + "notfoundEmpty": "No 404 hosts configured.", + "notfoundSearchEmpty": "No 404 hosts match the search.", + "prometheusTrustedNoToken": "Allow token-free reads from trusted CIDRs", + "prometheusTrustedNoTokenHelp": "Clients still must match Allowed client CIDRs. Enable only on a private, trusted monitoring network; forwarded headers are never trusted for this check.", + "docker-vhosts": "Docker vhosts", + "docker-vhostsTitle": "Docker services, named.", + "docker-vhostsDescription": "Discover published Docker ports and map services to base-domain names, custom domains and aliases without copying observed state into SQLite.", + "dockerVhosts": "Docker vhosts", + "dockerVhostsIntro": "Published TCP ports discovered by configured Docker agents. Map each service to a short name under the agent base domain or to any FQDN, add aliases, choose the Docker host IP, and inspect or tune live backend health.", + "dockerDiscovery": "DOCKER DISCOVERY", + "dockerRefresh": "Refresh agents", + "dockerAgentsSettings": "Docker agents settings", + "dockerAgents": "Docker agents", + "dockerDesiredState": "DESIRED STATE / SQLITE", + "dockerAgentsHelp": "Configure one agent per Docker host. HTTPS with a persistent self-signed certificate is the agent default; paste its SHA-256 fingerprint to pin it. Each agent keeps its own base domain and optional default backend IP.", + "dockerAgentAdd": "Add Docker agent", + "dockerAgentsSave": "Save and connect agents", + "dockerAgent": "DOCKER AGENT", + "dockerAgentNew": "New agent", + "dockerAgentId": "Agent ID", + "dockerAgentName": "Display name", + "dockerAgentEndpoint": "Agent endpoint", + "dockerAgentToken": "Bearer token", + "dockerBaseDomain": "Base domain", + "dockerTargetOverride": "Target IP override", + "dockerTargetAuto": "automatic", + "dockerListeners": "Listeners", + "dockerListenersRequired": "Select at least one listener for the Docker agent.", + "dockerNoAgents": "No Docker agents configured.", + "dockerNoAgentsConfigured": "Configure a Docker agent in Settings first.", + "dockerPublish": "Publish", + "dockerPreserveHost": "Preserve Host", + "dockerServiceMissing": "Not present in the latest inventory", + "dockerConnected": "CONNECTED", + "dockerError": "ERROR", + "dockerWaiting": "WAITING", + "dockerAgentDisabled": "This Docker agent is disabled.", + "dockerNoObservation": "No observation yet. Refresh the agents.", + "dockerHost": "Docker host", + "dockerDetectedIp": "Detected IP", + "dockerEffectiveIp": "Routing IP", + "dockerNoPublishedPorts": "No published TCP ports were reported.", + "dockerAssignmentsSave": "Save Docker vhosts", + "dockerDefaultTarget": "Default backend IP", + "dockerDetectedIps": "Detected host IPs", + "dockerHostname": "Hostname", + "dockerHostnameHelp": "Short names use {domain}; a full FQDN uses its own domain.", + "dockerAliases": "Aliases", + "dockerAliasAdd": "Add alias", + "dockerAliasesHelp": "Add aliases with Enter or comma. Short names use the agent base domain; full FQDNs are kept as entered.", + "dockerBackendIp": "Backend host IP", + "dockerBackendIpAuto": "Auto / agent default", + "dockerBackendScheme": "Backend protocol", + "dockerBindingIp": "Docker binding", + "dockerAgentDefaultIp": "agent default", + "dockerAgentEndpointHelp": "Use https:// for the default agent setup. Plain HTTP is supported only for compatibility and is visibly marked insecure.", + "dockerTlsFingerprint": "TLS certificate SHA-256", + "dockerTlsFingerprintHelp": "For the default self-signed agent certificate, paste the fingerprint printed by install.sh or rustproxy-docker-agent --print-fingerprint. Leave empty only for a certificate trusted by a public CA.", + "dockerTlsPinned": "TLS PINNED", + "dockerTlsPublicCa": "TLS / PUBLIC CA", + "dockerTlsPlain": "PLAIN HTTP", + "dockerTlsPlainHelp": "The agent token and inventory are not protected by TLS on this endpoint.", + "dockerTlsPublicCaHelp": "Certificate chain and hostname are verified against the system/public CA roots.", + "dockerAgentConnectionFailed": "Agent connection failed", + "dockerAgentVersion": "Agent version", + "dockerLastChecked": "Last checked", + "dockerNeverChecked": "never", + "dockerJustNow": "just now", + "dockerSecondsAgo": "{seconds}s ago", + "dockerMinutesAgo": "{minutes}m ago", + "dockerBackendMissing": "SERVICE MISSING", + "dockerBackendNotActive": "NOT PUBLISHED", + "dockerBackendChecking": "CHECKING", + "dockerBackendHealthOff": "HEALTH OFF", + "dockerBackendUp": "UP", + "dockerBackendDown": "DOWN", + "dockerBackendDraining": "DRAINING", + "dockerBackendNoMetrics": "Runtime metrics appear after the dynamic backend is active.", + "dockerHealthCheck": "Backend health check", + "dockerHealthSummary": "Active TCP/HTTP probes; passive health is configured separately", + "dockerPassiveHealth": "Passive backend health", + "dockerPassiveHealthSummary": "Off by default; opt in to health decisions from normal requests", + "dockerHealthMode": "Mode", + "dockerHealthHttp": "HTTP", + "dockerHealthTcp": "TCP", + "dockerHealthOff": "Off", + "dockerHealthPath": "HTTP path", + "dockerHealthHost": "Health Host header", + "dockerHealthHostAuto": "backend host / automatic", + "dockerHealthInterval": "Interval (ms)", + "dockerHealthTimeout": "Timeout (ms)", + "dockerHealthSlow": "Slow threshold (ms)", + "dockerHealthFall": "Failures to mark down", + "dockerHealthRise": "Successes to mark up", + "dockerHealthStatusMin": "Min HTTP status", + "dockerHealthStatusMax": "Max HTTP status", + "dockerHealthLatency": "Latency", + "dockerHealthResult": "Last probe", + "dockerHealthRequests": "Requests", + "dockerHealthErrors": "Errors", + "dockerHealthActive": "Active", + "loggingPerVhost": "Separate file per vhost", + "loggingDirectory": "Per-vhost directory", + "loggingPerVhostHelp": "When enabled, each vhost writes to its own JSONL file. Unmatched traffic uses _unmatched.jsonl.", + "listenerStartupLocked": "This startup/systemd address cannot be changed or removed here. Other addresses and listener options remain editable.", + "administrationStartupLocked": "This address is fixed by the process startup/systemd configuration and cannot be changed here.", + "notfoundStatusInvalid": "Select a supported HTTP error status.", + "tlsEffectiveCiphers": "Currently effective cipher suites", + "certificateManaged": "ACME managed", + "certManagedReadOnly": "ACME-managed certificates are renewed automatically and cannot be edited as custom file certificates.", + "vhWebsocketTransport": "WebSocket transport", + "vhWebsocketHttp1": "HTTP/1.1 Upgrade (recommended)", + "vhWebsocketRfc9220": "RFC 9220 Extended CONNECT over HTTP/3", + "vhWebsocketTransportHelp": "Enable WebSocket with the separate switch, then choose the transport. H2/H3 modes use Extended CONNECT while HTTP/1.1 Upgrade remains the fallback.", + "dockerLiveView": "Live view", + "dockerPollInterval": "Agent poll interval (s)", + "dockerPollIntervalHelp": "How often RustProxy contacts this agent for Docker inventory. Live view only reads RustProxy memory.", + "dockerAgentPollEvery": "Agent poll interval", + "dockerSearch": "Search Docker vhosts", + "dockerSearchPlaceholder": "Search service, host, alias or agent...", + "dockerShowHidden": "Show Hidden", + "dockerHideHidden": "Hide Hidden", + "dockerHideVhost": "Hide from view", + "dockerUnhideVhost": "Show in view", + "dockerCertificate": "Frontend certificate", + "dockerCertificateHelp": "Certificate assigned to every generated vhost for this agent. Default uses normal TLS/SNI certificate selection.", + "dockerDefaultAcl": "Default ACL profile", + "dockerDefaultAclNone": "No default ACL profile", + "dockerDefaultAclHelp": "Inherited by generated Docker vhosts that do not select their own per-app ACL profile.", + "dockerApplyService": "Apply changes", + "dockerAccessControl": "Access control", + "dockerAclSummary": "Optional ACL profile and per-app IP rules", + "dockerAclProfile": "ACL profile", + "dockerAclProfileNone": "No ACL profile", + "dockerAclProfileInherit": "Agent default", + "dockerAclInline": "Use additional per-app ACL", + "dockerAclDefault": "Default ACL action", + "dockerAclRules": "IP/CIDR rules", + "dockerAclHelp": "One rule per line, for example allow 10.0.0.0/8. Profile and per-app ACL are both enforced.", + "dockerProxyTimeouts": "Proxy timeouts", + "dockerProxyTimeoutsHelp": "Explicit per-app limits: connect 10 s, response headers 120 s, upstream read 60 s and request send 60 s by default.", + "dockerHostnameRequired": "Hostname is required before publishing.", + "dockerForceSsl": "Redirect HTTP to HTTPS", + "dockerForceSslUnavailable": "Requires an active plain HTTP listener and one unambiguous TLS listener on this agent.", + "dockerWebsockets": "WebSockets", + "dockerCache": "Cache", + "vhProxyTimeouts": "Proxy timeouts", + "vhProxyConnectTimeout": "Proxy connect timeout (s)", + "vhProxyHeaderTimeout": "Proxy response header timeout (s)", + "vhProxyReadTimeout": "Proxy read timeout (s)", + "vhProxySendTimeout": "Proxy send timeout (s)", + "vhProxyTimeoutsHelp": "Defaults: connect 10 s, response headers 120 s, read 60 s and send 60 s. Read/send are idle-gap timeouts for streaming bodies.", + "notfoundModeBuiltin": "Application-style status page", + "pageBuiltin": "Built-in status page", + "vhOpenBrowser": "Open", + "securityPasswordHint": "Requires the current password and signs out all sessions.", + "securityAccessControl": "ACCESS CONTROL", + "securityPoliciesHint": "Keep the policy list visible; open the editor only when adding or changing a rule set.", + "securityPolicyEditorHint": "Hostname scope, default action and CIDR rules.", + "securityAuditOpen": "Administration audit", + "securityAuditHint": "Recent administration changes are loaded only when this window is opened.", + "dockerConfigureService": "Configure vhost", + "dockerAliasesShort": "aliases", + "dockerAgentDetails": "Agent details", + "dockerServices": "Services", + "dockerOpenApp": "Open app", + "networkInterfacesHistory": "Traffic by interface", + "networkInterfaceRate": "RX / TX", + "networkNoInterfaces": "No non-loopback network interfaces are available.", + "networkInterfacesCount": "{count} interfaces", + "logExpandBuffer": "Increase buffer", + "logExpandedBuffer": "Buffer 4096", + "logBufferExpanded": "Live buffer increased to {count} retained entries.", + "vhIdRenameHelp": "Changing the vhost ID starts a new metrics/log/cache identity and resets its live health/traffic history. Hostnames and configured backend IDs are unchanged.", + "vhIdRenameConfirm": "Change vhost ID from {old} to {new}? Live health/traffic history and metric/cache identity for this vhost will restart.", + "cacheDomainFilter": "Show", + "cacheDomainFilterAll": "All domains", + "cacheDomainFilterEnabled": "Cache enabled", + "cacheDomainFilterDisabled": "Cache disabled", + "cacheNoDomainsFiltered": "No domains match this filter.", + "cacheColdCleanup": "Clean cold cache", + "cacheColdCleanupHelp": "Runs asynchronously and uses the same eviction mechanism as automatic cold-cache GC.", + "cacheColdUnusedSeconds": "Unused for at least (seconds, optional)", + "cacheColdOldestCount": "Remove up to oldest objects", + "cacheColdHitsZero": "Only objects with hits = 0", + "cacheColdCleanupStart": "Start cleanup", + "cacheColdCleanupRunning": "Cold-cache cleanup is running…", + "cacheColdCleanupDone": "Removed {count} objects and freed {bytes}.", + "cacheColdCleanupFailed": "Cold-cache cleanup failed.", + "cacheColdCleanupInvalidJob": "Cold-cache cleanup did not return a job identifier.", + "cacheColdGcInterval": "Cold-cache GC interval (seconds)", + "cacheColdGcMaxDelete": "Maximum deletes per GC pass", + "transformSettings": "Static response transformation", + "transformEnable": "Enable transformation engine globally", + "transformHelp": "Transformation happens after upstream decoding and before cache storage and client compression. Each vhost must opt in separately.", + "transformJavascript": "JavaScript minification", + "transformCss": "CSS minification", + "transformHtml": "HTML minification", + "transformSvg": "SVG optimization", + "transformJson": "JSON compaction", + "transformExtensions": "Allowed file extensions, one per line", + "transformMaxBody": "Maximum transformable response (KiB)", + "transformResourcePresetTitle": "Resource preset", + "transformResourcePresetHelp": "Presets tune the temporary memory ceiling, maximum transformable response size and global concurrent transformation limit. Content types and extension allow-lists are left unchanged.", + "transformPresetConservative": "RAM saver", + "transformPresetRecommended": "Recommended", + "transformPresetPerformance": "Performance", + "transformPresetUber": "Uber performance", + "transformMemoryBudget": "Temporary transform memory budget (MiB)", + "transformMaxInflight": "Maximum concurrent transformations", + "transformMaxInflightShort": "concurrent", + "transformResourceCurrent": "Current limits", + "transformBudgetTooSmallWarning": "The memory budget is smaller than the worst-case temporary buffers for one maximum-size compressed response. Such responses can be skipped with memory_pressure.", + "transformBudgetHighWarning": "The transform memory ceiling is more than 50% of effective host/cgroup RAM:", + "transformSafety": "Cache-Control: no-transform is always respected. Transformed representations receive a new ETag and are cached before gzip, Brotli or zstd encoding.", + "saveTransform": "Apply transformation policy", + "vhTransform": "Transform", + "vhTransformEnable": "Enable transformations for this vhost", + "vhTransformExtensionsCustom": "Override global transform extensions", + "vhTransformHelp": "The global engine must also be enabled. Format selectors inherit the global policy unless explicitly enabled or disabled here.", + "dockerTransform": "Transform static responses", + "vhPassive5xxWarning": "Counting HTTP 5xx can quarantine the whole backend after repeated application errors from one endpoint.", + "vhPassiveSlowWarning": "Counting slow responses can quarantine the backend after repeated responses that are correct but exceed the slow-response threshold.", + "transform": "Transform", + "transformTitle": "Static response transformation.", + "transformDescription": "Runtime transformation effectiveness, savings, skips and cache reuse.", + "transformApplied": "Transformed responses", + "transformExamined": "Examined", + "transformCacheHits": "Transformed cache HITs", + "transformCacheHitsHelp": "Served without running the transformer again", + "transformSaved": "Bytes saved before compression", + "transformReduction": "Average reduction", + "transformReductionHelp": "For responses that changed representation", + "transformSkipped": "Skipped / fail-open", + "transformErrors": "Body / transport errors", + "transformAvgTime": "Avg time", + "transformByType": "Transformations by type", + "transformType": "Type", + "transformSkipReasons": "Skip / fail-open reasons", + "transformNoSkips": "No skipped transformations in this scope.", + "transformNoSkipsShort": "No skips", + "transformVhosts": "Vhost effectiveness", + "transformScopeHint": "Counters are in-memory runtime diagnostics. A transformed cache HIT does not execute the transformer again.", + "transformNoData": "No transform activity yet.", + "transformBadge": "transformed", + "cacheLiveChartTitle": "Live cache activity", + "cacheLiveChartHelp": "HIT / MISS / BYPASS per second for the selected scope", + "liveChartSamples": "Samples", + "transformLiveChartTitle": "Live transformation activity", + "transformLiveChartHelp": "Applied / cache HIT / skipped / errors per second for the selected scope", + "transformChartApplied": "Applied", + "transformChartCacheHits": "Cache HIT", + "transformChartSkipped": "Skipped", + "cacheInvalidationTitle": "Cache purge / ban", + "cacheInvalidationOperation": "Operation", + "cacheInvalidationSelector": "Selector", + "cacheInvalidationValue": "Value", + "cacheInvalidationHost": "Host (optional)", + "cacheBanTtl": "BAN TTL (seconds)", + "cacheInvalidationHelp": "The selected vhost limits the operation. Exact and prefix values include the query string. Regex and root-prefix / operations require an additional confirmation.", + "cacheRunInvalidation": "Run operation", + "cacheActiveBans": "Active BAN rules", + "cacheBanExpires": "Expires", + "cacheNoBans": "No active BAN rules.", + "cacheTarget": "Target", + "cacheKeyTags": "Cache key / tags", + "cachePurgeUrl": "Purge URL", + "cacheRemoveBan": "Remove BAN", + "cacheBanCreated": "BAN created", + "cacheConfirmPurgeUrl": "Purge this cached URL from RAM and cold storage?", + "cacheConfirmRemoveBan": "Remove this BAN rule?", + "cacheWideInvalidationConfirm": "This broad invalidation may affect many cached objects. Continue?", + "cacheCollapseWaiters": "waiting", + "cacheCollapsed": "collapsed", + "actions": "Actions", + "cacheCollapseTitle": "Request collapsing", + "cacheCollapseEnable": "Collapse concurrent fills for one cache key", + "cacheCollapseTimeout": "Follower wait timeout (ms)", + "cacheCollapseFallback": "Timeout fallback", + "cacheCollapseFallbackOrigin": "Origin", + "cacheCollapseFallbackStale": "Stale if available", + "cacheStaleErrorTitle": "Stale-if-error policy", + "cacheSieTimeout": "Timeout", + "cacheSieConnection": "Connection failure", + "cacheSieDns": "DNS failure", + "cacheSieTls": "TLS failure", + "cacheSieStatuses": "HTTP 5xx statuses eligible for stale fallback", + "cacheProactiveTitle": "Proactive refresh", + "cacheProactiveEnable": "Refresh sampled cached objects before expiry", + "cacheProactiveBefore": "Refresh before expiry (seconds)", + "cacheProactivePercent": "Sampled objects (%)", + "cacheProactiveInflight": "Maximum concurrent refreshes", + "cacheProactiveHelp": "Uses validator revalidation, deterministic sampling and a global concurrency cap to avoid refresh storms.", + "cacheInvalidationOpen": "Purge / Ban", + "cacheBanListOpen": "Active BANs", + "cacheBanRemoved": "BAN rule removed", + "tunnelsOpen": "Active tunnels", + "tunnelsTitle": "Active WebSocket / tunnels", + "tunnelsReload": "Reload", + "tunnelsEmpty": "No active tunnels.", + "tunnelId": "ID", + "tunnelClient": "Client", + "tunnelHost": "Host", + "tunnelUpstream": "Upstream", + "tunnelProtocol": "Protocol", + "tunnelDuration": "Duration", + "tunnelRx": "RX", + "tunnelTx": "TX", + "tunnelKill": "Kill", + "tunnelKilled": "Tunnel closed by administrator", + "tunnelKillConfirm": "Close this tunnel?", + "tunnelKillReason": "Close reason", + "tunnelKillReasonPlaceholder": "Administrative close", + "tunnelKillReasonDefault": "admin panel", + "listenerH2c": "h2c cleartext HTTP/2 (prior knowledge + HTTP/1.1 Upgrade)", + "vhWebsocketRfc8441": "RFC 8441 Extended CONNECT over HTTP/2", + "wsH1": "H1 Upgrade", + "wsH2Rfc8441": "H2 RFC 8441", + "wsH3Rfc9220": "H3 RFC 9220", + "wsEstablished": "Established", + "httpProtocolMix": "HTTP protocol mix", + "wsProtocolMix": "WebSocket protocol mix", + "vhWebsocketMode": "WebSocket transport", + "vhWebsocketDisabled": "Disabled", + "vhWebsocketH1": "HTTP/1.1 Upgrade", + "vhWebsocketH2Fallback": "HTTP/2 RFC 8441 + H1 fallback", + "vhWebsocketH3Fallback": "HTTP/3 RFC 9220 + H1 fallback", + "vhWebsocketH2H3Fallback": "HTTP/2 + HTTP/3 + H1 fallback", + "vhMaxConcurrentRequests": "Max concurrent requests", + "vhBackendQueueTimeout": "Capacity queue timeout (ms)", + "vhBackendCapacityHelp": "0 concurrent requests means unlimited. A queue timeout of 0 rejects immediately with HTTP 503 when the backend is at capacity.", + "vhLastFailure": "Last failure", + "vhLastRecovery": "Last recovery", + "certificateIssuerName": "Certificate issuer", + "certificateValidFrom": "Valid from", + "certificateDaysRemaining": "Days remaining", + "certificateExpired": "Certificate expired", + "certificateExpiresSoon": "Certificate expires soon", + "certificateRenewalStatus": "Renewal status", + "certificateRenewalError": "Last renewal error", + "vhActiveHealth": "Active health", + "vhPassiveFailures": "Passive failures", + "certificateAdminRestartRequired": "Administration TLS uses a startup-fixed listener; restart RustProxy to refresh that certificate.", + "cacheTabGeneral": "General", + "cacheTabResilience": "Resilience", + "cacheTabCold": "Cold cache", + "cacheTabDiagnostics": "Static & diagnostics", + "certificateApiTitle": "Certificate API", + "certificateApiHelp": "Create separate Key ID + Bearer Token credentials for certificate deploy/reload automation. Tokens cannot read configuration or use other administration APIs.", + "certificateApiKeyId": "Key ID", + "certificateApiToken": "Bearer token (optional custom value)", + "certificateApiTokenHelp": "Leave the field empty to generate a strong token. Each cleartext token is shown only once; RustProxy stores only its hash.", + "certificateApiRotate": "Generate / rotate token", + "certificateApiRevoke": "Revoke token", + "certificateApiOneTimeToken": "Copy this token now", + "certificateApiCurlHelp": "External automation sends the Key ID header and Bearer token to the certificate deploy/reload endpoints over HTTPS (or loopback HTTP).", + "certificateApiUnknown": "Loading certificate API status…", + "certificateApiConfigured": "Certificate API enabled", + "certificateApiDisabled": "Certificate API disabled", + "certificateApiLastUsed": "last used", + "certificateApiRotated": "Certificate API token created / rotated. Copy the token now.", + "certificateApiRevoked": "Certificate API token revoked.", + "certificateApiRevokeConfirm": "Revoke the external certificate API token? Certbot/API deployments using it will stop immediately.", + "certificate_api.invalid_token": "Invalid certificate API Key ID or Bearer Token.", + "certificate_api.https_required": "External certificate API tokens require HTTPS unless the request comes from loopback.", + "certificate_api.invalid_token_format": "Certificate API tokens must be 32–128 URL-safe characters.", + "certificate_api.invalid_key_id": "Invalid certificate API Key ID.", + "vhWebsocketLegacySupport": "Enable WebSocket legacy support", + "vhWebsocketLegacySupportHelp": "For older appliances and embedded servers. WebSocket handshakes use HTTP/1.1 upstream, Host and Origin are aligned to the configured backend authority, and legacy 101 response framing is tolerated. Ordinary HTTP traffic is unchanged.", + "vhWebsocketLegacyBadge": "WebSocket legacy", + "runtimeInformation": "Runtime information", + "runtimeInformationHelp": "Reported by the running RustProxy process and available only from the authenticated administrator status API.", + "runtimePlatform": "Platform", + "statisticsSource": "Statistics source", + "dataDirectory": "Data directory", + "databaseLocation": "Database", + "connectionActivity": "CONNECTION ACTIVITY", + "reloadCertificate": "Reload certificate", + "certificateApiComment": "Comment", + "certificateApiConfiguredCount": "Certificate API tokens: {count} / {max}", + "certificateApiNeverUsed": "never used", + "certificateApiRevokeAll": "Revoke all tokens", + "certificateApiRevokeOneConfirm": "Revoke Certificate API token {key}? Any automation using it will stop immediately.", + "certificateApiRevokeAllConfirm": "Revoke every Certificate API token? All external certificate automation using these tokens will stop immediately.", + "certificate_api.invalid_comment": "Certificate API comments must be at most 256 characters and contain no control characters.", + "certificate_api.limit_reached": "The Certificate API token limit has been reached.", + "certificate_api.not_found": "Certificate API token not found.", + "networkInterfacesVisibleCount": "{visible} / {total} interfaces", + "hideMetric": "Hide", + "showMetric": "Show", + "hiddenInterfaces": "Hidden interfaces", + "networkNoVisibleInterfaces": "All detected interfaces are hidden in this browser.", + "cacheMemorySizingTitle": "Memory sizing", + "cacheMemorySizingHelp": "Presets use effective memory available to RustProxy (host RAM capped by cgroup when present). They tune HOT, transient RAM, object size, entry count and the demotion queue; the COLD disk budget is left unchanged.", + "cachePresetConservative": "Conservative", + "cachePresetRecommended": "Recommended", + "cachePresetPerformance": "Performance", + "cachePresetSelected": "Selected", + "cachePresetCustom": "Custom", + "cacheColdPresetTitle": "COLD policy preset", + "cacheColdPresetHelp": "The recommended policy enables idle/LRU/shutdown demotion, sizes the COLD queue from transient RAM and uses conservative GC timings. Disk path, disk budget and object limit are left unchanged.", + "cacheTransientLimit": "Transient RAM budget (MiB)", + "cacheEvictionLimit": "LRU removals per admission", + "cacheColdQueueLimit": "COLD queue RAM budget (MiB)", + "cacheMemoryNotDetected": "Memory not detected", + "cacheMemoryPresetUnavailable": "Automatic presets require host or cgroup memory telemetry.", + "cacheMemoryCgroup": "Effective cgroup RAM", + "cacheMemoryDetected": "Detected RAM", + "cacheQueueOverTransientWarning": "COLD queue budget cannot exceed the transient RAM budget.", + "cacheMemoryHighWarning": "Warning: HOT + transient cache budgets are a large share of effective RAM:", + "cachePresetTransientShort": "transient", + "cachePresetObjectShort": "max object", + "cachePresetQueueShort": "COLD queue", + "cacheLogicalShort": "logical", + "cacheLimitShort": "limit", + "cacheMemoryPressureShort": "memory pressure", + "cacheNukeLimitShort": "LRU limit", + "cacheMemoryPresetTooSmall": "Automatic cache presets are disabled below 256 MiB of effective RAM; configure the cache manually if this is intentional.", + "cacheMemoryRecommendedFor": "Recommended for detected memory:", + "cacheMemoryHeadroomWarning": "Warning: the additional cache budget is large compared with currently available host/cgroup memory:", + "cacheObjectOverTransientWarning": "Maximum object exceeds the transient RAM budget; objects near that size will pass through instead of being cached.", + "vhCacheGlobalDisabled": "Global cache is disabled. This vhost cannot enable cache until the global cache is enabled.", + "responseLatencyInfo": "Response time information", + "responseLatencyHint": "The value is the cumulative mean duration of completed HTTP exchanges since process start. The chart shows successive samples of that mean; it is not a percentile or the latency of one request.", + "web-server": "Web Server", + "web-serverTitle": "Serve local files.", + "web-serverDescription": "Create reusable Web Services and attach them to vhosts or Custom locations.", + "webServer": "Web Server", + "webServerIntro": "Create reusable local Web Services here, then attach them to a vhost or Custom location.", + "webServiceList": "Web Services", + "webServiceSearch": "Search Web Services", + "webServiceSearchPlaceholder": "Search name, ID or document root", + "webServiceNew": "New Web Service", + "webServiceEditor": "Web Service configuration", + "webServiceTabGeneral": "General", + "webServiceTabRouting": "Routing", + "webServiceTabMime": "MIME", + "webServiceTabCacheHeaders": "Cache & headers", + "webServiceTabDelivery": "Delivery", + "webServiceTabPhp": "PHP-FPM", + "webServiceTabSecurity": "Security", + "webServiceId": "Service ID", + "webServiceName": "Name", + "webServiceRoot": "Document root", + "webServiceIndex": "Index files", + "webServiceDirectoryListing": "Directory listing", + "webServiceMimeOverrides": "MIME overrides", + "webServiceMimeBuiltin": "Built-in mappings", + "webServiceMimeHelp": "Optional extension-to-Content-Type overrides, one per line. Use: ext = media/type.", + "webServiceMimeInvalid": "MIME overrides must use one unique 'ext = media/type' entry per line.", + "webServiceDefaultMime": "Default MIME type", + "webServiceCacheControl": "Cache-Control", + "webServiceCacheRules": "Cache-Control rules", + "webServiceCacheRulesHelp": "Specific rules are evaluated in order before the default policy. Match ext:css or mime:image/.", + "webServiceCacheRulesInvalid": "Cache-Control rules must use matcher = value, for example ext:css = public, max-age=3600.", + "webServiceResponseHeaders": "Response headers", + "webServiceResponseHeadersHelp": "Fixed headers for this Web Service. Vhost/location response headers run later and can override them.", + "webServiceResponseHeadersInvalid": "Response headers must use one unique Header-Name = value entry per line.", + "webServiceCacheHelp": "Local files use filesystem/OS page cache. These settings control browser/proxy caching and do not create a second RustProxy object cache.", + "webServiceTryFiles": "try_files", + "webServiceTryFilesHelp": "One candidate per line. Supports $uri, $query_string and a final =404/other error status.", + "webServiceRewrites": "Rewrite rules", + "webServiceRewritesHelp": "One regex rule per line. Use pattern => /target for an internal rewrite or pattern => 301:/target for a redirect.", + "webServiceRewritesInvalid": "Rewrite rules must use pattern => /target or pattern => 301:/target (301/302/307/308).", + "webServicePrecompressed": "Serve precompressed sidecars", + "webServicePrecompressedBr": "Brotli (.br)", + "webServicePrecompressedGzip": "Gzip (.gz)", + "webServiceDownloadExtensions": "Download extensions", + "webServiceDownloadExtensionsHelp": "Files with these extensions receive Content-Disposition: attachment.", + "webServiceRangeHelp": "Static and precompressed representations keep validators, single-range requests, 206/416 and streaming delivery.", + "webServicePhpEnabled": "Enable PHP-FPM / FastCGI", + "webServicePhpEndpoint": "PHP-FPM endpoint", + "webServicePhpEndpointHelp": "Unix: unix:/run/php/php-fpm.sock. TCP: tcp:127.0.0.1:9000 or tcp:[::1]:9000. TCP is intentionally limited to loopback addresses.", + "webServicePhpExtensions": "PHP extensions", + "webServicePhpPassAuthorization": "Forward Authorization header", + "webServicePhpConnectTimeout": "Connect timeout (ms)", + "webServicePhpRequestTimeout": "Total FastCGI request timeout (ms)", + "webServicePhpConcurrency": "Max concurrent PHP requests", + "webServicePhpBodyLimit": "PHP request body limit (bytes, 0 = unlimited)", + "webServicePhpHeaderLimit": "Max FastCGI response header bytes", + "webServicePhpStderrLimit": "Max PHP-FPM stderr log bytes", + "webServicePhpCustomParams": "Custom FastCGI parameters", + "webServicePhpCustomParamsHelp": "One NAME = value entry per line. Static trusted values only; core CGI, HTTP_* and PHP_* control names are reserved.", + "webServicePhpCustomParamsInvalid": "Custom FastCGI parameters must use one unique NAME = value entry per line.", + "webServicePhpCustomDataTooLarge": "Custom FastCGI parameters and PHP INI overrides may use at most 128 KiB combined.", + "webServicePhpValues": "PHP INI overrides (PHP_VALUE)", + "webServicePhpValuesHelp": "One php.ini directive = value per line. RustProxy sends the validated set as PHP_VALUE; PHP_ADMIN_VALUE is never accepted here.", + "webServicePhpValuesInvalid": "PHP INI overrides must use one unique directive = value entry per line.", + "webServicePhpDocsButton": "FastCGI syntax and safety", + "webServicePhpDocsTitle": "PHP-FPM / FastCGI configuration", + "webServicePhpDocsIntro": "RustProxy connects directly to an existing PHP-FPM pool. Prefer a Unix socket on the same host. TCP is accepted only on loopback and is not a public/network FastCGI transport.", + "webServicePhpDocsEndpointTitle": "Endpoint syntax", + "webServicePhpDocsEndpoint": "For TCP, include the tcp: prefix, a literal loopback IP and port. Hostnames and non-loopback addresses are rejected. For Unix sockets, RustProxy must have permission to connect to the socket.", + "webServicePhpDocsCustomTitle": "Custom FastCGI parameters", + "webServicePhpDocsCustom": "Use one NAME = value entry per line. Names are normalized to uppercase and may contain A-Z, 0-9 and underscore. These are static trusted operator values. RustProxy rejects core CGI names, HTTP_* names, PHP_VALUE and PHP_ADMIN_VALUE so they cannot override request routing, script selection or HTTP-derived parameters.", + "webServicePhpDocsValuesTitle": "PHP INI overrides", + "webServicePhpDocsValues": "These lines are combined into the FastCGI PHP_VALUE parameter. PHP-FPM/PHP still decides which directives are changeable at this scope. Newlines/control characters are rejected and PHP_ADMIN_VALUE is intentionally unavailable.", + "webServicePhpDocsLimitsTitle": "Limits and headers", + "webServicePhpDocsLimits": "Request timeout covers the FastCGI exchange. The body limit is enforced while streaming and returns 413 when exceeded; 0 disables the RustProxy-side body limit. Response-header and stderr limits bound memory/diagnostic data. Up to 64 custom FastCGI parameters and 64 PHP INI overrides are accepted, with at most 128 KiB of combined custom data. Authorization forwarding can be disabled for applications that do not need HTTP_AUTHORIZATION.", + "webServicePhpDocsSecurity": "Do not put secrets in custom parameters or PHP_VALUE unless you accept storing them in normal Web Service configuration. Use a dedicated non-root PHP-FPM pool identity and keep PHP-FPM off public networks.", + "webServicePhpHelp": "RustProxy speaks FastCGI directly to a long-running PHP-FPM pool. PHP is not spawned per request and PHP source is never served when PHP handling is selected.", + "webServicePhpSymlinkConflict": "PHP-FPM currently requires the symlink policy to be Deny.", + "webServiceSymlinkPolicy": "Symlink policy", + "webServiceSymlinkDeny": "Deny", + "webServiceSymlinkInsideRoot": "Allow only inside document root (Linux)", + "webServiceSafety": "Document root is a strict filesystem boundary. The default denies symlinks. Linux can optionally follow only targets that resolve inside the root; PHP-FPM currently requires the deny policy.", + "webServiceSelect": "Select Web Service", + "webService": "Web Service", + "webServiceUsedBy": "Used by", + "webServiceUnused": "Not attached", + "webServiceEmpty": "No Web Services yet.", + "webServiceSearchEmpty": "No Web Services match this search.", + "webServiceInUse": "Web Service is still used by", + "webServiceDelete": "Delete this Web Service?", + "webServiceIndexRequired": "Index files are optional.", + "webServiceDuplicate": "A Web Service with this ID already exists.", + "webServiceRequired": "Select a Web Service.", + "sourceType": "Source type", + "sourceReverseProxy": "Reverse Proxy", + "sourceWebServer": "Web Server", + "sourceHelp": "The vhost stores only the source choice. Web Server settings remain in the selected reusable Web Service.", + "locationWebServerAction": "Web Server", + "locationWebServerShort": "Web Server", + "docsReader": "Reader", + "docsApi": "API", + "docsReaderSearch": "Search documentation", + "docsReaderSearchPlaceholder": "Search title or path", + "docsReaderEmpty": "No documentation matches this search.", + "docsCategoryProject": "Project", + "docsCategoryGuides": "Functional guides", + "docsCategoryTechnical": "Technical", + "docsCategoryAudits": "Audits and history", + "docsCategoryHistorical": "Historical", + "webServiceIndexHelp": "Optional. Leave empty to skip index lookup; with directory listing enabled, the file list is shown directly.", + "webServiceNoIndex": "No index files", + "vhBackendRequired": "Reverse Proxy requires at least one backend. Add a backend or change the source to Web Server.", + "vhListenerRequired": "Select at least one listener for this vhost.", + "traffic": "Traffic", + "trafficTitle": "Traffic, per vhost.", + "trafficDescription": "Bounded request analytics: countries, User-Agents, client IPs, paths, routes and protocol outcomes.", + "trafficSinceStart": "Since process start", + "trafficResponseBytes": "Response bytes", + "trafficRequestBytes": "Request bytes", + "trafficMeanLatency": "Mean latency", + "trafficDroppedSamples": "Dropped analytics samples", + "trafficBoundedLabel": "BOUNDED / ASYNC", + "trafficDimensionsTitle": "Traffic dimensions", + "trafficApproxHelp": "Top lists are approximate and bounded so high-cardinality traffic cannot grow proxy memory without limit.", + "trafficTopCountries": "Top countries", + "trafficTopUserAgents": "Top User-Agents", + "trafficTopClientIps": "Top client IPs", + "trafficClientIp": "Client IP", + "trafficTopPaths": "Top paths", + "trafficTopRoutes": "Top routes", + "trafficMethods": "Methods", + "trafficStatusClasses": "Status classes", + "trafficCacheOutcomes": "Cache outcomes", + "trafficValue": "Value", + "trafficOther": "Other", + "trafficNoCountryData": "Country collection is disabled or no GeoIP data is available.", + "trafficNoUserAgentData": "No User-Agent data collected.", + "trafficNoData": "No traffic data yet.", + "trafficUserAgentEnabled": "User-Agent collection enabled", + "trafficUserAgentDisabled": "User-Agent collection disabled", + "trafficCountryEnabled": "Country collection enabled", + "trafficCountryDisabled": "Country collection disabled", + "trafficCountryNoDb": "Country collection enabled, GeoIP database unavailable", + "trafficUpdated": "Updated", + "loggingCaptureTitle": "Captured request dimensions", + "loggingCaptureUserAgent": "Capture User-Agent", + "loggingCaptureCountry": "Capture country from GeoIP", + "loggingCaptureCountryHelp": "Country lookup is optional and disabled by default. Enable it only when country logs/statistics are needed; country ACL/rate-limit rules still resolve GeoIP when required.", + "cacheAutoTrimEnabled": "Automatically release idle HOT cache memory", + "cacheAutoTrimAfter": "Idle age before HOT trim (seconds)", + "cacheAutoTrimTarget": "HOT trim target (%)", + "cacheAutoTrimHelp": "When HOT memory is above the target, only entries idle for the configured age are removed in bounded passes. Active objects are not purged.", + "webServiceTabHtaccess": ".htaccess", + "webServiceHtaccessEnabled": "Enable .htaccess compatibility", + "webServiceHtaccessFilename": "Configuration file", + "webServiceHtaccessRecursive": "Scan subdirectories", + "webServiceHtaccessStrict": "Strict unsupported-directive mode", + "webServiceHtaccessDocs": "Compatibility documentation", + "webServiceHtaccessHelp": "RustProxy compiles a bounded Apache-compatible subset when the Web Service is applied. Files are not parsed on every request; apply the Web Service again after editing .htaccess on disk.", + "webServiceHtaccessDocsTitle": ".htaccess compatibility", + "webServiceHtaccessDocsIntro": "This is a migration-oriented compatibility layer, not a complete Apache runtime. Supported directives are compiled into RustProxy Web Server rules.", + "webServiceHtaccessDocsSupportedTitle": "Supported subset", + "webServiceHtaccessDocsRewriteTitle": "Rewrite compatibility", + "webServiceHtaccessDocsRewrite": "Rewrite conditions support REQUEST_FILENAME file tests (-f, -d, -s), REQUEST_URI, REQUEST_METHOD, QUERY_STRING, HTTP_HOST, HTTPS, DOCUMENT_ROOT, THE_REQUEST and HTTP headers. Flags: L, END, R, R=301/302/307/308, QSA, NC, F, OR. PT/NE are accepted as no-ops. E= is accepted as a compatibility no-op because request HTTP headers already reach PHP-FPM.", + "webServiceHtaccessDocsPhpTitle": "PHP-FPM", + "webServiceHtaccessDocsPhp": ".htaccess may add PHP extensions with AddHandler, but the PHP-FPM endpoint, timeouts and concurrency remain controlled by the Web Service PHP-FPM tab. Apache SetHandler proxy socket syntax is intentionally not accepted.", + "webServiceHtaccessDocsReloadTitle": "Loading and limits", + "webServiceHtaccessDocsReload": "Files are read and compiled on Validate, save and apply. RustProxy does not parse .htaccess per request. Re-apply after changing a file. The scan is bounded to 128 files, depth 16, 128 KiB per file and 1 MiB total.", + "webServiceHtaccessDocsUnsupportedTitle": "Not Apache-complete", + "webServiceHtaccessDocsUnsupported": "ErrorDocument, SetEnvIf, Redirect/RedirectMatch and FallbackResource are not implemented in this compatibility layer. General Files/FilesMatch, unsupported authentication/authorization directives, non-PHP handlers and SetHandler are rejected even when Strict mode is off because silently ignoring them could weaken access control or expose source. .htaccess/.htpasswd files are always blocked from HTTP delivery. Other unsupported non-security directives are logged and ignored unless Strict mode is enabled.", + "webServiceHtaccessDocsSecurity": "Vhost/location ACL, authentication, error pages and response rules still remain authoritative. .htaccess cannot escape the document root, select an arbitrary FastCGI socket or override protected framing headers.", + "webServicePresetTitle": "Configuration preset", + "webServicePreset": "Preset", + "webServicePresetCustom": "Custom", + "webServicePresetStatic": "Static site", + "webServicePresetSpa": "SPA", + "webServicePresetPhpGeneric": "PHP generic", + "webServicePresetDownloads": "Downloads / file repository", + "webServicePresetAction": "Preset action", + "webServicePresetApply": "Apply preset", + "webServicePresetHelp": "Presets fill normal Web Service settings and remain fully editable. Document root, service ID/name and PHP-FPM endpoint are not replaced.", + "webServicePresetChoose": "Choose a preset before applying it.", + "webServicePresetApplied": "Preset applied. Review the generated settings before saving.", + "webServicePresetHintStatic": "Static site: HTML indexes, precompressed sidecars and cache rules for CSS/JS/images/fonts.", + "webServicePresetHintSpa": "SPA: index.html fallback via try_files, precompressed assets and long-lived static asset caching.", + "webServicePresetHintPhpGeneric": "Generic PHP: PHP-FPM enabled, index.php first and only existing files/directories are served directly.", + "webServicePresetHintWordpress": "WordPress: PHP-FPM, index.php and front-controller routing. Keep document root on the WordPress public directory.", + "webServicePresetHintDrupal": "Drupal: PHP-FPM, index.php and front-controller routing with static asset caching.", + "webServicePresetHintLaravel": "Laravel: PHP-FPM and front-controller routing. Point document root at the application public/ directory.", + "webServicePresetHintSymfony": "Symfony: PHP-FPM and front-controller routing. Point document root at the application public/ directory.", + "webServicePresetHintJoomla": "Joomla: PHP-FPM, index.php and front-controller routing with static asset caching.", + "webServicePresetHintPrestashop": "PrestaShop: PHP-FPM, index.php and front-controller routing with static asset caching.", + "webServicePresetHintDownloads": "Downloads: directory listing enabled, Range-friendly static delivery and common archive/document extensions forced as attachments.", + "webServiceHardeningTitle": "Hardening", + "webServiceHardeningAttacks": "Block common attack probes", + "webServiceHardeningHeaders": "Strip unnecessary fingerprint headers", + "webServiceHardeningSecurityHelp": "Hardening switches are shown beside the preset selector on General. They remain independent settings after a preset is applied.", + "trafficTabOverview": "Overview", + "trafficTabClients": "Clients", + "trafficTabRequests": "Requests", + "trafficTabDelivery": "Delivery", + "trafficVolume": "Traffic volume", + "vhMethodMode": "HTTP method policy", + "vhMethodList": "HTTP methods (one per line)", + "vhMethodHelp": "Allow only listed methods or block listed methods for this vhost. The policy stacks with location rules.", + "locationAclProfile": "ACL profile", + "locationMethodMode": "HTTP method policy", + "locationMethodList": "HTTP methods (one per line)", + "locationMethodAllow": "Allow only", + "locationMethodBlock": "Block listed", + "locationMethodHelp": "The location policy stacks with the vhost method policy. Example: GET, HEAD and POST.", + "locationCountryMode": "Country access policy", + "locationCountryList": "Country codes (one per line)", + "locationCountryHelp": "Location country policy stacks with vhost/profile policy. GeoIP is resolved only when required.", + "configHistory": "Revision history", + "configHistoryRetention": "SQLITE / LAST 512 REVISIONS", + "configHistoryHelp": "Select a marked day to inspect retained configuration revisions and their changes. History retention starts with 0.25.3.", + "configHistoryChanges": "CHANGES", + "configHistorySelectDay": "Select a day.", + "configHistoryRevision": "Revision", + "configHistoryRevisionShort": "rev", + "configHistoryBefore": "Before", + "configHistoryAfter": "After", + "configHistoryBaseline": "This is the oldest retained baseline; no earlier revision is available for comparison.", + "configHistoryNoChanges": "No configuration differences were found.", + "configHistoryDiffLimit": "Diff truncated after 200 changed paths.", + "configHistoryMissing": "(not present)", + "configHistoryEntries": "revisions", + "configHistorySummary": "{count} retained revisions", + "configHistoryEmpty": "No retained revisions.", + "configHistoryLoading": "Loading revision history...", + "configHistoryFailed": "Could not load revision history.", + "configHistoryRestoreAction": "Restore revision", + "configHistoryRestoreConfirm": "Restore revision {revision}? It will be validated and saved as a new revision after current revision {current}. The existing history will be preserved.", + "configHistoryRestored": "Revision {revision} restored as new revision {new_revision}.", + "about": "About", + "aboutTitle": "About RustProxy", + "aboutAuthor": "Author", + "aboutLicense": "License", + "aboutLicenseValue": "Open Source", + "aboutOpenSourceText": "RustProxy is an open-source project. Its source code is publicly available for inspection, development and community contribution.", + "aboutRepository": "Source repository", + "vhPoolRecycleRequests": "Recycle upstream pool after requests (0 = off)", + "vhPoolRecycleSeconds": "Maximum upstream pool age (seconds, 0 = off)", + "vhHttp1MaxBuffer": "HTTP/1 upstream max read buffer (bytes)", + "vhPoolRecycleHelp": "Recycling replaces only the Hyper client generation for each backend; active exchanges continue normally. Defaults bound long-lived pool/TLS buffer retention without reloading the vhost or cache. Request recycling accepts 0 or 1000..10000000; age accepts 0 or 60..604800.", + "backendSearch": "Search backends", + "backendSearchPlaceholder": "Search vhost, backend or state", + "backendSortBy": "Sort by", + "backendSortAscending": "Ascending sort", + "backendSortDescending": "Descending sort", + "backendColumns": "Columns", + "backendSearchEmpty": "No backends match the current search.", + "vhQuickEnable": "Enable", + "vhQuickDisable": "Disable", + "vhEnableHint": "Controls whether this vhost accepts traffic.", + "backendColumnsRequired": "At least one backend table column must remain visible." + } } diff --git a/langs/pl_pl.json b/langs/pl_pl.json index eead9e0..af89ac2 100644 --- a/langs/pl_pl.json +++ b/langs/pl_pl.json @@ -1,1967 +1,1978 @@ { - "meta": { - "locale": "pl-PL", - "name": "Polish", - "native_name": "Polski", - "direction": "ltr" - }, - "translations": { - "overview": "Przegląd", - "mainMenu": "Menu", - "routing": "Starsze trasy", - "configuration": "Konfiguracja", - "manualConfig": "Konfiguracja ręczna", - "runtime": "ŚRODOWISKO", - "localOnly": "ADMINISTRACJA", - "logout": "Wyloguj", - "firstSlice": "NIEZALEŻNY RDZEŃ / JAWNY DOSTĘP", - "loginTitle": "Administracja", - "unlock": "Odblokuj administrację", - "tokenHelp": "Uruchom polecenie w drugim terminalu i wklej token poniżej.", - "token": "Lokalny token dostępu", - "connect": "Połącz z proxy", - "tokenNote": "Administracja domyślnie używa HTTP na loopback. Przed użyciem adresu spoza loopback włącz HTTPS panelu.", - "requests": "Żądania", - "activeExchanges": "Aktywne żądania", - "bodyLifetime": "Do zakończenia strumienia", - "bandwidth": "Przekazane dane", - "bothDirections": "W obu kierunkach", - "errors": "Błędy", - "errorDescription": "5xx / body / przerwane", - "liveTraffic": "RUCH NA ŻYWO", - "liveTransformed": "Transformowane", - "requestsPerSecond": "Żądania na sekundę", - "live": "NA ŻYWO", - "lastMinute": "Ostatnie próbki / reset po odświeżeniu", - "coreState": "STAN RDZENIA", - "configurationRevision": "Aktywna rewizja", - "backends": "Backendy", - "routes": "Trasy", - "connections": "Otwarte połączenia", - "uptime": "Czas działania", - "activity": "AKTYWNOŚĆ", - "accessLog": "Log dostępu", - "boundedLog": "Ostatnie 50 / bufor 4096", - "time": "Czas", - "request": "Żądanie", - "status": "Status", - "duration": "Czas obsługi", - "outcome": "Wynik", - "noTraffic": "Brak ruchu. Otwórz proxy, aby wysłać pierwsze żądanie.", - "reload": "Wczytaj konfigurację", - "addBackend": "Dodaj / edytuj backend", - "backendUrl": "Adres backendu (HTTP / HTTPS, IP / DNS)", - "allowPrivate": "Jawnie zezwól na prywatny IP / loopback", - "preserveHost": "Zachowaj oryginalny nagłówek Host", - "saveBackend": "Zapisz backend", - "clear": "Wyczyść", - "addRoute": "Dodaj / edytuj trasę", - "hostnames": "Hostname i aliasy, oddzielone przecinkami", - "pathPrefix": "Prefiks ścieżki (bez usuwania)", - "backend": "Backend", - "enabled": "Włączona", - "saveRoute": "Zapisz trasę", - "rawConfig": "Dokument konfiguracji", - "export": "Eksportuj JSON", - "configHelp": "Poprawny zapis jest stosowany atomowo. Błędne lub nieaktualne zmiany nie zastępują działającej konfiguracji.", - "apply": "Sprawdź, zapisz i zastosuj", - "noRestart": "Routing i polityki odpowiedzi działają od razu; zmiana portów wymaga restartu.", - "roadmapHelp": "Zmiany w wydaniach i planowane funkcje opisuje plik ROADMAP.md.", - "overviewTitle": "Ruch pod kontrolą.", - "overviewDescription": "Ruch, cache i pomiary systemu operacyjnego w jednym zwartym panelu.", - "routingTitle": "Połącz właściwe adresy.", - "routingDescription": "Dotychczasowy format backendów i tras pozostaje obsługiwany. Nowe konfiguracje mogą używać vhosta z własnym frontendem i pulą.", - "configurationTitle": "Jedno źródło prawdy.", - "configurationDescription": "Jedna konfiguracja: vhosty, listenery i wspolne polityki.", - "connected": "POŁĄCZONO Z LOKALNYM RDZENIEM", - "disconnected": "RDZEŃ NIEDOSTĘPNY", - "edit": "Edytuj", - "remove": "Usuń", - "privateAllowed": "ZGODA NA PRYWATNY IP", - "configured": "SKONFIGUROWANY / BEZ PROBE", - "disabled": "WYŁĄCZONA", - "emptyBackends": "Brak backendów. Dodaj jawny adres HTTP lub HTTPS.", - "emptyRoutes": "Brak tras. Nieznane hostname zwracają 404.", - "saving": "Zapisywanie…", - "unsavedChanges": "Niezapisane zmiany", - "saved": "Zastosowano konfigurację.", - "confirmDelete": "Usunąć ten element? Zmiana zadziała natychmiast.", - "confirmTitle": "Potwierdź operację", - "confirmationLabel": "POTWIERDZENIE", - "warningLabel": "OSTRZEŻENIE", - "continueAction": "Kontynuuj", - "cancelAction": "Anuluj", - "discardAction": "Odrzuć zmiany", - "errorContext": "{area}: {message}", - "stale": "Konfiguracja zmieniła się w innym miejscu. Wczytaj ją przed zapisem.", - "busy": "Trwa już zapis.", - "loginError": "Nie udało się zalogować.", - "fresh": "Wczytano konfigurację.", - "locked": "Wylogowano i unieważniono sesję.", - "backendUsed": "Backend jest używany przez trasę. Najpierw usuń lub zmień trasę.", - "renaming": "Nie można zmienić ID w formularzu. Użyj edytora JSON i zmień również powiązania.", - "complete": "zakończono", - "cancelled": "przerwano", - "body_error": "błąd body", - "proxy_or_upstream_error": "błąd proxy/backendu", - "security": "Bezpieczeństwo", - "sessionNote": "Lokalna administracja HTTP. Hasła używają Argon2id, a cookies sesji są HttpOnly. Nie udostępniaj panelu publicznie.", - "setupHelp": "Utwórz pierwsze konto administratora. Jednorazowy token odczytasz lokalnie w terminalu.", - "setupToken": "Jednorazowy token instalacyjny", - "username": "Nazwa użytkownika", - "password": "Hasło", - "confirmPassword": "Powtórz hasło", - "setupTitle": "Utwórz administratora", - "signIn": "Zaloguj się", - "createAndSignIn": "Utwórz konto i zaloguj", - "securityTitle": "Dostęp pod kontrolą.", - "securityDescription": "Jeden administrator. Odwoływalne sesje. Jawne polityki hostów i tras.", - "manualBackends": "RĘCZNE BACKENDY", - "routePolicies": "Kontrola dostępu i nagłówki", - "useRouteAcl": "Włącz ACL trasy", - "aclDefault": "Domyślna akcja", - "allow": "Zezwól", - "deny": "Zablokuj", - "aclRules": "Jedna reguła w wierszu: allow/deny oraz CIDR", - "aclHelp": "Podaj CIDR IPv4/IPv6, np. 192.168.1.0/24 lub 10.0.0.5/32. Odmowa ma pierwszeństwo. Dozwolone IP nadal wymaga uwierzytelnienia. Lokalizacja nie omija ACL hosta.", - "routeHeaders": "Nagłówki request / response (JSON)", - "headersHelp": "Operacje: ustaw, dodaj, usuń. Nagłówki transportu, kodowania body i tożsamości klienta są chronione.", - "currentSession": "BIEŻĄCA SESJA", - "recoveryHelp": "Utrata dostępu? Uruchom lokalnie rust-proxy admin reset-password. Dotychczasowe sesje zostaną unieważnione.", - "revokeAll": "Wyloguj wszystkie sesje", - "changePassword": "Zmień hasło", - "currentPassword": "Obecne hasło", - "newPassword": "Nowe hasło (12-128 bajtów UTF-8)", - "savePassword": "Zmień i wyloguj", - "hostPolicies": "Polityki dostępu hostów", - "editHostPolicy": "Dodaj / zastąp politykę hosta", - "savePolicy": "Zastosuj politykę", - "auditRetention": "SQLITE / OSTATNIE 100 / LIMIT 10 000", - "audit": "Audyt administracyjny", - "reloadAudit": "Odśwież", - "actor": "Użytkownik", - "action": "Operacja", - "detail": "Szczegóły", - "noAudit": "Brak wpisów audytu.", - "noPolicies": "Brak ACL hostów. Dostęp mogą ograniczać reguły tras.", - "expires": "Sesja wygaśnie najpóźniej: ", - "passwordChanged": "Zmieniono hasło i unieważniono sesje. Zaloguj się ponownie.", - "passwordMismatch": "Hasła nie są takie same.", - "ruleSyntax": "Wpisz jedną regułę w wierszu, np. allow 127.0.0.1/32", - "confirmRevoke": "Wylogować wszystkie sesje, również bieżącą?", - "streamLive": "SSE na żywo", - "streamFallback": "Odpytywanie awaryjne", - "auth.required": "Sesja wygasla lub zostala odwolana. Zaloguj sie ponownie.", - "auth.invalid_credentials": "Nieprawidłowa nazwa użytkownika lub hasło.", - "auth.password_policy": "Haslo musi miec 12-128 bajtow UTF-8, bez znakow nowego wiersza.", - "auth.invalid_username": "Uzyj 3-64 liter, cyfr, kropek, myslnikow lub podkreslen.", - "auth.invalid_setup_token": "Niepoprawny token instalacyjny. Odczytaj go w lokalnym terminalu.", - "auth.already_initialized": "Administrator juz istnieje. Zaloguj sie.", - "auth.rate_limited": "Zbyt wiele prob. Ponow po 60 sekundach lub uzyj lokalnego resetu hasla.", - "auth.busy": "Trwa weryfikacja innych hasel. Ponow za chwile.", - "auth.csrf": "Niepoprawna ochrona zadania. Odswiez strone i ponow.", - "auth.invalid_host": "Użyj skonfigurowanego adresu administracji i dozwolonej nazwy hosta.", - "auth.invalid_origin": "Zablokowano dostep administracyjny z innego originu.", - "auth.credentials_changed": "Dane logowania zostaly zmienione. Zaloguj sie ponownie.", - "auth.unavailable": "Baza administracyjna jest chwilowo niedostepna.", - "events.too_many_viewers": "Osiagnieto limit odbiorcow SSE; pozostaje odpytywanie.", - "protocol": "Protokół upstream", - "protocolHelp": "HTTP/2 i auto używają authority backendu. Preserve Host jest dostępne tylko z HTTP/1.1. RFC 8441 może użyć jawnego upstreamu HTTP/2; pozostałe transporty WebSocket są mostkowane przez HTTP/1.1.", - "addressAllowlist": "Opcjonalna lista dozwolonych adresów (CIDR, po jednym w wierszu)", - "caPem": "Dodatkowy zaufany CA / certyfikat (PEM, opcjonalnie)", - "backendTlsHelp": "Szyfrowanie TLS pozostaje dostępne, ale weryfikacja certyfikatu i nazwy jest domyślnie wyłączona, dopóki nie włączysz jej jawnie. Prywatne adresy nadal wymagają zgody, także po rozwiązaniu DNS.", - "advancedTransport": "Transport i zaufanie", - "tls": "Certyfikaty", - "tlsTitle": "Szyfrowanie pod kontrolą.", - "tlsDescription": "Dokładne nazwy SNI. Prywatne pliki certyfikatów. Zmiany bez restartu.", - "certificateBindings": "Powiązania certyfikatów", - "addCertificate": "Dodaj certyfikat", - "certificateId": "ID certyfikatu", - "certificateFile": "Nazwa pliku certyfikatu", - "privateKeyFile": "Nazwa pliku klucza prywatnego", - "defaultCertificate": "Użyj jako certyfikatu domyślnego", - "saveCertificate": "Zastosuj certyfikat", - "reloadCertificates": "Wczytaj pliki certyfikatów", - "certificateHelp": "Wgraj parę PEM, wskaż pliki w data/certs albo wdrażaj certyfikat z zewnętrznego wystawcy poleceniem `./dev.sh tls deploy --id ID --cert FULLCHAIN --key PRIVKEY`. Wczytanie ponownie odczytuje skonfigurowane pliki bez zmiany revision.", - "certificateHint": "Hook Certbota: ./dev.sh tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem", - "emptyCertificates": "Brak jawnych powiązań SNI. Aktywny listener TLS używa wygenerowanego certyfikatu domyślnego.", - "certificateSafety": "Certyfikaty samopodpisane służą do testów. Certyfikat nie tworzy trasy. Zmiana dotyczy nowych połączeń TLS.", - "wsActive": "Tunele WebSocket", - "h2Requests": "Żądania HTTP/2", - "h2ActiveConnections": "Aktywne połączenia H2", - "tlsFailures": "Błędy handshake TLS", - "tlsListener": "Listener TLS", - "notEnabled": "Wyłączony", - "websocket_closed": "WebSocket zamknięty", - "defaultLabel": "DOMYŚLNY", - "language": "Język", - "settings": "Ustawienia", - "settingsTitle": "Ustawienia proxy.", - "settingsDescription": "Przelaczaj karty funkcji. Niezapisane zmiany pozostaja w formularzach.", - "cacheHitRatio": "Trafienia cache", - "processMemory": "Pamięć procesu", - "systemLoad": "OBCIĄŻENIE SYSTEMU", - "systemChart": "Ostatnie próbki obciążenia CPU", - "systemMemory": "RAM systemu", - "systemSwap": "Swap systemu", - "systemUptime": "Czas działania systemu", - "loadAverage": "Load 1 / 5 / 15 min", - "cacheOverview": "Cache RAM", - "cacheObjects": "Obiekty / pamięć", - "cacheEvictions": "Usunięte / wygasłe", - "processDiagnostics": "Proces", - "platform": "Platforma", - "processCpu": "CPU (100% = 1 rdzeń)", - "fileDescriptors": "Deskryptory / limit", - "processThreads": "Wątki systemowe", - "processVirtualMemory": "Pamięć wirtualna / limit", - "processStartTime": "Start procesu", - "containerMemory": "RAM cgroup / limit", - "networkDiagnostics": "Sieć i odpowiedzi", - "hostScope": "Zakres systemu", - "networkRate": "RX / TX na sekundę", - "meanLatency": "Średni czas obsługi", - "filterLogs": "Filtruj host lub ścieżkę", - "filterResult": "Filtruj wynik", - "allResults": "Wszystkie", - "routeCache": "Cache dla trasy", - "inheritCache": "Dziedzicz ustawienia globalne", - "bypassCache": "Zawsze pomijaj cache", - "listeners": "Listenery", - "httpConnections": "Połączenia HTTP", - "httpConnectionsHelp": "Cykl życia połączeń i limity transportu dla HTTP/2 oraz HTTP/3.", - "http2Tab": "HTTP/2", - "http3Tab": "HTTP/3", - "http2Settings": "Połączenia HTTP/2", - "http2SettingsHelp": "HTTP/2 włącza się osobno dla każdego listenera. Tutaj ustawisz bezczynność, maksymalny czas życia i graceful drain po GOAWAY.", - "http2IdleTimeout": "Idle timeout (sekundy)", - "http2MaxLifetime": "Maksymalny czas życia połączenia (sekundy, 0 = wyłączony)", - "http2DrainTimeout": "Drain timeout (sekundy)", - "http2DrainHelp": "Te limity dotyczą tego listenera. Idle timeout obejmuje tylko nieużywane połączenia, maksymalny lifetime jest bezwzględny, a drain ogranicza czas aktywnych strumieni po GOAWAY. Zmiany wymagają restartu.", - "http2Save": "Zapisz ustawienia HTTP/2", - "http2NoEnabledListeners": "Żaden listener nie ma włączonego HTTP/2. Najpierw włącz HTTP/2 lub h2c w Ustawienia > Listenery.", - "http2ListenersDirty": "Najpierw zapisz oczekujące zmiany w Listenerach, a następnie edytuj ustawienia HTTP/2.", - "restartLabel": "RESTART", - "listenersHelp": "Nazwane adresy IP i porty. Zmiany wymagają restartu. Panel administracyjny pozostaje osobno.", - "httpAddress": "Adres nasłuchu i port HTTP", - "httpsAddress": "Adres nasłuchu i port HTTPS", - "enableHttps": "Włącz nasłuch HTTPS", - "lowPortsHelp": "Porty uprzywilejowane mogą wymagać CAP_NET_BIND_SERVICE. Nie uruchamiaj całej aplikacji jako root.", - "saveListeners": "Zapisz ustawienia portów", - "inheritListeners": "Użyj ustawień startowych", - "responseSettings": "Odpowiedź do klienta", - "hotApply": "BEZ RESTARTU", - "serverHeader": "Nagłówek Server", - "serverPreserve": "Zachowaj wartość backendu", - "serverHide": "Ukryj całkowicie", - "serverCustom": "Nadpisz / dodaj własną wartość", - "serverValue": "Własna wartość Server", - "compression": "Kompresja strumieniowa", - "compressionMin": "Minimalny rozmiar odpowiedzi (bajty)", - "compressionHelp": "Negocjacja Accept-Encoding. Pomija dane prywatne, cookies, zakresy, SSE i no-transform. Nie kompresuje ponownie zakodowanych odpowiedzi.", - "saveResponse": "Zastosuj ustawienia odpowiedzi", - "cacheSettings": "Cache", - "enableCache": "Włącz cache", - "cacheSafety": "Cache zapisuje kompletne, bezpieczne odpowiedzi GET. Authorization, cookies oraz odpowiedzi private/no-store nadal omijają cache. Pojedynczy zakres bajtów może być obsłużony z pełnego obiektu cache; multipart i nieobsługiwane zakresy przechodzą do originu.", - "cacheMemory": "Limit alokowanej pamięci HOT (MiB)", - "cacheObject": "Limit obiektu (KiB)", - "cacheEntries": "Maksymalna liczba wpisów", - "cacheMaxTtl": "Maksymalny TTL (sekundy)", - "cacheDefaultTtl": "Zapasowy TTL odpowiedzi publicznych (0 = wył.)", - "bypassQuery": "Pomijaj adresy z parametrami query", - "cachePrefixes": "Pomijane prefiksy ścieżek, po jednym w wierszu", - "cacheAgeHelp": "Trafienia zawsze zawierają Age. Liczniki działają również przy ukrytych nagłówkach diagnostycznych. Tylko zmiany wpływające na cache unieważniają niezgodne obiekty; podczas zarządzanej aktualizacji hot cache jest przenoszony do cold storage, jeśli cold tier jest włączony.", - "saveCache": "Zastosuj ustawienia cache", - "purgeCache": "Wyczyść cały cache", - "customHeaders": "Globalne reguły nagłówków", - "globalHeadersHelp": "Request trafia do backendu, response do klienta. Reguły trasy są stosowane po globalnych. Polityka Server ma ostateczne pierwszeństwo.", - "responseHeaders": "Odpowiedź do klienta", - "requestHeaders": "Żądanie do backendu", - "addHeader": "Dodaj regułę nagłówka", - "saveHeaders": "Zastosuj reguły nagłówków", - "unavailable": "Brak danych", - "threads": "wątków", - "realSample": "Pomiar", - "noKnownLimit": "nieznany / bez limitu", - "unlimited": "bez limitu", - "restartPending": "Zapisano zmianę portów. Uruchom ponownie RustProxy, aby ją zastosować.", - "activeListeners": "Aktualnie aktywne", - "headerLimit": "Maksymalnie 32 reguły w każdym kierunku.", - "headerOperation": "Operacja", - "header_set": "Ustaw", - "header_append": "Dodaj", - "header_remove": "Usuń", - "headerName": "Nazwa nagłówka", - "headerValue": "Wartość nagłówka", - "confirmInherit": "Przywrócić ustawienia portów z parametrów startowych i środowiska po restarcie?", - "confirmPurge": "Usunąć wszystkie obiekty cache i anulować zapis trwających pobrań?", - "cachePurged": "Cache wyczyszczony; usunięte wpisy", - "logsDropped": "odrzucone", - "updateAvailable": "Nowa wersja", - "vhosts": "Vhosty", - "vhostsTitle": "Vhosty i backendy", - "vhostsDescription": "Zarządzaj domenami, frontendami, backendami i politykami hostów.", - "vhHealthTitle": "Backendy", - "vhManage": "Zarządzaj vhostami", - "vhHealthHint": "Stan bieżący: aktywność obejmuje całą wymianę; transfer to średnia EWMA danych.", - "vhHealthEmpty": "Brak danych diagnostycznych backendów.", - "vhVhost": "Vhost", - "vhActive": "Aktywne", - "vhRequests": "Żądania", - "vhErrors": "Błędy", - "vhLatency": "Opóźnienie (EWMA)", - "vhTraffic": "Transfer/s", - "vhClientGeneration": "Gen. klienta", - "vhGenerationRequests": "Żądania gen.", - "vhGenerationAge": "Wiek gen.", - "vhClientRotations": "Rotacje", - "vhIntro": "Każdy vhost ma własne adresy IP, ścieżki i backendy. Inne adresy go nie obsługują. Zmiana nasłuchu wymaga restartu.", - "vhList": "Hosty wirtualne", - "vhSearch": "Szukaj vhostów", - "vhSearchPlaceholder": "Szukaj domeny, vhosta lub backendu", - "vhSearchEmpty": "Brak vhostów pasujących do wyszukiwania.", - "vhNew": "Nowy vhost", - "vhMigrate": "Migracja grupy starszych tras", - "vhImport": "Wczytaj do edytora", - "vhMigrationHint": "Migracja jest atomowa. Trasy tych samych hostów i backendu są grupowane; niejednoznaczne przypisanie hostów jest odrzucane.", - "vhEditor": "Konfiguracja vhosta", - "vhReset": "Odrzuć zmiany", - "vhSafetyHint": "Prywatny IP nie zastępuje uwierzytelniania. Zachowaj firewall i ACL. Preload HSTS jest opcjonalny; cookie affinity nie jest sesją logowania.", - "vhId": "Identyfikator vhosta", - "vhHosts": "Nazwy hostów", - "vhEnabled": "Włączony", - "vhFrontends": "Frontendy / adresy nasłuchu", - "vhAddFrontend": "Dodaj frontend", - "vhAddress": "IP:port (IPv6: [adres]:port)", - "vhTls": "TLS włączony", - "vhHttp2": "Preferuj HTTP/2 przez TLS; zachowaj HTTP/1.1", - "vhBackendPool": "Backendy", - "vhAddBackend": "Dodaj backend", - "vhMemberId": "Identyfikator backendu", - "vhUrl": "Adres URL backendu", - "vhWeight": "Waga", - "vhBackup": "Tylko zapasowy", - "vhDrain": "Wstrzymaj nowe sesje", - "vhPrivate": "Zezwól na prywatny IP backendu", - "vhPreserveHost": "Zachowaj Host klienta (tylko HTTP/1.1)", - "vhProtocol": "Protokół backendu", - "vhProtocolHttp1": "HTTP/1.1", - "vhProtocolAuto": "TLS ALPN: HTTP/2 + HTTP/1.1", - "vhProtocolHttp2": "HTTP/2 (TLS: także HTTP/1.1; bez TLS: h2c)", - "vhAddressAllowlist": "Dozwolone IP/CIDR backendu (opcjonalne)", - "vhTlsServerName": "Nazwa serwera TLS / SNI (opcjonalna)", - "vhTlsVerify": "Weryfikuj certyfikat i nazwę hosta backendu", - "vhTlsVerifyHelp": "Przy pominięciu ustawienia weryfikacja jest wyłączona. Włącz ją, gdy RustProxy ma weryfikować łańcuch i tożsamość certyfikatu backendu. Jeśli walidacja nie przechodzi, ustaw nazwę serwera TLS na nazwę DNS obecną w certyfikacie i/lub dodaj PEM prywatnego CA. Nie używaj adresu IP jako SNI.", - "vhCa": "Dodatkowy zaufany CA (PEM, opcjonalny)", - "vhBalancing": "Balansowanie i ponowne użycie połączeń", - "vhAlgorithm": "Algorytm", - "vhRoundRobin": "Płynny ważony round-robin", - "vhLeastConnections": "Najmniej aktywnych wymian, z wagami", - "vhLeastTraffic": "Najmniejszy transfer (EWMA), z wagami", - "vhAdaptive": "Adaptacyjny: aktywność + opóźnienie + transfer", - "vhIpHash": "Skrót IP klienta", - "vhSlowStart": "Łagodny powrót (sekundy)", - "vhRetryMax": "Ponowienia failover", - "vhRetryConnect": "Ponawiaj błędy połączenia", - "vhRetryTimeouts": "Ponawiaj timeout nagłówków odpowiedzi", - "vhRetryStatuses": "Ponawiane statusy HTTP", - "vhRetryHelp": "Retry działa tylko dla bezbody GET, HEAD i OPTIONS, wybiera inny zdrowy backend i nigdy nie ponawia WebSocketów ani żądań zapisu.", - "vhKeepalive": "Używaj ponownie połączeń do backendu (keepalive)", - "vhIdleTimeout": "Limit bezczynności w puli (sekundy)", - "vhMaxIdle": "Maks. bezczynnych połączeń / backend", - "vhTcpKeepalive": "Interwał keepalive TCP / HTTP/2 (sekundy)", - "vhHealth": "Zdrowie backendów", - "vhHealthMode": "Rodzaj testu", - "vhOff": "Wyłączone", - "vhTcp": "Połączenie TCP", - "vhHttp": "Status HTTP + czas odpowiedzi", - "vhHealthPath": "Ścieżka testu HTTP", - "vhHealthHost": "Własny Host testu HTTP (opcjonalny)", - "vhInterval": "Interwał (ms)", - "vhTimeout": "Limit czasu (ms)", - "vhSlow": "Próg wolnej odpowiedzi (ms; 0 = wył.)", - "vhFall": "Niepowodzenia przed wyłączeniem", - "vhRise": "Sukcesy przed przywróceniem", - "vhStatusMin": "Minimalny status HTTP", - "vhStatusMax": "Maksymalny status HTTP", - "vhHealthNote": "Testy HTTP używają HTTP/1.1 i mierzą czas do nagłówków, nie całej treści. Dla usług tylko h2c wybierz TCP. Nowe backendy czekają na udane testy. Aktywny health-check jest niezależny od pasywnego.", - "vhPassiveHealth": "Pasywne zdrowie backendu", - "vhPassiveEnabled": "Pozwól, aby błędy zwykłych requestów oznaczały backend jako niedostępny", - "vhPassiveHelp": "Domyślnie wyłączone. Błędy nadal są logowane i zliczane, ale zwykły ruch użytkowników nie zmienia stanu backendu bez świadomego włączenia.", - "vhPassiveConnect": "Zliczaj błędy połączenia", - "vhPassiveTimeouts": "Zliczaj timeouty", - "vhPassiveIo": "Zliczaj błędy I/O body/odczytu/zapisu", - "vhPassive5xx": "Zliczaj odpowiedzi HTTP 5xx", - "vhPassiveSlow": "Zliczaj wolne odpowiedzi", - "vhPassiveFall": "Pasywne błędy przed wyłączeniem (puste = active fall)", - "vhPassiveRise": "Pasywne sukcesy przed przywróceniem (puste = active rise)", - "vhPassiveWarning": "Włączenie 5xx lub wolnych odpowiedzi może wyłączyć cały backend po serii błędów z pojedynczego endpointu.", - "vhSticky": "Sticky sessions", - "vhStickyMode": "Tryb przypisania", - "vhCookie": "Nieprzezroczyste cookie proxy", - "vhCookieName": "Nazwa cookie (pusta = domyślna per vhost)", - "vhCookieTtl": "Ważność cookie (sekundy)", - "vhStickyNote": "Sticky cookie omija współdzielony cache. Drain zachowuje istniejące sesje cookie. Przypisanie po IP używa zweryfikowanego adresu klienta zgodnie z polityką zaufanych proxy.", - "vhSecurity": "Bezpieczeństwo", - "vhHsts": "Włącz HSTS (tylko odpowiedzi TLS)", - "vhHstsAge": "HSTS max-age (sekundy)", - "vhHstsSub": "HSTS includeSubDomains", - "vhHstsPreload": "HSTS preload (świadome włączenie)", - "vhNosniff": "X-Content-Type-Options: nosniff", - "vhFrame": "X-Frame-Options", - "vhPreserve": "Zachowaj wartość backendu", - "vhDeny": "DENY", - "vhSameorigin": "SAMEORIGIN", - "vhReferrer": "Referrer-Policy (opcjonalne)", - "vhCsp": "Content-Security-Policy (opcjonalne)", - "vhPermissions": "Permissions-Policy (opcjonalne)", - "vhAdvanced": "Zaawansowane: ścieżki, ACL i własne nagłówki", - "vhPaths": "Sciezki (JSON; opcjonalne backend_id przypina sciezke do jednego backendu)", - "vhAcl": "ACL vhosta (JSON lub null)", - "vhHeaders": "Reguły nagłówków żądania / odpowiedzi (JSON)", - "vhEmpty": "Brak vhostów. Dotychczasowe trasy nadal działają.", - "vhUnsaved": "Odrzucić niezapisane zmiany vhosta?", - "vhDelete": "Usunąć vhost? Gniazda nasłuchu zostaną zamknięte po restarcie.", - "vhConflict": "Vhost o takim identyfikatorze już istnieje.", - "vhRowLimit": "Osiągnięto maksymalną liczbę wierszy.", - "vhMigrationAmbiguous": "Hosty pokrywają się z innymi trasami. Uporządkuj przypisanie w JSON przed migracją.", - "vhMigrationPending": "Migracja starszych tras zostanie zatwierdzona przy zapisie.", - "vhMigrationNone": "Wybierz starszą trasę", - "vhJsonInvalid": "Nieprawidłowy JSON lub typ danych w ścieżkach, ACL lub nagłówkach.", - "vhUp": "Działa", - "vhDown": "Niedostępny", - "vhChecking": "Sprawdzanie", - "vhDraining": "Wygaszanie", - "vhDisabled": "Wyłączony", - "vhHealthDisabled": "Testy wyłączone", - "vhHealthUnknown": "Nieznany", - "vhNewLabel": "NOWY", - "vhEditLabel": "EDYCJA", - "vhFrontendNote": "Użyj IP przypisanego do serwera. Wildcard przyjmuje wszystkie IP danej rodziny; routing nadal sprawdza lokalny adres docelowy. Certyfikaty ustaw w zakładce TLS.", - "close": "Zamknij", - "inherit": "Dziedzicz", - "liveLogs": "Logi na żywo", - "logVhost": "Filtruj vhost", - "logAllVhosts": "Wszystkie vhosty", - "logAllMethods": "Wszystkie metody", - "logPause": "Wstrzymaj", - "logPaused": "WSTRZYMANO", - "logResume": "Wznów", - "logPin": "Przypnij", - "logUndock": "Otwórz modalnie", - "logColumns": "Kolumny", - "logColumnsRequired": "Co najmniej jedna kolumna Live Logs musi pozostać widoczna.", - "logLoadHistory": "Zwiększ bufor", - "logHistoryLoaded": "Bufor live zwiększono do {count} zachowanych wpisów.", - "logHost": "Host", - "logBufferHint": "Widok na żywo zaczyna od ostatnich 256 zakończonych wymian. Zwiększenie bufora wczytuje zachowaną historię i dalej dopisuje logi na żywo do 4096 wpisów, aż do zamknięcia okna. Eksport obejmuje aktualnie przefiltrowane wiersze.", - "settingsSecurityHint": "Konta i ACL są globalne. SSL, HSTS, nagłówki i cache konfigurujesz także wewnątrz vhosta.", - "theme": "Motyw", - "themeDark": "Ciemny", - "themeLight": "Jasny", - "density": "Gęstość interfejsu", - "densityCompact": "Kompaktowy", - "densityDense": "Gęsty", - "densityComfortable": "Przestronny", - "globalPages": "Domyślne odpowiedzi", - "pagesHelp": "Strony dla adresu IP, nieznanych hostów i błędów. Pusty status zachowuje kod odpowiedzi. Strony statyczne nie odpytują backendu.", - "pageInherit": "Domyślna / dziedziczona", - "pageWelcome": "Strona gratulacyjna", - "pageEmpty": "Pusta odpowiedź", - "pageHtml": "Własny HTML", - "pageStatus": "Kod odpowiedzi", - "pageOriginalStatus": "Oryginalny status", - "pageHtmlSource": "Kod HTML", - "pageUploadHtml": "Opcjonalny plik HTML (maks. 32 KiB)", - "pageTooLarge": "HTML nie może przekraczać 32 KiB w UTF-8.", - "customErrorPages": "Własne strony błędów", - "pageStaticHost": "Host statyczny / przerwa techniczna", - "pageMissingPath": "Niepasująca ścieżka", - "pageDirectIp": "Wejście bezpośrednio po IP", - "pageUnknownHost": "Nieznany host", - "pagesSafetyHint": "HTML to treść publiczna. ACL nadal działa przed odpowiedzią. Jawne HTTP 200 dla błędu ukrywa kod przed klientami i monitoringiem. Cała konfiguracja ma limit rozmiaru.", - "vhDetailsTab": "Szczegóły", - "vhSsl": "Certyfikaty SSL", - "vhCertificate": "Wybrany certyfikat", - "vhCertificateDefault": "Globalne SNI / certyfikat domyślny", - "vhCertificateFile": "Certyfikat / pełny łańcuch (PEM)", - "vhPrivateKeyFile": "Klucz prywatny (PEM)", - "vhUploadCertificate": "Wgraj i zweryfikuj parę", - "vhSelectCertificateFiles": "Wybierz plik certyfikatu i klucza prywatnego.", - "vhCertificateTooLarge": "Każdy plik PEM ma limit 128 KiB.", - "vhCertificateNeedsHosts": "Najpierw wpisz domeny vhosta w Szczegółach.", - "vhCertificateStaged": "Para zweryfikowana i zapisana. Zapisz vhost, aby aktywować certyfikat.", - "vhCertificateUploadHint": "Upload sprawdza zgodność klucza i domen. Klucz trafia do prywatnego pliku, nie do API. Zapis vhosta aktywuje wybór. Upload nie zapisuje pozostałych zmian. Zmiany listenerów wymagają restartu.", - "vhCache": "Cache", - "vhCacheTtl": "Maks. TTL (sekundy, puste = dziedzicz)", - "vhCacheDefault": "Domyślny TTL public (puste = dziedzicz)", - "vhCacheObject": "Limit obiektu (KiB, puste = dziedzicz)", - "cacheEnabled": "Włącz cache", - "cacheBypassQuery": "Pomijaj adresy z parametrami", - "cacheStatusHeader": "Dodaj X-Cache", - "cacheHitsHeader": "Dodaj X-Cache-Hits", - "cacheRfcHeader": "Dodaj Cache-Status", - "cacheBypassPrefixes": "Pomijane prefiksy ścieżek", - "vhCacheCustomPrefixes": "Nadpisz odziedziczone pomijane ścieżki", - "vhCacheHint": "Polityka hosta może włączyć cache niezależnie od ustawienia globalnego. Vhosty współdzielą limit RAM i wpisów. Sticky cookie, dane prywatne i autoryzacja nadal omijają cache.", - "vhPurgeCache": "Wyczyść cache hosta", - "vhPurgeConfirm": "Wyczyścić cache tylko tego vhosta? Trwające zapisy tego hosta także zostaną unieważnione.", - "vhPages": "Strony błędów", - "vhHeadersOrder": "Kolejność: reguły globalne, vhost, ścieżka, następnie security/Server. Nadal dostępny jest zaawansowany JSON.", - "vhNewHealthHint": "Zapisz vhost, aby rozpocząć obserwację backendów.", - "listenerAdd": "Dodaj listener", - "listenerMigrate": "Zamień domyślne porty na nazwane listenery", - "listenerScopeHint": "Wewnętrzny / publiczny to etykieta, nie firewall. Nowe listenery nie udostępniają starych tras bez jawnego wyboru.", - "listenerLimit": "Maksymalnie 64 nazwane listenery.", - "listenerEndpoint": "Listener", - "listenerName": "Nazwa wyświetlana", - "listenerScope": "Etykieta", - "listenerInternal": "Wewnętrzny", - "listenerPublic": "Publiczny", - "listenerLegacy": "Udostępnij stare trasy", - "listenerInUse": "Listener jest przypisany do vhostów", - "listenerDuplicate": "Identyfikatory listenerów muszą być unikalne.", - "listenerChooseHint": "Wybierz nazwane listenery skonfigurowane w Ustawienia > Listenery. Wyłączony listener nie daje dostępu.", - "listenerMissing": "Brakujący listener", - "http3Settings": "HTTP/3 / QUIC", - "http3SettingsHelp": "HTTP/3 włącza się w Ustawienia > Listenery. Tutaj ustawisz ogłaszanie usługi oraz limity połączeń i strumieni.", - "http3NoTlsListeners": "Brak listenerów TLS. Najpierw dodaj i zapisz listener TLS.", - "http3NoEnabledListeners": "Żaden listener TLS nie ma włączonego HTTP/3. Najpierw włącz HTTP/3 w Ustawienia > Listenery.", - "http3ListenersDirty": "Najpierw zapisz oczekujące zmiany w Listenerach, a następnie edytuj ustawienia HTTP/3.", - "http3Save": "Zapisz ustawienia HTTP/3", - "h2Configure": "Ustaw limity HTTP/2", - "h3Enable": "Włącz HTTP/3 przez QUIC (UDP)", - "h3Configure": "Ustaw limity HTTP/3", - "h3Limits": "Limity HTTP/3 i ogłaszanie usługi", - "h3_alt_svc_max_age": "Ważność Alt-Svc (s)", - "h3_max_concurrent_connections": "Połączenia na listener", - "h3_max_concurrent_bidistream": "Strumienie dwukierunkowe na połączenie", - "h3_max_concurrent_unistream": "Strumienie jednokierunkowe na połączenie", - "h3_max_idle_timeout": "Bezczynność QUIC (s; 0 = bez limitu)", - "h3Help": "HTTP/3 wymaga TLS. Udostępnij TCP i UDP na tym samym porcie; HTTP/1.1 i HTTP/2 pozostają. Zero wyłącza lokalny timeout QUIC. Zmiana wymaga restartu.", - "h3TuningHelp": "Te limity obowiązują tylko wtedy, gdy HTTP/3 jest włączone dla danego listenera TLS. Zmiana wymaga restartu.", - "h3Requests": "Żądania HTTP/3", - "certImport": "Importuj certyfikat", - "certImportSave": "Importuj i zapisz w bibliotece", - "certLibraryHint": "Wgraj certyfikat/fullchain i klucz prywatny PEM. Zapisz raz, następnie przypisz certyfikat do jednego lub wielu vhostów.", - "certCheckDomains": "Domeny do sprawdzenia (po przecinku)", - "certAcmeLater": "Wydane certyfikaty trafiaja do biblioteki i sa przypisywane do vhostow.", - "certAdvanced": "Istniejące pliki / zaawansowane", - "certLegacyNames": "Stare nazwy SNI (opcjonalne; zalecane przypisanie w vhoście)", - "certAssigned": "Przypisane vhosty", - "certUnassigned": "Nieprzypisany", - "certInUse": "Certyfikat jest używany. Zmień przypisania vhostów i certyfikat domyślny przed usunięciem.", - "certDuplicate": "Ten identyfikator certyfikatu istnieje. Do bezpiecznej rotacji użyj nowego.", - "certManage": "Zarządzaj biblioteką certyfikatów", - "certSelectHint": "Wybierz zaimportowany certyfikat. Import i rotacja są w zakładce Certyfikaty. Przypisania są sprawdzane względem nazw vhosta.", - "vhTinyauth": "Uwierzytelnianie i dostęp IP", - "vhTabAuth": "Uwierzytelnianie", - "taEnable": "Włącz ochronę Tinyauth", - "taUrl": "URL Tinyauth / punkt weryfikacji", - "taLogin": "Publiczny URL logowania", - "taRedirectForbidden": "Akceptuj przekierowanie Tinyauth dla 403 (ten sam origin)", - "taConnect": "Limit połączenia (s)", - "taTimeout": "Łączny limit weryfikacji (s)", - "taRequestHeaders": "Nagłówki klienta do Tinyauth", - "taResponseHeaders": "Zweryfikowane nagłówki tożsamości do aplikacji", - "taHelp": "Do adresu serwera dodawane jest /api/auth/nginx. Weryfikacja bez body działa przed cache i WebSocket. Chronione odpowiedzi mają private, no-store. Ustaw w Tinyauth zaufanie do rzeczywistego IP RustProxy.", - "vhResponsePolicy": "Identyfikacja odpowiedzi i diagnostyka", - "vhInherit": "Dziedzicz ustawienia globalne", - "diagnosticHeaders": "Diagnostyczne nagłówki odpowiedzi", - "diagInherit": "Dziedzicz nagłówki diagnostyczne", - "diagRequestId": "Udostępnij X-Request-ID", - "hideMockOrigin": "Ukryj X-Mock-Origin", - "diagHelp": "X-Request-ID jest opcjonalny. Pozostale naglowki odpowiedzi upstreamu kontroluj zwyklymi regulami naglowkow odpowiedzi.", - "forwardingSettings": "Tożsamość klienta / forwarding", - "forwardingHelp": "Domyślnie nagłówki forwarding od klienta są usuwane. Dodaj tylko kontrolowane proxy. Łańcuch jest sprawdzany od prawej do pierwszego niezaufanego adresu.", - "forwardingCanonical": "RustProxy generuje Forwarded, X-Forwarded-For, X-Real-IP, X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port i X-Forwarded-URI. Adres docelowy połączenia nigdy nie pochodzi z nagłówka.", - "trustedProxies": "Zaufane sieci proxy CIDR (po jednej w wierszu; /32 dla IPv4, /128 dla IPv6)", - "trustForwardedProto": "Ufaj X-Forwarded-Proto tylko od zaufanych proxy", - "listenerId": "ID listenera", - "cache": "Cache", - "cacheTitle": "Cache pod kontrolą.", - "cacheDescription": "Obiekty, skuteczność domen i dokładne przyczyny decyzji.", - "cacheRefresh": "Odśwież", - "cacheLive": "Na żywo (3 s)", - "cachePurgeScope": "Wyczyść wybrany zakres", - "cacheObjectCount": "Obiekty w pamięci", - "cacheSaved": "Dane odpowiedzi z RAM", - "cacheCounterScope": "Liczniki domen od zmiany konfiguracji", - "cacheDomains": "Domeny i skuteczność", - "cacheScopeHint": "Limity RAM, zapisy i usunięcia są globalne. Liczniki domen zerują się przy zmianie konfiguracji; czyszczenie obiektów ich nie zeruje.", - "cacheDomain": "Domena", - "cacheReasons": "Liczniki decyzji", - "cacheNoDomains": "Brak decyzji cache. Wyślij żądania do skonfigurowanego hosta.", - "cacheObjectList": "Zapisane obiekty", - "cachePrevious": "Poprzednie", - "cacheNext": "Następne", - "cacheObjectHint": "Najpierw ostatnio używane. Kliknij Target albo Cache key / tags, aby skopiować pełną wartość. Treści i nagłówki żądań nie są ujawniane.", - "cachePath": "Ścieżka", - "cacheBodySize": "Treść", - "cacheAge": "Wiek", - "cacheTtlRemaining": "Pozostały TTL", - "cacheNoObjects": "Brak świeżych obiektów w tym zakresie. Sprawdź powyższe liczniki decyzji.", - "cacheLegacy": "Nieprzypisane", - "cacheGlobalLimit": "Limit globalny", - "cacheFills": "Aktywne zapisy (globalnie)", - "cacheRejected": "Odrzucone zapisy (globalnie)", - "cacheUpdated": "Aktualizacja", - "acmeTitle": "Let's Encrypt / ACME", - "acmeHelp": "Wydaj certyfikat ACME, dodaj go do biblioteki i przypisz do vhosta. Automatyczne odnawianie rozpocznie się po imporcie.", - "acmeEmail": "Email kontaktowy ACME", - "acmeDomains": "Nazwy DNS, rozdzielone przecinkami (wildcard tylko z DNS-01)", - "acmeEnvironment": "Środowisko CA", - "acmeStaging": "Staging - niezaufane przez przeglądarkę", - "acmeProduction": "Produkcja", - "acmeDnsServer": "IP serwera aktualizacji DNS", - "acmeDnsPort": "Port aktualizacji DNS", - "acmeKeyName": "Nazwa klucza TSIG", - "acmeSecret": "Sekret TSIG (base64)", - "acmeAlgorithm": "Algorytm TSIG", - "acmePropagation": "Oczekiwanie na propagację DNS (sekundy)", - "acmeSignQuery": "Podpisuj zapytanie SOA", - "acmeTos": "Akceptuje umowe subskrybenta Let's Encrypt i zezwalam na walidacje domen.", - "acmeConfirmProduction": "Potwierdzam wydanie produkcyjne (obowiązują limity CA).", - "acmeIssue": "Zamów certyfikat", - "acmeIdle": "Brak zadania wydania w tym procesie.", - "acmeImport": "Dodaj wydany certyfikat do biblioteki", - "acmeRenewalHint": "Pierwsze wydanie/import pozostaje ręczne. Profile zarządzanych certyfikatów są następnie sprawdzane automatycznie podczas działania RustProxy; po restarcie zapisany stan odnowień jest odtwarzany z SQLite.", - "acmeReplace": "Zastąpić certyfikat w bibliotece? Przypisania vhostów zostaną zachowane i ponownie sprawdzone.", - "acmeImported": "Certyfikat zapisany. Przypisz go w zakładce SSL vhosta.", - "certFuture": "Automatyczne odnawianie jest dostępne dla obsługiwanych dostawców ACME; obserwacje odnowień są zapisywane w SQLite.", - "cacheReason_cache_hit": "Użyto świeżego obiektu", - "cacheReason_cache_miss": "Brak pasującego świeżego obiektu", - "cacheReason_cache_disabled": "Cache wyłączony", - "cacheReason_route_disabled": "Cache wyłączony na trasie", - "cacheReason_request_cookie": "Cookie aplikacji", - "cacheReason_request_authorization": "Nagłówek Authorization", - "cacheReason_request_cache_control": "Dyrektywa klienta / twarde odświeżenie", - "cacheReason_request_pragma": "Pragma klienta", - "cacheReason_request_method": "Metoda inna niż GET", - "cacheReason_request_body": "Niepusta treść żądania", - "cacheReason_request_range": "Żądanie zakresu", - "cacheReason_request_conditional": "Żądanie warunkowe", - "cacheReason_request_upgrade": "Zmiana protokołu", - "cacheReason_query_excluded": "Wykluczone query", - "cacheReason_path_excluded": "Wykluczona ścieżka", - "cacheReason_request_cache_control_invalid": "Błędne dyrektywy cache klienta", - "cacheReason_response_status": "Odpowiedź inna niż 200", - "cacheReason_response_set_cookie": "Set-Cookie z backendu", - "cacheReason_response_cache_control": "Prywatność / dyrektywa backendu", - "cacheReason_response_cache_control_invalid": "Błędne dyrektywy backendu", - "cacheReason_response_vary": "Niedozwolony wariant Vary", - "cacheReason_response_range": "Odpowiedź częściowa", - "cacheReason_response_trailers": "Trailers odpowiedzi", - "cacheReason_response_ttl_size_or_metadata": "Odrzucony TTL, rozmiar lub metadane", - "cacheReason_response_headers_policy": "Reguła nagłówków blokuje zapis", - "cacheReason_configuration_changed": "Zmieniona konfiguracja", - "cacheReason_not_proxy_response": "Strona lokalna / odrzucone żądanie", - "cacheReason_tinyauth": "Treść chroniona Tinyauth", - "cacheReason_sticky_cookie": "Tryb cookie sticky session", - "acme.working": "Trwa zamawianie certyfikatu.", - "acme.ready_to_import": "Certyfikat sprawdzony; gotowy do dodania do biblioteki.", - "acme.certbot_not_installed": "Brak Certbota w PATH usługi. Zainstaluj Certbota i certbot-dns-rfc2136.", - "acme.certbot_failed_check_private_log": "Błąd Certbota. Sprawdź prywatne logi ACME; dokładna ścieżka jest pokazana przy błędzie operacji.", - "acme.production_confirmation": "Wymagane potwierdzenie wydania produkcyjnego.", - "acme.consent_required": "Zaakceptuj umowę i potwierdź wybrane środowisko CA.", - "acme.provider_timeout": "Przekroczono czas operacji CA. Przed ponowieniem sprawdź logi Certbota wskazane przy błędzie operacji.", - "acme.invalid_key_secret": "Nieprawidłowy sekret TSIG: wymagany base64 kodujący 16-512 bajtów.", - "acme.job_busy": "Inne zadanie certyfikatu już trwa.", - "acme.cancelled": "Zadanie certyfikatu anulowane podczas zamykania.", - "acme.certificate_validation_failed": "Walidacja certyfikatu, klucza lub domen nie powiodła się. Nic nie aktywowano.", - "acme.invalid_request": "Nieprawidłowe żądanie ACME.", - "acme.unknown_field": "Żądanie zawiera nieobsługiwane pole.", - "acme.invalid_id": "Identyfikator certyfikatu: 1-64 litery, cyfry, myślnik lub podkreślenie.", - "acme.invalid_email": "Podaj prawidłowy adres e-mail kontaktu ACME.", - "acme.invalid_domains": "Podaj od 1 do 16 nazw DNS.", - "acme.invalid_domain": "Podaj prawidłową nazwę DNS (ASCII/punycode).", - "acme.dns_names_only": "Certyfikat wymaga nazw DNS, nie adresów IP.", - "acme.invalid_environment": "Wybierz staging albo produkcję.", - "acme.tos_required": "ACME: tos required.", - "acme.invalid_dns_server": "Podaj adres IPv4 lub IPv6 serwera aktualizacji DNS.", - "acme.invalid_limits": "Port musi mieścić się w 1-65535, a czas propagacji w 10-900 s.", - "acme.invalid_key_algorithm": "Dozwolone algorytmy TSIG: HMAC-SHA256, HMAC-SHA384 i HMAC-SHA512.", - "acme.invalid_sign_query": "Opcja podpisywania SOA musi mieć wartość true albo false.", - "acme.unsafe_directory": "Katalog certyfikatów musi należeć do usługi i mieć prawa 0700; bez dowiązań.", - "acme.unsafe_output_path": "Plik wyniku wykracza poza prywatne archiwum Certbota.", - "acme.invalid_pem_size": "Plik PEM jest za duży lub nie jest zwykłym plikiem.", - "acme.invalid_pem": "Certbot nie zwrócił prawidłowego pliku PEM.", - "acme.profile_limit": "Osiągnięto limit 128 profili ACME. Sprawdź nieużywane profile lokalnie.", - "acme.profile_busy": "Ten profil ACME jest już używany przez inny proces.", - "acme.staging_limit": "Osiągnięto limit 128 par ACME. Usuń lokalnie wyłącznie nieużywane pliki.", - "acme.request_too_large": "Żądanie ACME przekracza 16 KiB.", - "acme.local_io_or_json_error": "Błąd lokalnego pliku lub formatu JSON. Sprawdź katalog i uprawnienia.", - "acme.no_certificate_directory": "Brak katalogu certyfikatów w konfiguracji uruchomienia.", - "acme.python_not_available": "Proces usługi nie może uruchomić python3. Sprawdź PATH i uprawnienia.", - "acme.worker_io": "Nie udała się komunikacja z lokalnym procesem ACME.", - "acme.invalid_worker_response": "Proces ACME zwrócił nieprawidłowy wynik.", - "acme.worker_failed": "Proces ACME zakończył się błędem.", - "acme.validation_worker_failed": "Nie udało się zakończyć walidacji pary certyfikatu i klucza.", - "cacheResidentLabel": "Pamięć cache", - "certificateFuture": "Dostawcy ACME: HTTP-01, Cloudflare, OVH i RFC2136. Odnawianie jest ręczne.", - "prometheusTitle": "Prometheus", - "prometheusHelp": "Osobny endpoint metryk, niezależny od sesji administratora. Domyślnie wyłączony.", - "prometheusEnable": "Włącz endpoint Prometheusa", - "prometheusListen": "IP i port eksportera", - "prometheusPath": "Ścieżka metryk", - "prometheusCidrs": "Dozwolone adresy kolektora (CIDR, po jednym w wierszu)", - "prometheusTokenEnv": "Nazwa zmiennej środowiskowej z tokenem", - "prometheusTokenHelp": "Podaj nazwę zmiennej, nie sekret. Token musi mieć co najmniej 32 znaki. Zmiana adresu lub tokenu wymaga restartu.", - "prometheusCollectors": "Grupy metryk", - "prometheusPreview": "Podgląd metryk", - "prometheusPreviewFailed": "Nie udało się pobrać metryk.", - "prometheusActive": "Aktywny endpoint", - "prometheusDisabled": "Endpoint metryk jest wyłączony.", - "certificateProvider": "Dostawca certyfikatu", - "providerHttp01": "Let's Encrypt - walidacja domeny (HTTP-01)", - "providerCloudflare": "Let's Encrypt - Cloudflare API (DNS-01)", - "providerOvh": "Let's Encrypt - OVH API (DNS-01)", - "providerRfc2136": "Let's Encrypt - RFC2136 / TSIG (DNS-01)", - "providerImport": "Import certyfikatu i klucza prywatnego (PEM)", - "providerExisting": "Istniejące pliki na serwerze", - "providerHint_http01": "Walidacja domeny HTTP-01 wymaga publicznego portu 80 prowadzącego do aktywnego listenera HTTP. Nie obsługuje wildcardów.", - "providerHint_cloudflare": "DNS-01 przez API Cloudflare. Użyj tokenu z uprawnieniem Zone:DNS:Edit ograniczonym do odpowiednich stref.", - "providerHint_ovh": "DNS-01 przez API OVH. Podaj klucze aplikacji i klienta z uprawnieniami do rekordów odpowiednich stref DNS.", - "providerHint_rfc2136": "DNS-01 przez dynamiczną aktualizację DNS i klucz TSIG. Serwer musi zezwalać na zmianę rekordów walidacyjnych.", - "providerHint_import": "Wgraj certyfikat lub fullchain i odpowiadający mu klucz prywatny w formacie PEM.", - "providerHint_existing": "Wskaż pliki PEM z katalogu certyfikatów RustProxy. Treść klucza nie trafia do konfiguracji.", - "acmeCfToken": "Token API Cloudflare", - "acmeOvhEndpoint": "Region API OVH", - "acmeOvhApplicationKey": "OVH application key", - "acmeOvhApplicationSecret": "OVH application secret", - "acmeOvhConsumerKey": "OVH consumer key", - "acme.invalid_provider": "Nieobsługiwany dostawca certyfikatu.", - "acme.invalid_api_credential": "Brak klucza API lub niedozwolone znaki w kluczu.", - "acme.invalid_ovh_endpoint": "Wybierz OVH Europa lub Kanada.", - "acme.http01_no_wildcard": "HTTP-01 nie obsługuje wildcardów. Wybierz dostawcę DNS-01.", - "acme.http01_listener_required": "HTTP-01 wymaga aktywnego listenera HTTP bez TLS.", - "cacheScopeLegacy": "Nieprzypisany / poprzedni zakres", - "certificateLibrary": "Certyfikaty", - "certificateWorkspaceHelp": "Zarządzaj zainstalowanymi certyfikatami, automatycznym odnawianiem i generowaniem/importem w osobnych widokach.", - "certificateTabInstalled": "Zainstalowane", - "certificateTabRenewal": "Odnowienie", - "certificateTabGenerate": "Generowanie", - "certificateInstalledTitle": "Zainstalowane certyfikaty", - "certificateInstalledHelp": "Lista certyfikatów dostępnych dla vhostów, redirectów, hostów 404 i panelu administracyjnego.", - "certificateGenerateTitle": "Generowanie i import", - "certificateGenerateHelp": "Wybierz metodę: Let's Encrypt/ACME, import plików PEM albo istniejące pliki z prywatnego katalogu RustProxy.", - "certificateOperationStatus": "Ostatnia operacja ACME", - "certificateNoRenewalOperation": "Brak operacji odnowienia w tym procesie.", - "certificateStateIdle": "Bezczynne", - "certificateStateRunning": "W toku", - "certificateStateReady": "Gotowe", - "certificateStateComplete": "Zakończone", - "certificateStateFailed": "Błąd", - "certbotLogs": "Logi Certbota", - "systemDiagnostics": "System / proces", - "vhWebsockets": "Obsługa WebSocket", - "vhLocations": "Własne lokalizacje", - "locationPath": "Prefiks lokalizacji", - "locationPool": "Backendy vhosta", - "locationMissing": "Brak backendu", - "locationLimit": "Host obsługuje do 64 lokalizacji.", - "locationAccess": "Dostęp do lokalizacji", - "locationHeaders": "Nagłówki lokalizacji", - "locationAddBackend": "Dodaj osobny backend", - "locationAdd": "Dodaj lokalizację", - "locationHelp": "Wygrywa najdłuższy pasujący prefiks. Ścieżka i query pozostają bez zmian. Wybierz backend hosta lub dodaj osobny. Uwierzytelnianie i ACL hosta obowiązują zawsze.", - "aclUse": "Włącz listę dostępu IP", - "aclAllow": "Zezwól", - "aclNetwork": "Sieć IP (CIDR)", - "aclAction": "Akcja", - "aclAdd": "Dodaj regułę IP", - "authMode": "Uwierzytelnianie", - "authNone": "Brak", - "authTinyauth": "Tinyauth", - "authBasic": "HTTP Basic Auth", - "basicRealm": "Realm (nazwa logowania)", - "basicRequireTls": "Wymagaj HTTPS dla Basic Auth", - "basicForward": "Przekaż zweryfikowany Authorization do backendu", - "basicPassword": "Hasło (12-128 bajtów)", - "basicKeepPassword": "Puste pole zachowuje hasło", - "basicHashSaved": "Hasło ustawione", - "basicHashRequired": "Ustaw hasło dla każdego użytkownika.", - "basicAddUser": "Dodaj użytkownika", - "basicHelp": "Zapisywane są wyłącznie skróty Argon2id. Dane logowania nie trafiają do backendu, chyba że włączysz przekazywanie. Używaj go tylko z zaufanym backendem HTTPS lub w izolowanej sieci. Chronione hosty omijają współdzielony cache.", - "basic.too_many_users": "Maksymalnie 64 użytkowników na hosta.", - "basic.invalid_username": "Nieprawidłowa nazwa użytkownika.", - "basic.duplicate_username": "Powtórzona nazwa użytkownika.", - "basic.unsupported_hash": "Użyj skrótu Argon2id wygenerowanego przez RustProxy.", - "basic.invalid_hash": "Nieprawidłowy skrót hasła.", - "basic.invalid_realm": "Nieprawidłowa nazwa realm.", - "basic.users_required": "Basic Auth wymaga przynajmniej jednego użytkownika.", - "basic.busy": "Weryfikacja haseł jest zajęta. Spróbuj ponownie.", - "renewalTitle": "Automatyczne odnawianie", - "renewalHelp": "Certyfikaty ACME są sprawdzane co około 12 godzin, gdy RustProxy działa. Certbot określa termin odnowienia. Poprawne certyfikaty są wdrażane bez restartu listenerów. Zachowaj dane dostawcy i dostępność portu 80 dla HTTP-01.", - "renewalNone": "W bibliotece nie ma zarządzanych certyfikatów ACME.", - "renewalEnabled": "Automatyczne odnawianie włączone", - "renewalDisabled": "Automatyczne odnawianie wyłączone", - "renewalEnable": "Włącz odnawianie", - "renewalDisable": "Wyłącz odnawianie", - "renewalNow": "Sprawdź teraz", - "renewalDryRun": "Sprawdź odnowienie (dry run)", - "renewalLast": "Ostatnia kontrola", - "renewalNext": "Kolejna kontrola", - "renewalExpires": "Ważny do", - "acme.renewing": "Sprawdzanie odnowienia certyfikatu", - "acme.renewed": "Certyfikat odnowiony i wdrożony", - "acme.not_due": "Certyfikat nie wymaga jeszcze odnowienia", - "acme.renewal_test_ok": "Weryfikacja odnowienia poprawna; aktywny certyfikat bez zmian", - "acme.renewal_profile_missing": "Brak dostępu do zapisanego profilu odnowienia. Przywróć prywatny profil ACME.", - "acme.configuration_changed": "Konfiguracja certyfikatu zmieniła się podczas odnowienia. Nie wdrożono zmian.", - "acme.deployment_failed": "Odnowiony certyfikat nie przeszedł walidacji konfiguracji. Poprzedni nadal jest aktywny.", - "acme.not_managed": "Automatycznie można odnawiać tylko zarządzane certyfikaty ACME.", - "acme.certificate_not_found": "Certyfikat już nie istnieje.", - "acme.renewal_disabled": "Automatyczne odnawianie jest wyłączone.", - "acme.openssl_not_installed": "OpenSSL jest wymagany do odczytu dat ważności certyfikatu.", - "cacheReason_basic_auth": "Uwierzytelnianie HTTP Basic", - "locationPoolEligible": "Uwzględnij w domyślnej puli backendów", - "locationId": "Identyfikator lokalizacji", - "vhIpAccess": "Dostęp do vhosta według IP", - "apiDocs": "Dokumentacja", - "auth.invalid_request": "Nieprawidłowe żądanie. Sprawdź podane pola.", - "locationProxyHeaders": "Nagłówki żądania proxy (do backendu)", - "locationResponseHeaders": "Nagłówki odpowiedzi (do klienta)", - "locationHeadersHelp": "Ustaw nadpisuje nagłówek, dopisz dodaje wartość, usuń kasuje go. Reguły lokalizacji są stosowane po globalnych i vhosta. Wartości są dosłowne (bez zmiennych nginx). Nagłówkami transportu i zweryfikowanej tożsamości zarządza system.", - "headersAdvancedJson": "Zaawansowane reguły nagłówków (JSON)", - "headersInvalid": "Nieprawidłowa reguła nagłówka. Sprawdź nazwę, operację i wartość.", - "headersProtected": "Nie można tu nadpisać nagłówków transportu i tożsamości proxy. Użyj ustawień forwardingu, autentykacji lub odpowiedzi.", - "docsTitle": "Dokumentacja", - "docsSession": "Korzysta z sesji administratora. Operacje zapisu API wymagają ochrony CSRF.", - "docsSignIn": "Zaloguj się, aby otworzyć dokumentację", - "docsPanel": "Powrót do panelu", - "docsWrites": "Włącz operacje zapisu", - "docsWriteConfirm": "Ta operacja naprawdę zmieni RustProxy. Kontynuować?", - "docsExpired": "Sesja wygasła. Zaloguj się ponownie.", - "docsError": "Nie udało się wczytać dokumentacji.", - "docsAccount": "Zalogowano jako", - "docsReadOnly": "Domyślnie wykonywane są tylko odczyty. Strumienie SSE oraz logowanie i setup nie są tu uruchamiane.", - "docsLogout": "Wyloguj", - "authPrivateNote": "Dostęp tylko dla uprawnionych administratorów.", - "advanced": "Zaawansowane", - "docsLicenses": "Licencje Swagger UI", - "vhTrafficPolicy": "Polityka ruchu", - "vhHttp3Enabled": "Włącz HTTP/3 dla tego vhosta", - "vhCloudflareClientIp": "Używaj zweryfikowanego IP klienta z Cloudflare", - "vhTimingHeaders": "Udostępniaj diagnostykę Server-Timing", - "vhRateEnabled": "Włącz limit żądań per IP klienta", - "vhRateRequests": "Żądania na okno", - "vhRateWindow": "Okno (sekundy)", - "vhRateBurst": "Dopuszczalny burst", - "vhCountryMode": "Polityka dostępu krajów", - "vhCountryBlock": "Blokuj wskazane kraje", - "vhCountryAllow": "Zezwalaj tylko wskazanym krajom", - "vhCountryList": "Kraje (ISO 3166-1 alpha-2)", - "vhCountryPolicyHelp": "Reguły krajów korzystają z zainstalowanej bazy GeoIP. Tryb „tylko zezwolone” blokuje także klienta, którego kraju nie da się ustalić.", - "vhCountry": "Kraj", - "vhAddCountryRate": "Dodaj limit dla kraju", - "vhCountryRateLimit": "Dozwolone są maksymalnie 64 limity przypisane do krajów.", - "vhRateHelp": "Limit dla kraju nadpisuje podstawowy limit per IP. Przekroczenie daje 429, a zabroniony kraj 403.", - "vhHealthOffWarning": "Aktywne sondy backendu są wyłączone. Passive Backend Health jest konfigurowany osobno i pozostaje wyłączony, dopóki nie zostanie świadomie włączony.", - "vhFrontendSelectionOnly": "Wybierz listenery dla vhosta. Adresy IP, porty oraz dostępność H2/H3 konfiguruje się wyłącznie w Ustawienia > Listenery.", - "vhForceSsl": "Wymuś SSL (przekieruj HTTP do HTTPS)", - "vhForceSslHelp": "Żądania HTTP tego vhosta dostają przekierowanie 308 do HTTPS z zachowaniem ścieżki i parametrów. Wybierz co najmniej jeden listener zwykłego HTTP oraz co najmniej jeden listener TLS. Jeśli wybrano kilka portów TLS, używany jest port 443; w innym przypadku port docelowy TLS musi być jednoznaczny.", - "vhForceSslNeedsTls": "Wymuszenie SSL wymaga co najmniej jednego włączonego listenera TLS dla tego vhosta.", - "vhForceSslPortConflict": "Nie można jednoznacznie wybrać portu docelowego HTTPS: wybrane listenery TLS używają kilku niestandardowych portów. Wybierz jeden port TLS albo listener na porcie 443.", - "vhForwardClientIp": "Przekazuj IP klienta do backendu", - "vhForwardClientIpHelp": "Pozostaw włączone dla standardowego reverse proxy. Wyłącz, aby nie wysyłać do aplikacji nagłówków Forwarded, X-Forwarded-For i X-Real-IP; RustProxy, ACL, limity i Tinyauth nadal korzystają z prawdziwego IP klienta.", - "vhClientIpHidden": "IP klienta ukryte przed backendem", - "listenerMigrateInline": "Istniejący listener vhosta (zostanie zmigrowany)", - "vhDebugOriginPreset": "Zastosuj preset zalecany", - "vhDebugOriginTlsWarning": "Ten preset pozostawia wyłączoną walidację certyfikatu TLS backendu. Połączenie jest szyfrowane, ale CA i nazwa hosta nie są sprawdzane. Kontynuować?", - "vhOriginPresetHelp": "Domyślne ustawienia nowego backendu do debugowania: origin HTTPS po IP, domyślna pula LB ON, prywatny origin ON, HTTP/1.1, zachowanie Host klienta ON i weryfikacja TLS OFF. Włącz weryfikację TLS, gdy certyfikat originu da się poprawnie zweryfikować.", - "vhDebugOriginMismatch": "Ten origin HTTPS po IP nie odpowiada presetowi debugowania (pula ON, prywatny origin ON, HTTP/1.1, zachowanie Host ON, walidacja TLS OFF). Jeśli włączysz walidację, ustaw nazwę serwera TLS na DNS z certyfikatu i w razie potrzeby dodaj jego prywatne CA. Kontynuować z bieżącymi wartościami?", - "vhCacheStaticCookie": "Ignoruj Cookie żądania dla wybranych rozszerzeń statycznych", - "vhCacheStaticCustom": "Użyj własnej listy rozszerzeń statycznych", - "vhCacheStaticExtensions": "Rozszerzenia statyczne (po jednym w linii, bez kropki)", - "vhCacheStaticHelp": "Dziedzicz ustawienie globalne albo nadpisz je dla vhosta. Ignorowanie Cookie stosuj tylko do plików, których treść nie zależy od sesji; Set-Cookie, private/no-store i Vary: Cookie nadal blokują zapis do shared cache.", - "cacheStaticTitle": "Cache statycznych zasobów", - "cacheStaticCookie": "Ignoruj Cookie żądania dla statycznych plików", - "cacheStaticExtensions": "Globalne rozszerzenia statyczne (po jednym w linii, bez kropki)", - "cacheStaticHelp": "Włączaj tylko dla plików, których treść nie zależy od sesji. Cookie żądania nie wpływa wtedy na klucz cache dla podanych rozszerzeń; odpowiedzi z Set-Cookie, private/no-store lub Vary: Cookie nadal nie są zapisywane we współdzielonym cache.", - "vhHttp2Enabled": "Włącz HTTP/2 dla tego vhosta", - "vhFrontendProtocolsHelp": "H2 i H3 są przełącznikami per vhost. Opcja jest aktywna tylko wtedy, gdy co najmniej jeden wybrany listener ma dany protokół włączony w Ustawienia > Listenery.", - "administration": "Panel administracyjny", - "administrationActiveHttp": "Aktywny panel HTTP", - "administrationActiveHttps": "Aktywny panel HTTPS", - "administrationCertificate": "Certyfikat", - "administrationGeneratedCertificate": "Domyślny certyfikat wygenerowany przez aplikację", - "administrationHelp": "HTTPS pozwala wystawić panel administracyjny poza loopback. Zwykły HTTP na porcie HTTPS jest automatycznie przekierowywany. Zmiany listenera i certyfikatu działają po restarcie.", - "administrationHosts": "Dozwolone hosty DNS (opcjonalna ścisła lista)", - "administrationHttps": "Włącz HTTPS dla panelu administracyjnego", - "administrationListen": "Adres nasłuchu", - "cacheOverhead": "Narzut", - "cacheResidentAge": "X-Cache-Resident-Age", - "controlPlane": "PANEL STEROWANIA", - "logging": "Logowanie", - "loggingTitle": "Strukturalne logi dostępu", - "loggingTabOutputs": "Wyjścia", - "loggingTabFormat": "Format JSON", - "loggingTabErrors": "Log błędów", - "loggingDescription": "Zapisuj konfigurowalne logi dostępu JSON do pliku, Logstash lub Loki.", - "loggingHelp": "Podgląd logów na żywo pozostaje w pamięci. Zewnętrzne wyjścia używają ograniczonej kolejki w tle i nie blokują obsługi żądań.", - "loggingFile": "Plik JSON", - "loggingPath": "Ścieżka pliku", - "loggingAddress": "Adres TCP", - "loggingTokenEnv": "Zmienna środowiskowa z tokenem Bearer", - "loggingLabels": "Etykiety (obiekt JSON)", - "loggingFormat": "Konfigurowalny format JSON", - "loggingFormatHelp": "Mapuj nazwy pól wyjściowych na pola źródłowe. Puste mapowanie zapisuje pełny standardowy wpis.", - "loggingFields": "Mapowanie pól (obiekt JSON)", - "loggingStatic": "Pola stałe (obiekt JSON)", - "loggingJsonInvalid": "Pola konfiguracji logów muszą zawierać poprawne obiekty JSON.", - "loggingQueue": "Kolejka wyjść", - "loggingDropped": "odrzuconych", - "loggingSent": "wysłanych", - "loggingCapacity": "pojemność", - "errorLogTitle": "Plik błędów", - "errorLogPath": "Ścieżka logu błędów", - "errorLogFormat": "Format", - "tls12": "TLS 1.2", - "tls13": "TLS 1.3", - "tlsPolicy": "Polityka TLS", - "tlsPolicyHelp": "To globalna polityka TLS dziedziczona przez każdy host TLS w aplikacji. Ustawienia per-vhost mogą ją tylko zawężać. HTTP/3 wymaga TLS 1.3.", - "tlsCiphers": "Szyfry (jeden na linię; puste = domyślne rustls)", - "tlsAvailableCiphers": "Dostępne szyfry", - "tlsPolicyVersionRequired": "Włącz co najmniej jedną wersję TLS.", - "vhTlsOverride": "Nadpisz globalną politykę TLS", - "vhTlsOverrideHelp": "Użyj tylko, gdy ten vhost wymaga innych wersji TLS lub szyfrów. Pusta lista szyfrów zachowuje domyślne rustls.", - "vhTlsHttp3Conflict": "HTTP/3 korzysta z globalnej polityki TLS. Wyłącz HTTP/3 dla tego vhosta przed użyciem innego nadpisania TLS.", - "vhListeners": "Listenery", - "vhProtocols": "Protokoły", - "loggingMode": "JSON / ASYNC / OGRANICZONA KOLEJKA", - "loggingPushUrl": "Adres Push URL", - "cacheHotObjects": "Obiekty hot", - "cacheHotMemory": "Pamięć hot", - "cacheColdObjects": "Obiekty cold", - "cacheColdDisk": "Dysk cold", - "cacheTierMoves": "Przeniesienia między warstwami", - "cacheColdHits": "trafień cold", - "cacheTier": "Warstwa", - "cacheStorage": "Pamięć / dysk", - "cacheColdTitle": "Trwały cache cold", - "cacheColdEnable": "Włącz trwałą warstwę dyskową", - "cacheColdHelp": "Wybierz, które obiekty z hot RAM mają trafiać na trwały dysk. Trafienie cold jest odczytywane asynchronicznie i promowane z powrotem do RAM. Metadane są w JSON, a body w plikach .body.", - "cacheColdPath": "Ścieżka cold (wewnątrz katalogu danych)", - "cacheColdBytes": "Limit dysku cold (MiB)", - "cacheColdEntries": "Limit obiektów cold", - "cacheColdAfter": "Przenieś po sekundach bezczynności", - "cacheHot": "Hot", - "cacheCold": "Cold", - "cacheReason_request_no_cache": "no-cache klienta / twarde odświeżenie wymaga rewalidacji", - "cacheReason_request_max_age": "max-age klienta wymaga rewalidacji", - "cacheReason_request_min_fresh": "min-fresh klienta wymaga rewalidacji", - "cacheReason_request_pragma_no_cache": "Pragma no-cache klienta / starszy tryb twardego odświeżenia", - "cacheReason_cache_revalidated": "Obiekt z cache potwierdzony przez backend", - "cacheReason_cache_conditional_hit": "Świeży obiekt obsłużył żądanie warunkowe", - "cacheReason_request_no_store": "no-store klienta omija cache", - "cacheReason_request_precondition": "Warunek klienta wymaga backendu", - "loggingPreset": "Preset formatu", - "loggingPresetCustom": "Własny", - "loggingPresetStandard": "Standard RustProxy", - "loggingPresetNginx": "JSON w stylu Nginx", - "loggingPresetEcs": "Nazwy pól w stylu ECS", - "loggingPresetMinimal": "Minimalny", - "loggingBuilder": "Graficzny konfigurator pól", - "loggingBuilderOpen": "Konfiguruj pola", - "loggingAdvancedJson": "Zaawansowane mapowanie JSON", - "loggingBuilderHelp": "Wybierz pola źródłowe i opcjonalnie zmień ich nazwy w JSON. Zastosowanie edytora graficznego normalizuje każde pole źródłowe do maksymalnie jednego klucza wyjściowego; duplikaty aliasów ustawisz w trybie zaawansowanym.", - "loggingSourceField": "Pole źródłowe", - "loggingOutputField": "Klucz JSON na wyjściu", - "loggingPreview": "Podgląd", - "loggingOutputRequired": "Każde włączone pole logu musi mieć klucz JSON na wyjściu.", - "loggingOutputDuplicate": "Klucze JSON na wyjściu muszą być unikalne.", - "aclProfiles": "Profile ACL", - "acl-profiles": "Profile ACL", - "acl-profilesTitle": "Wielokrotnego użytku profile ACL", - "acl-profilesDescription": "Definiuj wspólne reguły dostępu IP i krajów, a następnie przypinaj je do wielu vhostów.", - "aclProfilesIntro": "Profile dostępu można przypinać do wielu vhostów. Indywidualne reguły ACL i krajów w vhoście nadal działają i są egzekwowane razem z profilem.", - "aclProfilesReusable": "WSPÓLNA POLITYKA", - "aclProfileNew": "Nowy profil", - "aclProfileEdit": "Edycja profilu", - "aclProfileEditor": "Konfiguracja profilu", - "aclProfileId": "ID profilu", - "aclProfileName": "Nazwa wyświetlana", - "aclProfileIpEnabled": "Włącz ACL IP", - "aclProfileRules": "Reguły IP — po jednej „allow|deny CIDR” w wierszu", - "aclProfileCombineHelp": "Profil i reguły vhosta są łączone restrykcyjnie: żądanie musi przejść obie polityki.", - "aclProfileIpRulesShort": "reguł IP", - "aclProfileIpOff": "ACL IP wyłączony", - "aclProfileCountriesOff": "Filtrowanie krajów wyłączone", - "aclProfileAttached": "Przypięty do", - "aclProfileInUse": "Profil jest przypięty do vhostów", - "aclProfilesEmpty": "Brak profili ACL wielokrotnego użytku.", - "aclProfileCountryInvalid": "Kody krajów muszą mieć dwuliterowy format ISO.", - "aclProfileDuplicate": "Profil ACL o tym ID już istnieje.", - "vhAclProfile": "Profil ACL", - "vhAclProfileNone": "Bez wspólnego profilu", - "vhAclProfileHelp": "Opcjonalny profil wielokrotnego użytku. Indywidualne ACL i reguły krajów vhosta poniżej nadal są dodatkowo egzekwowane.", - "vhHostAdd": "Dodaj hostname", - "vhHostsHelp": "Naciśnij Enter lub przecinek, aby dodać hostname. Wildcard jest dozwolony tylko jako początkowe *. (np. *.example.com). Dokładny host ma pierwszeństwo przed wildcardem.", - "vhHostInvalid": "Nieprawidłowy hostname lub wzorzec wildcard.", - "vhHostRequired": "Dodaj co najmniej jeden hostname.", - "vhLifetimeChart": "Przebieg ruchu od otwarcia panelu", - "vhReqPerSecond": "żąd./s", - "vhPeak": "max", - "listenerAddresses": "Adresy nasłuchu", - "listenerAddressesInvalid": "Podaj 1–16 unikalnych adresów nasłuchu.", - "listenerAddressesExplicit": "Przy wielu adresach wybierz konkretne IP; 0.0.0.0 i :: nie są dozwolone.", - "ruleSyntaxLine": "Nieprawidłowa reguła ACL w wierszu", - "vhForceSslNeedsHttp": "Wymuszenie SSL wymaga co najmniej jednego wybranego listenera zwykłego HTTP (bez TLS). Listener nazwany „HTTP” może mimo nazwy mieć włączony TLS w Ustawienia > Listenery.", - "aclProfileRuleBuilder": "Reguły IP", - "aclProfileBulkRules": "Wklej / importuj reguły", - "aclProfileBulkHelp": "Wklej po jednej regule „allow|deny CIDR” w wierszu. Niewidoczne odstępy Unicode są normalizowane, a błąd wskazuje dokładny wiersz.", - "aclProfileImportRules": "Importuj reguły", - "aclProfileRulesImported": "Reguły ACL zaimportowano do edytora graficznego.", - "streamHosts": "Hosty stream", - "streamsHelp": "Surowe przekazywanie TCP/UDP na osobnych portach. Ruch stream omija vhosty HTTP, ACL, cache, nagłówki i kompresję.", - "streamAdd": "Dodaj host stream", - "saveStreams": "Zapisz hosty stream", - "streamRestartHelp": "Zmiana listenera stream wymaga restartu RustProxy.", - "streamRestartPending": "Zapisano zmiany streamów. Uruchom ponownie RustProxy, aby je zastosować.", - "streamActive": "Aktualnie aktywne streamy", - "streamNone": "Brak aktywnych hostów stream", - "streamEndpoint": "Endpoint stream", - "streamId": "ID streamu", - "streamName": "Nazwa wyświetlana", - "streamProtocol": "Protokół", - "streamListen": "Adres nasłuchu", - "streamUpstream": "Adres upstream", - "streamConnectTimeout": "Timeout połączenia TCP (sekundy)", - "streamIdleTimeout": "Timeout bezczynności/sesji (sekundy)", - "streamMaxConnections": "Maks. połączeń/sesji", - "streamTcp": "TCP", - "streamUdp": "UDP", - "streamLimit": "Obsługiwane jest maksymalnie 128 hostów stream.", - "streamDuplicate": "ID hostów stream muszą być unikalne.", - "streams": "Streamy", - "streamsTitle": "Proxy TCP / UDP", - "streamsDescription": "Zarządzaj surowymi listenerami Layer 4, upstreamami i statystykami ruchu na żywo.", - "streamsPageIntro": "Streamy TCP/UDP są niezależnymi proxy Layer 4. Każdy stream ma własny listener i upstream oraz omija warstwę vhostów HTTP, ACL i cache.", - "streamLayer4": "LAYER 4 / TCP + UDP", - "streamList": "Streamy", - "streamSearch": "Szukaj streamów", - "streamSearchPlaceholder": "ID, nazwa, listener lub upstream…", - "streamSearchEmpty": "Brak streamów pasujących do wyszukiwania.", - "streamEmpty": "Brak streamów TCP/UDP. Dodaj listener, aby rozpocząć proxowanie ruchu Layer 4.", - "streamNew": "Nowy stream", - "streamAddListener": "Dodaj listener TCP/UDP", - "streamEditor": "Konfiguracja streamu", - "streamEditLabel": "EDYCJA", - "streamNewLabel": "NOWY", - "streamDetailsTab": "Szczegóły", - "streamNetworkTab": "Listener i upstream", - "streamLimitsTab": "Limity", - "streamNetwork": "Listener i upstream", - "streamLimits": "Limity połączeń / sesji", - "streamDedicatedListenerHelp": "Listener streamu jest tworzony razem ze streamem i jest niezależny od listenerów HTTP/HTTPS.", - "streamLimitsHelp": "Limity dotyczą równoległych połączeń TCP lub sesji UDP per klient. Timeout łączenia TCP nie jest używany przez UDP.", - "streamListenAdd": "Dodaj adres nasłuchu", - "streamListenHelp": "Wpisz jeden adres IP:port i naciśnij Enter. Zmiana listenera zacznie działać po restarcie RustProxy.", - "streamListenInvalid": "Adres listenera musi być pojedynczą wartością IP:port bez spacji i przecinków.", - "streamListenRequired": "Dodaj adres nasłuchu.", - "streamDelete": "Usunąć ten stream? Aktywny listener pozostanie do restartu RustProxy.", - "streamPendingRestart": "Oczekuje na restart", - "streamRunning": "Działa", - "streamActiveSessions": "Aktywne połączenia / sesje", - "streamSessionsTotal": "Połączenia / sesje", - "streamErrors": "Błędy", - "streamRejected": "Odrzucone", - "streamTransferred": "Przesłano", - "streamTrafficChart": "Ruch na żywo", - "streamClientToUpstream": "klient → upstream", - "streamUpstreamToClient": "upstream → klient", - "streamNoLiveMetrics": "Statystyki pojawią się, gdy stream będzie aktywny po restarcie.", - "streamIdleShort": "Timeout bezczynności", - "listenerAddressAdd": "Dodaj adres nasłuchu", - "listenerAddressesHelp": "Naciśnij Enter lub przecinek, aby dodać adres. Wiele adresów korzysta z tej samej polityki listenera; wildcard 0.0.0.0/:: nie może być mieszany z konkretnymi adresami.", - "cacheColdOnIdle": "Przenoś stare/nieużywane obiekty do cold storage", - "cacheColdOnLru": "Przenoś obiekty wyrzucane z hot LRU do cold storage", - "cacheColdOnShutdown": "Przy łagodnym restarcie zrzucaj hot cache do cold storage", - "certificateCovers": "Domeny certyfikatu", - "certificateCoverageUnknown": "Brak danych o domenach (DNS SAN). Wczytaj ponownie pliki certyfikatów lub zaimportuj certyfikat ponownie.", - "certificateDetails": "Szczegóły certyfikatu", - "certificateFiles": "Pliki certyfikatu / klucza", - "redirects": "Przekierowania", - "redirectsTitle": "Przekieruj świadomie.", - "redirectsDescription": "Lokalne hosty przekierowań z jawnym dopasowaniem, celem, kodem oraz obsługą ścieżki i query.", - "redirectsPageIntro": "Hosty przekierowań odpowiadają lokalnie, bez otwierania połączenia do backendu. Reguły mogą dopasować protokół i ścieżkę, a następnie przekierować do URL, innego hosta lub ścieżki.", - "redirectLayer": "PRZEKIEROWANIA HTTP", - "redirectList": "Hosty przekierowań", - "redirectSearch": "Szukaj przekierowań", - "redirectSearchPlaceholder": "ID, domena, cel…", - "redirectNew": "Nowe przekierowanie", - "redirectEmpty": "Brak skonfigurowanych hostów przekierowań.", - "redirectSearchEmpty": "Brak przekierowań pasujących do wyszukiwania.", - "redirectEditor": "Konfiguracja przekierowania", - "redirectId": "ID przekierowania", - "redirectName": "Nazwa", - "redirectHosts": "Domeny źródłowe", - "redirectFrontend": "FRONTEND", - "redirectListeners": "Listenery", - "redirectBehavior": "ZACHOWANIE", - "redirectRules": "Reguły", - "redirectAddRule": "Dodaj regułę", - "redirectRulesHelp": "Wygrywa najdłuższa pasująca ścieżka. 307/308 zachowują metodę żądania; 301/302/303 mogą ją zmienić po stronie klienta.", - "redirectSafetyHint": "Host przekierowania nie łączy się z backendem. Globalne ACL hostów nadal obowiązują. Unikaj reguł kierujących bezwarunkowo do samych siebie.", - "redirectRule": "Reguła", - "redirectRuleId": "ID reguły", - "redirectSourceScheme": "Protokół wejściowy", - "redirectSchemeAny": "HTTP lub HTTPS", - "redirectSchemeHttp": "HTTP", - "redirectSchemeHttps": "HTTPS", - "redirectSchemePreserve": "Zachowaj protokół wejściowy", - "redirectMatchType": "Dopasowanie ścieżki", - "redirectMatchPrefix": "Prefiks", - "redirectMatchExact": "Dokładnie", - "redirectSourcePath": "Ścieżka źródłowa", - "redirectTargetType": "Typ celu", - "redirectTargetUrl": "Pełny URL", - "redirectTargetHost": "Host / aplikacja", - "redirectTargetPath": "Ścieżka na tym samym hoście", - "redirectTarget": "Cel", - "redirectTargetScheme": "Protokół celu", - "redirectPathMode": "Obsługa ścieżki", - "redirectPathAppend": "Dopisz pełną ścieżkę źródłową", - "redirectPathStrip": "Usuń dopasowany prefiks i dopisz resztę", - "redirectPathReplace": "Użyj tylko skonfigurowanej ścieżki celu", - "redirectQueryMode": "Obsługa query", - "redirectQueryPreserve": "Zachowaj query źródłowe", - "redirectQueryDrop": "Usuń query źródłowe", - "redirectStatus": "Status HTTP", - "redirect301": "301 Moved Permanently", - "redirect302": "302 Found", - "redirect303": "303 See Other", - "redirect307": "307 Temporary Redirect (zachowaj metodę)", - "redirect308": "308 Permanent Redirect (zachowaj metodę)", - "redirectCacheSeconds": "max-age cache przeglądarki/proxy (sekundy; 0 = no-store)", - "redirectHostsRequired": "Dodaj co najmniej jedną domenę źródłową.", - "redirectListenersRequired": "Wybierz co najmniej jeden listener.", - "redirectRulesRequired": "Dodaj co najmniej jedną regułę przekierowania.", - "redirectDuplicate": "Przekierowanie o tym ID już istnieje.", - "redirectUnsaved": "Odrzucić niezapisane zmiany przekierowania?", - "redirectNewLabel": "NOWE", - "administrationSessionDays": "Czas ważności sesji administratora (dni)", - "administrationSessionDaysHelp": "Sesje przeglądarkowe mają bezwzględny czas ważności 7–30 dni. Zmiana działa od razu; zmiana hasła i „wyloguj wszystkie sesje” nadal natychmiast unieważniają sesje.", - "vhLocalListenerRisk": "Zezwól na lokalny listener RustProxy jako backend (ryzyko)", - "vhLocalListenerRiskHelp": "Ta opcja pojawia się, gdy URL backendu bezpośrednio wskazuje skonfigurowany lub aktywny listener administracyjny RustProxy. localhost, 127.0.0.1 i ::1 są traktowane jako równoważne adresy loopback na tym samym porcie panelu. Jej włączenie może wystawić panel lub utworzyć pętlę proxy; adres prywatny/loopback nadal wymaga opcji „Zezwól na prywatny IP backendu”.", - "vhLocalListenerRiskConfirm": "Ta opcja może kierować żądania do lokalnego listenera RustProxy, w tym portu administracyjnego, oraz utworzyć pętlę lub wystawić control plane. Akceptujesz to ryzyko?", - "cacheResidentHistory": "Historia zajętości RAM cache", - "networkHistory": "Historia RX / TX", - "responseLatencyHistory": "Historia czasu odpowiedzi", - "sourceIp": "IP źródłowe", - "cacheColdOnAge": "Przenoś obiekty do cold po maksymalnym czasie w hot RAM", - "cacheColdMaxHot": "Maksymalny czas w hot RAM (sekundy)", - "cacheColdPolicyHelp": "Czas bezczynności określa, jak długo obiekt nie był używany. Wiek hot określa ciągły czas przebywania w RAM nawet przy dalszych odczytach. Presja LRU i zrzut przy łagodnym zamknięciu są niezależnymi regułami.", - "documentation": "Dokumentacja", - "locationPathPattern": "Ścieżka / wzorzec regex", - "locationMatchType": "Sposób dopasowania", - "locationMatchPrefix": "Prefiks", - "locationMatchPriority": "Priorytetowy prefiks (^~)", - "locationMatchExact": "Dokładna ścieżka (=)", - "locationMatchRegex": "Regex (~)", - "locationMatchRegexI": "Regex bez rozróżniania wielkości liter (~*)", - "locationMatch_prefix": "prefiks", - "locationMatch_prefix_priority": "prefiks priorytetowy", - "locationMatch_exact": "dokładne", - "locationMatch_regex": "regex", - "locationMatch_regex_insensitive": "regex i", - "locationAction": "Akcja", - "locationProxyAction": "Proxy do backendu", - "locationReturnAction": "Własna odpowiedź (return)", - "locationProxyShort": "proxy", - "locationReturnShort": "odpowiedź lokalna", - "locationHandling": "Obsługa żądania", - "locationRewriteMode": "Przepisanie ścieżki do backendu", - "locationRewritePreserve": "Zachowaj oryginalną ścieżkę", - "locationRewriteStrip": "Usuń dopasowany prefiks", - "locationRewriteReplace": "Zastąp dopasowany prefiks", - "locationRewriteRegex": "Zamiana regex", - "locationRewriteValue": "Ścieżka / wyrażenie zastępujące", - "locationRewriteHelp": "Parametry query są zachowywane. Przepisywanie prefiksu działa na znormalizowanej ścieżce routingu. Zamiana regex obsługuje grupy Rust regex, np. $1. Wynik jest walidowany przed wysłaniem do backendu.", - "locationResponseStatus": "Kod odpowiedzi", - "locationResponseType": "Content-Type", - "locationResponseBody": "Treść odpowiedzi", - "headersVisualBuilder": "Graficzny konfigurator", - "locationDocsTitle": "Dokumentacja Custom locations", - "headersDocsTitle": "Dokumentacja reguł nagłówków", - "locationDocsIntro": "Custom locations są oceniane wewnątrz wybranego vhosta po autentykacji i ACL hosta. Nie mogą omijać zabezpieczeń vhosta.", - "locationDocsPrefix": "Prefiks: dopasowuje pełny prefiks segmentów ścieżki. Wygrywa najdłuższy prefiks. Priorytetowy prefiks działa jak nginx ^~ i blokuje pierwszeństwo regexów.", - "locationDocsExact": "Dokładne: pasuje wyłącznie do dokładnej znormalizowanej ścieżki, jak nginx location = /path.", - "locationDocsRegex": "Regex: po obsłudze exact/prioritetowego prefiksu wygrywa pierwszy pasujący regex. Dostępny jest tryb czuły i nieczuły na wielkość liter. Używana jest składnia Rust regex; look-around i backreference w samym wzorcu są celowo niedostępne.", - "locationDocsReturn": "Własna odpowiedź: RustProxy odpowiada lokalnie wybranym kodem HTTP, Content-Type i body bez otwierania połączenia do backendu. Reguły nagłówków odpowiedzi lokalizacji nadal obowiązują.", - "locationDocsRewrite": "Przepisanie ścieżki backendu: zachowanie oryginału, usunięcie/zamiana prefiksu albo zamiana z grupami regex. Oryginalny query string jest zachowany.", - "locationDocsAccess": "ACL IP lokalizacji, nadpisanie cache i reguły nagłówków są łączone z polityką vhosta. Lokalizacja nie może wyłączyć autentykacji ani ACL hosta.", - "locationDocsLimits": "Do 64 lokalizacji na vhost. Regexy i body odpowiedzi mają limity; nagłówki transportu, zweryfikowanej tożsamości i protokołu WebSocket pozostają zarządzane przez system.", - "headersDocsIntro": "Reguły nagłówków są stosowane kolejno: globalne → vhost → pasująca lokalizacja. Do zwykłej konfiguracji użyj graficznego konfiguratora; JSON pozostaje trybem zaawansowanym.", - "headersDocsSet": "Ustaw: zastępuje wszystkie istniejące wartości nagłówka skonfigurowaną wartością dosłowną.", - "headersDocsAppend": "Dopisz: dodaje kolejną wartość bez usuwania istniejących.", - "headersDocsRemove": "Usuń: kasuje nagłówek przed wysłaniem do backendu albo klienta.", - "headersDocsProtected": "Chronionych nagłówków transportu/tożsamości (Host, Connection, Content-Length, Forwarded/X-Forwarded-*, nagłówki dowodu WebSocket itd.) nie można tu nadpisywać.", - "headersDocsOrder": "Wartości są dosłowne; zmienne nginx nie są interpretowane. Reguły request działają przed nałożeniem kanonicznych danych forwardingu, a response przed końcową polityką bezpieczeństwa/diagnostyki RustProxy.", - "cacheColdPolicyTitle": "Polityka hot → cold", - "headerRule": "Reguła nagłówka", - "headerRulesEmpty": "Brak reguł. Dodaj regułę poniżej.", - "headerRuleHelp": "Wybierz Ustaw, Dodaj lub Usuń. Nagłówki transportowe, tożsamości forwardingu i protokołu WebSocket pozostają chronione.", - "locationPreviewTitle": "Podgląd efektywnego działania", - "locationPreviewMatch": "Dopasowanie", - "locationPreviewHandling": "Obsługa", - "locationPreviewRewrite": "Ścieżka do backendu", - "locationPreviewCache": "Cache", - "locationPreviewAccess": "Dostęp", - "locationPreviewHeaders": "Reguły nagłówków", - "locationPreviewDisabled": "Ta lokalizacja jest wyłączona i nie będzie dopasowywać żądań.", - "locationPreviewBackendSkipped": "backend nie jest wywoływany", - "locationPreviewVhostAcl": "Tylko autentykacja i ACL vhosta", - "locationPreviewCustomAcl": "Polityka vhosta + ACL lokalizacji", - "locationPreviewRequestRules": "request", - "locationPreviewResponseRules": "response", - "locationPreviewQueryPreserved": "query string jest zachowywany", - "locationDocsMatchHeading": "1. Dopasowanie i kolejność", - "locationDocsActionHeading": "2. Proxy, rewrite i odpowiedź lokalna", - "locationDocsPolicyHeading": "3. Dostęp, cache i nagłówki", - "locationDocsExamplesHeading": "Popularne przykłady", - "locationDocsExampleExact": "Endpoint health: Dokładna ścieżka (=) /health + Własna odpowiedź 200 odpowiada lokalnie bez łączenia z backendem.", - "locationDocsExampleStatic": "Pliki statyczne: Priorytetowy prefiks (^~) /static/ blokuje przejęcie przez regex; dla tej lokalizacji można osobno włączyć cache.", - "locationDocsExampleRegex": "Wersjonowane API: Regex (~) ^/api/v[0-9]+/ może wybrać backend i używać grup zamiany regex, np. $1.", - "cacheOutcomeHistory": "Aktywność HIT / MISS / BYPASS", - "cacheHotMemoryHistory": "Zajętość RAM HOT / limit", - "cacheTransientMemoryHistory": "Zajętość RAM przejściowego / limit", - "cacheColdStorageHistory": "Zajętość COLD / limit", - "processCpuHistory": "Historia CPU procesu", - "processRssHistory": "Historia RSS procesu", - "cacheMemoryBreakdown": "Cache hot / pamięć przejściowa", - "cacheTransientBreakdown": "Fill / kolejka cold / I/O cold", - "cacheColdStorageUsage": "Zajętość COLD / limit", - "cacheColdStorageObjects": "obiektów", - "cacheTransientMemory": "Pamięć przejściowa cache", - "cacheTransientShort": "RAZEM", - "cacheFillShort": "fill", - "cacheQueueShort": "kolejka cold", - "cacheIoShort": "I/O cold", - "processRssTotal": "RSS łącznie", - "memoryCacheHot": "RAM cache HOT / limit", - "memoryCacheTransient": "RAM przejściowy cache / limit", - "memoryTransform": "RAM zarezerwowany przez transformacje / budżet", - "memoryTransformInflight": "Aktywne transformacje / limit", - "memoryNonCacheRss": "RSS procesu poza cache", - "transformMemoryUsage": "Rezerwacja RAM transformacji", - "transformConcurrencyUsage": "Aktywne sloty transformacji", - "transformBudgetShort": "budżet", - "processRssAnon": "RSS anonimowy", - "processRssFile": "RSS plików / współdzielony", - "processDataSwap": "Obszar danych / swap", - "memoryAccountingHint": "RSS pokazuje rzeczywisty ślad pamięci procesu. HOT i pamięć przejściowa cache są księgowane przez RustProxy, a pamięć transformacji jest konserwatywną rezerwacją aktywnej pracy. RSS poza cache to RSS pomniejszony o księgowany cache i obejmuje m.in. transformacje, połączenia, TLS, logowanie, Tokio/runtime, narzut alokatora i inne bufory, więc nie wszystkie wiersze należy sumować.", - "memoryAccountingInfo": "Informacje o rozliczaniu pamięci", - "logTransport": "Transport", - "logWebSocket": "WebSocket", - "logUpstreamError": "Błąd upstreamu", - "listenerDefaultPortsHint": "Nowy vhost automatycznie wybiera standardowy listener HTTP :80, jeśli jest dostępny.", - "vhBackendDiagnostics": "Diagnostyka backendu", - "vhBackendHeader": "Udostępniaj wybrany backend (X-RustProxy-Backend)", - "vhBackendTimingHeader": "Udostępniaj czas odpowiedzi backendu (X-RustProxy-Backend-Time)", - "vhBackendDiagnosticsHelp": "Opcjonalne nagłówki odpowiedzi. Czas backendu oznacza czas od wysłania żądania do otrzymania nagłówków odpowiedzi; odpowiedzi obsłużone bez kontaktu z originem nie raportują backendu.", - "authModeHelp": "Wybierz jedną metodę uwierzytelniania. Lista dostępu IP poniżej działa niezależnie i może być używana razem z dowolną metodą.", - "taAdvanced": "Zaawansowane ustawienia Tinyauth", - "notfound": "Hosty 404", - "notfoundTitle": "Hosty 404 pod kontrolą.", - "notfoundDescription": "Rezerwuj domeny, które mają lokalnie zwracać kod, zaślepkę albo własny HTML.", - "notfoundPageIntro": "Hosty 404 rezerwują wybrane domeny i odpowiadają lokalnie bez łączenia z backendem. Mogą używać tych samych listenerów i certyfikatów co vhosty.", - "notfoundLayer": "ODPOWIEDŹ LOKALNA", - "notfoundList": "Hosty 404", - "notfoundSearch": "Szukaj hostów 404", - "notfoundSearchPlaceholder": "ID, nazwa lub domena…", - "notfoundNew": "Nowy host 404", - "notfoundEditor": "Konfiguracja hosta 404", - "notfoundId": "ID hosta", - "notfoundName": "Nazwa wyświetlana", - "notfoundFrontend": "FRONTEND", - "notfoundBehavior": "ODPOWIEDŹ", - "notfoundResponse": "Odpowiedź lokalna", - "notfoundMode": "Typ odpowiedzi", - "notfoundModeWelcome": "Zaślepka RustProxy", - "notfoundModeEmpty": "Tylko status / pusta", - "notfoundModeHtml": "Własny HTML", - "notfoundStatus": "Status HTTP", - "notfoundHtml": "Własny HTML", - "notfoundResponseHelp": "Host nigdy nie otwiera połączenia do backendu. Wbudowana zaślepka ma no-store i celowo nie dodaje opcjonalnych nagłówków diagnostycznych ani Server RustProxy.", - "notfoundHosts": "Domeny", - "notfoundNewLabel": "NOWY", - "notfoundHostsRequired": "Dodaj co najmniej jedną domenę.", - "notfoundListenersRequired": "Wybierz co najmniej jeden listener.", - "notfoundHtmlRequired": "Własny HTML nie może być pusty.", - "notfound204Empty": "Odpowiedzi HTTP 204, 205 i 304 muszą używać trybu Pusta.", - "notfoundDuplicate": "Host 404 o takim ID już istnieje.", - "notfoundUnsaved": "Odrzucić niezapisane zmiany hosta 404?", - "notfoundEmpty": "Brak skonfigurowanych hostów 404.", - "notfoundSearchEmpty": "Brak hostów 404 pasujących do wyszukiwania.", - "prometheusTrustedNoToken": "Zezwól zaufanym CIDR na odczyt bez tokenu", - "prometheusTrustedNoTokenHelp": "Klient nadal musi pasować do listy dozwolonych CIDR. Włączaj tylko w prywatnej, zaufanej sieci monitoringu; nagłówki przekazywane nie są używane do tej decyzji.", - "docker-vhosts": "Docker vhosty", - "docker-vhostsTitle": "Usługi Dockera pod nazwami.", - "docker-vhostsDescription": "Wykrywaj wystawione porty Dockera i mapuj uslugi na nazwy w domenie agenta, wlasne domeny oraz aliasy bez zapisywania obserwowanego stanu do SQLite.", - "dockerVhosts": "Docker vhosty", - "dockerVhostsIntro": "Wystawione porty TCP wykryte przez skonfigurowane agenty Dockera. Dla każdej usługi ustaw krótką nazwę w domenie agenta albo dowolny FQDN, dodaj aliasy, wybierz IP hosta Dockera oraz sprawdzaj i konfiguruj stan backendu na żywo.", - "dockerDiscovery": "WYKRYWANIE DOCKERA", - "dockerRefresh": "Odśwież agentów", - "dockerAgentsSettings": "Ustawienia agentów Dockera", - "dockerAgents": "Agenty Dockera", - "dockerDesiredState": "STAN ŻĄDANY / SQLITE", - "dockerAgentsHelp": "Skonfiguruj osobnego agenta dla każdego hosta Dockera. Domyślnie agent używa HTTPS ze stałym certyfikatem self-signed; wklej jego fingerprint SHA-256, aby przypiąć certyfikat. Każdy agent ma własną domenę bazową i opcjonalne domyślne IP backendu.", - "dockerAgentAdd": "Dodaj agenta Dockera", - "dockerAgentsSave": "Zapisz i połącz agentów", - "dockerAgent": "AGENT DOCKERA", - "dockerAgentNew": "Nowy agent", - "dockerAgentId": "ID agenta", - "dockerAgentName": "Nazwa wyświetlana", - "dockerAgentEndpoint": "Adres agenta", - "dockerAgentToken": "Token Bearer", - "dockerBaseDomain": "Domena bazowa", - "dockerTargetOverride": "Nadpisanie IP docelowego", - "dockerTargetAuto": "automatyczne", - "dockerListeners": "Listenery", - "dockerListenersRequired": "Wybierz co najmniej jeden listener dla agenta Docker.", - "dockerNoAgents": "Brak skonfigurowanych agentów Dockera.", - "dockerNoAgentsConfigured": "Najpierw skonfiguruj agenta Dockera w Ustawieniach.", - "dockerPublish": "Wystaw", - "dockerPreserveHost": "Zachowaj Host", - "dockerServiceMissing": "Brak w ostatnim odczycie", - "dockerConnected": "POŁĄCZONO", - "dockerError": "BŁĄD", - "dockerWaiting": "OCZEKIWANIE", - "dockerAgentDisabled": "Ten agent Dockera jest wyłączony.", - "dockerNoObservation": "Brak odczytu. Odśwież agentów.", - "dockerHost": "Host Dockera", - "dockerDetectedIp": "Wykryte IP", - "dockerEffectiveIp": "IP routingu", - "dockerNoPublishedPorts": "Agent nie zgłosił wystawionych portów TCP.", - "dockerAssignmentsSave": "Zapisz Docker vhosty", - "dockerDefaultTarget": "Domyslne IP backendu", - "dockerDetectedIps": "Wykryte adresy IP hosta", - "dockerHostname": "Nazwa hosta", - "dockerHostnameHelp": "Krotka nazwa uzyje {domain}; pelny FQDN uzyje wlasnej domeny.", - "dockerAliases": "Aliasy", - "dockerAliasAdd": "Dodaj alias", - "dockerAliasesHelp": "Dodawaj aliasy klawiszem Enter lub przecinkiem. Krótkie nazwy użyją domeny bazowej agenta, a pełne FQDN pozostaną bez zmian.", - "dockerBackendIp": "IP hosta backendu", - "dockerBackendIpAuto": "Auto / domyslne agenta", - "dockerBackendScheme": "Protokol backendu", - "dockerBindingIp": "binding Dockera", - "dockerAgentDefaultIp": "domyslne agenta", - "dockerAgentEndpointHelp": "Dla domyślnej konfiguracji agenta użyj https://. Zwykły HTTP pozostaje tylko dla zgodności i jest wyraźnie oznaczony jako niezabezpieczony.", - "dockerTlsFingerprint": "SHA-256 certyfikatu TLS", - "dockerTlsFingerprintHelp": "Dla domyślnego certyfikatu self-signed wklej fingerprint wypisany przez install.sh albo rustproxy-docker-agent --print-fingerprint. Zostaw puste wyłącznie dla certyfikatu zaufanego przez publiczne CA.", - "dockerTlsPinned": "TLS PRZYPIĘTY", - "dockerTlsPublicCa": "TLS / PUBLICZNE CA", - "dockerTlsPlain": "ZWYKŁY HTTP", - "dockerTlsPlainHelp": "Token agenta i dane inventory nie są chronione przez TLS na tym endpointcie.", - "dockerTlsPublicCaHelp": "Łańcuch certyfikatu i nazwa hosta są weryfikowane względem publicznych CA.", - "dockerAgentConnectionFailed": "Nie udało się połączyć z agentem", - "dockerAgentVersion": "Wersja agenta", - "dockerLastChecked": "Ostatnie sprawdzenie", - "dockerNeverChecked": "nigdy", - "dockerJustNow": "przed chwilą", - "dockerSecondsAgo": "{seconds} s temu", - "dockerMinutesAgo": "{minutes} min temu", - "dockerBackendMissing": "BRAK USŁUGI", - "dockerBackendNotActive": "NIEWYSTAWIONY", - "dockerBackendChecking": "SPRAWDZANIE", - "dockerBackendHealthOff": "HEALTH WYŁ.", - "dockerBackendUp": "UP", - "dockerBackendDown": "DOWN", - "dockerBackendDraining": "WYGASZANIE", - "dockerBackendNoMetrics": "Metryki runtime pojawią się po aktywacji dynamicznego backendu.", - "dockerHealthCheck": "Badanie backendu", - "dockerHealthSummary": "Aktywne testy TCP/HTTP; pasywne zdrowie jest konfigurowane osobno", - "dockerPassiveHealth": "Pasywne zdrowie backendu", - "dockerPassiveHealthSummary": "Domyślnie wyłączone; wymaga świadomego użycia zwykłego ruchu do decyzji health", - "dockerHealthMode": "Tryb", - "dockerHealthHttp": "HTTP", - "dockerHealthTcp": "TCP", - "dockerHealthOff": "Wyłączone", - "dockerHealthPath": "Ścieżka HTTP", - "dockerHealthHost": "Nagłówek Host health-checka", - "dockerHealthHostAuto": "host backendu / automatycznie", - "dockerHealthInterval": "Interwał (ms)", - "dockerHealthTimeout": "Timeout (ms)", - "dockerHealthSlow": "Próg wolnej odpowiedzi (ms)", - "dockerHealthFall": "Błędy do oznaczenia DOWN", - "dockerHealthRise": "Sukcesy do oznaczenia UP", - "dockerHealthStatusMin": "Min. status HTTP", - "dockerHealthStatusMax": "Maks. status HTTP", - "dockerHealthLatency": "Opóźnienie", - "dockerHealthResult": "Ostatni probe", - "dockerHealthRequests": "Żądania", - "dockerHealthErrors": "Błędy", - "dockerHealthActive": "Aktywne", - "loggingPerVhost": "Osobny plik per vhost", - "loggingDirectory": "Katalog logów per-vhost", - "loggingPerVhostHelp": "Po włączeniu każdy vhost zapisuje do własnego pliku JSONL. Ruch niedopasowany trafia do _unmatched.jsonl.", - "listenerStartupLocked": "Tego adresu ustawionego przy starcie procesu/systemd nie można zmienić ani usunąć. Pozostałe adresy i opcje listenera nadal można edytować.", - "administrationStartupLocked": "Ten adres jest ustawiony przy starcie procesu/systemd i nie można go tutaj zmienić.", - "notfoundStatusInvalid": "Wybierz obsługiwany status błędu HTTP.", - "tlsEffectiveCiphers": "Aktualnie używane szyfry", - "certificateManaged": "Zarządzany przez ACME", - "certManagedReadOnly": "Certyfikaty zarządzane przez ACME są odnawiane automatycznie i nie można ich edytować jak własnych certyfikatów z plików.", - "vhWebsocketTransport": "Transport WebSocket", - "vhWebsocketHttp1": "HTTP/1.1 Upgrade (zalecane)", - "vhWebsocketRfc9220": "RFC 9220 Extended CONNECT przez HTTP/3", - "vhWebsocketTransportHelp": "Włącz WebSocket osobnym przełącznikiem, a następnie wybierz transport. Tryby H2/H3 używają Extended CONNECT, a HTTP/1.1 Upgrade pozostaje fallbackiem.", - "dockerLiveView": "Widok live", - "dockerPollInterval": "Interwał odpytywania agenta (s)", - "dockerPollIntervalHelp": "Jak często RustProxy pobiera inventory Dockera z tego agenta. Widok live czyta tylko stan z pamięci RustProxy.", - "dockerAgentPollEvery": "Interwał agenta", - "dockerSearch": "Szukaj Docker vhostów", - "dockerSearchPlaceholder": "Szukaj usługi, hosta, aliasu lub agenta...", - "dockerShowHidden": "Pokaż ukryte", - "dockerHideHidden": "Ukryj ukryte", - "dockerHideVhost": "Ukryj z widoku", - "dockerUnhideVhost": "Pokaż w widoku", - "dockerCertificate": "Certyfikat frontendu", - "dockerCertificateHelp": "Certyfikat przypisany do wszystkich generowanych vhostów tego agenta. Domyślna opcja używa standardowego wyboru TLS/SNI.", - "dockerDefaultAcl": "Domyślny profil ACL", - "dockerDefaultAclNone": "Bez domyślnego profilu ACL", - "dockerDefaultAclHelp": "Dziedziczony przez generowane Docker vhosty, które nie mają wybranego własnego profilu ACL per aplikacja.", - "dockerApplyService": "Zastosuj zmiany", - "dockerAccessControl": "Kontrola dostępu", - "dockerAclSummary": "Opcjonalny profil ACL i reguły IP per aplikacja", - "dockerAclProfile": "Profil ACL", - "dockerAclProfileNone": "Bez profilu ACL", - "dockerAclProfileInherit": "Domyślny agenta", - "dockerAclInline": "Użyj dodatkowego ACL per aplikacja", - "dockerAclDefault": "Domyślna akcja ACL", - "dockerAclRules": "Reguły IP/CIDR", - "dockerAclHelp": "Jedna reguła w linii, np. allow 10.0.0.0/8. Profil i ACL per aplikacja są egzekwowane łącznie.", - "dockerProxyTimeouts": "Timeouty proxy", - "dockerProxyTimeoutsHelp": "Jawne limity per aplikacja: domyślnie połączenie 10 s, nagłówki odpowiedzi 120 s, odczyt 60 s i wysyłanie 60 s.", - "dockerHostnameRequired": "Przed wystawieniem wymagany jest hostname.", - "dockerForceSsl": "Przekieruj HTTP do HTTPS", - "dockerForceSslUnavailable": "Wymaga aktywnego listenera zwykłego HTTP oraz jednego jednoznacznego listenera TLS dla tego agenta.", - "dockerWebsockets": "WebSockety", - "dockerCache": "Cache", - "vhProxyTimeouts": "Timeouty proxy", - "vhProxyConnectTimeout": "Proxy connect timeout (s)", - "vhProxyHeaderTimeout": "Proxy response header timeout (s)", - "vhProxyReadTimeout": "Proxy read timeout (s)", - "vhProxySendTimeout": "Proxy send timeout (s)", - "vhProxyTimeoutsHelp": "Domyślnie: połączenie 10 s, nagłówki odpowiedzi 120 s, odczyt 60 s i wysyłanie 60 s. Read/send to timeout bezczynności podczas streamowania body.", - "notfoundModeBuiltin": "Zaślepka aplikacyjna dla statusu", - "pageBuiltin": "Wbudowana strona statusu", - "vhOpenBrowser": "Otwórz", - "securityPasswordHint": "Wymaga obecnego hasła i wyloguje wszystkie sesje.", - "securityAccessControl": "KONTROLA DOSTĘPU", - "securityPoliciesHint": "Lista polityk pozostaje widoczna; edytor otwieraj tylko przy dodawaniu lub zmianie reguł.", - "securityPolicyEditorHint": "Zakres hostów, domyślna akcja i reguły CIDR.", - "securityAuditOpen": "Audyt administracyjny", - "securityAuditHint": "Ostatnie operacje administracyjne są pobierane dopiero po otwarciu tego okna.", - "dockerConfigureService": "Konfiguruj vhost", - "dockerAliasesShort": "aliasów", - "dockerAgentDetails": "Szczegóły agenta", - "dockerServices": "Usługi", - "dockerOpenApp": "Otwórz aplikację", - "networkInterfacesHistory": "Ruch według interfejsów", - "networkInterfaceRate": "RX / TX", - "networkNoInterfaces": "Brak dostępnych interfejsów sieciowych innych niż loopback.", - "networkInterfacesCount": "{count} interfejsów", - "logExpandBuffer": "Zwiększ bufor", - "logExpandedBuffer": "Bufor 4096", - "logBufferExpanded": "Bufor live zwiększono do {count} zachowanych wpisów.", - "vhIdRenameHelp": "Zmiana ID vhosta tworzy nową tożsamość metryk/logów/cache i resetuje bieżącą historię health/traffic. Hostname’y i skonfigurowane ID backendów pozostają bez zmian.", - "vhIdRenameConfirm": "Zmienić ID vhosta z {old} na {new}? Bieżąca historia health/traffic oraz tożsamość metryk/cache tego vhosta zostaną rozpoczęte od nowa.", - "cacheDomainFilter": "Pokaż", - "cacheDomainFilterAll": "Wszystkie domeny", - "cacheDomainFilterEnabled": "Cache włączony", - "cacheDomainFilterDisabled": "Cache wyłączony", - "cacheNoDomainsFiltered": "Brak domen pasujących do tego filtra.", - "cacheColdCleanup": "Wyczyść cold cache", - "cacheColdCleanupHelp": "Operacja działa asynchronicznie i korzysta z tego samego mechanizmu eviction co automatyczny GC cold cache.", - "cacheColdUnusedSeconds": "Nieużywane co najmniej przez (sekundy, opcjonalnie)", - "cacheColdOldestCount": "Usuń maksymalnie najstarszych obiektów", - "cacheColdHitsZero": "Tylko obiekty z hits = 0", - "cacheColdCleanupStart": "Uruchom czyszczenie", - "cacheColdCleanupRunning": "Trwa czyszczenie cold cache…", - "cacheColdCleanupDone": "Usunięto {count} obiektów i zwolniono {bytes}.", - "cacheColdCleanupFailed": "Czyszczenie cold cache nie powiodło się.", - "cacheColdCleanupInvalidJob": "Czyszczenie cold cache nie zwróciło identyfikatora zadania.", - "cacheColdGcInterval": "Interwał GC cold cache (sekundy)", - "cacheColdGcMaxDelete": "Maksymalna liczba usunięć na przebieg GC", - "transformSettings": "Transformacja odpowiedzi statycznych", - "transformEnable": "Włącz globalnie silnik transformacji", - "transformHelp": "Transformacja odbywa się po dekodowaniu upstreamu, a przed zapisem do cache i kompresją dla klienta. Każdy vhost musi zostać włączony osobno.", - "transformJavascript": "Minifikacja JavaScript", - "transformCss": "Minifikacja CSS", - "transformHtml": "Minifikacja HTML", - "transformSvg": "Optymalizacja SVG", - "transformJson": "Kompaktowanie JSON", - "transformExtensions": "Dozwolone rozszerzenia plików, po jednym w linii", - "transformMaxBody": "Maksymalny rozmiar transformowanej odpowiedzi (KiB)", - "transformResourcePresetTitle": "Preset zasobów", - "transformResourcePresetHelp": "Presety ustawiają limit pamięci tymczasowej, maksymalny rozmiar transformowanej odpowiedzi i globalny limit równoległych transformacji. Typy treści i lista rozszerzeń pozostają bez zmian.", - "transformPresetConservative": "Oszczędny RAM", - "transformPresetRecommended": "Rekomendowany", - "transformPresetPerformance": "Wydajność", - "transformPresetUber": "Uber wydajność", - "transformMemoryBudget": "Budżet pamięci tymczasowej transformacji (MiB)", - "transformMaxInflight": "Maksymalna liczba równoległych transformacji", - "transformMaxInflightShort": "równolegle", - "transformResourceCurrent": "Aktualne limity", - "transformBudgetTooSmallWarning": "Budżet pamięci jest mniejszy niż pesymistyczny koszt buforów dla jednej maksymalnej skompresowanej odpowiedzi. Takie odpowiedzi mogą zostać pominięte z powodem memory_pressure.", - "transformBudgetHighWarning": "Limit pamięci transformacji przekracza 50% efektywnej pamięci RAM hosta/cgroup:", - "transformSafety": "Cache-Control: no-transform jest zawsze respektowane. Przetransformowana reprezentacja otrzymuje nowy ETag i jest zapisywana do cache przed gzip, Brotli lub zstd.", - "saveTransform": "Zastosuj ustawienia transformacji", - "vhTransform": "Transformacja", - "vhTransformEnable": "Włącz transformacje dla tego vhosta", - "vhTransformExtensionsCustom": "Nadpisz globalne rozszerzenia transformacji", - "vhTransformHelp": "Globalny silnik również musi być włączony. Ustawienia formatów dziedziczą politykę globalną, chyba że zostaną jawnie nadpisane.", - "dockerTransform": "Transformuj odpowiedzi statyczne", - "vhPassive5xxWarning": "Zliczanie HTTP 5xx może wyłączyć cały backend po serii błędów aplikacyjnych z pojedynczego endpointu.", - "vhPassiveSlowWarning": "Zliczanie wolnych odpowiedzi może wyłączyć backend po serii poprawnych odpowiedzi przekraczających próg slow-response.", - "transform": "Transformacja", - "transformTitle": "Transformacja odpowiedzi statycznych.", - "transformDescription": "Skuteczność transformacji, oszczędność, pominięcia i ponowne użycie z cache.", - "transformApplied": "Przetransformowane odpowiedzi", - "transformExamined": "Sprawdzone", - "transformCacheHits": "HIT-y transformowanych obiektów", - "transformCacheHitsHelp": "Obsłużone bez ponownego uruchamiania transformacji", - "transformSaved": "Bajty oszczędzone przed kompresją", - "transformReduction": "Średnia redukcja", - "transformReductionHelp": "Dla odpowiedzi, których reprezentacja faktycznie się zmieniła", - "transformSkipped": "Pominięte / fail-open", - "transformErrors": "Błędy body / transportu", - "transformAvgTime": "Średni czas", - "transformByType": "Transformacje według typu", - "transformType": "Typ", - "transformSkipReasons": "Powody pominięcia / fail-open", - "transformNoSkips": "Brak pominiętych transformacji w tym zakresie.", - "transformNoSkipsShort": "Brak pominięć", - "transformVhosts": "Skuteczność per vhost", - "transformScopeHint": "Liczniki są diagnostyką runtime w pamięci. HIT transformowanego obiektu z cache nie uruchamia transformera ponownie.", - "transformNoData": "Brak aktywności transformacji.", - "transformBadge": "transformowany", - "cacheLiveChartTitle": "Aktywność cache na żywo", - "cacheLiveChartHelp": "HIT / MISS / BYPASS na sekundę dla wybranego zakresu", - "liveChartSamples": "Próbki", - "transformLiveChartTitle": "Aktywność transformacji na żywo", - "transformLiveChartHelp": "Zastosowane / HIT cache / pominięte / błędy na sekundę dla wybranego zakresu", - "transformChartApplied": "Zastosowane", - "transformChartCacheHits": "HIT cache", - "transformChartSkipped": "Pominięte", - "cacheInvalidationTitle": "Purge / BAN cache", - "cacheInvalidationOperation": "Operacja", - "cacheInvalidationSelector": "Selektor", - "cacheInvalidationValue": "Wartość", - "cacheInvalidationHost": "Host (opcjonalnie)", - "cacheBanTtl": "TTL BAN (sekundy)", - "cacheInvalidationHelp": "Wybrany vhost ogranicza zakres operacji. Exact i prefix uwzględniają query string. Operacje regex i prefix / wymagają dodatkowego potwierdzenia.", - "cacheRunInvalidation": "Wykonaj operację", - "cacheActiveBans": "Aktywne reguły BAN", - "cacheBanExpires": "Wygasa", - "cacheNoBans": "Brak aktywnych reguł BAN.", - "cacheTarget": "Target", - "cacheKeyTags": "Klucz cache / tagi", - "cachePurgeUrl": "Purge URL", - "cacheRemoveBan": "Usuń BAN", - "cacheBanCreated": "Utworzono BAN", - "cacheConfirmPurgeUrl": "Usunąć ten URL z cache RAM i cold storage?", - "cacheConfirmRemoveBan": "Usunąć tę regułę BAN?", - "cacheWideInvalidationConfirm": "To szeroka operacja unieważniania i może objąć wiele obiektów cache. Kontynuować?", - "cacheCollapseWaiters": "oczekuje", - "cacheCollapsed": "scalone", - "actions": "Akcje", - "cacheCollapseTitle": "Scalanie żądań", - "cacheCollapseEnable": "Scalaj równoczesne fille dla jednego klucza cache", - "cacheCollapseTimeout": "Limit oczekiwania followera (ms)", - "cacheCollapseFallback": "Fallback po timeout", - "cacheCollapseFallbackOrigin": "Origin", - "cacheCollapseFallbackStale": "Stale, jeśli dostępny", - "cacheStaleErrorTitle": "Polityka stale-if-error", - "cacheSieTimeout": "Timeout", - "cacheSieConnection": "Błąd połączenia", - "cacheSieDns": "Błąd DNS", - "cacheSieTls": "Błąd TLS", - "cacheSieStatuses": "Statusy HTTP 5xx dopuszczające stale fallback", - "cacheProactiveTitle": "Proaktywne odświeżanie", - "cacheProactiveEnable": "Odświeżaj próbkę obiektów cache przed wygaśnięciem", - "cacheProactiveBefore": "Odśwież przed wygaśnięciem (sekundy)", - "cacheProactivePercent": "Próbkowane obiekty (%)", - "cacheProactiveInflight": "Maksymalna liczba równoległych odświeżeń", - "cacheProactiveHelp": "Używa rewalidacji validatorów, deterministycznego próbkowania i globalnego limitu współbieżności, aby zapobiegać lawinie odświeżeń.", - "cacheInvalidationOpen": "Purge / Ban", - "cacheBanListOpen": "Aktywne BAN-y", - "cacheBanRemoved": "Reguła BAN została usunięta", - "tunnelsOpen": "Aktywne tunele", - "tunnelsTitle": "Aktywne WebSockety / tunele", - "tunnelsReload": "Odśwież", - "tunnelsEmpty": "Brak aktywnych tuneli.", - "tunnelId": "ID", - "tunnelClient": "Klient", - "tunnelHost": "Host", - "tunnelUpstream": "Upstream", - "tunnelProtocol": "Protokół", - "tunnelDuration": "Czas", - "tunnelRx": "RX", - "tunnelTx": "TX", - "tunnelKill": "Zamknij", - "tunnelKilled": "Tunel zamknięty przez administratora", - "tunnelKillConfirm": "Zamknąć ten tunel?", - "tunnelKillReason": "Powód zamknięcia", - "tunnelKillReasonPlaceholder": "Zamknięcie administracyjne", - "tunnelKillReasonDefault": "panel administracyjny", - "listenerH2c": "h2c HTTP/2 bez TLS (prior knowledge + Upgrade z HTTP/1.1)", - "vhWebsocketRfc8441": "RFC 8441 Extended CONNECT przez HTTP/2", - "wsH1": "H1 Upgrade", - "wsH2Rfc8441": "H2 RFC 8441", - "wsH3Rfc9220": "H3 RFC 9220", - "wsEstablished": "Utworzone", - "httpProtocolMix": "Miks protokołów HTTP", - "wsProtocolMix": "Miks protokołów WebSocket", - "vhWebsocketMode": "Transport WebSocket", - "vhWebsocketDisabled": "Wyłączony", - "vhWebsocketH1": "HTTP/1.1 Upgrade", - "vhWebsocketH2Fallback": "HTTP/2 RFC 8441 + fallback H1", - "vhWebsocketH3Fallback": "HTTP/3 RFC 9220 + fallback H1", - "vhWebsocketH2H3Fallback": "HTTP/2 + HTTP/3 + fallback H1", - "vhMaxConcurrentRequests": "Maks. równoległych żądań", - "vhBackendQueueTimeout": "Timeout kolejki pojemności (ms)", - "vhBackendCapacityHelp": "0 równoległych żądań oznacza brak limitu. Timeout kolejki równy 0 natychmiast zwraca HTTP 503 po osiągnięciu limitu backendu.", - "vhLastFailure": "Ostatni błąd", - "vhLastRecovery": "Ostatni powrót", - "certificateIssuerName": "Wystawca certyfikatu", - "certificateValidFrom": "Ważny od", - "certificateDaysRemaining": "Pozostało dni", - "certificateExpired": "Certyfikat wygasł", - "certificateExpiresSoon": "Certyfikat wkrótce wygaśnie", - "certificateRenewalStatus": "Status odnawiania", - "certificateRenewalError": "Ostatni błąd odnawiania", - "vhActiveHealth": "Active health", - "vhPassiveFailures": "Błędy passive health", - "certificateAdminRestartRequired": "TLS panelu administracyjnego używa konfiguracji ładowanej przy starcie; uruchom ponownie RustProxy, aby odświeżyć ten certyfikat.", - "cacheTabGeneral": "Ogólne", - "cacheTabResilience": "Odporność", - "cacheTabCold": "Cold cache", - "cacheTabDiagnostics": "Statyczne i diagnostyka", - "certificateApiTitle": "API certyfikatów", - "certificateApiHelp": "Twórz osobne poświadczenia Key ID + Bearer Token dla automatyzacji wdrażania i przeładowywania certyfikatów. Tokeny nie dają dostępu do konfiguracji ani pozostałych API administracyjnych.", - "certificateApiKeyId": "Key ID", - "certificateApiToken": "Bearer token (opcjonalna własna wartość)", - "certificateApiTokenHelp": "Pozostaw pole puste, aby wygenerować silny token. Jawna wartość każdego tokenu jest pokazywana tylko raz; RustProxy zapisuje wyłącznie jego hash.", - "certificateApiRotate": "Generuj / obróć token", - "certificateApiRevoke": "Unieważnij token", - "certificateApiOneTimeToken": "Skopiuj ten token teraz", - "certificateApiCurlHelp": "Automatyzacja zewnętrzna wysyła nagłówek Key ID i Bearer Token do endpointów deploy/reload przez HTTPS (lub HTTP po loopback).", - "certificateApiUnknown": "Ładowanie statusu API certyfikatów…", - "certificateApiConfigured": "API certyfikatów włączone", - "certificateApiDisabled": "API certyfikatów wyłączone", - "certificateApiLastUsed": "ostatnio użyty", - "certificateApiRotated": "Token API certyfikatów został utworzony / zmieniony. Skopiuj go teraz.", - "certificateApiRevoked": "Token API certyfikatów został unieważniony.", - "certificateApiRevokeConfirm": "Unieważnić token zewnętrznego API certyfikatów? Certbot i integracje API używające go natychmiast przestaną działać.", - "certificate_api.invalid_token": "Nieprawidłowy Key ID lub Bearer Token API certyfikatów.", - "certificate_api.https_required": "Zewnętrzny token API certyfikatów wymaga HTTPS, chyba że żądanie pochodzi z loopback.", - "certificate_api.invalid_token_format": "Token API certyfikatów musi mieć 32–128 bezpiecznych znaków URL.", - "certificate_api.invalid_key_id": "Nieprawidłowy Key ID API certyfikatów.", - "vhWebsocketLegacySupport": "Włącz zgodność ze starym WebSocket", - "vhWebsocketLegacySupportHelp": "Dla starszych urządzeń i serwerów embedded. Handshake WebSocket do upstreamu używa HTTP/1.1, Host i Origin są dopasowane do skonfigurowanego adresu backendu, a stary format odpowiedzi 101 jest tolerowany. Zwykły ruch HTTP pozostaje bez zmian.", - "vhWebsocketLegacyBadge": "WebSocket legacy", - "runtimeInformation": "Informacje środowiska", - "runtimeInformationHelp": "Wartości raportuje uruchomiony proces RustProxy. Są dostępne tylko w uwierzytelnionym API administratora.", - "runtimePlatform": "Platforma", - "statisticsSource": "Źródło statystyk", - "dataDirectory": "Katalog danych", - "databaseLocation": "Baza danych", - "connectionActivity": "AKTYWNOŚĆ POŁĄCZEŃ", - "reloadCertificate": "Przeładuj certyfikat", - "certificateApiComment": "Komentarz", - "certificateApiConfiguredCount": "Tokeny API certyfikatów: {count} / {max}", - "certificateApiNeverUsed": "nigdy nie użyty", - "certificateApiRevokeAll": "Unieważnij wszystkie tokeny", - "certificateApiRevokeOneConfirm": "Unieważnić token API certyfikatów {key}? Automatyzacja używająca tego tokenu natychmiast przestanie działać.", - "certificateApiRevokeAllConfirm": "Unieważnić wszystkie tokeny API certyfikatów? Cała automatyzacja zewnętrzna korzystająca z tych tokenów natychmiast przestanie działać.", - "certificate_api.invalid_comment": "Komentarz tokenu API certyfikatów może mieć maksymalnie 256 znaków i nie może zawierać znaków sterujących.", - "certificate_api.limit_reached": "Osiągnięto limit tokenów API certyfikatów.", - "certificate_api.not_found": "Nie znaleziono tokenu API certyfikatów.", - "networkInterfacesVisibleCount": "{visible} / {total} interfejsów", - "hideMetric": "Ukryj", - "showMetric": "Pokaż", - "hiddenInterfaces": "Ukryte interfejsy", - "networkNoVisibleInterfaces": "Wszystkie wykryte interfejsy są ukryte w tej przeglądarce.", - "cacheMemorySizingTitle": "Dobór pamięci", - "cacheMemorySizingHelp": "Presety korzystają z efektywnej pamięci dostępnej dla RustProxy (RAM hosta ograniczony limitem cgroup, jeśli występuje). Ustawiają HOT, pamięć przejściową, rozmiar obiektu, liczbę wpisów i kolejkę demotion; limit dysku COLD pozostaje bez zmian.", - "cachePresetConservative": "Oszczędny", - "cachePresetRecommended": "Zalecany", - "cachePresetPerformance": "Wydajnościowy", - "cachePresetSelected": "Wybrany", - "cachePresetCustom": "Własny", - "cacheColdPresetTitle": "Preset polityki COLD", - "cacheColdPresetHelp": "Preset zalecany włącza przenoszenie po bezczynności/LRU/zamknięciu, dobiera kolejkę COLD do pamięci przejściowej i ustawia zachowawcze czasy GC. Ścieżka, limit dysku i limit obiektów pozostają bez zmian.", - "cacheTransientLimit": "Limit pamięci przejściowej (MiB)", - "cacheEvictionLimit": "Maks. usunięć LRU na przyjęcie obiektu", - "cacheColdQueueLimit": "Limit RAM kolejki COLD (MiB)", - "cacheMemoryNotDetected": "Nie wykryto pamięci", - "cacheMemoryPresetUnavailable": "Automatyczne presety wymagają telemetrii RAM hosta lub limitu cgroup.", - "cacheMemoryCgroup": "Efektywny RAM cgroup", - "cacheMemoryDetected": "Wykryty RAM", - "cacheQueueOverTransientWarning": "Limit kolejki COLD nie może przekraczać limitu pamięci przejściowej.", - "cacheMemoryHighWarning": "Ostrzeżenie: budżety HOT + pamięć przejściowa zajmują dużą część efektywnego RAM:", - "cachePresetTransientShort": "przejściowa", - "cachePresetObjectShort": "maks. obiekt", - "cachePresetQueueShort": "kolejka COLD", - "cacheLogicalShort": "logiczne", - "cacheLimitShort": "limit", - "cacheMemoryPressureShort": "presja pamięci", - "cacheNukeLimitShort": "limit LRU", - "cacheMemoryPresetTooSmall": "Automatyczne presety cache są wyłączone poniżej 256 MiB efektywnego RAM; jeśli to celowe, skonfiguruj cache ręcznie.", - "cacheMemoryRecommendedFor": "Zalecane dla wykrytej pamięci:", - "cacheMemoryHeadroomWarning": "Ostrzeżenie: dodatkowy budżet cache jest duży względem aktualnie dostępnej pamięci hosta/cgroup:", - "cacheObjectOverTransientWarning": "Maksymalny rozmiar obiektu przekracza limit pamięci przejściowej; obiekty zbliżone do tego rozmiaru przejdą bez zapisania w cache.", - "vhCacheGlobalDisabled": "Globalny cache jest wyłączony. Ten vhost nie może włączyć cache, dopóki cache globalny pozostaje wyłączony.", - "responseLatencyInfo": "Informacje o czasie odpowiedzi", - "responseLatencyHint": "Wartość to skumulowana średnia długość zakończonych wymian HTTP od startu procesu. Wykres pokazuje kolejne próbki tej średniej; nie jest to percentyl ani czas pojedynczego żądania.", - "web-server": "Serwer WWW", - "web-serverTitle": "Serwuj lokalne pliki.", - "web-serverDescription": "Twórz wielokrotnego użytku usługi WWW i podpinaj je do vhostów lub lokalizacji.", - "webServer": "Serwer WWW", - "webServerIntro": "Tutaj utwórz lokalne usługi WWW, a następnie podepnij je do vhosta lub lokalizacji.", - "webServiceList": "Usługi WWW", - "webServiceSearch": "Szukaj usług WWW", - "webServiceSearchPlaceholder": "Szukaj nazwy, ID lub document root", - "webServiceNew": "Nowa usługa WWW", - "webServiceEditor": "Konfiguracja usługi WWW", - "webServiceTabGeneral": "Ogólne", - "webServiceTabRouting": "Routing", - "webServiceTabMime": "MIME", - "webServiceTabCacheHeaders": "Cache i nagłówki", - "webServiceTabDelivery": "Serwowanie", - "webServiceTabPhp": "PHP-FPM", - "webServiceTabSecurity": "Bezpieczeństwo", - "webServiceId": "ID usługi", - "webServiceName": "Nazwa", - "webServiceRoot": "Document root", - "webServiceIndex": "Pliki index", - "webServiceDirectoryListing": "Listowanie katalogu", - "webServiceMimeOverrides": "Nadpisania MIME", - "webServiceMimeBuiltin": "Wbudowane mapowania", - "webServiceMimeHelp": "Opcjonalne nadpisania rozszerzenie → Content-Type, po jednym na linię. Format: ext = media/type.", - "webServiceMimeInvalid": "Nadpisania MIME muszą mieć unikalny format 'ext = media/type', po jednym wpisie na linię.", - "webServiceDefaultMime": "Domyślny typ MIME", - "webServiceCacheControl": "Cache-Control", - "webServiceCacheRules": "Reguły Cache-Control", - "webServiceCacheRulesHelp": "Bardziej szczegółowe reguły są sprawdzane przed polityką domyślną. Użyj ext:css albo mime:image/.", - "webServiceCacheRulesInvalid": "Reguły Cache-Control muszą mieć format dopasowanie = wartość, np. ext:css = public, max-age=3600.", - "webServiceResponseHeaders": "Nagłówki odpowiedzi", - "webServiceResponseHeadersHelp": "Stałe nagłówki tej usługi WWW. Reguły vhosta/lokalizacji są nakładane później i mogą je nadpisać.", - "webServiceResponseHeadersInvalid": "Nagłówki odpowiedzi muszą mieć unikalny format Nazwa-Nagłówka = wartość, po jednym wpisie na linię.", - "webServiceCacheHelp": "Lokalne pliki korzystają z filesystemu/cache stron systemu operacyjnego. Te ustawienia sterują cache przeglądarki/proxy i nie tworzą drugiego cache obiektowego RustProxy.", - "webServiceTryFiles": "try_files", - "webServiceTryFilesHelp": "Jeden kandydat na linię. Obsługuje $uri, $query_string oraz końcowy status błędu typu =404.", - "webServiceRewrites": "Reguły rewrite", - "webServiceRewritesHelp": "Jedna reguła regex na linię. Użyj wzorzec => /cel dla rewrite wewnętrznego albo wzorzec => 301:/cel dla przekierowania.", - "webServiceRewritesInvalid": "Reguły rewrite muszą mieć format wzorzec => /cel albo wzorzec => 301:/cel (301/302/307/308).", - "webServicePrecompressed": "Serwuj gotowe pliki skompresowane", - "webServicePrecompressedBr": "Brotli (.br)", - "webServicePrecompressedGzip": "Gzip (.gz)", - "webServiceDownloadExtensions": "Rozszerzenia do pobierania", - "webServiceDownloadExtensionsHelp": "Pliki z tymi rozszerzeniami otrzymają Content-Disposition: attachment.", - "webServiceRangeHelp": "Statyczne i gotowe skompresowane reprezentacje zachowują walidatory, pojedynczy Range, 206/416 i streaming.", - "webServicePhpEnabled": "Włącz PHP-FPM / FastCGI", - "webServicePhpEndpoint": "Endpoint PHP-FPM", - "webServicePhpEndpointHelp": "Unix: unix:/run/php/php-fpm.sock. TCP: tcp:127.0.0.1:9000 albo tcp:[::1]:9000. TCP jest celowo ograniczone do adresów loopback.", - "webServicePhpExtensions": "Rozszerzenia PHP", - "webServicePhpPassAuthorization": "Przekazuj nagłówek Authorization", - "webServicePhpConnectTimeout": "Timeout połączenia (ms)", - "webServicePhpRequestTimeout": "Łączny timeout żądania FastCGI (ms)", - "webServicePhpConcurrency": "Maks. równoległych żądań PHP", - "webServicePhpBodyLimit": "Limit body żądania PHP (bajty, 0 = bez limitu)", - "webServicePhpHeaderLimit": "Maks. bajtów nagłówków odpowiedzi FastCGI", - "webServicePhpStderrLimit": "Maks. bajtów stderr PHP-FPM w logu", - "webServicePhpCustomParams": "Własne parametry FastCGI", - "webServicePhpCustomParamsHelp": "Jeden wpis NAZWA = wartość na linię. Tylko statyczne, zaufane wartości; podstawowe CGI, HTTP_* i kontrolne PHP_* są zarezerwowane.", - "webServicePhpCustomParamsInvalid": "Własne parametry FastCGI muszą mieć unikalny format NAZWA = wartość, po jednym wpisie na linię.", - "webServicePhpCustomDataTooLarge": "Własne parametry FastCGI i nadpisania PHP INI mogą łącznie zajmować maksymalnie 128 KiB.", - "webServicePhpValues": "Nadpisania PHP INI (PHP_VALUE)", - "webServicePhpValuesHelp": "Jedna dyrektywa php.ini = wartość na linię. RustProxy wysyła zwalidowany zestaw jako PHP_VALUE; PHP_ADMIN_VALUE nie jest tutaj dozwolone.", - "webServicePhpValuesInvalid": "Nadpisania PHP INI muszą mieć unikalny format dyrektywa = wartość, po jednym wpisie na linię.", - "webServicePhpDocsButton": "Składnia i bezpieczeństwo FastCGI", - "webServicePhpDocsTitle": "Konfiguracja PHP-FPM / FastCGI", - "webServicePhpDocsIntro": "RustProxy łączy się bezpośrednio z istniejącą pulą PHP-FPM. Na tym samym hoście preferuj socket Unix. TCP jest akceptowane wyłącznie na loopback i nie jest publicznym/sieciowym transportem FastCGI.", - "webServicePhpDocsEndpointTitle": "Składnia endpointu", - "webServicePhpDocsEndpoint": "Dla TCP podaj prefiks tcp:, literalny adres IP loopback oraz port. Nazwy hostów i adresy inne niż loopback są odrzucane. Dla socketu Unix proces RustProxy musi mieć prawo połączenia z socketem.", - "webServicePhpDocsCustomTitle": "Własne parametry FastCGI", - "webServicePhpDocsCustom": "Użyj jednego wpisu NAZWA = wartość na linię. Nazwy są normalizowane do wielkich liter i mogą zawierać A-Z, 0-9 oraz podkreślenie. Są to statyczne, zaufane wartości operatora. RustProxy odrzuca podstawowe nazwy CGI, HTTP_*, PHP_VALUE i PHP_ADMIN_VALUE, więc nie można nimi nadpisać routingu requestu, wyboru skryptu ani parametrów pochodzących z HTTP.", - "webServicePhpDocsValuesTitle": "Nadpisania PHP INI", - "webServicePhpDocsValues": "Te linie są łączone w parametr FastCGI PHP_VALUE. PHP-FPM/PHP nadal decyduje, które dyrektywy można zmieniać w tym zakresie. Znaki nowej linii/kontrolne są odrzucane, a PHP_ADMIN_VALUE jest celowo niedostępne.", - "webServicePhpDocsLimitsTitle": "Limity i nagłówki", - "webServicePhpDocsLimits": "Timeout żądania obejmuje wymianę FastCGI. Limit body jest egzekwowany podczas streamingu i po przekroczeniu zwraca 413; 0 wyłącza limit body po stronie RustProxy. Limity nagłówków odpowiedzi i stderr ograniczają pamięć/dane diagnostyczne. Dozwolone są maks. 64 własne parametry FastCGI i 64 nadpisania PHP INI, łącznie do 128 KiB danych własnych. Przekazywanie Authorization można wyłączyć, gdy aplikacja nie potrzebuje HTTP_AUTHORIZATION.", - "webServicePhpDocsSecurity": "Nie umieszczaj sekretów we własnych parametrach ani PHP_VALUE, jeśli nie akceptujesz ich przechowywania w zwykłej konfiguracji Web Service. Używaj osobnej, nieuprzywilejowanej tożsamości puli PHP-FPM i nie wystawiaj PHP-FPM do publicznej sieci.", - "webServicePhpHelp": "RustProxy komunikuje się bezpośrednio przez FastCGI z długowieczną pulą PHP-FPM. PHP nie jest uruchamiane osobno dla każdego żądania, a kod źródłowy PHP nie jest serwowany, gdy obsługa PHP jest wybrana.", - "webServicePhpSymlinkConflict": "PHP-FPM wymaga obecnie polityki symlinków Deny.", - "webServiceSymlinkPolicy": "Polityka symlinków", - "webServiceSymlinkDeny": "Zabroń", - "webServiceSymlinkInsideRoot": "Zezwól tylko wewnątrz document root (Linux)", - "webServiceSafety": "Document root jest ścisłą granicą dostępu do filesystemu. Domyślnie symlinki są blokowane. Linux może opcjonalnie podążać wyłącznie do celów pozostających w document root; PHP-FPM wymaga obecnie polityki blokującej symlinki.", - "webServiceSelect": "Wybierz usługę WWW", - "webService": "Usługa WWW", - "webServiceUsedBy": "Używana przez", - "webServiceUnused": "Niepodpięta", - "webServiceEmpty": "Brak usług WWW.", - "webServiceSearchEmpty": "Brak usług WWW pasujących do wyszukiwania.", - "webServiceInUse": "Usługa WWW jest nadal używana przez", - "webServiceDelete": "Usunąć tę usługę WWW?", - "webServiceIndexRequired": "Pliki index są opcjonalne.", - "webServiceDuplicate": "Usługa WWW o tym ID już istnieje.", - "webServiceRequired": "Wybierz usługę WWW.", - "sourceType": "Typ źródła", - "sourceReverseProxy": "Reverse Proxy", - "sourceWebServer": "Serwer WWW", - "sourceHelp": "Vhost przechowuje tylko wybór źródła. Ustawienia Serwera WWW pozostają w wybranej, wielokrotnego użytku usłudze WWW.", - "locationWebServerAction": "Serwer WWW", - "locationWebServerShort": "Serwer WWW", - "docsReader": "Reader", - "docsApi": "API", - "docsReaderSearch": "Szukaj w dokumentacji", - "docsReaderSearchPlaceholder": "Szukaj tytułu lub ścieżki", - "docsReaderEmpty": "Brak dokumentów pasujących do wyszukiwania.", - "docsCategoryProject": "Projekt", - "docsCategoryGuides": "Dokumentacja funkcjonalna", - "docsCategoryTechnical": "Techniczna", - "docsCategoryAudits": "Audyty i historia", - "docsCategoryHistorical": "Historyczne", - "webServiceIndexHelp": "Opcjonalne. Pozostaw puste, aby pominąć wyszukiwanie indexu; przy włączonym listingu od razu zostanie pokazana lista plików.", - "webServiceNoIndex": "Brak plików index", - "vhBackendRequired": "Reverse Proxy wymaga co najmniej jednego backendu. Dodaj backend albo zmień źródło na Serwer WWW.", - "vhListenerRequired": "Wybierz co najmniej jeden listener dla tego vhosta.", - "traffic": "Ruch", - "trafficTitle": "Ruch per vhost.", - "trafficDescription": "Ograniczone statystyki żądań: kraje, User-Agenty, adresy IP klientów, ścieżki, trasy i wyniki obsługi.", - "trafficSinceStart": "Od startu procesu", - "trafficResponseBytes": "Bajty odpowiedzi", - "trafficRequestBytes": "Bajty żądań", - "trafficMeanLatency": "Średnie opóźnienie", - "trafficDroppedSamples": "Odrzucone próbki statystyk", - "trafficBoundedLabel": "OGRANICZONE / ASYNCHRONICZNE", - "trafficDimensionsTitle": "Wymiary ruchu", - "trafficApproxHelp": "Listy TOP są przybliżone i mają stały limit, aby ruch o dużej liczbie unikalnych wartości nie zwiększał pamięci proxy bez ograniczeń.", - "trafficTopCountries": "Top kraje", - "trafficTopUserAgents": "Top User-Agenty", - "trafficTopClientIps": "Top adresy IP klientów", - "trafficClientIp": "IP klienta", - "trafficTopPaths": "Top ścieżki", - "trafficTopRoutes": "Top trasy", - "trafficMethods": "Metody", - "trafficStatusClasses": "Klasy statusów", - "trafficCacheOutcomes": "Wyniki cache", - "trafficValue": "Wartość", - "trafficOther": "Pozostałe", - "trafficNoCountryData": "Zbieranie kraju jest wyłączone albo baza GeoIP jest niedostępna.", - "trafficNoUserAgentData": "Brak zebranych danych User-Agent.", - "trafficNoData": "Brak danych o ruchu.", - "trafficUserAgentEnabled": "Zbieranie User-Agent włączone", - "trafficUserAgentDisabled": "Zbieranie User-Agent wyłączone", - "trafficCountryEnabled": "Zbieranie kraju włączone", - "trafficCountryDisabled": "Zbieranie kraju wyłączone", - "trafficCountryNoDb": "Zbieranie kraju włączone, baza GeoIP niedostępna", - "trafficUpdated": "Odświeżono", - "loggingCaptureTitle": "Zbierane wymiary żądania", - "loggingCaptureUserAgent": "Zbieraj User-Agent", - "loggingCaptureCountry": "Zbieraj kraj z GeoIP", - "loggingCaptureCountryHelp": "Lookup kraju jest opcjonalny i domyślnie wyłączony. Włącz go tylko, gdy potrzebujesz kraju w logach/statystykach; reguły ACL/rate-limit per kraj nadal użyją GeoIP, gdy jest to wymagane.", - "cacheAutoTrimEnabled": "Automatycznie zwalniaj nieużywaną pamięć cache HOT", - "cacheAutoTrimAfter": "Czas bezczynności przed trim HOT (sekundy)", - "cacheAutoTrimTarget": "Docelowe użycie HOT po trim (%)", - "cacheAutoTrimHelp": "Gdy pamięć HOT przekracza próg, w ograniczonych partiach usuwane są wyłącznie obiekty nieużywane przez ustawiony czas. Aktywny working set nie jest czyszczony.", - "webServiceTabHtaccess": ".htaccess", - "webServiceHtaccessEnabled": "Włącz zgodność z .htaccess", - "webServiceHtaccessFilename": "Plik konfiguracyjny", - "webServiceHtaccessRecursive": "Skanuj podkatalogi", - "webServiceHtaccessStrict": "Tryb ścisły dla niewspieranych dyrektyw", - "webServiceHtaccessDocs": "Dokumentacja zgodności", - "webServiceHtaccessHelp": "RustProxy kompiluje ograniczony podzbiór zgodny z Apache podczas zastosowania Web Service. Pliki nie są parsowane przy każdym żądaniu; po zmianie .htaccess na dysku zastosuj Web Service ponownie.", - "webServiceHtaccessDocsTitle": "Zgodność .htaccess", - "webServiceHtaccessDocsIntro": "To warstwa zgodności przeznaczona do migracji, a nie pełne środowisko Apache. Wspierane dyrektywy są kompilowane do reguł Web Servera RustProxy.", - "webServiceHtaccessDocsSupportedTitle": "Wspierany podzbiór", - "webServiceHtaccessDocsRewriteTitle": "Zgodność rewrite", - "webServiceHtaccessDocsRewrite": "Warunki rewrite obsługują testy REQUEST_FILENAME (-f, -d, -s), REQUEST_URI, REQUEST_METHOD, QUERY_STRING, HTTP_HOST, HTTPS, DOCUMENT_ROOT, THE_REQUEST i nagłówki HTTP. Flagi: L, END, R, R=301/302/307/308, QSA, NC, F, OR. PT/NE są akceptowane jako no-op. E= jest akceptowane jako no-op zgodności, ponieważ nagłówki HTTP żądania i tak trafiają do PHP-FPM.", - "webServiceHtaccessDocsPhpTitle": "PHP-FPM", - "webServiceHtaccessDocsPhp": ".htaccess może dodawać rozszerzenia PHP przez AddHandler, ale endpoint PHP-FPM, timeouty i limit współbieżności nadal są kontrolowane w zakładce PHP-FPM Web Service. Składnia Apache SetHandler wskazująca socket proxy celowo nie jest akceptowana.", - "webServiceHtaccessDocsReloadTitle": "Ładowanie i limity", - "webServiceHtaccessDocsReload": "Pliki są odczytywane i kompilowane podczas „Validate, save and apply”. RustProxy nie parsuje .htaccess przy każdym żądaniu. Po zmianie pliku zastosuj konfigurację ponownie. Skan ma limity: 128 plików, głębokość 16, 128 KiB na plik i 1 MiB łącznie.", - "webServiceHtaccessDocsUnsupportedTitle": "To nie jest pełny Apache", - "webServiceHtaccessDocsUnsupported": "ErrorDocument, SetEnvIf, Redirect/RedirectMatch i FallbackResource nie są zaimplementowane w tej warstwie. Ogólne Files/FilesMatch, niewspierane dyrektywy uwierzytelniania/autoryzacji, handlery inne niż PHP i SetHandler są odrzucane nawet przy wyłączonym trybie ścisłym, ponieważ ich ciche pominięcie mogłoby osłabić kontrolę dostępu lub ujawnić kod źródłowy. Pliki .htaccess/.htpasswd są zawsze blokowane przed wysłaniem przez HTTP. Pozostałe niewspierane dyrektywy niesecurity są logowane i ignorowane, chyba że włączono tryb ścisły.", - "webServiceHtaccessDocsSecurity": "ACL vhost/location, uwierzytelnianie, strony błędów i reguły odpowiedzi nadal mają nadrzędną rolę. .htaccess nie może wyjść poza document root, wybrać dowolnego socketu FastCGI ani nadpisać chronionych nagłówków transportowych.", - "webServicePresetTitle": "Preset konfiguracji", - "webServicePreset": "Preset", - "webServicePresetCustom": "Własny", - "webServicePresetStatic": "Strona statyczna", - "webServicePresetSpa": "SPA", - "webServicePresetPhpGeneric": "PHP ogólny", - "webServicePresetDownloads": "Pliki / repozytorium pobrań", - "webServicePresetAction": "Akcja presetu", - "webServicePresetApply": "Zastosuj preset", - "webServicePresetHelp": "Preset wypełnia zwykłe ustawienia Web Service i wszystko nadal można edytować. Document root, ID/nazwa usługi i endpoint PHP-FPM nie są zmieniane.", - "webServicePresetChoose": "Wybierz preset przed jego zastosowaniem.", - "webServicePresetApplied": "Preset zastosowany. Sprawdź wygenerowane ustawienia przed zapisem.", - "webServicePresetHintStatic": "Strona statyczna: indeksy HTML, prekompresowane pliki i reguły cache dla CSS/JS/obrazów/fontów.", - "webServicePresetHintSpa": "SPA: fallback do index.html przez try_files, prekompresowane assety i długi cache zasobów statycznych.", - "webServicePresetHintPhpGeneric": "PHP ogólny: PHP-FPM włączony, index.php pierwszy, bez front-controllera dla brakujących plików.", - "webServicePresetHintWordpress": "WordPress: PHP-FPM, index.php i routing front-controller. Document root ustaw na publiczny katalog WordPressa.", - "webServicePresetHintDrupal": "Drupal: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", - "webServicePresetHintLaravel": "Laravel: PHP-FPM i routing front-controller. Document root ustaw na katalog public/ aplikacji.", - "webServicePresetHintSymfony": "Symfony: PHP-FPM i routing front-controller. Document root ustaw na katalog public/ aplikacji.", - "webServicePresetHintJoomla": "Joomla: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", - "webServicePresetHintPrestashop": "PrestaShop: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", - "webServicePresetHintDownloads": "Pobrania: directory listing włączony, obsługa Range i typowe archiwa/dokumenty wymuszane jako załączniki.", - "webServiceHardeningTitle": "Utwardzenie", - "webServiceHardeningAttacks": "Blokuj typowe próby ataków", - "webServiceHardeningHeaders": "Usuwaj zbędne nagłówki ujawniające technologię", - "webServiceHardeningSecurityHelp": "Przełączniki utwardzenia są widoczne obok wyboru presetu w zakładce Ogólne. Po zastosowaniu presetu pozostają niezależnymi ustawieniami.", - "trafficTabOverview": "Przegląd", - "trafficTabClients": "Klienci", - "trafficTabRequests": "Żądania", - "trafficTabDelivery": "Obsługa odpowiedzi", - "trafficVolume": "Wolumen ruchu", - "vhMethodMode": "Polityka metod HTTP", - "vhMethodList": "Metody HTTP (jedna na linię)", - "vhMethodHelp": "Zezwalaj tylko na podane metody albo blokuj podane metody dla tego vhosta. Reguła łączy się z polityką lokalizacji.", - "locationAclProfile": "Profil ACL", - "locationMethodMode": "Polityka metod HTTP", - "locationMethodList": "Metody HTTP (jedna na linię)", - "locationMethodAllow": "Zezwalaj tylko", - "locationMethodBlock": "Blokuj wskazane", - "locationMethodHelp": "Polityka lokalizacji łączy się z polityką vhosta. Przykład: GET, HEAD i POST.", - "locationCountryMode": "Polityka dostępu krajów", - "locationCountryList": "Kody krajów (jeden na linię)", - "locationCountryHelp": "Polityka krajów lokalizacji łączy się z polityką vhosta/profilu. GeoIP jest odczytywany tylko, gdy jest potrzebny.", - "configHistory": "Historia rewizji", - "configHistoryRetention": "SQLITE / OSTATNIE 512 REWIZJI", - "configHistoryHelp": "Wybierz oznaczony dzień, aby zobaczyć zachowane rewizje konfiguracji i ich zmiany. Historia jest zapisywana od wersji 0.25.3.", - "configHistoryChanges": "ZMIANY", - "configHistorySelectDay": "Wybierz dzień.", - "configHistoryRevision": "Rewizja", - "configHistoryRevisionShort": "rew.", - "configHistoryBefore": "Przed", - "configHistoryAfter": "Po", - "configHistoryBaseline": "To najstarsza zachowana baza; wcześniejsza rewizja nie jest dostępna do porównania.", - "configHistoryNoChanges": "Nie znaleziono różnic w konfiguracji.", - "configHistoryDiffLimit": "Podgląd różnic ograniczono do 200 zmienionych ścieżek.", - "configHistoryMissing": "(brak)", - "configHistoryEntries": "rewizji", - "configHistorySummary": "Zachowane rewizje: {count}", - "configHistoryEmpty": "Brak zachowanych rewizji.", - "configHistoryLoading": "Wczytywanie historii rewizji...", - "configHistoryFailed": "Nie udało się wczytać historii rewizji.", - "configHistoryRestoreAction": "Przywróć rewizję", - "configHistoryRestoreConfirm": "Przywrócić rewizję {revision}? Zostanie zwalidowana i zapisana jako nowa rewizja po bieżącej rewizji {current}. Dotychczasowa historia zostanie zachowana.", - "configHistoryRestored": "Rewizja {revision} została przywrócona jako nowa rewizja {new_revision}.", - "about": "O projekcie", - "aboutTitle": "O RustProxy", - "aboutAuthor": "Autor", - "aboutLicense": "Licencja", - "aboutLicenseValue": "Open Source", - "aboutOpenSourceText": "RustProxy jest projektem open source. Kod źródłowy jest publicznie dostępny do wglądu, rozwoju i współtworzenia.", - "aboutRepository": "Repozytorium źródłowe", - "vhPoolRecycleRequests": "Odśwież pulę upstream po liczbie żądań (0 = wył.)", - "vhPoolRecycleSeconds": "Maks. wiek puli upstream (sekundy, 0 = wył.)", - "vhHttp1MaxBuffer": "Maks. bufor odczytu HTTP/1 upstream (bajty)", - "vhPoolRecycleHelp": "Odświeżanie podmienia tylko generację klienta Hyper danego backendu; aktywne wymiany kończą się normalnie. Domyślne limity ograniczają retencję pamięci puli/TLS bez przeładowania vhosta ani cache. Limit żądań: 0 lub 1000..10000000; limit czasu: 0 lub 60..604800." - } + "meta": { + "locale": "pl-PL", + "name": "Polish", + "native_name": "Polski", + "direction": "ltr" + }, + "translations": { + "overview": "Przegląd", + "mainMenu": "Menu", + "routing": "Starsze trasy", + "configuration": "Konfiguracja", + "manualConfig": "Konfiguracja ręczna", + "runtime": "ŚRODOWISKO", + "localOnly": "ADMINISTRACJA", + "logout": "Wyloguj", + "firstSlice": "NIEZALEŻNY RDZEŃ / JAWNY DOSTĘP", + "loginTitle": "Administracja", + "unlock": "Odblokuj administrację", + "tokenHelp": "Uruchom polecenie w drugim terminalu i wklej token poniżej.", + "token": "Lokalny token dostępu", + "connect": "Połącz z proxy", + "tokenNote": "Administracja domyślnie używa HTTP na loopback. Przed użyciem adresu spoza loopback włącz HTTPS panelu.", + "requests": "Żądania", + "activeExchanges": "Aktywne żądania", + "bodyLifetime": "Do zakończenia strumienia", + "bandwidth": "Przekazane dane", + "bothDirections": "W obu kierunkach", + "errors": "Błędy", + "errorDescription": "5xx / body / przerwane", + "liveTraffic": "RUCH NA ŻYWO", + "liveTransformed": "Transformowane", + "requestsPerSecond": "Żądania na sekundę", + "live": "NA ŻYWO", + "lastMinute": "Ostatnie próbki / reset po odświeżeniu", + "coreState": "STAN RDZENIA", + "configurationRevision": "Aktywna rewizja", + "backends": "Backendy", + "routes": "Trasy", + "connections": "Otwarte połączenia", + "uptime": "Czas działania", + "activity": "AKTYWNOŚĆ", + "accessLog": "Log dostępu", + "boundedLog": "Ostatnie 50 / bufor 4096", + "time": "Czas", + "request": "Żądanie", + "status": "Status", + "duration": "Czas obsługi", + "outcome": "Wynik", + "noTraffic": "Brak ruchu. Otwórz proxy, aby wysłać pierwsze żądanie.", + "reload": "Wczytaj konfigurację", + "addBackend": "Dodaj / edytuj backend", + "backendUrl": "Adres backendu (HTTP / HTTPS, IP / DNS)", + "allowPrivate": "Jawnie zezwól na prywatny IP / loopback", + "preserveHost": "Zachowaj oryginalny nagłówek Host", + "saveBackend": "Zapisz backend", + "clear": "Wyczyść", + "addRoute": "Dodaj / edytuj trasę", + "hostnames": "Hostname i aliasy, oddzielone przecinkami", + "pathPrefix": "Prefiks ścieżki (bez usuwania)", + "backend": "Backend", + "enabled": "Włączona", + "saveRoute": "Zapisz trasę", + "rawConfig": "Dokument konfiguracji", + "export": "Eksportuj JSON", + "configHelp": "Poprawny zapis jest stosowany atomowo. Błędne lub nieaktualne zmiany nie zastępują działającej konfiguracji.", + "apply": "Sprawdź, zapisz i zastosuj", + "noRestart": "Routing i polityki odpowiedzi działają od razu; zmiana portów wymaga restartu.", + "roadmapHelp": "Zmiany w wydaniach i planowane funkcje opisuje plik ROADMAP.md.", + "overviewTitle": "Ruch pod kontrolą.", + "overviewDescription": "Ruch, cache i pomiary systemu operacyjnego w jednym zwartym panelu.", + "routingTitle": "Połącz właściwe adresy.", + "routingDescription": "Dotychczasowy format backendów i tras pozostaje obsługiwany. Nowe konfiguracje mogą używać vhosta z własnym frontendem i pulą.", + "configurationTitle": "Jedno źródło prawdy.", + "configurationDescription": "Jedna konfiguracja: vhosty, listenery i wspolne polityki.", + "connected": "POŁĄCZONO Z LOKALNYM RDZENIEM", + "disconnected": "RDZEŃ NIEDOSTĘPNY", + "edit": "Edytuj", + "remove": "Usuń", + "privateAllowed": "ZGODA NA PRYWATNY IP", + "configured": "SKONFIGUROWANY / BEZ PROBE", + "disabled": "WYŁĄCZONA", + "emptyBackends": "Brak backendów. Dodaj jawny adres HTTP lub HTTPS.", + "emptyRoutes": "Brak tras. Nieznane hostname zwracają 404.", + "saving": "Zapisywanie…", + "unsavedChanges": "Niezapisane zmiany", + "saved": "Zastosowano konfigurację.", + "confirmDelete": "Usunąć ten element? Zmiana zadziała natychmiast.", + "confirmTitle": "Potwierdź operację", + "confirmationLabel": "POTWIERDZENIE", + "warningLabel": "OSTRZEŻENIE", + "continueAction": "Kontynuuj", + "cancelAction": "Anuluj", + "discardAction": "Odrzuć zmiany", + "errorContext": "{area}: {message}", + "stale": "Konfiguracja zmieniła się w innym miejscu. Wczytaj ją przed zapisem.", + "busy": "Trwa już zapis.", + "loginError": "Nie udało się zalogować.", + "fresh": "Wczytano konfigurację.", + "locked": "Wylogowano i unieważniono sesję.", + "backendUsed": "Backend jest używany przez trasę. Najpierw usuń lub zmień trasę.", + "renaming": "Nie można zmienić ID w formularzu. Użyj edytora JSON i zmień również powiązania.", + "complete": "zakończono", + "cancelled": "przerwano", + "body_error": "błąd body", + "proxy_or_upstream_error": "błąd proxy/backendu", + "security": "Bezpieczeństwo", + "sessionNote": "Lokalna administracja HTTP. Hasła używają Argon2id, a cookies sesji są HttpOnly. Nie udostępniaj panelu publicznie.", + "setupHelp": "Utwórz pierwsze konto administratora. Jednorazowy token odczytasz lokalnie w terminalu.", + "setupToken": "Jednorazowy token instalacyjny", + "username": "Nazwa użytkownika", + "password": "Hasło", + "confirmPassword": "Powtórz hasło", + "setupTitle": "Utwórz administratora", + "signIn": "Zaloguj się", + "createAndSignIn": "Utwórz konto i zaloguj", + "securityTitle": "Dostęp pod kontrolą.", + "securityDescription": "Jeden administrator. Odwoływalne sesje. Jawne polityki hostów i tras.", + "manualBackends": "RĘCZNE BACKENDY", + "routePolicies": "Kontrola dostępu i nagłówki", + "useRouteAcl": "Włącz ACL trasy", + "aclDefault": "Domyślna akcja", + "allow": "Zezwól", + "deny": "Zablokuj", + "aclRules": "Jedna reguła w wierszu: allow/deny oraz CIDR", + "aclHelp": "Podaj CIDR IPv4/IPv6, np. 192.168.1.0/24 lub 10.0.0.5/32. Odmowa ma pierwszeństwo. Dozwolone IP nadal wymaga uwierzytelnienia. Lokalizacja nie omija ACL hosta.", + "routeHeaders": "Nagłówki request / response (JSON)", + "headersHelp": "Operacje: ustaw, dodaj, usuń. Nagłówki transportu, kodowania body i tożsamości klienta są chronione.", + "currentSession": "BIEŻĄCA SESJA", + "recoveryHelp": "Utrata dostępu? Uruchom lokalnie rust-proxy admin reset-password. Dotychczasowe sesje zostaną unieważnione.", + "revokeAll": "Wyloguj wszystkie sesje", + "changePassword": "Zmień hasło", + "currentPassword": "Obecne hasło", + "newPassword": "Nowe hasło (12-128 bajtów UTF-8)", + "savePassword": "Zmień i wyloguj", + "hostPolicies": "Polityki dostępu hostów", + "editHostPolicy": "Dodaj / zastąp politykę hosta", + "savePolicy": "Zastosuj politykę", + "auditRetention": "SQLITE / OSTATNIE 100 / LIMIT 10 000", + "audit": "Audyt administracyjny", + "reloadAudit": "Odśwież", + "actor": "Użytkownik", + "action": "Operacja", + "detail": "Szczegóły", + "noAudit": "Brak wpisów audytu.", + "noPolicies": "Brak ACL hostów. Dostęp mogą ograniczać reguły tras.", + "expires": "Sesja wygaśnie najpóźniej: ", + "passwordChanged": "Zmieniono hasło i unieważniono sesje. Zaloguj się ponownie.", + "passwordMismatch": "Hasła nie są takie same.", + "ruleSyntax": "Wpisz jedną regułę w wierszu, np. allow 127.0.0.1/32", + "confirmRevoke": "Wylogować wszystkie sesje, również bieżącą?", + "streamLive": "SSE na żywo", + "streamFallback": "Odpytywanie awaryjne", + "auth.required": "Sesja wygasla lub zostala odwolana. Zaloguj sie ponownie.", + "auth.invalid_credentials": "Nieprawidłowa nazwa użytkownika lub hasło.", + "auth.password_policy": "Haslo musi miec 12-128 bajtow UTF-8, bez znakow nowego wiersza.", + "auth.invalid_username": "Uzyj 3-64 liter, cyfr, kropek, myslnikow lub podkreslen.", + "auth.invalid_setup_token": "Niepoprawny token instalacyjny. Odczytaj go w lokalnym terminalu.", + "auth.already_initialized": "Administrator juz istnieje. Zaloguj sie.", + "auth.rate_limited": "Zbyt wiele prob. Ponow po 60 sekundach lub uzyj lokalnego resetu hasla.", + "auth.busy": "Trwa weryfikacja innych hasel. Ponow za chwile.", + "auth.csrf": "Niepoprawna ochrona zadania. Odswiez strone i ponow.", + "auth.invalid_host": "Użyj skonfigurowanego adresu administracji i dozwolonej nazwy hosta.", + "auth.invalid_origin": "Zablokowano dostep administracyjny z innego originu.", + "auth.credentials_changed": "Dane logowania zostaly zmienione. Zaloguj sie ponownie.", + "auth.unavailable": "Baza administracyjna jest chwilowo niedostepna.", + "events.too_many_viewers": "Osiagnieto limit odbiorcow SSE; pozostaje odpytywanie.", + "protocol": "Protokół upstream", + "protocolHelp": "HTTP/2 i auto używają authority backendu. Preserve Host jest dostępne tylko z HTTP/1.1. RFC 8441 może użyć jawnego upstreamu HTTP/2; pozostałe transporty WebSocket są mostkowane przez HTTP/1.1.", + "addressAllowlist": "Opcjonalna lista dozwolonych adresów (CIDR, po jednym w wierszu)", + "caPem": "Dodatkowy zaufany CA / certyfikat (PEM, opcjonalnie)", + "backendTlsHelp": "Szyfrowanie TLS pozostaje dostępne, ale weryfikacja certyfikatu i nazwy jest domyślnie wyłączona, dopóki nie włączysz jej jawnie. Prywatne adresy nadal wymagają zgody, także po rozwiązaniu DNS.", + "advancedTransport": "Transport i zaufanie", + "tls": "Certyfikaty", + "tlsTitle": "Szyfrowanie pod kontrolą.", + "tlsDescription": "Dokładne nazwy SNI. Prywatne pliki certyfikatów. Zmiany bez restartu.", + "certificateBindings": "Powiązania certyfikatów", + "addCertificate": "Dodaj certyfikat", + "certificateId": "ID certyfikatu", + "certificateFile": "Nazwa pliku certyfikatu", + "privateKeyFile": "Nazwa pliku klucza prywatnego", + "defaultCertificate": "Użyj jako certyfikatu domyślnego", + "saveCertificate": "Zastosuj certyfikat", + "reloadCertificates": "Wczytaj pliki certyfikatów", + "certificateHelp": "Wgraj parę PEM, wskaż pliki w data/certs albo wdrażaj certyfikat z zewnętrznego wystawcy poleceniem `./dev.sh tls deploy --id ID --cert FULLCHAIN --key PRIVKEY`. Wczytanie ponownie odczytuje skonfigurowane pliki bez zmiany revision.", + "certificateHint": "Hook Certbota: ./dev.sh tls deploy --id shared-cert --cert /etc/letsencrypt/live/example/fullchain.pem --key /etc/letsencrypt/live/example/privkey.pem", + "emptyCertificates": "Brak jawnych powiązań SNI. Aktywny listener TLS używa wygenerowanego certyfikatu domyślnego.", + "certificateSafety": "Certyfikaty samopodpisane służą do testów. Certyfikat nie tworzy trasy. Zmiana dotyczy nowych połączeń TLS.", + "wsActive": "Tunele WebSocket", + "h2Requests": "Żądania HTTP/2", + "h2ActiveConnections": "Aktywne połączenia H2", + "tlsFailures": "Błędy handshake TLS", + "tlsListener": "Listener TLS", + "notEnabled": "Wyłączony", + "websocket_closed": "WebSocket zamknięty", + "defaultLabel": "DOMYŚLNY", + "language": "Język", + "settings": "Ustawienia", + "settingsTitle": "Ustawienia proxy.", + "settingsDescription": "Przelaczaj karty funkcji. Niezapisane zmiany pozostaja w formularzach.", + "cacheHitRatio": "Trafienia cache", + "processMemory": "Pamięć procesu", + "systemLoad": "OBCIĄŻENIE SYSTEMU", + "systemChart": "Ostatnie próbki obciążenia CPU", + "systemMemory": "RAM systemu", + "systemSwap": "Swap systemu", + "systemUptime": "Czas działania systemu", + "loadAverage": "Load 1 / 5 / 15 min", + "cacheOverview": "Cache RAM", + "cacheObjects": "Obiekty / pamięć", + "cacheEvictions": "Usunięte / wygasłe", + "processDiagnostics": "Proces", + "platform": "Platforma", + "processCpu": "CPU (100% = 1 rdzeń)", + "fileDescriptors": "Deskryptory / limit", + "processThreads": "Wątki systemowe", + "processVirtualMemory": "Pamięć wirtualna / limit", + "processStartTime": "Start procesu", + "containerMemory": "RAM cgroup / limit", + "networkDiagnostics": "Sieć i odpowiedzi", + "hostScope": "Zakres systemu", + "networkRate": "RX / TX na sekundę", + "meanLatency": "Średni czas obsługi", + "filterLogs": "Filtruj host lub ścieżkę", + "filterResult": "Filtruj wynik", + "allResults": "Wszystkie", + "routeCache": "Cache dla trasy", + "inheritCache": "Dziedzicz ustawienia globalne", + "bypassCache": "Zawsze pomijaj cache", + "listeners": "Listenery", + "httpConnections": "Połączenia HTTP", + "httpConnectionsHelp": "Cykl życia połączeń i limity transportu dla HTTP/2 oraz HTTP/3.", + "http2Tab": "HTTP/2", + "http3Tab": "HTTP/3", + "http2Settings": "Połączenia HTTP/2", + "http2SettingsHelp": "HTTP/2 włącza się osobno dla każdego listenera. Tutaj ustawisz bezczynność, maksymalny czas życia i graceful drain po GOAWAY.", + "http2IdleTimeout": "Idle timeout (sekundy)", + "http2MaxLifetime": "Maksymalny czas życia połączenia (sekundy, 0 = wyłączony)", + "http2DrainTimeout": "Drain timeout (sekundy)", + "http2DrainHelp": "Te limity dotyczą tego listenera. Idle timeout obejmuje tylko nieużywane połączenia, maksymalny lifetime jest bezwzględny, a drain ogranicza czas aktywnych strumieni po GOAWAY. Zmiany wymagają restartu.", + "http2Save": "Zapisz ustawienia HTTP/2", + "http2NoEnabledListeners": "Żaden listener nie ma włączonego HTTP/2. Najpierw włącz HTTP/2 lub h2c w Ustawienia > Listenery.", + "http2ListenersDirty": "Najpierw zapisz oczekujące zmiany w Listenerach, a następnie edytuj ustawienia HTTP/2.", + "restartLabel": "RESTART", + "listenersHelp": "Nazwane adresy IP i porty. Zmiany wymagają restartu. Panel administracyjny pozostaje osobno.", + "httpAddress": "Adres nasłuchu i port HTTP", + "httpsAddress": "Adres nasłuchu i port HTTPS", + "enableHttps": "Włącz nasłuch HTTPS", + "lowPortsHelp": "Porty uprzywilejowane mogą wymagać CAP_NET_BIND_SERVICE. Nie uruchamiaj całej aplikacji jako root.", + "saveListeners": "Zapisz ustawienia portów", + "inheritListeners": "Użyj ustawień startowych", + "responseSettings": "Odpowiedź do klienta", + "hotApply": "BEZ RESTARTU", + "serverHeader": "Nagłówek Server", + "serverPreserve": "Zachowaj wartość backendu", + "serverHide": "Ukryj całkowicie", + "serverCustom": "Nadpisz / dodaj własną wartość", + "serverValue": "Własna wartość Server", + "compression": "Kompresja strumieniowa", + "compressionMin": "Minimalny rozmiar odpowiedzi (bajty)", + "compressionHelp": "Negocjacja Accept-Encoding. Pomija dane prywatne, cookies, zakresy, SSE i no-transform. Nie kompresuje ponownie zakodowanych odpowiedzi.", + "saveResponse": "Zastosuj ustawienia odpowiedzi", + "cacheSettings": "Cache", + "enableCache": "Włącz cache", + "cacheSafety": "Cache zapisuje kompletne, bezpieczne odpowiedzi GET. Authorization, cookies oraz odpowiedzi private/no-store nadal omijają cache. Pojedynczy zakres bajtów może być obsłużony z pełnego obiektu cache; multipart i nieobsługiwane zakresy przechodzą do originu.", + "cacheMemory": "Limit alokowanej pamięci HOT (MiB)", + "cacheObject": "Limit obiektu (KiB)", + "cacheEntries": "Maksymalna liczba wpisów", + "cacheMaxTtl": "Maksymalny TTL (sekundy)", + "cacheDefaultTtl": "Zapasowy TTL odpowiedzi publicznych (0 = wył.)", + "bypassQuery": "Pomijaj adresy z parametrami query", + "cachePrefixes": "Pomijane prefiksy ścieżek, po jednym w wierszu", + "cacheAgeHelp": "Trafienia zawsze zawierają Age. Liczniki działają również przy ukrytych nagłówkach diagnostycznych. Tylko zmiany wpływające na cache unieważniają niezgodne obiekty; podczas zarządzanej aktualizacji hot cache jest przenoszony do cold storage, jeśli cold tier jest włączony.", + "saveCache": "Zastosuj ustawienia cache", + "purgeCache": "Wyczyść cały cache", + "customHeaders": "Globalne reguły nagłówków", + "globalHeadersHelp": "Request trafia do backendu, response do klienta. Reguły trasy są stosowane po globalnych. Polityka Server ma ostateczne pierwszeństwo.", + "responseHeaders": "Odpowiedź do klienta", + "requestHeaders": "Żądanie do backendu", + "addHeader": "Dodaj regułę nagłówka", + "saveHeaders": "Zastosuj reguły nagłówków", + "unavailable": "Brak danych", + "threads": "wątków", + "realSample": "Pomiar", + "noKnownLimit": "nieznany / bez limitu", + "unlimited": "bez limitu", + "restartPending": "Zapisano zmianę portów. Uruchom ponownie RustProxy, aby ją zastosować.", + "activeListeners": "Aktualnie aktywne", + "headerLimit": "Maksymalnie 32 reguły w każdym kierunku.", + "headerOperation": "Operacja", + "header_set": "Ustaw", + "header_append": "Dodaj", + "header_remove": "Usuń", + "headerName": "Nazwa nagłówka", + "headerValue": "Wartość nagłówka", + "confirmInherit": "Przywrócić ustawienia portów z parametrów startowych i środowiska po restarcie?", + "confirmPurge": "Usunąć wszystkie obiekty cache i anulować zapis trwających pobrań?", + "cachePurged": "Cache wyczyszczony; usunięte wpisy", + "logsDropped": "odrzucone", + "updateAvailable": "Nowa wersja", + "vhosts": "Vhosty", + "vhostsTitle": "Vhosty i backendy", + "vhostsDescription": "Zarządzaj domenami, frontendami, backendami i politykami hostów.", + "vhHealthTitle": "Backendy", + "vhManage": "Zarządzaj vhostami", + "vhHealthHint": "Stan bieżący: aktywność obejmuje całą wymianę; transfer to średnia EWMA danych.", + "vhHealthEmpty": "Brak danych diagnostycznych backendów.", + "vhVhost": "Vhost", + "vhActive": "Aktywne", + "vhRequests": "Żądania", + "vhErrors": "Błędy", + "vhLatency": "Opóźnienie (EWMA)", + "vhTraffic": "Transfer/s", + "vhClientGeneration": "Gen. klienta", + "vhGenerationRequests": "Żądania gen.", + "vhGenerationAge": "Wiek gen.", + "vhClientRotations": "Rotacje", + "vhIntro": "Każdy vhost ma własne adresy IP, ścieżki i backendy. Inne adresy go nie obsługują. Zmiana nasłuchu wymaga restartu.", + "vhList": "Hosty wirtualne", + "vhSearch": "Szukaj vhostów", + "vhSearchPlaceholder": "Szukaj domeny, vhosta lub backendu", + "vhSearchEmpty": "Brak vhostów pasujących do wyszukiwania.", + "vhNew": "Nowy vhost", + "vhMigrate": "Migracja grupy starszych tras", + "vhImport": "Wczytaj do edytora", + "vhMigrationHint": "Migracja jest atomowa. Trasy tych samych hostów i backendu są grupowane; niejednoznaczne przypisanie hostów jest odrzucane.", + "vhEditor": "Konfiguracja vhosta", + "vhReset": "Odrzuć zmiany", + "vhSafetyHint": "Prywatny IP nie zastępuje uwierzytelniania. Zachowaj firewall i ACL. Preload HSTS jest opcjonalny; cookie affinity nie jest sesją logowania.", + "vhId": "Identyfikator vhosta", + "vhHosts": "Nazwy hostów", + "vhEnabled": "Włączony", + "vhFrontends": "Frontendy / adresy nasłuchu", + "vhAddFrontend": "Dodaj frontend", + "vhAddress": "IP:port (IPv6: [adres]:port)", + "vhTls": "TLS włączony", + "vhHttp2": "Preferuj HTTP/2 przez TLS; zachowaj HTTP/1.1", + "vhBackendPool": "Backendy", + "vhAddBackend": "Dodaj backend", + "vhMemberId": "Identyfikator backendu", + "vhUrl": "Adres URL backendu", + "vhWeight": "Waga", + "vhBackup": "Tylko zapasowy", + "vhDrain": "Wstrzymaj nowe sesje", + "vhPrivate": "Zezwól na prywatny IP backendu", + "vhPreserveHost": "Zachowaj Host klienta (tylko HTTP/1.1)", + "vhProtocol": "Protokół backendu", + "vhProtocolHttp1": "HTTP/1.1", + "vhProtocolAuto": "TLS ALPN: HTTP/2 + HTTP/1.1", + "vhProtocolHttp2": "HTTP/2 (TLS: także HTTP/1.1; bez TLS: h2c)", + "vhAddressAllowlist": "Dozwolone IP/CIDR backendu (opcjonalne)", + "vhTlsServerName": "Nazwa serwera TLS / SNI (opcjonalna)", + "vhTlsVerify": "Weryfikuj certyfikat i nazwę hosta backendu", + "vhTlsVerifyHelp": "Przy pominięciu ustawienia weryfikacja jest wyłączona. Włącz ją, gdy RustProxy ma weryfikować łańcuch i tożsamość certyfikatu backendu. Jeśli walidacja nie przechodzi, ustaw nazwę serwera TLS na nazwę DNS obecną w certyfikacie i/lub dodaj PEM prywatnego CA. Nie używaj adresu IP jako SNI.", + "vhCa": "Dodatkowy zaufany CA (PEM, opcjonalny)", + "vhBalancing": "Balansowanie i ponowne użycie połączeń", + "vhAlgorithm": "Algorytm", + "vhRoundRobin": "Płynny ważony round-robin", + "vhLeastConnections": "Najmniej aktywnych wymian, z wagami", + "vhLeastTraffic": "Najmniejszy transfer (EWMA), z wagami", + "vhAdaptive": "Adaptacyjny: aktywność + opóźnienie + transfer", + "vhIpHash": "Skrót IP klienta", + "vhSlowStart": "Łagodny powrót (sekundy)", + "vhRetryMax": "Ponowienia failover", + "vhRetryConnect": "Ponawiaj błędy połączenia", + "vhRetryTimeouts": "Ponawiaj timeout nagłówków odpowiedzi", + "vhRetryStatuses": "Ponawiane statusy HTTP", + "vhRetryHelp": "Retry działa tylko dla bezbody GET, HEAD i OPTIONS, wybiera inny zdrowy backend i nigdy nie ponawia WebSocketów ani żądań zapisu.", + "vhKeepalive": "Używaj ponownie połączeń do backendu (keepalive)", + "vhIdleTimeout": "Limit bezczynności w puli (sekundy)", + "vhMaxIdle": "Maks. bezczynnych połączeń / backend", + "vhTcpKeepalive": "Interwał keepalive TCP / HTTP/2 (sekundy)", + "vhHealth": "Zdrowie backendów", + "vhHealthMode": "Rodzaj testu", + "vhOff": "Wyłączone", + "vhTcp": "Połączenie TCP", + "vhHttp": "Status HTTP + czas odpowiedzi", + "vhHealthPath": "Ścieżka testu HTTP", + "vhHealthHost": "Własny Host testu HTTP (opcjonalny)", + "vhInterval": "Interwał (ms)", + "vhTimeout": "Limit czasu (ms)", + "vhSlow": "Próg wolnej odpowiedzi (ms; 0 = wył.)", + "vhFall": "Niepowodzenia przed wyłączeniem", + "vhRise": "Sukcesy przed przywróceniem", + "vhStatusMin": "Minimalny status HTTP", + "vhStatusMax": "Maksymalny status HTTP", + "vhHealthNote": "Testy HTTP używają HTTP/1.1 i mierzą czas do nagłówków, nie całej treści. Dla usług tylko h2c wybierz TCP. Nowe backendy czekają na udane testy. Aktywny health-check jest niezależny od pasywnego.", + "vhPassiveHealth": "Pasywne zdrowie backendu", + "vhPassiveEnabled": "Pozwól, aby błędy zwykłych requestów oznaczały backend jako niedostępny", + "vhPassiveHelp": "Domyślnie wyłączone. Błędy nadal są logowane i zliczane, ale zwykły ruch użytkowników nie zmienia stanu backendu bez świadomego włączenia.", + "vhPassiveConnect": "Zliczaj błędy połączenia", + "vhPassiveTimeouts": "Zliczaj timeouty", + "vhPassiveIo": "Zliczaj błędy I/O body/odczytu/zapisu", + "vhPassive5xx": "Zliczaj odpowiedzi HTTP 5xx", + "vhPassiveSlow": "Zliczaj wolne odpowiedzi", + "vhPassiveFall": "Pasywne błędy przed wyłączeniem (puste = active fall)", + "vhPassiveRise": "Pasywne sukcesy przed przywróceniem (puste = active rise)", + "vhPassiveWarning": "Włączenie 5xx lub wolnych odpowiedzi może wyłączyć cały backend po serii błędów z pojedynczego endpointu.", + "vhSticky": "Sticky sessions", + "vhStickyMode": "Tryb przypisania", + "vhCookie": "Nieprzezroczyste cookie proxy", + "vhCookieName": "Nazwa cookie (pusta = domyślna per vhost)", + "vhCookieTtl": "Ważność cookie (sekundy)", + "vhStickyNote": "Sticky cookie omija współdzielony cache. Drain zachowuje istniejące sesje cookie. Przypisanie po IP używa zweryfikowanego adresu klienta zgodnie z polityką zaufanych proxy.", + "vhSecurity": "Bezpieczeństwo", + "vhHsts": "Włącz HSTS (tylko odpowiedzi TLS)", + "vhHstsAge": "HSTS max-age (sekundy)", + "vhHstsSub": "HSTS includeSubDomains", + "vhHstsPreload": "HSTS preload (świadome włączenie)", + "vhNosniff": "X-Content-Type-Options: nosniff", + "vhFrame": "X-Frame-Options", + "vhPreserve": "Zachowaj wartość backendu", + "vhDeny": "DENY", + "vhSameorigin": "SAMEORIGIN", + "vhReferrer": "Referrer-Policy (opcjonalne)", + "vhCsp": "Content-Security-Policy (opcjonalne)", + "vhPermissions": "Permissions-Policy (opcjonalne)", + "vhAdvanced": "Zaawansowane: ścieżki, ACL i własne nagłówki", + "vhPaths": "Sciezki (JSON; opcjonalne backend_id przypina sciezke do jednego backendu)", + "vhAcl": "ACL vhosta (JSON lub null)", + "vhHeaders": "Reguły nagłówków żądania / odpowiedzi (JSON)", + "vhEmpty": "Brak vhostów. Dotychczasowe trasy nadal działają.", + "vhUnsaved": "Odrzucić niezapisane zmiany vhosta?", + "vhDelete": "Usunąć vhost? Gniazda nasłuchu zostaną zamknięte po restarcie.", + "vhConflict": "Vhost o takim identyfikatorze już istnieje.", + "vhRowLimit": "Osiągnięto maksymalną liczbę wierszy.", + "vhMigrationAmbiguous": "Hosty pokrywają się z innymi trasami. Uporządkuj przypisanie w JSON przed migracją.", + "vhMigrationPending": "Migracja starszych tras zostanie zatwierdzona przy zapisie.", + "vhMigrationNone": "Wybierz starszą trasę", + "vhJsonInvalid": "Nieprawidłowy JSON lub typ danych w ścieżkach, ACL lub nagłówkach.", + "vhUp": "Działa", + "vhDown": "Niedostępny", + "vhChecking": "Sprawdzanie", + "vhDraining": "Wygaszanie", + "vhDisabled": "Wyłączony", + "vhHealthDisabled": "Testy wyłączone", + "vhHealthUnknown": "Nieznany", + "vhNewLabel": "NOWY", + "vhEditLabel": "EDYCJA", + "vhFrontendNote": "Użyj IP przypisanego do serwera. Wildcard przyjmuje wszystkie IP danej rodziny; routing nadal sprawdza lokalny adres docelowy. Certyfikaty ustaw w zakładce TLS.", + "close": "Zamknij", + "inherit": "Dziedzicz", + "liveLogs": "Logi na żywo", + "logVhost": "Filtruj vhost", + "logAllVhosts": "Wszystkie vhosty", + "logAllMethods": "Wszystkie metody", + "logPause": "Wstrzymaj", + "logPaused": "WSTRZYMANO", + "logResume": "Wznów", + "logPin": "Przypnij", + "logUndock": "Otwórz modalnie", + "logColumns": "Kolumny", + "logColumnsRequired": "Co najmniej jedna kolumna Live Logs musi pozostać widoczna.", + "logLoadHistory": "Zwiększ bufor", + "logHistoryLoaded": "Bufor live zwiększono do {count} zachowanych wpisów.", + "logHost": "Host", + "logBufferHint": "Widok na żywo zaczyna od ostatnich 256 zakończonych wymian. Zwiększenie bufora wczytuje zachowaną historię i dalej dopisuje logi na żywo do 4096 wpisów, aż do zamknięcia okna. Eksport obejmuje aktualnie przefiltrowane wiersze.", + "settingsSecurityHint": "Konta i ACL są globalne. SSL, HSTS, nagłówki i cache konfigurujesz także wewnątrz vhosta.", + "theme": "Motyw", + "themeDark": "Ciemny", + "themeLight": "Jasny", + "density": "Gęstość interfejsu", + "densityCompact": "Kompaktowy", + "densityDense": "Gęsty", + "densityComfortable": "Przestronny", + "globalPages": "Domyślne odpowiedzi", + "pagesHelp": "Strony dla adresu IP, nieznanych hostów i błędów. Pusty status zachowuje kod odpowiedzi. Strony statyczne nie odpytują backendu.", + "pageInherit": "Domyślna / dziedziczona", + "pageWelcome": "Strona gratulacyjna", + "pageEmpty": "Pusta odpowiedź", + "pageHtml": "Własny HTML", + "pageStatus": "Kod odpowiedzi", + "pageOriginalStatus": "Oryginalny status", + "pageHtmlSource": "Kod HTML", + "pageUploadHtml": "Opcjonalny plik HTML (maks. 32 KiB)", + "pageTooLarge": "HTML nie może przekraczać 32 KiB w UTF-8.", + "customErrorPages": "Własne strony błędów", + "pageStaticHost": "Host statyczny / przerwa techniczna", + "pageMissingPath": "Niepasująca ścieżka", + "pageDirectIp": "Wejście bezpośrednio po IP", + "pageUnknownHost": "Nieznany host", + "pagesSafetyHint": "HTML to treść publiczna. ACL nadal działa przed odpowiedzią. Jawne HTTP 200 dla błędu ukrywa kod przed klientami i monitoringiem. Cała konfiguracja ma limit rozmiaru.", + "vhDetailsTab": "Szczegóły", + "vhSsl": "Certyfikaty SSL", + "vhCertificate": "Wybrany certyfikat", + "vhCertificateDefault": "Globalne SNI / certyfikat domyślny", + "vhCertificateFile": "Certyfikat / pełny łańcuch (PEM)", + "vhPrivateKeyFile": "Klucz prywatny (PEM)", + "vhUploadCertificate": "Wgraj i zweryfikuj parę", + "vhSelectCertificateFiles": "Wybierz plik certyfikatu i klucza prywatnego.", + "vhCertificateTooLarge": "Każdy plik PEM ma limit 128 KiB.", + "vhCertificateNeedsHosts": "Najpierw wpisz domeny vhosta w Szczegółach.", + "vhCertificateStaged": "Para zweryfikowana i zapisana. Zapisz vhost, aby aktywować certyfikat.", + "vhCertificateUploadHint": "Upload sprawdza zgodność klucza i domen. Klucz trafia do prywatnego pliku, nie do API. Zapis vhosta aktywuje wybór. Upload nie zapisuje pozostałych zmian. Zmiany listenerów wymagają restartu.", + "vhCache": "Cache", + "vhCacheTtl": "Maks. TTL (sekundy, puste = dziedzicz)", + "vhCacheDefault": "Domyślny TTL public (puste = dziedzicz)", + "vhCacheObject": "Limit obiektu (KiB, puste = dziedzicz)", + "cacheEnabled": "Włącz cache", + "cacheBypassQuery": "Pomijaj adresy z parametrami", + "cacheStatusHeader": "Dodaj X-Cache", + "cacheHitsHeader": "Dodaj X-Cache-Hits", + "cacheRfcHeader": "Dodaj Cache-Status", + "cacheBypassPrefixes": "Pomijane prefiksy ścieżek", + "vhCacheCustomPrefixes": "Nadpisz odziedziczone pomijane ścieżki", + "vhCacheHint": "Polityka hosta może włączyć cache niezależnie od ustawienia globalnego. Vhosty współdzielą limit RAM i wpisów. Sticky cookie, dane prywatne i autoryzacja nadal omijają cache.", + "vhPurgeCache": "Wyczyść cache hosta", + "vhPurgeConfirm": "Wyczyścić cache tylko tego vhosta? Trwające zapisy tego hosta także zostaną unieważnione.", + "vhPages": "Strony błędów", + "vhHeadersOrder": "Kolejność: reguły globalne, vhost, ścieżka, następnie security/Server. Nadal dostępny jest zaawansowany JSON.", + "vhNewHealthHint": "Zapisz vhost, aby rozpocząć obserwację backendów.", + "listenerAdd": "Dodaj listener", + "listenerMigrate": "Zamień domyślne porty na nazwane listenery", + "listenerScopeHint": "Wewnętrzny / publiczny to etykieta, nie firewall. Nowe listenery nie udostępniają starych tras bez jawnego wyboru.", + "listenerLimit": "Maksymalnie 64 nazwane listenery.", + "listenerEndpoint": "Listener", + "listenerName": "Nazwa wyświetlana", + "listenerScope": "Etykieta", + "listenerInternal": "Wewnętrzny", + "listenerPublic": "Publiczny", + "listenerLegacy": "Udostępnij stare trasy", + "listenerInUse": "Listener jest przypisany do vhostów", + "listenerDuplicate": "Identyfikatory listenerów muszą być unikalne.", + "listenerChooseHint": "Wybierz nazwane listenery skonfigurowane w Ustawienia > Listenery. Wyłączony listener nie daje dostępu.", + "listenerMissing": "Brakujący listener", + "http3Settings": "HTTP/3 / QUIC", + "http3SettingsHelp": "HTTP/3 włącza się w Ustawienia > Listenery. Tutaj ustawisz ogłaszanie usługi oraz limity połączeń i strumieni.", + "http3NoTlsListeners": "Brak listenerów TLS. Najpierw dodaj i zapisz listener TLS.", + "http3NoEnabledListeners": "Żaden listener TLS nie ma włączonego HTTP/3. Najpierw włącz HTTP/3 w Ustawienia > Listenery.", + "http3ListenersDirty": "Najpierw zapisz oczekujące zmiany w Listenerach, a następnie edytuj ustawienia HTTP/3.", + "http3Save": "Zapisz ustawienia HTTP/3", + "h2Configure": "Ustaw limity HTTP/2", + "h3Enable": "Włącz HTTP/3 przez QUIC (UDP)", + "h3Configure": "Ustaw limity HTTP/3", + "h3Limits": "Limity HTTP/3 i ogłaszanie usługi", + "h3_alt_svc_max_age": "Ważność Alt-Svc (s)", + "h3_max_concurrent_connections": "Połączenia na listener", + "h3_max_concurrent_bidistream": "Strumienie dwukierunkowe na połączenie", + "h3_max_concurrent_unistream": "Strumienie jednokierunkowe na połączenie", + "h3_max_idle_timeout": "Bezczynność QUIC (s; 0 = bez limitu)", + "h3Help": "HTTP/3 wymaga TLS. Udostępnij TCP i UDP na tym samym porcie; HTTP/1.1 i HTTP/2 pozostają. Zero wyłącza lokalny timeout QUIC. Zmiana wymaga restartu.", + "h3TuningHelp": "Te limity obowiązują tylko wtedy, gdy HTTP/3 jest włączone dla danego listenera TLS. Zmiana wymaga restartu.", + "h3Requests": "Żądania HTTP/3", + "certImport": "Importuj certyfikat", + "certImportSave": "Importuj i zapisz w bibliotece", + "certLibraryHint": "Wgraj certyfikat/fullchain i klucz prywatny PEM. Zapisz raz, następnie przypisz certyfikat do jednego lub wielu vhostów.", + "certCheckDomains": "Domeny do sprawdzenia (po przecinku)", + "certAcmeLater": "Wydane certyfikaty trafiaja do biblioteki i sa przypisywane do vhostow.", + "certAdvanced": "Istniejące pliki / zaawansowane", + "certLegacyNames": "Stare nazwy SNI (opcjonalne; zalecane przypisanie w vhoście)", + "certAssigned": "Przypisane vhosty", + "certUnassigned": "Nieprzypisany", + "certInUse": "Certyfikat jest używany. Zmień przypisania vhostów i certyfikat domyślny przed usunięciem.", + "certDuplicate": "Ten identyfikator certyfikatu istnieje. Do bezpiecznej rotacji użyj nowego.", + "certManage": "Zarządzaj biblioteką certyfikatów", + "certSelectHint": "Wybierz zaimportowany certyfikat. Import i rotacja są w zakładce Certyfikaty. Przypisania są sprawdzane względem nazw vhosta.", + "vhTinyauth": "Uwierzytelnianie i dostęp IP", + "vhTabAuth": "Uwierzytelnianie", + "taEnable": "Włącz ochronę Tinyauth", + "taUrl": "URL Tinyauth / punkt weryfikacji", + "taLogin": "Publiczny URL logowania", + "taRedirectForbidden": "Akceptuj przekierowanie Tinyauth dla 403 (ten sam origin)", + "taConnect": "Limit połączenia (s)", + "taTimeout": "Łączny limit weryfikacji (s)", + "taRequestHeaders": "Nagłówki klienta do Tinyauth", + "taResponseHeaders": "Zweryfikowane nagłówki tożsamości do aplikacji", + "taHelp": "Do adresu serwera dodawane jest /api/auth/nginx. Weryfikacja bez body działa przed cache i WebSocket. Chronione odpowiedzi mają private, no-store. Ustaw w Tinyauth zaufanie do rzeczywistego IP RustProxy.", + "vhResponsePolicy": "Identyfikacja odpowiedzi i diagnostyka", + "vhInherit": "Dziedzicz ustawienia globalne", + "diagnosticHeaders": "Diagnostyczne nagłówki odpowiedzi", + "diagInherit": "Dziedzicz nagłówki diagnostyczne", + "diagRequestId": "Udostępnij X-Request-ID", + "hideMockOrigin": "Ukryj X-Mock-Origin", + "diagHelp": "X-Request-ID jest opcjonalny. Pozostale naglowki odpowiedzi upstreamu kontroluj zwyklymi regulami naglowkow odpowiedzi.", + "forwardingSettings": "Tożsamość klienta / forwarding", + "forwardingHelp": "Domyślnie nagłówki forwarding od klienta są usuwane. Dodaj tylko kontrolowane proxy. Łańcuch jest sprawdzany od prawej do pierwszego niezaufanego adresu.", + "forwardingCanonical": "RustProxy generuje Forwarded, X-Forwarded-For, X-Real-IP, X-Forwarded-Host, X-Forwarded-Proto, X-Forwarded-Port i X-Forwarded-URI. Adres docelowy połączenia nigdy nie pochodzi z nagłówka.", + "trustedProxies": "Zaufane sieci proxy CIDR (po jednej w wierszu; /32 dla IPv4, /128 dla IPv6)", + "trustForwardedProto": "Ufaj X-Forwarded-Proto tylko od zaufanych proxy", + "listenerId": "ID listenera", + "cache": "Cache", + "cacheTitle": "Cache pod kontrolą.", + "cacheDescription": "Obiekty, skuteczność domen i dokładne przyczyny decyzji.", + "cacheRefresh": "Odśwież", + "cacheLive": "Na żywo (3 s)", + "cachePurgeScope": "Wyczyść wybrany zakres", + "cacheObjectCount": "Obiekty w pamięci", + "cacheSaved": "Dane odpowiedzi z RAM", + "cacheCounterScope": "Liczniki domen od zmiany konfiguracji", + "cacheDomains": "Domeny i skuteczność", + "cacheScopeHint": "Limity RAM, zapisy i usunięcia są globalne. Liczniki domen zerują się przy zmianie konfiguracji; czyszczenie obiektów ich nie zeruje.", + "cacheDomain": "Domena", + "cacheReasons": "Liczniki decyzji", + "cacheNoDomains": "Brak decyzji cache. Wyślij żądania do skonfigurowanego hosta.", + "cacheObjectList": "Zapisane obiekty", + "cachePrevious": "Poprzednie", + "cacheNext": "Następne", + "cacheObjectHint": "Najpierw ostatnio używane. Kliknij Target albo Cache key / tags, aby skopiować pełną wartość. Treści i nagłówki żądań nie są ujawniane.", + "cachePath": "Ścieżka", + "cacheBodySize": "Treść", + "cacheAge": "Wiek", + "cacheTtlRemaining": "Pozostały TTL", + "cacheNoObjects": "Brak świeżych obiektów w tym zakresie. Sprawdź powyższe liczniki decyzji.", + "cacheLegacy": "Nieprzypisane", + "cacheGlobalLimit": "Limit globalny", + "cacheFills": "Aktywne zapisy (globalnie)", + "cacheRejected": "Odrzucone zapisy (globalnie)", + "cacheUpdated": "Aktualizacja", + "acmeTitle": "Let's Encrypt / ACME", + "acmeHelp": "Wydaj certyfikat ACME, dodaj go do biblioteki i przypisz do vhosta. Automatyczne odnawianie rozpocznie się po imporcie.", + "acmeEmail": "Email kontaktowy ACME", + "acmeDomains": "Nazwy DNS, rozdzielone przecinkami (wildcard tylko z DNS-01)", + "acmeEnvironment": "Środowisko CA", + "acmeStaging": "Staging - niezaufane przez przeglądarkę", + "acmeProduction": "Produkcja", + "acmeDnsServer": "IP serwera aktualizacji DNS", + "acmeDnsPort": "Port aktualizacji DNS", + "acmeKeyName": "Nazwa klucza TSIG", + "acmeSecret": "Sekret TSIG (base64)", + "acmeAlgorithm": "Algorytm TSIG", + "acmePropagation": "Oczekiwanie na propagację DNS (sekundy)", + "acmeSignQuery": "Podpisuj zapytanie SOA", + "acmeTos": "Akceptuje umowe subskrybenta Let's Encrypt i zezwalam na walidacje domen.", + "acmeConfirmProduction": "Potwierdzam wydanie produkcyjne (obowiązują limity CA).", + "acmeIssue": "Zamów certyfikat", + "acmeIdle": "Brak zadania wydania w tym procesie.", + "acmeImport": "Dodaj wydany certyfikat do biblioteki", + "acmeRenewalHint": "Pierwsze wydanie/import pozostaje ręczne. Profile zarządzanych certyfikatów są następnie sprawdzane automatycznie podczas działania RustProxy; po restarcie zapisany stan odnowień jest odtwarzany z SQLite.", + "acmeReplace": "Zastąpić certyfikat w bibliotece? Przypisania vhostów zostaną zachowane i ponownie sprawdzone.", + "acmeImported": "Certyfikat zapisany. Przypisz go w zakładce SSL vhosta.", + "certFuture": "Automatyczne odnawianie jest dostępne dla obsługiwanych dostawców ACME; obserwacje odnowień są zapisywane w SQLite.", + "cacheReason_cache_hit": "Użyto świeżego obiektu", + "cacheReason_cache_miss": "Brak pasującego świeżego obiektu", + "cacheReason_cache_disabled": "Cache wyłączony", + "cacheReason_route_disabled": "Cache wyłączony na trasie", + "cacheReason_request_cookie": "Cookie aplikacji", + "cacheReason_request_authorization": "Nagłówek Authorization", + "cacheReason_request_cache_control": "Dyrektywa klienta / twarde odświeżenie", + "cacheReason_request_pragma": "Pragma klienta", + "cacheReason_request_method": "Metoda inna niż GET", + "cacheReason_request_body": "Niepusta treść żądania", + "cacheReason_request_range": "Żądanie zakresu", + "cacheReason_request_conditional": "Żądanie warunkowe", + "cacheReason_request_upgrade": "Zmiana protokołu", + "cacheReason_query_excluded": "Wykluczone query", + "cacheReason_path_excluded": "Wykluczona ścieżka", + "cacheReason_request_cache_control_invalid": "Błędne dyrektywy cache klienta", + "cacheReason_response_status": "Odpowiedź inna niż 200", + "cacheReason_response_set_cookie": "Set-Cookie z backendu", + "cacheReason_response_cache_control": "Prywatność / dyrektywa backendu", + "cacheReason_response_cache_control_invalid": "Błędne dyrektywy backendu", + "cacheReason_response_vary": "Niedozwolony wariant Vary", + "cacheReason_response_range": "Odpowiedź częściowa", + "cacheReason_response_trailers": "Trailers odpowiedzi", + "cacheReason_response_ttl_size_or_metadata": "Odrzucony TTL, rozmiar lub metadane", + "cacheReason_response_headers_policy": "Reguła nagłówków blokuje zapis", + "cacheReason_configuration_changed": "Zmieniona konfiguracja", + "cacheReason_not_proxy_response": "Strona lokalna / odrzucone żądanie", + "cacheReason_tinyauth": "Treść chroniona Tinyauth", + "cacheReason_sticky_cookie": "Tryb cookie sticky session", + "acme.working": "Trwa zamawianie certyfikatu.", + "acme.ready_to_import": "Certyfikat sprawdzony; gotowy do dodania do biblioteki.", + "acme.certbot_not_installed": "Brak Certbota w PATH usługi. Zainstaluj Certbota i certbot-dns-rfc2136.", + "acme.certbot_failed_check_private_log": "Błąd Certbota. Sprawdź prywatne logi ACME; dokładna ścieżka jest pokazana przy błędzie operacji.", + "acme.production_confirmation": "Wymagane potwierdzenie wydania produkcyjnego.", + "acme.consent_required": "Zaakceptuj umowę i potwierdź wybrane środowisko CA.", + "acme.provider_timeout": "Przekroczono czas operacji CA. Przed ponowieniem sprawdź logi Certbota wskazane przy błędzie operacji.", + "acme.invalid_key_secret": "Nieprawidłowy sekret TSIG: wymagany base64 kodujący 16-512 bajtów.", + "acme.job_busy": "Inne zadanie certyfikatu już trwa.", + "acme.cancelled": "Zadanie certyfikatu anulowane podczas zamykania.", + "acme.certificate_validation_failed": "Walidacja certyfikatu, klucza lub domen nie powiodła się. Nic nie aktywowano.", + "acme.invalid_request": "Nieprawidłowe żądanie ACME.", + "acme.unknown_field": "Żądanie zawiera nieobsługiwane pole.", + "acme.invalid_id": "Identyfikator certyfikatu: 1-64 litery, cyfry, myślnik lub podkreślenie.", + "acme.invalid_email": "Podaj prawidłowy adres e-mail kontaktu ACME.", + "acme.invalid_domains": "Podaj od 1 do 16 nazw DNS.", + "acme.invalid_domain": "Podaj prawidłową nazwę DNS (ASCII/punycode).", + "acme.dns_names_only": "Certyfikat wymaga nazw DNS, nie adresów IP.", + "acme.invalid_environment": "Wybierz staging albo produkcję.", + "acme.tos_required": "ACME: tos required.", + "acme.invalid_dns_server": "Podaj adres IPv4 lub IPv6 serwera aktualizacji DNS.", + "acme.invalid_limits": "Port musi mieścić się w 1-65535, a czas propagacji w 10-900 s.", + "acme.invalid_key_algorithm": "Dozwolone algorytmy TSIG: HMAC-SHA256, HMAC-SHA384 i HMAC-SHA512.", + "acme.invalid_sign_query": "Opcja podpisywania SOA musi mieć wartość true albo false.", + "acme.unsafe_directory": "Katalog certyfikatów musi należeć do usługi i mieć prawa 0700; bez dowiązań.", + "acme.unsafe_output_path": "Plik wyniku wykracza poza prywatne archiwum Certbota.", + "acme.invalid_pem_size": "Plik PEM jest za duży lub nie jest zwykłym plikiem.", + "acme.invalid_pem": "Certbot nie zwrócił prawidłowego pliku PEM.", + "acme.profile_limit": "Osiągnięto limit 128 profili ACME. Sprawdź nieużywane profile lokalnie.", + "acme.profile_busy": "Ten profil ACME jest już używany przez inny proces.", + "acme.staging_limit": "Osiągnięto limit 128 par ACME. Usuń lokalnie wyłącznie nieużywane pliki.", + "acme.request_too_large": "Żądanie ACME przekracza 16 KiB.", + "acme.local_io_or_json_error": "Błąd lokalnego pliku lub formatu JSON. Sprawdź katalog i uprawnienia.", + "acme.no_certificate_directory": "Brak katalogu certyfikatów w konfiguracji uruchomienia.", + "acme.python_not_available": "Proces usługi nie może uruchomić python3. Sprawdź PATH i uprawnienia.", + "acme.worker_io": "Nie udała się komunikacja z lokalnym procesem ACME.", + "acme.invalid_worker_response": "Proces ACME zwrócił nieprawidłowy wynik.", + "acme.worker_failed": "Proces ACME zakończył się błędem.", + "acme.validation_worker_failed": "Nie udało się zakończyć walidacji pary certyfikatu i klucza.", + "cacheResidentLabel": "Pamięć cache", + "certificateFuture": "Dostawcy ACME: HTTP-01, Cloudflare, OVH i RFC2136. Odnawianie jest ręczne.", + "prometheusTitle": "Prometheus", + "prometheusHelp": "Osobny endpoint metryk, niezależny od sesji administratora. Domyślnie wyłączony.", + "prometheusEnable": "Włącz endpoint Prometheusa", + "prometheusListen": "IP i port eksportera", + "prometheusPath": "Ścieżka metryk", + "prometheusCidrs": "Dozwolone adresy kolektora (CIDR, po jednym w wierszu)", + "prometheusTokenEnv": "Nazwa zmiennej środowiskowej z tokenem", + "prometheusTokenHelp": "Podaj nazwę zmiennej, nie sekret. Token musi mieć co najmniej 32 znaki. Zmiana adresu lub tokenu wymaga restartu.", + "prometheusCollectors": "Grupy metryk", + "prometheusPreview": "Podgląd metryk", + "prometheusPreviewFailed": "Nie udało się pobrać metryk.", + "prometheusActive": "Aktywny endpoint", + "prometheusDisabled": "Endpoint metryk jest wyłączony.", + "certificateProvider": "Dostawca certyfikatu", + "providerHttp01": "Let's Encrypt - walidacja domeny (HTTP-01)", + "providerCloudflare": "Let's Encrypt - Cloudflare API (DNS-01)", + "providerOvh": "Let's Encrypt - OVH API (DNS-01)", + "providerRfc2136": "Let's Encrypt - RFC2136 / TSIG (DNS-01)", + "providerImport": "Import certyfikatu i klucza prywatnego (PEM)", + "providerExisting": "Istniejące pliki na serwerze", + "providerHint_http01": "Walidacja domeny HTTP-01 wymaga publicznego portu 80 prowadzącego do aktywnego listenera HTTP. Nie obsługuje wildcardów.", + "providerHint_cloudflare": "DNS-01 przez API Cloudflare. Użyj tokenu z uprawnieniem Zone:DNS:Edit ograniczonym do odpowiednich stref.", + "providerHint_ovh": "DNS-01 przez API OVH. Podaj klucze aplikacji i klienta z uprawnieniami do rekordów odpowiednich stref DNS.", + "providerHint_rfc2136": "DNS-01 przez dynamiczną aktualizację DNS i klucz TSIG. Serwer musi zezwalać na zmianę rekordów walidacyjnych.", + "providerHint_import": "Wgraj certyfikat lub fullchain i odpowiadający mu klucz prywatny w formacie PEM.", + "providerHint_existing": "Wskaż pliki PEM z katalogu certyfikatów RustProxy. Treść klucza nie trafia do konfiguracji.", + "acmeCfToken": "Token API Cloudflare", + "acmeOvhEndpoint": "Region API OVH", + "acmeOvhApplicationKey": "OVH application key", + "acmeOvhApplicationSecret": "OVH application secret", + "acmeOvhConsumerKey": "OVH consumer key", + "acme.invalid_provider": "Nieobsługiwany dostawca certyfikatu.", + "acme.invalid_api_credential": "Brak klucza API lub niedozwolone znaki w kluczu.", + "acme.invalid_ovh_endpoint": "Wybierz OVH Europa lub Kanada.", + "acme.http01_no_wildcard": "HTTP-01 nie obsługuje wildcardów. Wybierz dostawcę DNS-01.", + "acme.http01_listener_required": "HTTP-01 wymaga aktywnego listenera HTTP bez TLS.", + "cacheScopeLegacy": "Nieprzypisany / poprzedni zakres", + "certificateLibrary": "Certyfikaty", + "certificateWorkspaceHelp": "Zarządzaj zainstalowanymi certyfikatami, automatycznym odnawianiem i generowaniem/importem w osobnych widokach.", + "certificateTabInstalled": "Zainstalowane", + "certificateTabRenewal": "Odnowienie", + "certificateTabGenerate": "Generowanie", + "certificateInstalledTitle": "Zainstalowane certyfikaty", + "certificateInstalledHelp": "Lista certyfikatów dostępnych dla vhostów, redirectów, hostów 404 i panelu administracyjnego.", + "certificateGenerateTitle": "Generowanie i import", + "certificateGenerateHelp": "Wybierz metodę: Let's Encrypt/ACME, import plików PEM albo istniejące pliki z prywatnego katalogu RustProxy.", + "certificateOperationStatus": "Ostatnia operacja ACME", + "certificateNoRenewalOperation": "Brak operacji odnowienia w tym procesie.", + "certificateStateIdle": "Bezczynne", + "certificateStateRunning": "W toku", + "certificateStateReady": "Gotowe", + "certificateStateComplete": "Zakończone", + "certificateStateFailed": "Błąd", + "certbotLogs": "Logi Certbota", + "systemDiagnostics": "System / proces", + "vhWebsockets": "Obsługa WebSocket", + "vhLocations": "Własne lokalizacje", + "locationPath": "Prefiks lokalizacji", + "locationPool": "Backendy vhosta", + "locationMissing": "Brak backendu", + "locationLimit": "Host obsługuje do 64 lokalizacji.", + "locationAccess": "Dostęp do lokalizacji", + "locationHeaders": "Nagłówki lokalizacji", + "locationAddBackend": "Dodaj osobny backend", + "locationAdd": "Dodaj lokalizację", + "locationHelp": "Wygrywa najdłuższy pasujący prefiks. Ścieżka i query pozostają bez zmian. Wybierz backend hosta lub dodaj osobny. Uwierzytelnianie i ACL hosta obowiązują zawsze.", + "aclUse": "Włącz listę dostępu IP", + "aclAllow": "Zezwól", + "aclNetwork": "Sieć IP (CIDR)", + "aclAction": "Akcja", + "aclAdd": "Dodaj regułę IP", + "authMode": "Uwierzytelnianie", + "authNone": "Brak", + "authTinyauth": "Tinyauth", + "authBasic": "HTTP Basic Auth", + "basicRealm": "Realm (nazwa logowania)", + "basicRequireTls": "Wymagaj HTTPS dla Basic Auth", + "basicForward": "Przekaż zweryfikowany Authorization do backendu", + "basicPassword": "Hasło (12-128 bajtów)", + "basicKeepPassword": "Puste pole zachowuje hasło", + "basicHashSaved": "Hasło ustawione", + "basicHashRequired": "Ustaw hasło dla każdego użytkownika.", + "basicAddUser": "Dodaj użytkownika", + "basicHelp": "Zapisywane są wyłącznie skróty Argon2id. Dane logowania nie trafiają do backendu, chyba że włączysz przekazywanie. Używaj go tylko z zaufanym backendem HTTPS lub w izolowanej sieci. Chronione hosty omijają współdzielony cache.", + "basic.too_many_users": "Maksymalnie 64 użytkowników na hosta.", + "basic.invalid_username": "Nieprawidłowa nazwa użytkownika.", + "basic.duplicate_username": "Powtórzona nazwa użytkownika.", + "basic.unsupported_hash": "Użyj skrótu Argon2id wygenerowanego przez RustProxy.", + "basic.invalid_hash": "Nieprawidłowy skrót hasła.", + "basic.invalid_realm": "Nieprawidłowa nazwa realm.", + "basic.users_required": "Basic Auth wymaga przynajmniej jednego użytkownika.", + "basic.busy": "Weryfikacja haseł jest zajęta. Spróbuj ponownie.", + "renewalTitle": "Automatyczne odnawianie", + "renewalHelp": "Certyfikaty ACME są sprawdzane co około 12 godzin, gdy RustProxy działa. Certbot określa termin odnowienia. Poprawne certyfikaty są wdrażane bez restartu listenerów. Zachowaj dane dostawcy i dostępność portu 80 dla HTTP-01.", + "renewalNone": "W bibliotece nie ma zarządzanych certyfikatów ACME.", + "renewalEnabled": "Automatyczne odnawianie włączone", + "renewalDisabled": "Automatyczne odnawianie wyłączone", + "renewalEnable": "Włącz odnawianie", + "renewalDisable": "Wyłącz odnawianie", + "renewalNow": "Sprawdź teraz", + "renewalDryRun": "Sprawdź odnowienie (dry run)", + "renewalLast": "Ostatnia kontrola", + "renewalNext": "Kolejna kontrola", + "renewalExpires": "Ważny do", + "acme.renewing": "Sprawdzanie odnowienia certyfikatu", + "acme.renewed": "Certyfikat odnowiony i wdrożony", + "acme.not_due": "Certyfikat nie wymaga jeszcze odnowienia", + "acme.renewal_test_ok": "Weryfikacja odnowienia poprawna; aktywny certyfikat bez zmian", + "acme.renewal_profile_missing": "Brak dostępu do zapisanego profilu odnowienia. Przywróć prywatny profil ACME.", + "acme.configuration_changed": "Konfiguracja certyfikatu zmieniła się podczas odnowienia. Nie wdrożono zmian.", + "acme.deployment_failed": "Odnowiony certyfikat nie przeszedł walidacji konfiguracji. Poprzedni nadal jest aktywny.", + "acme.not_managed": "Automatycznie można odnawiać tylko zarządzane certyfikaty ACME.", + "acme.certificate_not_found": "Certyfikat już nie istnieje.", + "acme.renewal_disabled": "Automatyczne odnawianie jest wyłączone.", + "acme.openssl_not_installed": "OpenSSL jest wymagany do odczytu dat ważności certyfikatu.", + "cacheReason_basic_auth": "Uwierzytelnianie HTTP Basic", + "locationPoolEligible": "Uwzględnij w domyślnej puli backendów", + "locationId": "Identyfikator lokalizacji", + "vhIpAccess": "Dostęp do vhosta według IP", + "apiDocs": "Dokumentacja", + "auth.invalid_request": "Nieprawidłowe żądanie. Sprawdź podane pola.", + "locationProxyHeaders": "Nagłówki żądania proxy (do backendu)", + "locationResponseHeaders": "Nagłówki odpowiedzi (do klienta)", + "locationHeadersHelp": "Ustaw nadpisuje nagłówek, dopisz dodaje wartość, usuń kasuje go. Reguły lokalizacji są stosowane po globalnych i vhosta. Wartości są dosłowne (bez zmiennych nginx). Nagłówkami transportu i zweryfikowanej tożsamości zarządza system.", + "headersAdvancedJson": "Zaawansowane reguły nagłówków (JSON)", + "headersInvalid": "Nieprawidłowa reguła nagłówka. Sprawdź nazwę, operację i wartość.", + "headersProtected": "Nie można tu nadpisać nagłówków transportu i tożsamości proxy. Użyj ustawień forwardingu, autentykacji lub odpowiedzi.", + "docsTitle": "Dokumentacja", + "docsSession": "Korzysta z sesji administratora. Operacje zapisu API wymagają ochrony CSRF.", + "docsSignIn": "Zaloguj się, aby otworzyć dokumentację", + "docsPanel": "Powrót do panelu", + "docsWrites": "Włącz operacje zapisu", + "docsWriteConfirm": "Ta operacja naprawdę zmieni RustProxy. Kontynuować?", + "docsExpired": "Sesja wygasła. Zaloguj się ponownie.", + "docsError": "Nie udało się wczytać dokumentacji.", + "docsAccount": "Zalogowano jako", + "docsReadOnly": "Domyślnie wykonywane są tylko odczyty. Strumienie SSE oraz logowanie i setup nie są tu uruchamiane.", + "docsLogout": "Wyloguj", + "authPrivateNote": "Dostęp tylko dla uprawnionych administratorów.", + "advanced": "Zaawansowane", + "docsLicenses": "Licencje Swagger UI", + "vhTrafficPolicy": "Polityka ruchu", + "vhHttp3Enabled": "Włącz HTTP/3 dla tego vhosta", + "vhCloudflareClientIp": "Używaj zweryfikowanego IP klienta z Cloudflare", + "vhTimingHeaders": "Udostępniaj diagnostykę Server-Timing", + "vhRateEnabled": "Włącz limit żądań per IP klienta", + "vhRateRequests": "Żądania na okno", + "vhRateWindow": "Okno (sekundy)", + "vhRateBurst": "Dopuszczalny burst", + "vhCountryMode": "Polityka dostępu krajów", + "vhCountryBlock": "Blokuj wskazane kraje", + "vhCountryAllow": "Zezwalaj tylko wskazanym krajom", + "vhCountryList": "Kraje (ISO 3166-1 alpha-2)", + "vhCountryPolicyHelp": "Reguły krajów korzystają z zainstalowanej bazy GeoIP. Tryb „tylko zezwolone” blokuje także klienta, którego kraju nie da się ustalić.", + "vhCountry": "Kraj", + "vhAddCountryRate": "Dodaj limit dla kraju", + "vhCountryRateLimit": "Dozwolone są maksymalnie 64 limity przypisane do krajów.", + "vhRateHelp": "Limit dla kraju nadpisuje podstawowy limit per IP. Przekroczenie daje 429, a zabroniony kraj 403.", + "vhHealthOffWarning": "Aktywne sondy backendu są wyłączone. Passive Backend Health jest konfigurowany osobno i pozostaje wyłączony, dopóki nie zostanie świadomie włączony.", + "vhFrontendSelectionOnly": "Wybierz listenery dla vhosta. Adresy IP, porty oraz dostępność H2/H3 konfiguruje się wyłącznie w Ustawienia > Listenery.", + "vhForceSsl": "Wymuś SSL (przekieruj HTTP do HTTPS)", + "vhForceSslHelp": "Żądania HTTP tego vhosta dostają przekierowanie 308 do HTTPS z zachowaniem ścieżki i parametrów. Wybierz co najmniej jeden listener zwykłego HTTP oraz co najmniej jeden listener TLS. Jeśli wybrano kilka portów TLS, używany jest port 443; w innym przypadku port docelowy TLS musi być jednoznaczny.", + "vhForceSslNeedsTls": "Wymuszenie SSL wymaga co najmniej jednego włączonego listenera TLS dla tego vhosta.", + "vhForceSslPortConflict": "Nie można jednoznacznie wybrać portu docelowego HTTPS: wybrane listenery TLS używają kilku niestandardowych portów. Wybierz jeden port TLS albo listener na porcie 443.", + "vhForwardClientIp": "Przekazuj IP klienta do backendu", + "vhForwardClientIpHelp": "Pozostaw włączone dla standardowego reverse proxy. Wyłącz, aby nie wysyłać do aplikacji nagłówków Forwarded, X-Forwarded-For i X-Real-IP; RustProxy, ACL, limity i Tinyauth nadal korzystają z prawdziwego IP klienta.", + "vhClientIpHidden": "IP klienta ukryte przed backendem", + "listenerMigrateInline": "Istniejący listener vhosta (zostanie zmigrowany)", + "vhDebugOriginPreset": "Zastosuj preset zalecany", + "vhDebugOriginTlsWarning": "Ten preset pozostawia wyłączoną walidację certyfikatu TLS backendu. Połączenie jest szyfrowane, ale CA i nazwa hosta nie są sprawdzane. Kontynuować?", + "vhOriginPresetHelp": "Domyślne ustawienia nowego backendu do debugowania: origin HTTPS po IP, domyślna pula LB ON, prywatny origin ON, HTTP/1.1, zachowanie Host klienta ON i weryfikacja TLS OFF. Włącz weryfikację TLS, gdy certyfikat originu da się poprawnie zweryfikować.", + "vhDebugOriginMismatch": "Ten origin HTTPS po IP nie odpowiada presetowi debugowania (pula ON, prywatny origin ON, HTTP/1.1, zachowanie Host ON, walidacja TLS OFF). Jeśli włączysz walidację, ustaw nazwę serwera TLS na DNS z certyfikatu i w razie potrzeby dodaj jego prywatne CA. Kontynuować z bieżącymi wartościami?", + "vhCacheStaticCookie": "Ignoruj Cookie żądania dla wybranych rozszerzeń statycznych", + "vhCacheStaticCustom": "Użyj własnej listy rozszerzeń statycznych", + "vhCacheStaticExtensions": "Rozszerzenia statyczne (po jednym w linii, bez kropki)", + "vhCacheStaticHelp": "Dziedzicz ustawienie globalne albo nadpisz je dla vhosta. Ignorowanie Cookie stosuj tylko do plików, których treść nie zależy od sesji; Set-Cookie, private/no-store i Vary: Cookie nadal blokują zapis do shared cache.", + "cacheStaticTitle": "Cache statycznych zasobów", + "cacheStaticCookie": "Ignoruj Cookie żądania dla statycznych plików", + "cacheStaticExtensions": "Globalne rozszerzenia statyczne (po jednym w linii, bez kropki)", + "cacheStaticHelp": "Włączaj tylko dla plików, których treść nie zależy od sesji. Cookie żądania nie wpływa wtedy na klucz cache dla podanych rozszerzeń; odpowiedzi z Set-Cookie, private/no-store lub Vary: Cookie nadal nie są zapisywane we współdzielonym cache.", + "vhHttp2Enabled": "Włącz HTTP/2 dla tego vhosta", + "vhFrontendProtocolsHelp": "H2 i H3 są przełącznikami per vhost. Opcja jest aktywna tylko wtedy, gdy co najmniej jeden wybrany listener ma dany protokół włączony w Ustawienia > Listenery.", + "administration": "Panel administracyjny", + "administrationActiveHttp": "Aktywny panel HTTP", + "administrationActiveHttps": "Aktywny panel HTTPS", + "administrationCertificate": "Certyfikat", + "administrationGeneratedCertificate": "Domyślny certyfikat wygenerowany przez aplikację", + "administrationHelp": "HTTPS pozwala wystawić panel administracyjny poza loopback. Zwykły HTTP na porcie HTTPS jest automatycznie przekierowywany. Zmiany listenera i certyfikatu działają po restarcie.", + "administrationHosts": "Dozwolone hosty DNS (opcjonalna ścisła lista)", + "administrationHttps": "Włącz HTTPS dla panelu administracyjnego", + "administrationListen": "Adres nasłuchu", + "cacheOverhead": "Narzut", + "cacheResidentAge": "X-Cache-Resident-Age", + "controlPlane": "PANEL STEROWANIA", + "logging": "Logowanie", + "loggingTitle": "Strukturalne logi dostępu", + "loggingTabOutputs": "Wyjścia", + "loggingTabFormat": "Format JSON", + "loggingTabErrors": "Log błędów", + "loggingDescription": "Zapisuj konfigurowalne logi dostępu JSON do pliku, Logstash lub Loki.", + "loggingHelp": "Podgląd logów na żywo pozostaje w pamięci. Zewnętrzne wyjścia używają ograniczonej kolejki w tle i nie blokują obsługi żądań.", + "loggingFile": "Plik JSON", + "loggingPath": "Ścieżka pliku", + "loggingAddress": "Adres TCP", + "loggingTokenEnv": "Zmienna środowiskowa z tokenem Bearer", + "loggingLabels": "Etykiety (obiekt JSON)", + "loggingFormat": "Konfigurowalny format JSON", + "loggingFormatHelp": "Mapuj nazwy pól wyjściowych na pola źródłowe. Puste mapowanie zapisuje pełny standardowy wpis.", + "loggingFields": "Mapowanie pól (obiekt JSON)", + "loggingStatic": "Pola stałe (obiekt JSON)", + "loggingJsonInvalid": "Pola konfiguracji logów muszą zawierać poprawne obiekty JSON.", + "loggingQueue": "Kolejka wyjść", + "loggingDropped": "odrzuconych", + "loggingSent": "wysłanych", + "loggingCapacity": "pojemność", + "errorLogTitle": "Plik błędów", + "errorLogPath": "Ścieżka logu błędów", + "errorLogFormat": "Format", + "tls12": "TLS 1.2", + "tls13": "TLS 1.3", + "tlsPolicy": "Polityka TLS", + "tlsPolicyHelp": "To globalna polityka TLS dziedziczona przez każdy host TLS w aplikacji. Ustawienia per-vhost mogą ją tylko zawężać. HTTP/3 wymaga TLS 1.3.", + "tlsCiphers": "Szyfry (jeden na linię; puste = domyślne rustls)", + "tlsAvailableCiphers": "Dostępne szyfry", + "tlsPolicyVersionRequired": "Włącz co najmniej jedną wersję TLS.", + "vhTlsOverride": "Nadpisz globalną politykę TLS", + "vhTlsOverrideHelp": "Użyj tylko, gdy ten vhost wymaga innych wersji TLS lub szyfrów. Pusta lista szyfrów zachowuje domyślne rustls.", + "vhTlsHttp3Conflict": "HTTP/3 korzysta z globalnej polityki TLS. Wyłącz HTTP/3 dla tego vhosta przed użyciem innego nadpisania TLS.", + "vhListeners": "Listenery", + "vhProtocols": "Protokoły", + "loggingMode": "JSON / ASYNC / OGRANICZONA KOLEJKA", + "loggingPushUrl": "Adres Push URL", + "cacheHotObjects": "Obiekty hot", + "cacheHotMemory": "Pamięć hot", + "cacheColdObjects": "Obiekty cold", + "cacheColdDisk": "Dysk cold", + "cacheTierMoves": "Przeniesienia między warstwami", + "cacheColdHits": "trafień cold", + "cacheTier": "Warstwa", + "cacheStorage": "Pamięć / dysk", + "cacheColdTitle": "Trwały cache cold", + "cacheColdEnable": "Włącz trwałą warstwę dyskową", + "cacheColdHelp": "Wybierz, które obiekty z hot RAM mają trafiać na trwały dysk. Trafienie cold jest odczytywane asynchronicznie i promowane z powrotem do RAM. Metadane są w JSON, a body w plikach .body.", + "cacheColdPath": "Ścieżka cold (wewnątrz katalogu danych)", + "cacheColdBytes": "Limit dysku cold (MiB)", + "cacheColdEntries": "Limit obiektów cold", + "cacheColdAfter": "Przenieś po sekundach bezczynności", + "cacheHot": "Hot", + "cacheCold": "Cold", + "cacheReason_request_no_cache": "no-cache klienta / twarde odświeżenie wymaga rewalidacji", + "cacheReason_request_max_age": "max-age klienta wymaga rewalidacji", + "cacheReason_request_min_fresh": "min-fresh klienta wymaga rewalidacji", + "cacheReason_request_pragma_no_cache": "Pragma no-cache klienta / starszy tryb twardego odświeżenia", + "cacheReason_cache_revalidated": "Obiekt z cache potwierdzony przez backend", + "cacheReason_cache_conditional_hit": "Świeży obiekt obsłużył żądanie warunkowe", + "cacheReason_request_no_store": "no-store klienta omija cache", + "cacheReason_request_precondition": "Warunek klienta wymaga backendu", + "loggingPreset": "Preset formatu", + "loggingPresetCustom": "Własny", + "loggingPresetStandard": "Standard RustProxy", + "loggingPresetNginx": "JSON w stylu Nginx", + "loggingPresetEcs": "Nazwy pól w stylu ECS", + "loggingPresetMinimal": "Minimalny", + "loggingBuilder": "Graficzny konfigurator pól", + "loggingBuilderOpen": "Konfiguruj pola", + "loggingAdvancedJson": "Zaawansowane mapowanie JSON", + "loggingBuilderHelp": "Wybierz pola źródłowe i opcjonalnie zmień ich nazwy w JSON. Zastosowanie edytora graficznego normalizuje każde pole źródłowe do maksymalnie jednego klucza wyjściowego; duplikaty aliasów ustawisz w trybie zaawansowanym.", + "loggingSourceField": "Pole źródłowe", + "loggingOutputField": "Klucz JSON na wyjściu", + "loggingPreview": "Podgląd", + "loggingOutputRequired": "Każde włączone pole logu musi mieć klucz JSON na wyjściu.", + "loggingOutputDuplicate": "Klucze JSON na wyjściu muszą być unikalne.", + "aclProfiles": "Profile ACL", + "acl-profiles": "Profile ACL", + "acl-profilesTitle": "Wielokrotnego użytku profile ACL", + "acl-profilesDescription": "Definiuj wspólne reguły dostępu IP i krajów, a następnie przypinaj je do wielu vhostów.", + "aclProfilesIntro": "Profile dostępu można przypinać do wielu vhostów. Indywidualne reguły ACL i krajów w vhoście nadal działają i są egzekwowane razem z profilem.", + "aclProfilesReusable": "WSPÓLNA POLITYKA", + "aclProfileNew": "Nowy profil", + "aclProfileEdit": "Edycja profilu", + "aclProfileEditor": "Konfiguracja profilu", + "aclProfileId": "ID profilu", + "aclProfileName": "Nazwa wyświetlana", + "aclProfileIpEnabled": "Włącz ACL IP", + "aclProfileRules": "Reguły IP — po jednej „allow|deny CIDR” w wierszu", + "aclProfileCombineHelp": "Profil i reguły vhosta są łączone restrykcyjnie: żądanie musi przejść obie polityki.", + "aclProfileIpRulesShort": "reguł IP", + "aclProfileIpOff": "ACL IP wyłączony", + "aclProfileCountriesOff": "Filtrowanie krajów wyłączone", + "aclProfileAttached": "Przypięty do", + "aclProfileInUse": "Profil jest przypięty do vhostów", + "aclProfilesEmpty": "Brak profili ACL wielokrotnego użytku.", + "aclProfileCountryInvalid": "Kody krajów muszą mieć dwuliterowy format ISO.", + "aclProfileDuplicate": "Profil ACL o tym ID już istnieje.", + "vhAclProfile": "Profil ACL", + "vhAclProfileNone": "Bez wspólnego profilu", + "vhAclProfileHelp": "Opcjonalny profil wielokrotnego użytku. Indywidualne ACL i reguły krajów vhosta poniżej nadal są dodatkowo egzekwowane.", + "vhHostAdd": "Dodaj hostname", + "vhHostsHelp": "Naciśnij Enter lub przecinek, aby dodać hostname. Wildcard jest dozwolony tylko jako początkowe *. (np. *.example.com). Dokładny host ma pierwszeństwo przed wildcardem.", + "vhHostInvalid": "Nieprawidłowy hostname lub wzorzec wildcard.", + "vhHostRequired": "Dodaj co najmniej jeden hostname.", + "vhLifetimeChart": "Przebieg ruchu od otwarcia panelu", + "vhReqPerSecond": "żąd./s", + "vhPeak": "max", + "listenerAddresses": "Adresy nasłuchu", + "listenerAddressesInvalid": "Podaj 1–16 unikalnych adresów nasłuchu.", + "listenerAddressesExplicit": "Przy wielu adresach wybierz konkretne IP; 0.0.0.0 i :: nie są dozwolone.", + "ruleSyntaxLine": "Nieprawidłowa reguła ACL w wierszu", + "vhForceSslNeedsHttp": "Wymuszenie SSL wymaga co najmniej jednego wybranego listenera zwykłego HTTP (bez TLS). Listener nazwany „HTTP” może mimo nazwy mieć włączony TLS w Ustawienia > Listenery.", + "aclProfileRuleBuilder": "Reguły IP", + "aclProfileBulkRules": "Wklej / importuj reguły", + "aclProfileBulkHelp": "Wklej po jednej regule „allow|deny CIDR” w wierszu. Niewidoczne odstępy Unicode są normalizowane, a błąd wskazuje dokładny wiersz.", + "aclProfileImportRules": "Importuj reguły", + "aclProfileRulesImported": "Reguły ACL zaimportowano do edytora graficznego.", + "streamHosts": "Hosty stream", + "streamsHelp": "Surowe przekazywanie TCP/UDP na osobnych portach. Ruch stream omija vhosty HTTP, ACL, cache, nagłówki i kompresję.", + "streamAdd": "Dodaj host stream", + "saveStreams": "Zapisz hosty stream", + "streamRestartHelp": "Zmiana listenera stream wymaga restartu RustProxy.", + "streamRestartPending": "Zapisano zmiany streamów. Uruchom ponownie RustProxy, aby je zastosować.", + "streamActive": "Aktualnie aktywne streamy", + "streamNone": "Brak aktywnych hostów stream", + "streamEndpoint": "Endpoint stream", + "streamId": "ID streamu", + "streamName": "Nazwa wyświetlana", + "streamProtocol": "Protokół", + "streamListen": "Adres nasłuchu", + "streamUpstream": "Adres upstream", + "streamConnectTimeout": "Timeout połączenia TCP (sekundy)", + "streamIdleTimeout": "Timeout bezczynności/sesji (sekundy)", + "streamMaxConnections": "Maks. połączeń/sesji", + "streamTcp": "TCP", + "streamUdp": "UDP", + "streamLimit": "Obsługiwane jest maksymalnie 128 hostów stream.", + "streamDuplicate": "ID hostów stream muszą być unikalne.", + "streams": "Streamy", + "streamsTitle": "Proxy TCP / UDP", + "streamsDescription": "Zarządzaj surowymi listenerami Layer 4, upstreamami i statystykami ruchu na żywo.", + "streamsPageIntro": "Streamy TCP/UDP są niezależnymi proxy Layer 4. Każdy stream ma własny listener i upstream oraz omija warstwę vhostów HTTP, ACL i cache.", + "streamLayer4": "LAYER 4 / TCP + UDP", + "streamList": "Streamy", + "streamSearch": "Szukaj streamów", + "streamSearchPlaceholder": "ID, nazwa, listener lub upstream…", + "streamSearchEmpty": "Brak streamów pasujących do wyszukiwania.", + "streamEmpty": "Brak streamów TCP/UDP. Dodaj listener, aby rozpocząć proxowanie ruchu Layer 4.", + "streamNew": "Nowy stream", + "streamAddListener": "Dodaj listener TCP/UDP", + "streamEditor": "Konfiguracja streamu", + "streamEditLabel": "EDYCJA", + "streamNewLabel": "NOWY", + "streamDetailsTab": "Szczegóły", + "streamNetworkTab": "Listener i upstream", + "streamLimitsTab": "Limity", + "streamNetwork": "Listener i upstream", + "streamLimits": "Limity połączeń / sesji", + "streamDedicatedListenerHelp": "Listener streamu jest tworzony razem ze streamem i jest niezależny od listenerów HTTP/HTTPS.", + "streamLimitsHelp": "Limity dotyczą równoległych połączeń TCP lub sesji UDP per klient. Timeout łączenia TCP nie jest używany przez UDP.", + "streamListenAdd": "Dodaj adres nasłuchu", + "streamListenHelp": "Wpisz jeden adres IP:port i naciśnij Enter. Zmiana listenera zacznie działać po restarcie RustProxy.", + "streamListenInvalid": "Adres listenera musi być pojedynczą wartością IP:port bez spacji i przecinków.", + "streamListenRequired": "Dodaj adres nasłuchu.", + "streamDelete": "Usunąć ten stream? Aktywny listener pozostanie do restartu RustProxy.", + "streamPendingRestart": "Oczekuje na restart", + "streamRunning": "Działa", + "streamActiveSessions": "Aktywne połączenia / sesje", + "streamSessionsTotal": "Połączenia / sesje", + "streamErrors": "Błędy", + "streamRejected": "Odrzucone", + "streamTransferred": "Przesłano", + "streamTrafficChart": "Ruch na żywo", + "streamClientToUpstream": "klient → upstream", + "streamUpstreamToClient": "upstream → klient", + "streamNoLiveMetrics": "Statystyki pojawią się, gdy stream będzie aktywny po restarcie.", + "streamIdleShort": "Timeout bezczynności", + "listenerAddressAdd": "Dodaj adres nasłuchu", + "listenerAddressesHelp": "Naciśnij Enter lub przecinek, aby dodać adres. Wiele adresów korzysta z tej samej polityki listenera; wildcard 0.0.0.0/:: nie może być mieszany z konkretnymi adresami.", + "cacheColdOnIdle": "Przenoś stare/nieużywane obiekty do cold storage", + "cacheColdOnLru": "Przenoś obiekty wyrzucane z hot LRU do cold storage", + "cacheColdOnShutdown": "Przy łagodnym restarcie zrzucaj hot cache do cold storage", + "certificateCovers": "Domeny certyfikatu", + "certificateCoverageUnknown": "Brak danych o domenach (DNS SAN). Wczytaj ponownie pliki certyfikatów lub zaimportuj certyfikat ponownie.", + "certificateDetails": "Szczegóły certyfikatu", + "certificateFiles": "Pliki certyfikatu / klucza", + "redirects": "Przekierowania", + "redirectsTitle": "Przekieruj świadomie.", + "redirectsDescription": "Lokalne hosty przekierowań z jawnym dopasowaniem, celem, kodem oraz obsługą ścieżki i query.", + "redirectsPageIntro": "Hosty przekierowań odpowiadają lokalnie, bez otwierania połączenia do backendu. Reguły mogą dopasować protokół i ścieżkę, a następnie przekierować do URL, innego hosta lub ścieżki.", + "redirectLayer": "PRZEKIEROWANIA HTTP", + "redirectList": "Hosty przekierowań", + "redirectSearch": "Szukaj przekierowań", + "redirectSearchPlaceholder": "ID, domena, cel…", + "redirectNew": "Nowe przekierowanie", + "redirectEmpty": "Brak skonfigurowanych hostów przekierowań.", + "redirectSearchEmpty": "Brak przekierowań pasujących do wyszukiwania.", + "redirectEditor": "Konfiguracja przekierowania", + "redirectId": "ID przekierowania", + "redirectName": "Nazwa", + "redirectHosts": "Domeny źródłowe", + "redirectFrontend": "FRONTEND", + "redirectListeners": "Listenery", + "redirectBehavior": "ZACHOWANIE", + "redirectRules": "Reguły", + "redirectAddRule": "Dodaj regułę", + "redirectRulesHelp": "Wygrywa najdłuższa pasująca ścieżka. 307/308 zachowują metodę żądania; 301/302/303 mogą ją zmienić po stronie klienta.", + "redirectSafetyHint": "Host przekierowania nie łączy się z backendem. Globalne ACL hostów nadal obowiązują. Unikaj reguł kierujących bezwarunkowo do samych siebie.", + "redirectRule": "Reguła", + "redirectRuleId": "ID reguły", + "redirectSourceScheme": "Protokół wejściowy", + "redirectSchemeAny": "HTTP lub HTTPS", + "redirectSchemeHttp": "HTTP", + "redirectSchemeHttps": "HTTPS", + "redirectSchemePreserve": "Zachowaj protokół wejściowy", + "redirectMatchType": "Dopasowanie ścieżki", + "redirectMatchPrefix": "Prefiks", + "redirectMatchExact": "Dokładnie", + "redirectSourcePath": "Ścieżka źródłowa", + "redirectTargetType": "Typ celu", + "redirectTargetUrl": "Pełny URL", + "redirectTargetHost": "Host / aplikacja", + "redirectTargetPath": "Ścieżka na tym samym hoście", + "redirectTarget": "Cel", + "redirectTargetScheme": "Protokół celu", + "redirectPathMode": "Obsługa ścieżki", + "redirectPathAppend": "Dopisz pełną ścieżkę źródłową", + "redirectPathStrip": "Usuń dopasowany prefiks i dopisz resztę", + "redirectPathReplace": "Użyj tylko skonfigurowanej ścieżki celu", + "redirectQueryMode": "Obsługa query", + "redirectQueryPreserve": "Zachowaj query źródłowe", + "redirectQueryDrop": "Usuń query źródłowe", + "redirectStatus": "Status HTTP", + "redirect301": "301 Moved Permanently", + "redirect302": "302 Found", + "redirect303": "303 See Other", + "redirect307": "307 Temporary Redirect (zachowaj metodę)", + "redirect308": "308 Permanent Redirect (zachowaj metodę)", + "redirectCacheSeconds": "max-age cache przeglądarki/proxy (sekundy; 0 = no-store)", + "redirectHostsRequired": "Dodaj co najmniej jedną domenę źródłową.", + "redirectListenersRequired": "Wybierz co najmniej jeden listener.", + "redirectRulesRequired": "Dodaj co najmniej jedną regułę przekierowania.", + "redirectDuplicate": "Przekierowanie o tym ID już istnieje.", + "redirectUnsaved": "Odrzucić niezapisane zmiany przekierowania?", + "redirectNewLabel": "NOWE", + "administrationSessionDays": "Czas ważności sesji administratora (dni)", + "administrationSessionDaysHelp": "Sesje przeglądarkowe mają bezwzględny czas ważności 7–30 dni. Zmiana działa od razu; zmiana hasła i „wyloguj wszystkie sesje” nadal natychmiast unieważniają sesje.", + "vhLocalListenerRisk": "Zezwól na lokalny listener RustProxy jako backend (ryzyko)", + "vhLocalListenerRiskHelp": "Ta opcja pojawia się, gdy URL backendu bezpośrednio wskazuje skonfigurowany lub aktywny listener administracyjny RustProxy. localhost, 127.0.0.1 i ::1 są traktowane jako równoważne adresy loopback na tym samym porcie panelu. Jej włączenie może wystawić panel lub utworzyć pętlę proxy; adres prywatny/loopback nadal wymaga opcji „Zezwól na prywatny IP backendu”.", + "vhLocalListenerRiskConfirm": "Ta opcja może kierować żądania do lokalnego listenera RustProxy, w tym portu administracyjnego, oraz utworzyć pętlę lub wystawić control plane. Akceptujesz to ryzyko?", + "cacheResidentHistory": "Historia zajętości RAM cache", + "networkHistory": "Historia RX / TX", + "responseLatencyHistory": "Historia czasu odpowiedzi", + "sourceIp": "IP źródłowe", + "cacheColdOnAge": "Przenoś obiekty do cold po maksymalnym czasie w hot RAM", + "cacheColdMaxHot": "Maksymalny czas w hot RAM (sekundy)", + "cacheColdPolicyHelp": "Czas bezczynności określa, jak długo obiekt nie był używany. Wiek hot określa ciągły czas przebywania w RAM nawet przy dalszych odczytach. Presja LRU i zrzut przy łagodnym zamknięciu są niezależnymi regułami.", + "documentation": "Dokumentacja", + "locationPathPattern": "Ścieżka / wzorzec regex", + "locationMatchType": "Sposób dopasowania", + "locationMatchPrefix": "Prefiks", + "locationMatchPriority": "Priorytetowy prefiks (^~)", + "locationMatchExact": "Dokładna ścieżka (=)", + "locationMatchRegex": "Regex (~)", + "locationMatchRegexI": "Regex bez rozróżniania wielkości liter (~*)", + "locationMatch_prefix": "prefiks", + "locationMatch_prefix_priority": "prefiks priorytetowy", + "locationMatch_exact": "dokładne", + "locationMatch_regex": "regex", + "locationMatch_regex_insensitive": "regex i", + "locationAction": "Akcja", + "locationProxyAction": "Proxy do backendu", + "locationReturnAction": "Własna odpowiedź (return)", + "locationProxyShort": "proxy", + "locationReturnShort": "odpowiedź lokalna", + "locationHandling": "Obsługa żądania", + "locationRewriteMode": "Przepisanie ścieżki do backendu", + "locationRewritePreserve": "Zachowaj oryginalną ścieżkę", + "locationRewriteStrip": "Usuń dopasowany prefiks", + "locationRewriteReplace": "Zastąp dopasowany prefiks", + "locationRewriteRegex": "Zamiana regex", + "locationRewriteValue": "Ścieżka / wyrażenie zastępujące", + "locationRewriteHelp": "Parametry query są zachowywane. Przepisywanie prefiksu działa na znormalizowanej ścieżce routingu. Zamiana regex obsługuje grupy Rust regex, np. $1. Wynik jest walidowany przed wysłaniem do backendu.", + "locationResponseStatus": "Kod odpowiedzi", + "locationResponseType": "Content-Type", + "locationResponseBody": "Treść odpowiedzi", + "headersVisualBuilder": "Graficzny konfigurator", + "locationDocsTitle": "Dokumentacja Custom locations", + "headersDocsTitle": "Dokumentacja reguł nagłówków", + "locationDocsIntro": "Custom locations są oceniane wewnątrz wybranego vhosta po autentykacji i ACL hosta. Nie mogą omijać zabezpieczeń vhosta.", + "locationDocsPrefix": "Prefiks: dopasowuje pełny prefiks segmentów ścieżki. Wygrywa najdłuższy prefiks. Priorytetowy prefiks działa jak nginx ^~ i blokuje pierwszeństwo regexów.", + "locationDocsExact": "Dokładne: pasuje wyłącznie do dokładnej znormalizowanej ścieżki, jak nginx location = /path.", + "locationDocsRegex": "Regex: po obsłudze exact/prioritetowego prefiksu wygrywa pierwszy pasujący regex. Dostępny jest tryb czuły i nieczuły na wielkość liter. Używana jest składnia Rust regex; look-around i backreference w samym wzorcu są celowo niedostępne.", + "locationDocsReturn": "Własna odpowiedź: RustProxy odpowiada lokalnie wybranym kodem HTTP, Content-Type i body bez otwierania połączenia do backendu. Reguły nagłówków odpowiedzi lokalizacji nadal obowiązują.", + "locationDocsRewrite": "Przepisanie ścieżki backendu: zachowanie oryginału, usunięcie/zamiana prefiksu albo zamiana z grupami regex. Oryginalny query string jest zachowany.", + "locationDocsAccess": "ACL IP lokalizacji, nadpisanie cache i reguły nagłówków są łączone z polityką vhosta. Lokalizacja nie może wyłączyć autentykacji ani ACL hosta.", + "locationDocsLimits": "Do 64 lokalizacji na vhost. Regexy i body odpowiedzi mają limity; nagłówki transportu, zweryfikowanej tożsamości i protokołu WebSocket pozostają zarządzane przez system.", + "headersDocsIntro": "Reguły nagłówków są stosowane kolejno: globalne → vhost → pasująca lokalizacja. Do zwykłej konfiguracji użyj graficznego konfiguratora; JSON pozostaje trybem zaawansowanym.", + "headersDocsSet": "Ustaw: zastępuje wszystkie istniejące wartości nagłówka skonfigurowaną wartością dosłowną.", + "headersDocsAppend": "Dopisz: dodaje kolejną wartość bez usuwania istniejących.", + "headersDocsRemove": "Usuń: kasuje nagłówek przed wysłaniem do backendu albo klienta.", + "headersDocsProtected": "Chronionych nagłówków transportu/tożsamości (Host, Connection, Content-Length, Forwarded/X-Forwarded-*, nagłówki dowodu WebSocket itd.) nie można tu nadpisywać.", + "headersDocsOrder": "Wartości są dosłowne; zmienne nginx nie są interpretowane. Reguły request działają przed nałożeniem kanonicznych danych forwardingu, a response przed końcową polityką bezpieczeństwa/diagnostyki RustProxy.", + "cacheColdPolicyTitle": "Polityka hot → cold", + "headerRule": "Reguła nagłówka", + "headerRulesEmpty": "Brak reguł. Dodaj regułę poniżej.", + "headerRuleHelp": "Wybierz Ustaw, Dodaj lub Usuń. Nagłówki transportowe, tożsamości forwardingu i protokołu WebSocket pozostają chronione.", + "locationPreviewTitle": "Podgląd efektywnego działania", + "locationPreviewMatch": "Dopasowanie", + "locationPreviewHandling": "Obsługa", + "locationPreviewRewrite": "Ścieżka do backendu", + "locationPreviewCache": "Cache", + "locationPreviewAccess": "Dostęp", + "locationPreviewHeaders": "Reguły nagłówków", + "locationPreviewDisabled": "Ta lokalizacja jest wyłączona i nie będzie dopasowywać żądań.", + "locationPreviewBackendSkipped": "backend nie jest wywoływany", + "locationPreviewVhostAcl": "Tylko autentykacja i ACL vhosta", + "locationPreviewCustomAcl": "Polityka vhosta + ACL lokalizacji", + "locationPreviewRequestRules": "request", + "locationPreviewResponseRules": "response", + "locationPreviewQueryPreserved": "query string jest zachowywany", + "locationDocsMatchHeading": "1. Dopasowanie i kolejność", + "locationDocsActionHeading": "2. Proxy, rewrite i odpowiedź lokalna", + "locationDocsPolicyHeading": "3. Dostęp, cache i nagłówki", + "locationDocsExamplesHeading": "Popularne przykłady", + "locationDocsExampleExact": "Endpoint health: Dokładna ścieżka (=) /health + Własna odpowiedź 200 odpowiada lokalnie bez łączenia z backendem.", + "locationDocsExampleStatic": "Pliki statyczne: Priorytetowy prefiks (^~) /static/ blokuje przejęcie przez regex; dla tej lokalizacji można osobno włączyć cache.", + "locationDocsExampleRegex": "Wersjonowane API: Regex (~) ^/api/v[0-9]+/ może wybrać backend i używać grup zamiany regex, np. $1.", + "cacheOutcomeHistory": "Aktywność HIT / MISS / BYPASS", + "cacheHotMemoryHistory": "Zajętość RAM HOT / limit", + "cacheTransientMemoryHistory": "Zajętość RAM przejściowego / limit", + "cacheColdStorageHistory": "Zajętość COLD / limit", + "processCpuHistory": "Historia CPU procesu", + "processRssHistory": "Historia RSS procesu", + "cacheMemoryBreakdown": "Cache hot / pamięć przejściowa", + "cacheTransientBreakdown": "Fill / kolejka cold / I/O cold", + "cacheColdStorageUsage": "Zajętość COLD / limit", + "cacheColdStorageObjects": "obiektów", + "cacheTransientMemory": "Pamięć przejściowa cache", + "cacheTransientShort": "RAZEM", + "cacheFillShort": "fill", + "cacheQueueShort": "kolejka cold", + "cacheIoShort": "I/O cold", + "processRssTotal": "RSS łącznie", + "memoryCacheHot": "RAM cache HOT / limit", + "memoryCacheTransient": "RAM przejściowy cache / limit", + "memoryTransform": "RAM zarezerwowany przez transformacje / budżet", + "memoryTransformInflight": "Aktywne transformacje / limit", + "memoryNonCacheRss": "RSS procesu poza cache", + "transformMemoryUsage": "Rezerwacja RAM transformacji", + "transformConcurrencyUsage": "Aktywne sloty transformacji", + "transformBudgetShort": "budżet", + "processRssAnon": "RSS anonimowy", + "processRssFile": "RSS plików / współdzielony", + "processDataSwap": "Obszar danych / swap", + "memoryAccountingHint": "RSS pokazuje rzeczywisty ślad pamięci procesu. HOT i pamięć przejściowa cache są księgowane przez RustProxy, a pamięć transformacji jest konserwatywną rezerwacją aktywnej pracy. RSS poza cache to RSS pomniejszony o księgowany cache i obejmuje m.in. transformacje, połączenia, TLS, logowanie, Tokio/runtime, narzut alokatora i inne bufory, więc nie wszystkie wiersze należy sumować.", + "memoryAccountingInfo": "Informacje o rozliczaniu pamięci", + "logTransport": "Transport", + "logWebSocket": "WebSocket", + "logUpstreamError": "Błąd upstreamu", + "listenerDefaultPortsHint": "Nowy vhost automatycznie wybiera standardowy listener HTTP :80, jeśli jest dostępny.", + "vhBackendDiagnostics": "Diagnostyka backendu", + "vhBackendHeader": "Udostępniaj wybrany backend (X-RustProxy-Backend)", + "vhBackendTimingHeader": "Udostępniaj czas odpowiedzi backendu (X-RustProxy-Backend-Time)", + "vhBackendDiagnosticsHelp": "Opcjonalne nagłówki odpowiedzi. Czas backendu oznacza czas od wysłania żądania do otrzymania nagłówków odpowiedzi; odpowiedzi obsłużone bez kontaktu z originem nie raportują backendu.", + "authModeHelp": "Wybierz jedną metodę uwierzytelniania. Lista dostępu IP poniżej działa niezależnie i może być używana razem z dowolną metodą.", + "taAdvanced": "Zaawansowane ustawienia Tinyauth", + "notfound": "Hosty 404", + "notfoundTitle": "Hosty 404 pod kontrolą.", + "notfoundDescription": "Rezerwuj domeny, które mają lokalnie zwracać kod, zaślepkę albo własny HTML.", + "notfoundPageIntro": "Hosty 404 rezerwują wybrane domeny i odpowiadają lokalnie bez łączenia z backendem. Mogą używać tych samych listenerów i certyfikatów co vhosty.", + "notfoundLayer": "ODPOWIEDŹ LOKALNA", + "notfoundList": "Hosty 404", + "notfoundSearch": "Szukaj hostów 404", + "notfoundSearchPlaceholder": "ID, nazwa lub domena…", + "notfoundNew": "Nowy host 404", + "notfoundEditor": "Konfiguracja hosta 404", + "notfoundId": "ID hosta", + "notfoundName": "Nazwa wyświetlana", + "notfoundFrontend": "FRONTEND", + "notfoundBehavior": "ODPOWIEDŹ", + "notfoundResponse": "Odpowiedź lokalna", + "notfoundMode": "Typ odpowiedzi", + "notfoundModeWelcome": "Zaślepka RustProxy", + "notfoundModeEmpty": "Tylko status / pusta", + "notfoundModeHtml": "Własny HTML", + "notfoundStatus": "Status HTTP", + "notfoundHtml": "Własny HTML", + "notfoundResponseHelp": "Host nigdy nie otwiera połączenia do backendu. Wbudowana zaślepka ma no-store i celowo nie dodaje opcjonalnych nagłówków diagnostycznych ani Server RustProxy.", + "notfoundHosts": "Domeny", + "notfoundNewLabel": "NOWY", + "notfoundHostsRequired": "Dodaj co najmniej jedną domenę.", + "notfoundListenersRequired": "Wybierz co najmniej jeden listener.", + "notfoundHtmlRequired": "Własny HTML nie może być pusty.", + "notfound204Empty": "Odpowiedzi HTTP 204, 205 i 304 muszą używać trybu Pusta.", + "notfoundDuplicate": "Host 404 o takim ID już istnieje.", + "notfoundUnsaved": "Odrzucić niezapisane zmiany hosta 404?", + "notfoundEmpty": "Brak skonfigurowanych hostów 404.", + "notfoundSearchEmpty": "Brak hostów 404 pasujących do wyszukiwania.", + "prometheusTrustedNoToken": "Zezwól zaufanym CIDR na odczyt bez tokenu", + "prometheusTrustedNoTokenHelp": "Klient nadal musi pasować do listy dozwolonych CIDR. Włączaj tylko w prywatnej, zaufanej sieci monitoringu; nagłówki przekazywane nie są używane do tej decyzji.", + "docker-vhosts": "Docker vhosty", + "docker-vhostsTitle": "Usługi Dockera pod nazwami.", + "docker-vhostsDescription": "Wykrywaj wystawione porty Dockera i mapuj uslugi na nazwy w domenie agenta, wlasne domeny oraz aliasy bez zapisywania obserwowanego stanu do SQLite.", + "dockerVhosts": "Docker vhosty", + "dockerVhostsIntro": "Wystawione porty TCP wykryte przez skonfigurowane agenty Dockera. Dla każdej usługi ustaw krótką nazwę w domenie agenta albo dowolny FQDN, dodaj aliasy, wybierz IP hosta Dockera oraz sprawdzaj i konfiguruj stan backendu na żywo.", + "dockerDiscovery": "WYKRYWANIE DOCKERA", + "dockerRefresh": "Odśwież agentów", + "dockerAgentsSettings": "Ustawienia agentów Dockera", + "dockerAgents": "Agenty Dockera", + "dockerDesiredState": "STAN ŻĄDANY / SQLITE", + "dockerAgentsHelp": "Skonfiguruj osobnego agenta dla każdego hosta Dockera. Domyślnie agent używa HTTPS ze stałym certyfikatem self-signed; wklej jego fingerprint SHA-256, aby przypiąć certyfikat. Każdy agent ma własną domenę bazową i opcjonalne domyślne IP backendu.", + "dockerAgentAdd": "Dodaj agenta Dockera", + "dockerAgentsSave": "Zapisz i połącz agentów", + "dockerAgent": "AGENT DOCKERA", + "dockerAgentNew": "Nowy agent", + "dockerAgentId": "ID agenta", + "dockerAgentName": "Nazwa wyświetlana", + "dockerAgentEndpoint": "Adres agenta", + "dockerAgentToken": "Token Bearer", + "dockerBaseDomain": "Domena bazowa", + "dockerTargetOverride": "Nadpisanie IP docelowego", + "dockerTargetAuto": "automatyczne", + "dockerListeners": "Listenery", + "dockerListenersRequired": "Wybierz co najmniej jeden listener dla agenta Docker.", + "dockerNoAgents": "Brak skonfigurowanych agentów Dockera.", + "dockerNoAgentsConfigured": "Najpierw skonfiguruj agenta Dockera w Ustawieniach.", + "dockerPublish": "Wystaw", + "dockerPreserveHost": "Zachowaj Host", + "dockerServiceMissing": "Brak w ostatnim odczycie", + "dockerConnected": "POŁĄCZONO", + "dockerError": "BŁĄD", + "dockerWaiting": "OCZEKIWANIE", + "dockerAgentDisabled": "Ten agent Dockera jest wyłączony.", + "dockerNoObservation": "Brak odczytu. Odśwież agentów.", + "dockerHost": "Host Dockera", + "dockerDetectedIp": "Wykryte IP", + "dockerEffectiveIp": "IP routingu", + "dockerNoPublishedPorts": "Agent nie zgłosił wystawionych portów TCP.", + "dockerAssignmentsSave": "Zapisz Docker vhosty", + "dockerDefaultTarget": "Domyslne IP backendu", + "dockerDetectedIps": "Wykryte adresy IP hosta", + "dockerHostname": "Nazwa hosta", + "dockerHostnameHelp": "Krotka nazwa uzyje {domain}; pelny FQDN uzyje wlasnej domeny.", + "dockerAliases": "Aliasy", + "dockerAliasAdd": "Dodaj alias", + "dockerAliasesHelp": "Dodawaj aliasy klawiszem Enter lub przecinkiem. Krótkie nazwy użyją domeny bazowej agenta, a pełne FQDN pozostaną bez zmian.", + "dockerBackendIp": "IP hosta backendu", + "dockerBackendIpAuto": "Auto / domyslne agenta", + "dockerBackendScheme": "Protokol backendu", + "dockerBindingIp": "binding Dockera", + "dockerAgentDefaultIp": "domyslne agenta", + "dockerAgentEndpointHelp": "Dla domyślnej konfiguracji agenta użyj https://. Zwykły HTTP pozostaje tylko dla zgodności i jest wyraźnie oznaczony jako niezabezpieczony.", + "dockerTlsFingerprint": "SHA-256 certyfikatu TLS", + "dockerTlsFingerprintHelp": "Dla domyślnego certyfikatu self-signed wklej fingerprint wypisany przez install.sh albo rustproxy-docker-agent --print-fingerprint. Zostaw puste wyłącznie dla certyfikatu zaufanego przez publiczne CA.", + "dockerTlsPinned": "TLS PRZYPIĘTY", + "dockerTlsPublicCa": "TLS / PUBLICZNE CA", + "dockerTlsPlain": "ZWYKŁY HTTP", + "dockerTlsPlainHelp": "Token agenta i dane inventory nie są chronione przez TLS na tym endpointcie.", + "dockerTlsPublicCaHelp": "Łańcuch certyfikatu i nazwa hosta są weryfikowane względem publicznych CA.", + "dockerAgentConnectionFailed": "Nie udało się połączyć z agentem", + "dockerAgentVersion": "Wersja agenta", + "dockerLastChecked": "Ostatnie sprawdzenie", + "dockerNeverChecked": "nigdy", + "dockerJustNow": "przed chwilą", + "dockerSecondsAgo": "{seconds} s temu", + "dockerMinutesAgo": "{minutes} min temu", + "dockerBackendMissing": "BRAK USŁUGI", + "dockerBackendNotActive": "NIEWYSTAWIONY", + "dockerBackendChecking": "SPRAWDZANIE", + "dockerBackendHealthOff": "HEALTH WYŁ.", + "dockerBackendUp": "UP", + "dockerBackendDown": "DOWN", + "dockerBackendDraining": "WYGASZANIE", + "dockerBackendNoMetrics": "Metryki runtime pojawią się po aktywacji dynamicznego backendu.", + "dockerHealthCheck": "Badanie backendu", + "dockerHealthSummary": "Aktywne testy TCP/HTTP; pasywne zdrowie jest konfigurowane osobno", + "dockerPassiveHealth": "Pasywne zdrowie backendu", + "dockerPassiveHealthSummary": "Domyślnie wyłączone; wymaga świadomego użycia zwykłego ruchu do decyzji health", + "dockerHealthMode": "Tryb", + "dockerHealthHttp": "HTTP", + "dockerHealthTcp": "TCP", + "dockerHealthOff": "Wyłączone", + "dockerHealthPath": "Ścieżka HTTP", + "dockerHealthHost": "Nagłówek Host health-checka", + "dockerHealthHostAuto": "host backendu / automatycznie", + "dockerHealthInterval": "Interwał (ms)", + "dockerHealthTimeout": "Timeout (ms)", + "dockerHealthSlow": "Próg wolnej odpowiedzi (ms)", + "dockerHealthFall": "Błędy do oznaczenia DOWN", + "dockerHealthRise": "Sukcesy do oznaczenia UP", + "dockerHealthStatusMin": "Min. status HTTP", + "dockerHealthStatusMax": "Maks. status HTTP", + "dockerHealthLatency": "Opóźnienie", + "dockerHealthResult": "Ostatni probe", + "dockerHealthRequests": "Żądania", + "dockerHealthErrors": "Błędy", + "dockerHealthActive": "Aktywne", + "loggingPerVhost": "Osobny plik per vhost", + "loggingDirectory": "Katalog logów per-vhost", + "loggingPerVhostHelp": "Po włączeniu każdy vhost zapisuje do własnego pliku JSONL. Ruch niedopasowany trafia do _unmatched.jsonl.", + "listenerStartupLocked": "Tego adresu ustawionego przy starcie procesu/systemd nie można zmienić ani usunąć. Pozostałe adresy i opcje listenera nadal można edytować.", + "administrationStartupLocked": "Ten adres jest ustawiony przy starcie procesu/systemd i nie można go tutaj zmienić.", + "notfoundStatusInvalid": "Wybierz obsługiwany status błędu HTTP.", + "tlsEffectiveCiphers": "Aktualnie używane szyfry", + "certificateManaged": "Zarządzany przez ACME", + "certManagedReadOnly": "Certyfikaty zarządzane przez ACME są odnawiane automatycznie i nie można ich edytować jak własnych certyfikatów z plików.", + "vhWebsocketTransport": "Transport WebSocket", + "vhWebsocketHttp1": "HTTP/1.1 Upgrade (zalecane)", + "vhWebsocketRfc9220": "RFC 9220 Extended CONNECT przez HTTP/3", + "vhWebsocketTransportHelp": "Włącz WebSocket osobnym przełącznikiem, a następnie wybierz transport. Tryby H2/H3 używają Extended CONNECT, a HTTP/1.1 Upgrade pozostaje fallbackiem.", + "dockerLiveView": "Widok live", + "dockerPollInterval": "Interwał odpytywania agenta (s)", + "dockerPollIntervalHelp": "Jak często RustProxy pobiera inventory Dockera z tego agenta. Widok live czyta tylko stan z pamięci RustProxy.", + "dockerAgentPollEvery": "Interwał agenta", + "dockerSearch": "Szukaj Docker vhostów", + "dockerSearchPlaceholder": "Szukaj usługi, hosta, aliasu lub agenta...", + "dockerShowHidden": "Pokaż ukryte", + "dockerHideHidden": "Ukryj ukryte", + "dockerHideVhost": "Ukryj z widoku", + "dockerUnhideVhost": "Pokaż w widoku", + "dockerCertificate": "Certyfikat frontendu", + "dockerCertificateHelp": "Certyfikat przypisany do wszystkich generowanych vhostów tego agenta. Domyślna opcja używa standardowego wyboru TLS/SNI.", + "dockerDefaultAcl": "Domyślny profil ACL", + "dockerDefaultAclNone": "Bez domyślnego profilu ACL", + "dockerDefaultAclHelp": "Dziedziczony przez generowane Docker vhosty, które nie mają wybranego własnego profilu ACL per aplikacja.", + "dockerApplyService": "Zastosuj zmiany", + "dockerAccessControl": "Kontrola dostępu", + "dockerAclSummary": "Opcjonalny profil ACL i reguły IP per aplikacja", + "dockerAclProfile": "Profil ACL", + "dockerAclProfileNone": "Bez profilu ACL", + "dockerAclProfileInherit": "Domyślny agenta", + "dockerAclInline": "Użyj dodatkowego ACL per aplikacja", + "dockerAclDefault": "Domyślna akcja ACL", + "dockerAclRules": "Reguły IP/CIDR", + "dockerAclHelp": "Jedna reguła w linii, np. allow 10.0.0.0/8. Profil i ACL per aplikacja są egzekwowane łącznie.", + "dockerProxyTimeouts": "Timeouty proxy", + "dockerProxyTimeoutsHelp": "Jawne limity per aplikacja: domyślnie połączenie 10 s, nagłówki odpowiedzi 120 s, odczyt 60 s i wysyłanie 60 s.", + "dockerHostnameRequired": "Przed wystawieniem wymagany jest hostname.", + "dockerForceSsl": "Przekieruj HTTP do HTTPS", + "dockerForceSslUnavailable": "Wymaga aktywnego listenera zwykłego HTTP oraz jednego jednoznacznego listenera TLS dla tego agenta.", + "dockerWebsockets": "WebSockety", + "dockerCache": "Cache", + "vhProxyTimeouts": "Timeouty proxy", + "vhProxyConnectTimeout": "Proxy connect timeout (s)", + "vhProxyHeaderTimeout": "Proxy response header timeout (s)", + "vhProxyReadTimeout": "Proxy read timeout (s)", + "vhProxySendTimeout": "Proxy send timeout (s)", + "vhProxyTimeoutsHelp": "Domyślnie: połączenie 10 s, nagłówki odpowiedzi 120 s, odczyt 60 s i wysyłanie 60 s. Read/send to timeout bezczynności podczas streamowania body.", + "notfoundModeBuiltin": "Zaślepka aplikacyjna dla statusu", + "pageBuiltin": "Wbudowana strona statusu", + "vhOpenBrowser": "Otwórz", + "securityPasswordHint": "Wymaga obecnego hasła i wyloguje wszystkie sesje.", + "securityAccessControl": "KONTROLA DOSTĘPU", + "securityPoliciesHint": "Lista polityk pozostaje widoczna; edytor otwieraj tylko przy dodawaniu lub zmianie reguł.", + "securityPolicyEditorHint": "Zakres hostów, domyślna akcja i reguły CIDR.", + "securityAuditOpen": "Audyt administracyjny", + "securityAuditHint": "Ostatnie operacje administracyjne są pobierane dopiero po otwarciu tego okna.", + "dockerConfigureService": "Konfiguruj vhost", + "dockerAliasesShort": "aliasów", + "dockerAgentDetails": "Szczegóły agenta", + "dockerServices": "Usługi", + "dockerOpenApp": "Otwórz aplikację", + "networkInterfacesHistory": "Ruch według interfejsów", + "networkInterfaceRate": "RX / TX", + "networkNoInterfaces": "Brak dostępnych interfejsów sieciowych innych niż loopback.", + "networkInterfacesCount": "{count} interfejsów", + "logExpandBuffer": "Zwiększ bufor", + "logExpandedBuffer": "Bufor 4096", + "logBufferExpanded": "Bufor live zwiększono do {count} zachowanych wpisów.", + "vhIdRenameHelp": "Zmiana ID vhosta tworzy nową tożsamość metryk/logów/cache i resetuje bieżącą historię health/traffic. Hostname’y i skonfigurowane ID backendów pozostają bez zmian.", + "vhIdRenameConfirm": "Zmienić ID vhosta z {old} na {new}? Bieżąca historia health/traffic oraz tożsamość metryk/cache tego vhosta zostaną rozpoczęte od nowa.", + "cacheDomainFilter": "Pokaż", + "cacheDomainFilterAll": "Wszystkie domeny", + "cacheDomainFilterEnabled": "Cache włączony", + "cacheDomainFilterDisabled": "Cache wyłączony", + "cacheNoDomainsFiltered": "Brak domen pasujących do tego filtra.", + "cacheColdCleanup": "Wyczyść cold cache", + "cacheColdCleanupHelp": "Operacja działa asynchronicznie i korzysta z tego samego mechanizmu eviction co automatyczny GC cold cache.", + "cacheColdUnusedSeconds": "Nieużywane co najmniej przez (sekundy, opcjonalnie)", + "cacheColdOldestCount": "Usuń maksymalnie najstarszych obiektów", + "cacheColdHitsZero": "Tylko obiekty z hits = 0", + "cacheColdCleanupStart": "Uruchom czyszczenie", + "cacheColdCleanupRunning": "Trwa czyszczenie cold cache…", + "cacheColdCleanupDone": "Usunięto {count} obiektów i zwolniono {bytes}.", + "cacheColdCleanupFailed": "Czyszczenie cold cache nie powiodło się.", + "cacheColdCleanupInvalidJob": "Czyszczenie cold cache nie zwróciło identyfikatora zadania.", + "cacheColdGcInterval": "Interwał GC cold cache (sekundy)", + "cacheColdGcMaxDelete": "Maksymalna liczba usunięć na przebieg GC", + "transformSettings": "Transformacja odpowiedzi statycznych", + "transformEnable": "Włącz globalnie silnik transformacji", + "transformHelp": "Transformacja odbywa się po dekodowaniu upstreamu, a przed zapisem do cache i kompresją dla klienta. Każdy vhost musi zostać włączony osobno.", + "transformJavascript": "Minifikacja JavaScript", + "transformCss": "Minifikacja CSS", + "transformHtml": "Minifikacja HTML", + "transformSvg": "Optymalizacja SVG", + "transformJson": "Kompaktowanie JSON", + "transformExtensions": "Dozwolone rozszerzenia plików, po jednym w linii", + "transformMaxBody": "Maksymalny rozmiar transformowanej odpowiedzi (KiB)", + "transformResourcePresetTitle": "Preset zasobów", + "transformResourcePresetHelp": "Presety ustawiają limit pamięci tymczasowej, maksymalny rozmiar transformowanej odpowiedzi i globalny limit równoległych transformacji. Typy treści i lista rozszerzeń pozostają bez zmian.", + "transformPresetConservative": "Oszczędny RAM", + "transformPresetRecommended": "Rekomendowany", + "transformPresetPerformance": "Wydajność", + "transformPresetUber": "Uber wydajność", + "transformMemoryBudget": "Budżet pamięci tymczasowej transformacji (MiB)", + "transformMaxInflight": "Maksymalna liczba równoległych transformacji", + "transformMaxInflightShort": "równolegle", + "transformResourceCurrent": "Aktualne limity", + "transformBudgetTooSmallWarning": "Budżet pamięci jest mniejszy niż pesymistyczny koszt buforów dla jednej maksymalnej skompresowanej odpowiedzi. Takie odpowiedzi mogą zostać pominięte z powodem memory_pressure.", + "transformBudgetHighWarning": "Limit pamięci transformacji przekracza 50% efektywnej pamięci RAM hosta/cgroup:", + "transformSafety": "Cache-Control: no-transform jest zawsze respektowane. Przetransformowana reprezentacja otrzymuje nowy ETag i jest zapisywana do cache przed gzip, Brotli lub zstd.", + "saveTransform": "Zastosuj ustawienia transformacji", + "vhTransform": "Transformacja", + "vhTransformEnable": "Włącz transformacje dla tego vhosta", + "vhTransformExtensionsCustom": "Nadpisz globalne rozszerzenia transformacji", + "vhTransformHelp": "Globalny silnik również musi być włączony. Ustawienia formatów dziedziczą politykę globalną, chyba że zostaną jawnie nadpisane.", + "dockerTransform": "Transformuj odpowiedzi statyczne", + "vhPassive5xxWarning": "Zliczanie HTTP 5xx może wyłączyć cały backend po serii błędów aplikacyjnych z pojedynczego endpointu.", + "vhPassiveSlowWarning": "Zliczanie wolnych odpowiedzi może wyłączyć backend po serii poprawnych odpowiedzi przekraczających próg slow-response.", + "transform": "Transformacja", + "transformTitle": "Transformacja odpowiedzi statycznych.", + "transformDescription": "Skuteczność transformacji, oszczędność, pominięcia i ponowne użycie z cache.", + "transformApplied": "Przetransformowane odpowiedzi", + "transformExamined": "Sprawdzone", + "transformCacheHits": "HIT-y transformowanych obiektów", + "transformCacheHitsHelp": "Obsłużone bez ponownego uruchamiania transformacji", + "transformSaved": "Bajty oszczędzone przed kompresją", + "transformReduction": "Średnia redukcja", + "transformReductionHelp": "Dla odpowiedzi, których reprezentacja faktycznie się zmieniła", + "transformSkipped": "Pominięte / fail-open", + "transformErrors": "Błędy body / transportu", + "transformAvgTime": "Średni czas", + "transformByType": "Transformacje według typu", + "transformType": "Typ", + "transformSkipReasons": "Powody pominięcia / fail-open", + "transformNoSkips": "Brak pominiętych transformacji w tym zakresie.", + "transformNoSkipsShort": "Brak pominięć", + "transformVhosts": "Skuteczność per vhost", + "transformScopeHint": "Liczniki są diagnostyką runtime w pamięci. HIT transformowanego obiektu z cache nie uruchamia transformera ponownie.", + "transformNoData": "Brak aktywności transformacji.", + "transformBadge": "transformowany", + "cacheLiveChartTitle": "Aktywność cache na żywo", + "cacheLiveChartHelp": "HIT / MISS / BYPASS na sekundę dla wybranego zakresu", + "liveChartSamples": "Próbki", + "transformLiveChartTitle": "Aktywność transformacji na żywo", + "transformLiveChartHelp": "Zastosowane / HIT cache / pominięte / błędy na sekundę dla wybranego zakresu", + "transformChartApplied": "Zastosowane", + "transformChartCacheHits": "HIT cache", + "transformChartSkipped": "Pominięte", + "cacheInvalidationTitle": "Purge / BAN cache", + "cacheInvalidationOperation": "Operacja", + "cacheInvalidationSelector": "Selektor", + "cacheInvalidationValue": "Wartość", + "cacheInvalidationHost": "Host (opcjonalnie)", + "cacheBanTtl": "TTL BAN (sekundy)", + "cacheInvalidationHelp": "Wybrany vhost ogranicza zakres operacji. Exact i prefix uwzględniają query string. Operacje regex i prefix / wymagają dodatkowego potwierdzenia.", + "cacheRunInvalidation": "Wykonaj operację", + "cacheActiveBans": "Aktywne reguły BAN", + "cacheBanExpires": "Wygasa", + "cacheNoBans": "Brak aktywnych reguł BAN.", + "cacheTarget": "Target", + "cacheKeyTags": "Klucz cache / tagi", + "cachePurgeUrl": "Purge URL", + "cacheRemoveBan": "Usuń BAN", + "cacheBanCreated": "Utworzono BAN", + "cacheConfirmPurgeUrl": "Usunąć ten URL z cache RAM i cold storage?", + "cacheConfirmRemoveBan": "Usunąć tę regułę BAN?", + "cacheWideInvalidationConfirm": "To szeroka operacja unieważniania i może objąć wiele obiektów cache. Kontynuować?", + "cacheCollapseWaiters": "oczekuje", + "cacheCollapsed": "scalone", + "actions": "Akcje", + "cacheCollapseTitle": "Scalanie żądań", + "cacheCollapseEnable": "Scalaj równoczesne fille dla jednego klucza cache", + "cacheCollapseTimeout": "Limit oczekiwania followera (ms)", + "cacheCollapseFallback": "Fallback po timeout", + "cacheCollapseFallbackOrigin": "Origin", + "cacheCollapseFallbackStale": "Stale, jeśli dostępny", + "cacheStaleErrorTitle": "Polityka stale-if-error", + "cacheSieTimeout": "Timeout", + "cacheSieConnection": "Błąd połączenia", + "cacheSieDns": "Błąd DNS", + "cacheSieTls": "Błąd TLS", + "cacheSieStatuses": "Statusy HTTP 5xx dopuszczające stale fallback", + "cacheProactiveTitle": "Proaktywne odświeżanie", + "cacheProactiveEnable": "Odświeżaj próbkę obiektów cache przed wygaśnięciem", + "cacheProactiveBefore": "Odśwież przed wygaśnięciem (sekundy)", + "cacheProactivePercent": "Próbkowane obiekty (%)", + "cacheProactiveInflight": "Maksymalna liczba równoległych odświeżeń", + "cacheProactiveHelp": "Używa rewalidacji validatorów, deterministycznego próbkowania i globalnego limitu współbieżności, aby zapobiegać lawinie odświeżeń.", + "cacheInvalidationOpen": "Purge / Ban", + "cacheBanListOpen": "Aktywne BAN-y", + "cacheBanRemoved": "Reguła BAN została usunięta", + "tunnelsOpen": "Aktywne tunele", + "tunnelsTitle": "Aktywne WebSockety / tunele", + "tunnelsReload": "Odśwież", + "tunnelsEmpty": "Brak aktywnych tuneli.", + "tunnelId": "ID", + "tunnelClient": "Klient", + "tunnelHost": "Host", + "tunnelUpstream": "Upstream", + "tunnelProtocol": "Protokół", + "tunnelDuration": "Czas", + "tunnelRx": "RX", + "tunnelTx": "TX", + "tunnelKill": "Zamknij", + "tunnelKilled": "Tunel zamknięty przez administratora", + "tunnelKillConfirm": "Zamknąć ten tunel?", + "tunnelKillReason": "Powód zamknięcia", + "tunnelKillReasonPlaceholder": "Zamknięcie administracyjne", + "tunnelKillReasonDefault": "panel administracyjny", + "listenerH2c": "h2c HTTP/2 bez TLS (prior knowledge + Upgrade z HTTP/1.1)", + "vhWebsocketRfc8441": "RFC 8441 Extended CONNECT przez HTTP/2", + "wsH1": "H1 Upgrade", + "wsH2Rfc8441": "H2 RFC 8441", + "wsH3Rfc9220": "H3 RFC 9220", + "wsEstablished": "Utworzone", + "httpProtocolMix": "Miks protokołów HTTP", + "wsProtocolMix": "Miks protokołów WebSocket", + "vhWebsocketMode": "Transport WebSocket", + "vhWebsocketDisabled": "Wyłączony", + "vhWebsocketH1": "HTTP/1.1 Upgrade", + "vhWebsocketH2Fallback": "HTTP/2 RFC 8441 + fallback H1", + "vhWebsocketH3Fallback": "HTTP/3 RFC 9220 + fallback H1", + "vhWebsocketH2H3Fallback": "HTTP/2 + HTTP/3 + fallback H1", + "vhMaxConcurrentRequests": "Maks. równoległych żądań", + "vhBackendQueueTimeout": "Timeout kolejki pojemności (ms)", + "vhBackendCapacityHelp": "0 równoległych żądań oznacza brak limitu. Timeout kolejki równy 0 natychmiast zwraca HTTP 503 po osiągnięciu limitu backendu.", + "vhLastFailure": "Ostatni błąd", + "vhLastRecovery": "Ostatni powrót", + "certificateIssuerName": "Wystawca certyfikatu", + "certificateValidFrom": "Ważny od", + "certificateDaysRemaining": "Pozostało dni", + "certificateExpired": "Certyfikat wygasł", + "certificateExpiresSoon": "Certyfikat wkrótce wygaśnie", + "certificateRenewalStatus": "Status odnawiania", + "certificateRenewalError": "Ostatni błąd odnawiania", + "vhActiveHealth": "Active health", + "vhPassiveFailures": "Błędy passive health", + "certificateAdminRestartRequired": "TLS panelu administracyjnego używa konfiguracji ładowanej przy starcie; uruchom ponownie RustProxy, aby odświeżyć ten certyfikat.", + "cacheTabGeneral": "Ogólne", + "cacheTabResilience": "Odporność", + "cacheTabCold": "Cold cache", + "cacheTabDiagnostics": "Statyczne i diagnostyka", + "certificateApiTitle": "API certyfikatów", + "certificateApiHelp": "Twórz osobne poświadczenia Key ID + Bearer Token dla automatyzacji wdrażania i przeładowywania certyfikatów. Tokeny nie dają dostępu do konfiguracji ani pozostałych API administracyjnych.", + "certificateApiKeyId": "Key ID", + "certificateApiToken": "Bearer token (opcjonalna własna wartość)", + "certificateApiTokenHelp": "Pozostaw pole puste, aby wygenerować silny token. Jawna wartość każdego tokenu jest pokazywana tylko raz; RustProxy zapisuje wyłącznie jego hash.", + "certificateApiRotate": "Generuj / obróć token", + "certificateApiRevoke": "Unieważnij token", + "certificateApiOneTimeToken": "Skopiuj ten token teraz", + "certificateApiCurlHelp": "Automatyzacja zewnętrzna wysyła nagłówek Key ID i Bearer Token do endpointów deploy/reload przez HTTPS (lub HTTP po loopback).", + "certificateApiUnknown": "Ładowanie statusu API certyfikatów…", + "certificateApiConfigured": "API certyfikatów włączone", + "certificateApiDisabled": "API certyfikatów wyłączone", + "certificateApiLastUsed": "ostatnio użyty", + "certificateApiRotated": "Token API certyfikatów został utworzony / zmieniony. Skopiuj go teraz.", + "certificateApiRevoked": "Token API certyfikatów został unieważniony.", + "certificateApiRevokeConfirm": "Unieważnić token zewnętrznego API certyfikatów? Certbot i integracje API używające go natychmiast przestaną działać.", + "certificate_api.invalid_token": "Nieprawidłowy Key ID lub Bearer Token API certyfikatów.", + "certificate_api.https_required": "Zewnętrzny token API certyfikatów wymaga HTTPS, chyba że żądanie pochodzi z loopback.", + "certificate_api.invalid_token_format": "Token API certyfikatów musi mieć 32–128 bezpiecznych znaków URL.", + "certificate_api.invalid_key_id": "Nieprawidłowy Key ID API certyfikatów.", + "vhWebsocketLegacySupport": "Włącz zgodność ze starym WebSocket", + "vhWebsocketLegacySupportHelp": "Dla starszych urządzeń i serwerów embedded. Handshake WebSocket do upstreamu używa HTTP/1.1, Host i Origin są dopasowane do skonfigurowanego adresu backendu, a stary format odpowiedzi 101 jest tolerowany. Zwykły ruch HTTP pozostaje bez zmian.", + "vhWebsocketLegacyBadge": "WebSocket legacy", + "runtimeInformation": "Informacje środowiska", + "runtimeInformationHelp": "Wartości raportuje uruchomiony proces RustProxy. Są dostępne tylko w uwierzytelnionym API administratora.", + "runtimePlatform": "Platforma", + "statisticsSource": "Źródło statystyk", + "dataDirectory": "Katalog danych", + "databaseLocation": "Baza danych", + "connectionActivity": "AKTYWNOŚĆ POŁĄCZEŃ", + "reloadCertificate": "Przeładuj certyfikat", + "certificateApiComment": "Komentarz", + "certificateApiConfiguredCount": "Tokeny API certyfikatów: {count} / {max}", + "certificateApiNeverUsed": "nigdy nie użyty", + "certificateApiRevokeAll": "Unieważnij wszystkie tokeny", + "certificateApiRevokeOneConfirm": "Unieważnić token API certyfikatów {key}? Automatyzacja używająca tego tokenu natychmiast przestanie działać.", + "certificateApiRevokeAllConfirm": "Unieważnić wszystkie tokeny API certyfikatów? Cała automatyzacja zewnętrzna korzystająca z tych tokenów natychmiast przestanie działać.", + "certificate_api.invalid_comment": "Komentarz tokenu API certyfikatów może mieć maksymalnie 256 znaków i nie może zawierać znaków sterujących.", + "certificate_api.limit_reached": "Osiągnięto limit tokenów API certyfikatów.", + "certificate_api.not_found": "Nie znaleziono tokenu API certyfikatów.", + "networkInterfacesVisibleCount": "{visible} / {total} interfejsów", + "hideMetric": "Ukryj", + "showMetric": "Pokaż", + "hiddenInterfaces": "Ukryte interfejsy", + "networkNoVisibleInterfaces": "Wszystkie wykryte interfejsy są ukryte w tej przeglądarce.", + "cacheMemorySizingTitle": "Dobór pamięci", + "cacheMemorySizingHelp": "Presety korzystają z efektywnej pamięci dostępnej dla RustProxy (RAM hosta ograniczony limitem cgroup, jeśli występuje). Ustawiają HOT, pamięć przejściową, rozmiar obiektu, liczbę wpisów i kolejkę demotion; limit dysku COLD pozostaje bez zmian.", + "cachePresetConservative": "Oszczędny", + "cachePresetRecommended": "Zalecany", + "cachePresetPerformance": "Wydajnościowy", + "cachePresetSelected": "Wybrany", + "cachePresetCustom": "Własny", + "cacheColdPresetTitle": "Preset polityki COLD", + "cacheColdPresetHelp": "Preset zalecany włącza przenoszenie po bezczynności/LRU/zamknięciu, dobiera kolejkę COLD do pamięci przejściowej i ustawia zachowawcze czasy GC. Ścieżka, limit dysku i limit obiektów pozostają bez zmian.", + "cacheTransientLimit": "Limit pamięci przejściowej (MiB)", + "cacheEvictionLimit": "Maks. usunięć LRU na przyjęcie obiektu", + "cacheColdQueueLimit": "Limit RAM kolejki COLD (MiB)", + "cacheMemoryNotDetected": "Nie wykryto pamięci", + "cacheMemoryPresetUnavailable": "Automatyczne presety wymagają telemetrii RAM hosta lub limitu cgroup.", + "cacheMemoryCgroup": "Efektywny RAM cgroup", + "cacheMemoryDetected": "Wykryty RAM", + "cacheQueueOverTransientWarning": "Limit kolejki COLD nie może przekraczać limitu pamięci przejściowej.", + "cacheMemoryHighWarning": "Ostrzeżenie: budżety HOT + pamięć przejściowa zajmują dużą część efektywnego RAM:", + "cachePresetTransientShort": "przejściowa", + "cachePresetObjectShort": "maks. obiekt", + "cachePresetQueueShort": "kolejka COLD", + "cacheLogicalShort": "logiczne", + "cacheLimitShort": "limit", + "cacheMemoryPressureShort": "presja pamięci", + "cacheNukeLimitShort": "limit LRU", + "cacheMemoryPresetTooSmall": "Automatyczne presety cache są wyłączone poniżej 256 MiB efektywnego RAM; jeśli to celowe, skonfiguruj cache ręcznie.", + "cacheMemoryRecommendedFor": "Zalecane dla wykrytej pamięci:", + "cacheMemoryHeadroomWarning": "Ostrzeżenie: dodatkowy budżet cache jest duży względem aktualnie dostępnej pamięci hosta/cgroup:", + "cacheObjectOverTransientWarning": "Maksymalny rozmiar obiektu przekracza limit pamięci przejściowej; obiekty zbliżone do tego rozmiaru przejdą bez zapisania w cache.", + "vhCacheGlobalDisabled": "Globalny cache jest wyłączony. Ten vhost nie może włączyć cache, dopóki cache globalny pozostaje wyłączony.", + "responseLatencyInfo": "Informacje o czasie odpowiedzi", + "responseLatencyHint": "Wartość to skumulowana średnia długość zakończonych wymian HTTP od startu procesu. Wykres pokazuje kolejne próbki tej średniej; nie jest to percentyl ani czas pojedynczego żądania.", + "web-server": "Serwer WWW", + "web-serverTitle": "Serwuj lokalne pliki.", + "web-serverDescription": "Twórz wielokrotnego użytku usługi WWW i podpinaj je do vhostów lub lokalizacji.", + "webServer": "Serwer WWW", + "webServerIntro": "Tutaj utwórz lokalne usługi WWW, a następnie podepnij je do vhosta lub lokalizacji.", + "webServiceList": "Usługi WWW", + "webServiceSearch": "Szukaj usług WWW", + "webServiceSearchPlaceholder": "Szukaj nazwy, ID lub document root", + "webServiceNew": "Nowa usługa WWW", + "webServiceEditor": "Konfiguracja usługi WWW", + "webServiceTabGeneral": "Ogólne", + "webServiceTabRouting": "Routing", + "webServiceTabMime": "MIME", + "webServiceTabCacheHeaders": "Cache i nagłówki", + "webServiceTabDelivery": "Serwowanie", + "webServiceTabPhp": "PHP-FPM", + "webServiceTabSecurity": "Bezpieczeństwo", + "webServiceId": "ID usługi", + "webServiceName": "Nazwa", + "webServiceRoot": "Document root", + "webServiceIndex": "Pliki index", + "webServiceDirectoryListing": "Listowanie katalogu", + "webServiceMimeOverrides": "Nadpisania MIME", + "webServiceMimeBuiltin": "Wbudowane mapowania", + "webServiceMimeHelp": "Opcjonalne nadpisania rozszerzenie → Content-Type, po jednym na linię. Format: ext = media/type.", + "webServiceMimeInvalid": "Nadpisania MIME muszą mieć unikalny format 'ext = media/type', po jednym wpisie na linię.", + "webServiceDefaultMime": "Domyślny typ MIME", + "webServiceCacheControl": "Cache-Control", + "webServiceCacheRules": "Reguły Cache-Control", + "webServiceCacheRulesHelp": "Bardziej szczegółowe reguły są sprawdzane przed polityką domyślną. Użyj ext:css albo mime:image/.", + "webServiceCacheRulesInvalid": "Reguły Cache-Control muszą mieć format dopasowanie = wartość, np. ext:css = public, max-age=3600.", + "webServiceResponseHeaders": "Nagłówki odpowiedzi", + "webServiceResponseHeadersHelp": "Stałe nagłówki tej usługi WWW. Reguły vhosta/lokalizacji są nakładane później i mogą je nadpisać.", + "webServiceResponseHeadersInvalid": "Nagłówki odpowiedzi muszą mieć unikalny format Nazwa-Nagłówka = wartość, po jednym wpisie na linię.", + "webServiceCacheHelp": "Lokalne pliki korzystają z filesystemu/cache stron systemu operacyjnego. Te ustawienia sterują cache przeglądarki/proxy i nie tworzą drugiego cache obiektowego RustProxy.", + "webServiceTryFiles": "try_files", + "webServiceTryFilesHelp": "Jeden kandydat na linię. Obsługuje $uri, $query_string oraz końcowy status błędu typu =404.", + "webServiceRewrites": "Reguły rewrite", + "webServiceRewritesHelp": "Jedna reguła regex na linię. Użyj wzorzec => /cel dla rewrite wewnętrznego albo wzorzec => 301:/cel dla przekierowania.", + "webServiceRewritesInvalid": "Reguły rewrite muszą mieć format wzorzec => /cel albo wzorzec => 301:/cel (301/302/307/308).", + "webServicePrecompressed": "Serwuj gotowe pliki skompresowane", + "webServicePrecompressedBr": "Brotli (.br)", + "webServicePrecompressedGzip": "Gzip (.gz)", + "webServiceDownloadExtensions": "Rozszerzenia do pobierania", + "webServiceDownloadExtensionsHelp": "Pliki z tymi rozszerzeniami otrzymają Content-Disposition: attachment.", + "webServiceRangeHelp": "Statyczne i gotowe skompresowane reprezentacje zachowują walidatory, pojedynczy Range, 206/416 i streaming.", + "webServicePhpEnabled": "Włącz PHP-FPM / FastCGI", + "webServicePhpEndpoint": "Endpoint PHP-FPM", + "webServicePhpEndpointHelp": "Unix: unix:/run/php/php-fpm.sock. TCP: tcp:127.0.0.1:9000 albo tcp:[::1]:9000. TCP jest celowo ograniczone do adresów loopback.", + "webServicePhpExtensions": "Rozszerzenia PHP", + "webServicePhpPassAuthorization": "Przekazuj nagłówek Authorization", + "webServicePhpConnectTimeout": "Timeout połączenia (ms)", + "webServicePhpRequestTimeout": "Łączny timeout żądania FastCGI (ms)", + "webServicePhpConcurrency": "Maks. równoległych żądań PHP", + "webServicePhpBodyLimit": "Limit body żądania PHP (bajty, 0 = bez limitu)", + "webServicePhpHeaderLimit": "Maks. bajtów nagłówków odpowiedzi FastCGI", + "webServicePhpStderrLimit": "Maks. bajtów stderr PHP-FPM w logu", + "webServicePhpCustomParams": "Własne parametry FastCGI", + "webServicePhpCustomParamsHelp": "Jeden wpis NAZWA = wartość na linię. Tylko statyczne, zaufane wartości; podstawowe CGI, HTTP_* i kontrolne PHP_* są zarezerwowane.", + "webServicePhpCustomParamsInvalid": "Własne parametry FastCGI muszą mieć unikalny format NAZWA = wartość, po jednym wpisie na linię.", + "webServicePhpCustomDataTooLarge": "Własne parametry FastCGI i nadpisania PHP INI mogą łącznie zajmować maksymalnie 128 KiB.", + "webServicePhpValues": "Nadpisania PHP INI (PHP_VALUE)", + "webServicePhpValuesHelp": "Jedna dyrektywa php.ini = wartość na linię. RustProxy wysyła zwalidowany zestaw jako PHP_VALUE; PHP_ADMIN_VALUE nie jest tutaj dozwolone.", + "webServicePhpValuesInvalid": "Nadpisania PHP INI muszą mieć unikalny format dyrektywa = wartość, po jednym wpisie na linię.", + "webServicePhpDocsButton": "Składnia i bezpieczeństwo FastCGI", + "webServicePhpDocsTitle": "Konfiguracja PHP-FPM / FastCGI", + "webServicePhpDocsIntro": "RustProxy łączy się bezpośrednio z istniejącą pulą PHP-FPM. Na tym samym hoście preferuj socket Unix. TCP jest akceptowane wyłącznie na loopback i nie jest publicznym/sieciowym transportem FastCGI.", + "webServicePhpDocsEndpointTitle": "Składnia endpointu", + "webServicePhpDocsEndpoint": "Dla TCP podaj prefiks tcp:, literalny adres IP loopback oraz port. Nazwy hostów i adresy inne niż loopback są odrzucane. Dla socketu Unix proces RustProxy musi mieć prawo połączenia z socketem.", + "webServicePhpDocsCustomTitle": "Własne parametry FastCGI", + "webServicePhpDocsCustom": "Użyj jednego wpisu NAZWA = wartość na linię. Nazwy są normalizowane do wielkich liter i mogą zawierać A-Z, 0-9 oraz podkreślenie. Są to statyczne, zaufane wartości operatora. RustProxy odrzuca podstawowe nazwy CGI, HTTP_*, PHP_VALUE i PHP_ADMIN_VALUE, więc nie można nimi nadpisać routingu requestu, wyboru skryptu ani parametrów pochodzących z HTTP.", + "webServicePhpDocsValuesTitle": "Nadpisania PHP INI", + "webServicePhpDocsValues": "Te linie są łączone w parametr FastCGI PHP_VALUE. PHP-FPM/PHP nadal decyduje, które dyrektywy można zmieniać w tym zakresie. Znaki nowej linii/kontrolne są odrzucane, a PHP_ADMIN_VALUE jest celowo niedostępne.", + "webServicePhpDocsLimitsTitle": "Limity i nagłówki", + "webServicePhpDocsLimits": "Timeout żądania obejmuje wymianę FastCGI. Limit body jest egzekwowany podczas streamingu i po przekroczeniu zwraca 413; 0 wyłącza limit body po stronie RustProxy. Limity nagłówków odpowiedzi i stderr ograniczają pamięć/dane diagnostyczne. Dozwolone są maks. 64 własne parametry FastCGI i 64 nadpisania PHP INI, łącznie do 128 KiB danych własnych. Przekazywanie Authorization można wyłączyć, gdy aplikacja nie potrzebuje HTTP_AUTHORIZATION.", + "webServicePhpDocsSecurity": "Nie umieszczaj sekretów we własnych parametrach ani PHP_VALUE, jeśli nie akceptujesz ich przechowywania w zwykłej konfiguracji Web Service. Używaj osobnej, nieuprzywilejowanej tożsamości puli PHP-FPM i nie wystawiaj PHP-FPM do publicznej sieci.", + "webServicePhpHelp": "RustProxy komunikuje się bezpośrednio przez FastCGI z długowieczną pulą PHP-FPM. PHP nie jest uruchamiane osobno dla każdego żądania, a kod źródłowy PHP nie jest serwowany, gdy obsługa PHP jest wybrana.", + "webServicePhpSymlinkConflict": "PHP-FPM wymaga obecnie polityki symlinków Deny.", + "webServiceSymlinkPolicy": "Polityka symlinków", + "webServiceSymlinkDeny": "Zabroń", + "webServiceSymlinkInsideRoot": "Zezwól tylko wewnątrz document root (Linux)", + "webServiceSafety": "Document root jest ścisłą granicą dostępu do filesystemu. Domyślnie symlinki są blokowane. Linux może opcjonalnie podążać wyłącznie do celów pozostających w document root; PHP-FPM wymaga obecnie polityki blokującej symlinki.", + "webServiceSelect": "Wybierz usługę WWW", + "webService": "Usługa WWW", + "webServiceUsedBy": "Używana przez", + "webServiceUnused": "Niepodpięta", + "webServiceEmpty": "Brak usług WWW.", + "webServiceSearchEmpty": "Brak usług WWW pasujących do wyszukiwania.", + "webServiceInUse": "Usługa WWW jest nadal używana przez", + "webServiceDelete": "Usunąć tę usługę WWW?", + "webServiceIndexRequired": "Pliki index są opcjonalne.", + "webServiceDuplicate": "Usługa WWW o tym ID już istnieje.", + "webServiceRequired": "Wybierz usługę WWW.", + "sourceType": "Typ źródła", + "sourceReverseProxy": "Reverse Proxy", + "sourceWebServer": "Serwer WWW", + "sourceHelp": "Vhost przechowuje tylko wybór źródła. Ustawienia Serwera WWW pozostają w wybranej, wielokrotnego użytku usłudze WWW.", + "locationWebServerAction": "Serwer WWW", + "locationWebServerShort": "Serwer WWW", + "docsReader": "Reader", + "docsApi": "API", + "docsReaderSearch": "Szukaj w dokumentacji", + "docsReaderSearchPlaceholder": "Szukaj tytułu lub ścieżki", + "docsReaderEmpty": "Brak dokumentów pasujących do wyszukiwania.", + "docsCategoryProject": "Projekt", + "docsCategoryGuides": "Dokumentacja funkcjonalna", + "docsCategoryTechnical": "Techniczna", + "docsCategoryAudits": "Audyty i historia", + "docsCategoryHistorical": "Historyczne", + "webServiceIndexHelp": "Opcjonalne. Pozostaw puste, aby pominąć wyszukiwanie indexu; przy włączonym listingu od razu zostanie pokazana lista plików.", + "webServiceNoIndex": "Brak plików index", + "vhBackendRequired": "Reverse Proxy wymaga co najmniej jednego backendu. Dodaj backend albo zmień źródło na Serwer WWW.", + "vhListenerRequired": "Wybierz co najmniej jeden listener dla tego vhosta.", + "traffic": "Ruch", + "trafficTitle": "Ruch per vhost.", + "trafficDescription": "Ograniczone statystyki żądań: kraje, User-Agenty, adresy IP klientów, ścieżki, trasy i wyniki obsługi.", + "trafficSinceStart": "Od startu procesu", + "trafficResponseBytes": "Bajty odpowiedzi", + "trafficRequestBytes": "Bajty żądań", + "trafficMeanLatency": "Średnie opóźnienie", + "trafficDroppedSamples": "Odrzucone próbki statystyk", + "trafficBoundedLabel": "OGRANICZONE / ASYNCHRONICZNE", + "trafficDimensionsTitle": "Wymiary ruchu", + "trafficApproxHelp": "Listy TOP są przybliżone i mają stały limit, aby ruch o dużej liczbie unikalnych wartości nie zwiększał pamięci proxy bez ograniczeń.", + "trafficTopCountries": "Top kraje", + "trafficTopUserAgents": "Top User-Agenty", + "trafficTopClientIps": "Top adresy IP klientów", + "trafficClientIp": "IP klienta", + "trafficTopPaths": "Top ścieżki", + "trafficTopRoutes": "Top trasy", + "trafficMethods": "Metody", + "trafficStatusClasses": "Klasy statusów", + "trafficCacheOutcomes": "Wyniki cache", + "trafficValue": "Wartość", + "trafficOther": "Pozostałe", + "trafficNoCountryData": "Zbieranie kraju jest wyłączone albo baza GeoIP jest niedostępna.", + "trafficNoUserAgentData": "Brak zebranych danych User-Agent.", + "trafficNoData": "Brak danych o ruchu.", + "trafficUserAgentEnabled": "Zbieranie User-Agent włączone", + "trafficUserAgentDisabled": "Zbieranie User-Agent wyłączone", + "trafficCountryEnabled": "Zbieranie kraju włączone", + "trafficCountryDisabled": "Zbieranie kraju wyłączone", + "trafficCountryNoDb": "Zbieranie kraju włączone, baza GeoIP niedostępna", + "trafficUpdated": "Odświeżono", + "loggingCaptureTitle": "Zbierane wymiary żądania", + "loggingCaptureUserAgent": "Zbieraj User-Agent", + "loggingCaptureCountry": "Zbieraj kraj z GeoIP", + "loggingCaptureCountryHelp": "Lookup kraju jest opcjonalny i domyślnie wyłączony. Włącz go tylko, gdy potrzebujesz kraju w logach/statystykach; reguły ACL/rate-limit per kraj nadal użyją GeoIP, gdy jest to wymagane.", + "cacheAutoTrimEnabled": "Automatycznie zwalniaj nieużywaną pamięć cache HOT", + "cacheAutoTrimAfter": "Czas bezczynności przed trim HOT (sekundy)", + "cacheAutoTrimTarget": "Docelowe użycie HOT po trim (%)", + "cacheAutoTrimHelp": "Gdy pamięć HOT przekracza próg, w ograniczonych partiach usuwane są wyłącznie obiekty nieużywane przez ustawiony czas. Aktywny working set nie jest czyszczony.", + "webServiceTabHtaccess": ".htaccess", + "webServiceHtaccessEnabled": "Włącz zgodność z .htaccess", + "webServiceHtaccessFilename": "Plik konfiguracyjny", + "webServiceHtaccessRecursive": "Skanuj podkatalogi", + "webServiceHtaccessStrict": "Tryb ścisły dla niewspieranych dyrektyw", + "webServiceHtaccessDocs": "Dokumentacja zgodności", + "webServiceHtaccessHelp": "RustProxy kompiluje ograniczony podzbiór zgodny z Apache podczas zastosowania Web Service. Pliki nie są parsowane przy każdym żądaniu; po zmianie .htaccess na dysku zastosuj Web Service ponownie.", + "webServiceHtaccessDocsTitle": "Zgodność .htaccess", + "webServiceHtaccessDocsIntro": "To warstwa zgodności przeznaczona do migracji, a nie pełne środowisko Apache. Wspierane dyrektywy są kompilowane do reguł Web Servera RustProxy.", + "webServiceHtaccessDocsSupportedTitle": "Wspierany podzbiór", + "webServiceHtaccessDocsRewriteTitle": "Zgodność rewrite", + "webServiceHtaccessDocsRewrite": "Warunki rewrite obsługują testy REQUEST_FILENAME (-f, -d, -s), REQUEST_URI, REQUEST_METHOD, QUERY_STRING, HTTP_HOST, HTTPS, DOCUMENT_ROOT, THE_REQUEST i nagłówki HTTP. Flagi: L, END, R, R=301/302/307/308, QSA, NC, F, OR. PT/NE są akceptowane jako no-op. E= jest akceptowane jako no-op zgodności, ponieważ nagłówki HTTP żądania i tak trafiają do PHP-FPM.", + "webServiceHtaccessDocsPhpTitle": "PHP-FPM", + "webServiceHtaccessDocsPhp": ".htaccess może dodawać rozszerzenia PHP przez AddHandler, ale endpoint PHP-FPM, timeouty i limit współbieżności nadal są kontrolowane w zakładce PHP-FPM Web Service. Składnia Apache SetHandler wskazująca socket proxy celowo nie jest akceptowana.", + "webServiceHtaccessDocsReloadTitle": "Ładowanie i limity", + "webServiceHtaccessDocsReload": "Pliki są odczytywane i kompilowane podczas „Validate, save and apply”. RustProxy nie parsuje .htaccess przy każdym żądaniu. Po zmianie pliku zastosuj konfigurację ponownie. Skan ma limity: 128 plików, głębokość 16, 128 KiB na plik i 1 MiB łącznie.", + "webServiceHtaccessDocsUnsupportedTitle": "To nie jest pełny Apache", + "webServiceHtaccessDocsUnsupported": "ErrorDocument, SetEnvIf, Redirect/RedirectMatch i FallbackResource nie są zaimplementowane w tej warstwie. Ogólne Files/FilesMatch, niewspierane dyrektywy uwierzytelniania/autoryzacji, handlery inne niż PHP i SetHandler są odrzucane nawet przy wyłączonym trybie ścisłym, ponieważ ich ciche pominięcie mogłoby osłabić kontrolę dostępu lub ujawnić kod źródłowy. Pliki .htaccess/.htpasswd są zawsze blokowane przed wysłaniem przez HTTP. Pozostałe niewspierane dyrektywy niesecurity są logowane i ignorowane, chyba że włączono tryb ścisły.", + "webServiceHtaccessDocsSecurity": "ACL vhost/location, uwierzytelnianie, strony błędów i reguły odpowiedzi nadal mają nadrzędną rolę. .htaccess nie może wyjść poza document root, wybrać dowolnego socketu FastCGI ani nadpisać chronionych nagłówków transportowych.", + "webServicePresetTitle": "Preset konfiguracji", + "webServicePreset": "Preset", + "webServicePresetCustom": "Własny", + "webServicePresetStatic": "Strona statyczna", + "webServicePresetSpa": "SPA", + "webServicePresetPhpGeneric": "PHP ogólny", + "webServicePresetDownloads": "Pliki / repozytorium pobrań", + "webServicePresetAction": "Akcja presetu", + "webServicePresetApply": "Zastosuj preset", + "webServicePresetHelp": "Preset wypełnia zwykłe ustawienia Web Service i wszystko nadal można edytować. Document root, ID/nazwa usługi i endpoint PHP-FPM nie są zmieniane.", + "webServicePresetChoose": "Wybierz preset przed jego zastosowaniem.", + "webServicePresetApplied": "Preset zastosowany. Sprawdź wygenerowane ustawienia przed zapisem.", + "webServicePresetHintStatic": "Strona statyczna: indeksy HTML, prekompresowane pliki i reguły cache dla CSS/JS/obrazów/fontów.", + "webServicePresetHintSpa": "SPA: fallback do index.html przez try_files, prekompresowane assety i długi cache zasobów statycznych.", + "webServicePresetHintPhpGeneric": "PHP ogólny: PHP-FPM włączony, index.php pierwszy, bez front-controllera dla brakujących plików.", + "webServicePresetHintWordpress": "WordPress: PHP-FPM, index.php i routing front-controller. Document root ustaw na publiczny katalog WordPressa.", + "webServicePresetHintDrupal": "Drupal: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", + "webServicePresetHintLaravel": "Laravel: PHP-FPM i routing front-controller. Document root ustaw na katalog public/ aplikacji.", + "webServicePresetHintSymfony": "Symfony: PHP-FPM i routing front-controller. Document root ustaw na katalog public/ aplikacji.", + "webServicePresetHintJoomla": "Joomla: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", + "webServicePresetHintPrestashop": "PrestaShop: PHP-FPM, index.php i routing front-controller z cache zasobów statycznych.", + "webServicePresetHintDownloads": "Pobrania: directory listing włączony, obsługa Range i typowe archiwa/dokumenty wymuszane jako załączniki.", + "webServiceHardeningTitle": "Utwardzenie", + "webServiceHardeningAttacks": "Blokuj typowe próby ataków", + "webServiceHardeningHeaders": "Usuwaj zbędne nagłówki ujawniające technologię", + "webServiceHardeningSecurityHelp": "Przełączniki utwardzenia są widoczne obok wyboru presetu w zakładce Ogólne. Po zastosowaniu presetu pozostają niezależnymi ustawieniami.", + "trafficTabOverview": "Przegląd", + "trafficTabClients": "Klienci", + "trafficTabRequests": "Żądania", + "trafficTabDelivery": "Obsługa odpowiedzi", + "trafficVolume": "Wolumen ruchu", + "vhMethodMode": "Polityka metod HTTP", + "vhMethodList": "Metody HTTP (jedna na linię)", + "vhMethodHelp": "Zezwalaj tylko na podane metody albo blokuj podane metody dla tego vhosta. Reguła łączy się z polityką lokalizacji.", + "locationAclProfile": "Profil ACL", + "locationMethodMode": "Polityka metod HTTP", + "locationMethodList": "Metody HTTP (jedna na linię)", + "locationMethodAllow": "Zezwalaj tylko", + "locationMethodBlock": "Blokuj wskazane", + "locationMethodHelp": "Polityka lokalizacji łączy się z polityką vhosta. Przykład: GET, HEAD i POST.", + "locationCountryMode": "Polityka dostępu krajów", + "locationCountryList": "Kody krajów (jeden na linię)", + "locationCountryHelp": "Polityka krajów lokalizacji łączy się z polityką vhosta/profilu. GeoIP jest odczytywany tylko, gdy jest potrzebny.", + "configHistory": "Historia rewizji", + "configHistoryRetention": "SQLITE / OSTATNIE 512 REWIZJI", + "configHistoryHelp": "Wybierz oznaczony dzień, aby zobaczyć zachowane rewizje konfiguracji i ich zmiany. Historia jest zapisywana od wersji 0.25.3.", + "configHistoryChanges": "ZMIANY", + "configHistorySelectDay": "Wybierz dzień.", + "configHistoryRevision": "Rewizja", + "configHistoryRevisionShort": "rew.", + "configHistoryBefore": "Przed", + "configHistoryAfter": "Po", + "configHistoryBaseline": "To najstarsza zachowana baza; wcześniejsza rewizja nie jest dostępna do porównania.", + "configHistoryNoChanges": "Nie znaleziono różnic w konfiguracji.", + "configHistoryDiffLimit": "Podgląd różnic ograniczono do 200 zmienionych ścieżek.", + "configHistoryMissing": "(brak)", + "configHistoryEntries": "rewizji", + "configHistorySummary": "Zachowane rewizje: {count}", + "configHistoryEmpty": "Brak zachowanych rewizji.", + "configHistoryLoading": "Wczytywanie historii rewizji...", + "configHistoryFailed": "Nie udało się wczytać historii rewizji.", + "configHistoryRestoreAction": "Przywróć rewizję", + "configHistoryRestoreConfirm": "Przywrócić rewizję {revision}? Zostanie zwalidowana i zapisana jako nowa rewizja po bieżącej rewizji {current}. Dotychczasowa historia zostanie zachowana.", + "configHistoryRestored": "Rewizja {revision} została przywrócona jako nowa rewizja {new_revision}.", + "about": "O projekcie", + "aboutTitle": "O RustProxy", + "aboutAuthor": "Autor", + "aboutLicense": "Licencja", + "aboutLicenseValue": "Open Source", + "aboutOpenSourceText": "RustProxy jest projektem open source. Kod źródłowy jest publicznie dostępny do wglądu, rozwoju i współtworzenia.", + "aboutRepository": "Repozytorium źródłowe", + "vhPoolRecycleRequests": "Odśwież pulę upstream po liczbie żądań (0 = wył.)", + "vhPoolRecycleSeconds": "Maks. wiek puli upstream (sekundy, 0 = wył.)", + "vhHttp1MaxBuffer": "Maks. bufor odczytu HTTP/1 upstream (bajty)", + "vhPoolRecycleHelp": "Odświeżanie podmienia tylko generację klienta Hyper danego backendu; aktywne wymiany kończą się normalnie. Domyślne limity ograniczają retencję pamięci puli/TLS bez przeładowania vhosta ani cache. Limit żądań: 0 lub 1000..10000000; limit czasu: 0 lub 60..604800.", + "backendSearch": "Szukaj backendów", + "backendSearchPlaceholder": "Szukaj vhosta, backendu lub stanu", + "backendSortBy": "Sortuj według", + "backendSortAscending": "Sortowanie rosnące", + "backendSortDescending": "Sortowanie malejące", + "backendColumns": "Kolumny", + "backendSearchEmpty": "Brak backendów pasujących do wyszukiwania.", + "vhQuickEnable": "Włącz", + "vhQuickDisable": "Wyłącz", + "vhEnableHint": "Określa, czy ten vhost przyjmuje ruch.", + "backendColumnsRequired": "Co najmniej jedna kolumna tabeli backendów musi pozostać widoczna." + } } diff --git a/make_zip.py b/make_zip.py index a6dff64..51ad6dc 100755 --- a/make_zip.py +++ b/make_zip.py @@ -88,7 +88,7 @@ def add_file(archive: zipfile.ZipFile, rel: Path, data: bytes, timestamp: tuple[ def main() -> None: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.25.6.zip') + parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.25.7.zip') output = parser.parse_args().output.resolve() paths = files() checksum = ROOT / 'SHA256SUMS' diff --git a/scripts/check_source.py b/scripts/check_source.py index 6c4b748..fe40d79 100755 --- a/scripts/check_source.py +++ b/scripts/check_source.py @@ -24,7 +24,7 @@ def read_docker_agent_source() -> str: preflight(root) manifest = tomllib.loads((root / "Cargo.toml").read_text()) -assert manifest["package"]["version"] == "0.25.6" +assert manifest["package"]["version"] == "0.25.7" assert manifest["dependencies"]["quinn"]["version"] == "0.11.12" h3dep = manifest["dependencies"]["h3"] assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.19" and "quinn" in h3dep["features"] @@ -32,14 +32,14 @@ assert "h3-quinn" not in manifest["dependencies"] lock_path = root / "Cargo.lock" if lock_path.exists(): lock = lock_path.read_text() - assert 'name = "rust-proxy"\nversion = "0.25.6"' in lock + assert 'name = "rust-proxy"\nversion = "0.25.7"' in lock assert 'name = "systemstat"' in lock and 'name = "metrics-process"' in lock and 'name = "sysinfo"' in lock, "Cargo.lock must be resolver-generated after adding cross-platform statistics libraries" for release_doc, marker in { - "README.md": "# RustProxy 0.25.6", - "CHANGELOG.md": "## 0.25.6", - "ROADMAP.md": "## 0.25.6", - "AGENTS.md": "Current source version: 0.25.6.", - "docs/TEST_REPORT.md": "# Verification report - RustProxy 0.25.6", + "README.md": "# RustProxy 0.25.7", + "CHANGELOG.md": "## 0.25.7", + "ROADMAP.md": "## 0.25.7", + "AGENTS.md": "Current source version: 0.25.7.", + "docs/TEST_REPORT.md": "# Verification report - RustProxy 0.25.7", }.items(): assert marker in (root / release_doc).read_text(), f"stale release identity in {release_doc}" assert tomllib.loads((root / "rust-toolchain.toml").read_text())["toolchain"]["channel"] == "stable" @@ -183,6 +183,15 @@ assert '"force-ssl", "vhForceSsl"' in vhosts_js and 'force_ssl: yes("force-ssl") assert 'vhForceSslNeedsHttp' in vhosts_js and 'tlsPorts.has(443)' in vhosts_js assert '"forward-client-ip", "vhForwardClientIp"' in vhosts_js and 'forward_client_ip: yes("forward-client-ip")' in vhosts_js assert 'id="vhost-search"' in html and '$("vhost-search").addEventListener("input", render)' in vhosts_js +for marker in ['id="pool-search"', 'id="pool-sort"', 'data-pool-column-toggle="vhost"', 'data-pool-column="generationAge"']: + assert marker in html, marker +for marker in ['toggleVhostEnabled', 'vhQuickEnable', 'vhQuickDisable', 'backend_table_columns', 'applyPoolTableView', 'saveSection("vhosts", next.vhosts || [])', 'vh-enable-control']: + assert marker in vhosts_js, marker +assert 'rustproxy-backend-table-v1' not in vhosts_js and 'poolTablePreferenceKey' not in vhosts_js +assert 'window.rustProxyPreferences.update({' in vhosts_js and 'backend_table_sort' in vhosts_js and 'backend_table_descending' in vhosts_js +style_ui = (root / 'src/admin/web/style.css').read_text() +for marker in ['--scrollbar-thumb', '*::-webkit-scrollbar-thumb', '.backend-table-tools', '.vh-enable-control', '.vhost-quick-toggle']: + assert marker in style_ui, marker assert 'id="admin-session-days"' in html and 'min="7" max="30"' in html assert 'member-local-risk' in vhosts_js and 'vhLocalListenerRiskConfirm' in vhosts_js assert 'accept_local_listener_risk: yes("member-local-risk", row)' in vhosts_js @@ -231,7 +240,7 @@ assert 'Opt-in health decisions based on ordinary user traffic. Defaults to disa assert '"force_ssl"' in openapi and '"forward_client_ip"' in openapi assert '"backend_header"' in openapi and '"backend_timing_header"' in openapi assert '"StreamMetrics"' in openapi and '"streams"' in openapi -for marker in ['"version": "0.25.6"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']: +for marker in ['"version": "0.25.7"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']: assert marker in openapi, marker for marker in ['"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']: assert marker in openapi, marker @@ -655,7 +664,7 @@ diagnostics_source = rust_source(root, 'src/diagnostics.rs') + rust_source(root, for marker in ['process_rss_anon_bytes', 'process_rss_file_bytes', 'process_rss_shmem_bytes', 'process_data_bytes', 'process_swap_bytes', 'RssAnon', 'RssFile', 'RssShmem', 'VmData', 'VmSwap']: assert marker in diagnostics_source, marker prometheus_source = rust_source(root, 'src/prometheus.rs') -for marker in ['allow_trusted_network_without_token', 'include_traffic', 'include_docker_vhosts', 'include_streams', 'include_logging', 'rust_proxy_docker_vhost_{name}', 'rust_proxy_docker_backend_{name}', 'rust_proxy_geoip_loaded', 'not_after_timestamp_seconds', 'ewma_latency_seconds', 'passive_failures', 'active_health_failures_total', 'passive_health_failures_total', 'passive_http_5xx_total', 'passive_timeouts_total', 'passive_connect_errors_total', 'passive_io_errors_total', 'passive_slow_total', 'http_5xx_total', 'timeouts_total', 'connect_errors_total', 'io_errors_total', 'slow_responses_total', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_not_found_hosts_configured', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests', 'rust_proxy_web_services_configured', 'rust_proxy_web_service_info', 'rust_proxy_vhost_source_info']: +for marker in ['allow_trusted_network_without_token', 'include_traffic', 'include_docker_vhosts', 'include_streams', 'include_logging', 'rust_proxy_docker_vhost_{name}', 'rust_proxy_docker_backend_{name}', 'rust_proxy_geoip_loaded', 'not_after_timestamp_seconds', 'ewma_latency_seconds', 'passive_failures', 'active_health_failures_total', 'passive_health_failures_total', 'passive_http_5xx_total', 'passive_timeouts_total', 'passive_connect_errors_total', 'passive_io_errors_total', 'passive_slow_total', 'http_5xx_total', 'timeouts_total', 'connect_errors_total', 'io_errors_total', 'slow_responses_total', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_not_found_hosts_configured', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests', 'rust_proxy_web_services_configured', 'rust_proxy_web_service_info', 'rust_proxy_vhost_source_info', 'retry_attempts_total', 'retry_successes_total', 'upstream_client_generation', 'upstream_client_generation_requests', 'upstream_client_generation_age_seconds', 'upstream_client_rotations_total']: assert marker in prometheus_source, marker assert 'if docker_targets.contains_key(&pool.id)' in prometheus_source assert 'if docker_targets.contains_key(id)' in prometheus_source @@ -680,7 +689,7 @@ for marker in ['locationMatchRegex', 'headersVisualBuilder', 'headersAdvancedJso for marker in ['lastApiLatencyMs', 'cacheMemorySamples', 'cacheTransientSamples', 'cacheColdStorageSamples', 'cacheHitSamples', 'processCpuSamples', 'processRssSamples', 'networkRxSamples', 'responseLatencySamples', 'client_ip']: assert marker in app_js, marker logging_source = rust_source(root, 'src/logging.rs') -assert 'pub client_ip: Option' in logging_source and '"client_ip" => entry.client_ip' in logging_source +assert 'pub client_ip: Option' in logging_source and '"client_ip" => entry' in logging_source and '.client_ip' in logging_source for marker in ['check_rustproxy_api', 'response time', 'backend']: assert marker in (root / 'nagios/README.md').read_text(), marker stream_source = rust_source(root, "src/stream.rs") @@ -720,7 +729,7 @@ for marker in ['dpkg-scanpackages', 'apt-ftparchive', 'Packages.gz', 'RUSTPROXY_ grafana = json.loads((root / 'grafana/rustproxy-overview.json').read_text()) assert grafana['uid'] == 'rustproxy-0170' and grafana['schemaVersion'] >= 39 expressions = '\n'.join(target.get('expr','') for panel in grafana['panels'] for target in panel.get('targets',[])) -for marker in ['rust_proxy_process_rss_bytes', 'rust_proxy_cache_transient_bytes', 'rust_proxy_backend_latency_seconds', 'rust_proxy_stream_active', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests']: +for marker in ['rust_proxy_process_rss_bytes', 'rust_proxy_cache_transient_bytes', 'rust_proxy_backend_latency_seconds', 'rust_proxy_stream_active', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests', 'rust_proxy_backend_upstream_client_generation_requests', 'rust_proxy_backend_upstream_client_generation_age_seconds', 'rust_proxy_backend_retry_attempts_total', 'rust_proxy_backend_upstream_client_rotations_total', 'rust_proxy_docker_backend_upstream_client_generation_requests', 'rust_proxy_docker_backend_retry_attempts_total']: assert marker in expressions, marker assert any(variable.get('name') == 'traffic_vhost' for variable in grafana['templating']['list']) assert any(panel.get('title') == 'Traffic analytics and Web Server' for panel in grafana['panels']) @@ -882,7 +891,7 @@ assert 'class="app-loading"' in html and 'document.documentElement.classList.rem assert 'id="mobile-menu-toggle"' in html and 'id="main-navigation"' in html and 'aria-controls="main-navigation"' in html assert '.sidebar.mobile-nav-open .main-navigation' in style_source and 'display: none;' in style_source and 'grid-template-columns: repeat(2, minmax(0, 1fr))' in style_source assert 'function setMobileMenu(open)' in app_js and 'setPanel(button.dataset.panel); setMobileMenu(false);' in app_js and 'event.key === "Escape"' in app_js -assert 'id="about-open"' in html and 'id="about-dialog"' in html and 'Mateusz Griszczynski' in html +assert 'id="about-open"' in html and 'id="about-dialog"' in html and 'Mateusz Gruszczynski' in html assert 'https://git.linuxiarz.pl/gru/RustProxy' in html and 'data-i18n="documentation" id="api-docs"' in html assert '$("about-open").addEventListener("click"' in app_js and '$("about-close").addEventListener("click"' in app_js assert '.about-dialog {' in style_source and '.about-meta {' in style_source and '.top-actions {\n width: 100%;\n flex-wrap: wrap;' in style_source @@ -908,7 +917,7 @@ assert '.check>span {' in style_source and 'transform: translateY(-1px)' in styl assert '.docker-alias-field>span:first-child {' in style_source and 'margin-bottom: 0' in style_source and '.docker-alias-editor {' in style_source and 'min-height: 38px' in style_source and 'height: 30px' in style_source assert 'field.append(box, el("small", t("dockerAliasesHelp")' not in docker_ui assert 'readOnly: !!editing' not in vhosts_js and 'vhIdRenameConfirm' in vhosts_js and 'v.id === value.id && v.id !== editing' in vhosts_js -assert 'enforce_local_page_no_cache' in proxy_source and 'LocalGeneratedResponse' in proxy_source and 'get::().is_none()' in proxy_source +assert 'enforce_local_page_no_cache' in proxy_source and 'LocalGeneratedResponse' in proxy_source and 'get::()' in proxy_source and '.is_none()' in proxy_source assert 'locally_generated_pages_remove_cache_metadata' in proxy_source and '"x-cache-reason"' in proxy_source and '"cache-status"' in proxy_source assert 'local_page_method_rejection_is_still_marked_non_cacheable' in pages_rust and 'response.extensions_mut().insert(PageServed);' in pages_rust assert "rel.as_posix() == 'docker-agent/docker-agent'" in (root / 'make_zip.py').read_text() @@ -921,7 +930,7 @@ assert '
INDEPENDENT BY DESIGN ' not in html, "release assert '
INDEPENDENT BY DESIGN
' in html # tls_verify=false must not feed legacy appliance certificates back through webpki. upstream_source = rust_source(root, "src/upstream.rs") -assert "BackendCertificateVerificationDisabled { supported_schemes }" in upstream_source +assert "BackendCertificateVerificationDisabled" in upstream_source and "supported_schemes" in upstream_source disabled_verifier = upstream_source.split("impl ServerCertVerifier for BackendCertificateVerificationDisabled", 1)[1].split("pub fn client(", 1)[0] assert disabled_verifier.count("Ok(HandshakeSignatureValid::assertion())") == 2 assert "WebPkiServerVerifier" not in disabled_verifier @@ -1194,7 +1203,7 @@ assert '"error_log" => {' not in admin_0241 and 'request("/api/config/error_log" assert '"error_log"' in openapi and 'logging, error_log, forwarding' not in openapi assert 'logging_section_persists_error_log_settings_atomically' in admin_0241 and 'error_log_is_not_a_standalone_configuration_section' in admin_0241 assert 'location.pathname === "/logging"' in settings_js_0241 -assert '"RuntimeInformation"' in openapi and '"version": "0.25.6"' in openapi +assert '"RuntimeInformation"' in openapi and '"version": "0.25.7"' in openapi # 0.24.1 compiler and hostname-cardinality regressions. tls_0241 = rust_source(root, "src/tls.rs") @@ -1239,5 +1248,5 @@ for schema_name in ["RedirectHost", "NotFoundHost"]: node = openapi_0241["components"]["schemas"][schema_name]["properties"]["frontend"]["properties"]["hosts"] assert "maxItems" not in node, schema_name -print("PASS: 0.25.6 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, Debian/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v8 migrations.") +print("PASS: 0.25.7 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, Debian/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v8 migrations.") print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.") diff --git a/scripts/deploy_core.py b/scripts/deploy_core.py index e902307..1eb252d 100755 --- a/scripts/deploy_core.py +++ b/scripts/deploy_core.py @@ -97,7 +97,7 @@ def digest(path: Path) -> str: def fetch_https(url: str, max_bytes: int) -> bytes: if urllib.parse.urlparse(url).scheme != 'https': raise ValueError('GeoIP downloads require HTTPS.') - request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.25.6'}) + request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.25.7'}) with urllib.request.urlopen(request, timeout=30) as response: if urllib.parse.urlparse(response.geturl()).scheme != 'https': raise ValueError('GeoIP download redirected away from HTTPS.') diff --git a/scripts/docs_check.py b/scripts/docs_check.py index 7ae54a5..fa64c1c 100755 --- a/scripts/docs_check.py +++ b/scripts/docs_check.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Rust-independent documentation/Reader consistency checks for the 0.25.6 release.""" +"""Rust-independent documentation/Reader consistency checks for the 0.25.7 release.""" from pathlib import Path import re from rust_source import rust_source @@ -43,25 +43,28 @@ for marker in ["docs-tab-reader", "docs-reader-list", "docs-reader-content", "do assert marker in reader_html, marker for marker in ["renderMarkdown", "selectDocument", 'get("/docs/content.json")', "docsByPath", "docsCategoryHistorical"]: assert marker in reader_js, marker -documentation_rs = (ROOT / "src/admin/documentation.rs").read_text(encoding="utf-8") +documentation_rs = rust_source(ROOT, "src/admin/documentation.rs") + (ROOT / "src/admin/documentation/documents.rs").read_text(encoding="utf-8") assert "READER_DOCUMENTS" in documentation_rs and "reader_bundle" in documentation_rs assert 'include_str!(concat!(env!("CARGO_MANIFEST_DIR")' in documentation_rs assert 'docs-content.json' not in documentation_rs and 'documentation_bundle' not in build for document in sorted(DOCS.glob("*.md")): - marker = f'/{document.relative_to(ROOT).as_posix()}")))' + marker = f'/{document.relative_to(ROOT).as_posix()}"' assert marker in documentation_rs, f"Reader does not embed {document.relative_to(ROOT)}" assert '"/docs/content.json"' in admin readme = (ROOT / "README.md").read_text(encoding="utf-8") roadmap = (ROOT / "ROADMAP.md").read_text(encoding="utf-8") changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8") -assert readme.startswith("# RustProxy 0.25.6") +assert readme.startswith("# RustProxy 0.25.7") assert "docs/WEB_SERVER.md" in readme and "docs/README.md" in readme assert readme.count("## What changed in ") == 1, "README duplicates historical release notes; use CHANGELOG/archive" assert "## Release history" in readme and "docs/ROADMAP_HISTORY.md" in readme -assert roadmap.startswith("# RustProxy roadmap") and "## 0.25.6" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap +assert roadmap.startswith("# RustProxy roadmap") and "## 0.25.7" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap assert "## 0.24." not in roadmap and "## Web Server follow-up" in roadmap and "docs/ROADMAP_HISTORY.md" in roadmap -assert changelog.startswith("# Changelog\n") and "## 0.25.6" in changelog[:1000] and "## 0.25.5" in changelog[:1600] and "## 0.25.4" in changelog[:1800] and "## 0.25.3" in changelog[:3000] +assert changelog.startswith("# Changelog\n") +for release in ["0.25.7", "0.25.6", "0.25.5", "0.25.4", "0.25.3"]: + assert f"## {release}" in changelog, release +assert changelog.index("## 0.25.7") < changelog.index("## 0.25.6") < changelog.index("## 0.25.5") assert "CHANGELOG_TECHNICAL_ARCHIVE.md" in changelog for developer_only in ["Clean the remaining compiler warnings", "Update package/source/UI/OpenAPI/release identity", "source regressions and update release identity"]: assert developer_only not in changelog, f"developer-only CHANGELOG detail: {developer_only}" diff --git a/scripts/preflight.py b/scripts/preflight.py index ce4308d..32ad610 100755 --- a/scripts/preflight.py +++ b/scripts/preflight.py @@ -75,10 +75,10 @@ def check(root: Path, repair_known: bool = False) -> list[str]: raise ValueError(f"Conflicting Rust modules: {flat.relative_to(root)} and {module.relative_to(root)}") for path in ["src/auth/mod.rs", "src/auth/store.rs", "src/backup/snapshot.rs", "src/upstream.rs", "src/tls.rs", "src/proxy/websocket.rs", "src/cache/mod.rs", "src/cache/model.rs", "src/cache/lifecycle.rs", "src/cache/cold.rs", "src/cache/dashboard.rs", "src/cache/tickets.rs", "src/cache/lookup.rs", "src/cache/policy.rs", "src/cache/fill.rs", "src/cache/tests.rs", "src/settings.rs", "src/compression.rs", "src/diagnostics.rs", "src/traffic.rs", "src/system_stats/mod.rs", "src/system_stats/linux.rs", "src/vhost.rs", "src/web_server/mod.rs", "src/web_server/config.rs", "src/web_server/filesystem.rs", "src/web_server/security.rs", "src/web_server/response.rs", "src/web_server/request.rs", "src/web_server/routing.rs", "src/web_server/fastcgi.rs", "src/web_server/htaccess.rs", "src/web_server/serve.rs", "src/web_server/tests.rs", "src/balance.rs", "src/security.rs", "src/admin/web/vhosts/core.js", "src/admin/web/vhosts/editor.js", "src/admin/web/vhosts/render.js", "src/admin/web/web-server.js", "src/admin/web/streams.js", "src/admin/web/host404.js", "src/admin/web/app/core.js", "src/admin/web/app/config-history.js", "src/admin/web/app/runtime.js", "src/admin/web/app/settings.js", "src/admin/web/management.js", "src/pages.rs", "scripts/mock_server.py", "scripts/mock_auth.py", "src/forwarding.rs", "src/tinyauth.rs", "src/http3.rs", "src/stream.rs", "src/admin/web/integrations.js", "src/admin/web/traffic-panel.js", "src/prometheus.rs", "src/admin/web/settings.js", "src/admin/web/docker.js", "src/docker.rs", "docker-agent/main.go", "docker-agent/model.go", "docker-agent/docker.go", "docker-agent/network.go", "docker-agent/certificate.go", "docker-agent/server.go", "docker-agent/main_test.go", "docker-agent/rustproxy-docker-agent.service", "docker-agent/install.sh", "docs/DOCKER_DISCOVERY.md", "docs/WEB_SERVER.md", "docs/PHP_FPM.md", "docs/README.md", "docs/TODO.md", "docs/V0.25.5_AUDIT.md", "docs/V0.25.4_AUDIT.md", "docs/V0.25.3_AUDIT.md", "docs/V0.25.2_AUDIT.md", "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", "docs/ROADMAP_HISTORY.md", "scripts/docs_check.py", "scripts/web_server_contracts.py", "scripts/rust_source.py", "scripts/rust_module_contracts.py", "scripts/source_module_contracts.py", "scripts/acme_provider.py", "src/basic_auth.rs", "scripts/deploy.py", "scripts/deploy_core.py", "scripts/deploy_runtime.py", "scripts/migrate_npm.py", "scripts/migrate_npm_core.py", "scripts/migrate_npm_api.py", "docs/NPM_MIGRATION.md", "docs/STREAMS.md", "install.sh", "install-debian13.sh", "update.sh", "build.rs", "scripts/swagger_assets.py", "src/admin/documentation.rs", "src/admin/openapi.json", "langs/en_US.json", "langs/pl_pl.json", "Dockerfile", ".dockerignore", "docs/CONTAINER.md", "docs/PROMETHEUS.md", "docs/NOT_FOUND_HOSTS.md", "debian/control", "debian/rules", "debian/rustproxy.service", "debian/rustproxy.logrotate", "grafana/rustproxy-overview.json"]: if not (root / path).is_file(): - raise ValueError(f"Incomplete RustProxy 0.25.6 source tree: missing {path}") + raise ValueError(f"Incomplete RustProxy 0.25.7 source tree: missing {path}") text = (root / "src/lib.rs").read_text(encoding="utf-8") if '#[path = "auth/mod.rs"]' not in text: - raise ValueError("src/lib.rs is not the 0.25.6 entry point; extract the complete package, not individual files.") + raise ValueError("src/lib.rs is not the 0.25.7 entry point; extract the complete package, not individual files.") return messages diff --git a/scripts/release_smoke.py b/scripts/release_smoke.py index 71d9051..4ad4e7f 100755 --- a/scripts/release_smoke.py +++ b/scripts/release_smoke.py @@ -123,7 +123,7 @@ def upgrade_smoke(tmp: Path) -> None: assert backup.is_dir() assert (backup / "src/obsolete.rs").is_file() assert not (target / "src/obsolete.rs").exists() - assert 'version = "0.25.6"' in (target / "Cargo.toml").read_text(encoding="utf-8") + assert 'version = "0.25.7"' in (target / "Cargo.toml").read_text(encoding="utf-8") assert (target / "data/keep.txt").read_text(encoding="utf-8") == "preserve\n" assert (target / ".env").read_text(encoding="utf-8") == "RUST_PROXY_DEMO=0\n" assert (target / "langs/site.json").is_file() @@ -134,7 +134,7 @@ def upgrade_smoke(tmp: Path) -> None: assert (target / "docker-agent/certificate.go").is_file() assert (target / "docker-agent/server.go").is_file() manifest = json.loads((backup / "upgrade.json").read_text(encoding="utf-8")) - assert manifest["to_version"] == "0.25.6" + assert manifest["to_version"] == "0.25.7" assert manifest["removed_obsolete_runtime_state"] is True assert not legacy.exists() assert not (backup / "legacy-data").exists() @@ -392,6 +392,15 @@ def ui_contract_smoke() -> None: assert "vhForceSslNeedsTls" in vhosts and "vhForceSslNeedsHttp" in vhosts and "vhForceSslPortConflict" in vhosts assert "tlsPorts.has(443)" in vhosts assert '$("vhost-search").addEventListener("input", render)' in vhosts and "vhSearchEmpty" in vhosts + for marker in ['toggleVhostEnabled', 'vhQuickEnable', 'vhQuickDisable', 'backend_table_columns', 'applyPoolTableView', 'vh-enable-control']: + assert marker in vhosts, marker + assert 'rustproxy-backend-table-v1' not in vhosts and 'poolTablePreferenceKey' not in vhosts + assert 'window.rustProxyPreferences.update({' in vhosts and 'backend_table_sort' in vhosts and 'backend_table_descending' in vhosts + for marker in ['id="pool-search"', 'id="pool-sort"', 'data-pool-column-toggle="vhost"']: + assert marker in html, marker + style = (ROOT / "src/admin/web/style.css").read_text(encoding="utf-8") + for marker in ['--scrollbar-thumb', '*::-webkit-scrollbar-thumb', '.backend-table-tools', '.vhost-quick-toggle']: + assert marker in style, marker assert "pool-vhost-disabled" in vhosts for marker in ["locationMatchRegex", "headersVisualBuilder", "headersAdvancedJson", "openLocationHelp", "cloudflare-client-ip", "timing-headers"]: assert marker in vhosts, marker @@ -545,7 +554,7 @@ def source_contract_smoke() -> None: assert marker in admin, marker anonymous_block = admin.split("fn anonymous_allowed", 1)[1].split("const CERTIFICATE_API_KEY_HEADER", 1)[0] assert '"/api/status"' not in anonymous_block - assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.25.6"' in openapi_0241 + assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.25.7"' in openapi_0241 assert 'id="panel-logging"' not in html for marker in ['id="settings-tab-logging"', 'id="settings-page-logging"', 'id="logging-form"', 'id="error-log-form"']: assert marker in html, marker @@ -885,7 +894,7 @@ def source_contract_smoke() -> None: assert "RedirectResponse" in proxy and "snapshot.redirect_on" in proxy assert "#[serde(default)]\n pub tls_verify: bool" in config upstream = rust_source(ROOT, "src/upstream.rs") - assert "BackendCertificateVerificationDisabled { supported_schemes }" in upstream + assert "BackendCertificateVerificationDisabled" in upstream and "supported_schemes" in upstream disabled_verifier = upstream.split("impl ServerCertVerifier for BackendCertificateVerificationDisabled", 1)[1].split("pub fn client(", 1)[0] assert disabled_verifier.count("Ok(HandshakeSignatureValid::assertion())") == 2 assert "WebPkiServerVerifier" not in disabled_verifier @@ -952,7 +961,7 @@ def source_contract_smoke() -> None: assert 'function setMobileMenu(open)' in app_source and 'setPanel(button.dataset.panel); setMobileMenu(false);' in app_source assert 'id="mobile-menu-toggle"' in html and 'id="main-navigation"' in html assert '.sidebar.mobile-nav-open .main-navigation' in style_source - assert 'id="about-open"' in html and 'id="about-dialog"' in html and 'Mateusz Griszczynski' in html + assert 'id="about-open"' in html and 'id="about-dialog"' in html and 'Mateusz Gruszczynski' in html assert 'https://git.linuxiarz.pl/gru/RustProxy' in html and 'data-i18n="documentation" id="api-docs"' in html assert '$("about-open").addEventListener("click"' in app_source and '.about-dialog {' in style_source assert 'id="config-history-restore"' in html @@ -1002,7 +1011,7 @@ def source_contract_smoke() -> None: assert '.managed-update' in main and "flush_hot_to_cold_for_update" in main openapi = (ROOT / "src/admin/openapi.json").read_text(encoding="utf-8") assert '"/api/config/history/restore"' in openapi - for marker in ['"version": "0.25.6"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']: + for marker in ['"version": "0.25.7"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']: assert marker in openapi, marker assert '"software_update"' in openapi and '"update_available"' in openapi for marker in ['"/api/certificates/deploy"', '"CertificateDeploy"', '"CertificateDeployResult"', '"/api/certificates/reload"']: @@ -1104,7 +1113,7 @@ def debian_grafana_contract_smoke() -> None: assert "rustproxy.linuxiarz.pl" in repo and "dpkg-scanpackages" in repo and "gzip -9 -n" in repo assert dashboard.get("uid") == "rustproxy-0170" queries = json.dumps(dashboard) - for marker in ["rust_proxy_process_rss_bytes", "rust_proxy_cache_transient_bytes", "rust_proxy_backend_ewma_latency_seconds", "rust_proxy_certificate_renewal_not_after_timestamp_seconds", "rust_proxy_not_found_hosts_configured", "rust_proxy_http1_requests_total"]: + for marker in ["rust_proxy_process_rss_bytes", "rust_proxy_cache_transient_bytes", "rust_proxy_backend_ewma_latency_seconds", "rust_proxy_certificate_renewal_not_after_timestamp_seconds", "rust_proxy_not_found_hosts_configured", "rust_proxy_http1_requests_total", "rust_proxy_backend_upstream_client_generation_requests", "rust_proxy_backend_upstream_client_generation_age_seconds", "rust_proxy_backend_retry_attempts_total", "rust_proxy_backend_upstream_client_rotations_total", "rust_proxy_docker_backend_upstream_client_generation_requests", "rust_proxy_docker_backend_retry_attempts_total"]: assert marker in queries, marker @@ -1177,7 +1186,7 @@ def main() -> None: source_contract_smoke() container_contract_smoke() debian_grafana_contract_smoke() - print("PASS: 0.25.6 SQLite/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, Debian packaging, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.") + print("PASS: 0.25.7 SQLite/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, Debian packaging, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.") if __name__ == "__main__": diff --git a/scripts/rust_module_contracts.py b/scripts/rust_module_contracts.py index 024c062..20f8c8b 100755 --- a/scripts/rust_module_contracts.py +++ b/scripts/rust_module_contracts.py @@ -20,7 +20,7 @@ MAX_LINES = 500 def is_test_source(path: Path) -> bool: relative = path.relative_to(SRC) - return path.name == "tests.rs" or "tests" in relative.parts + return path.name == "tests.rs" or path.stem.endswith("_tests") or "tests" in relative.parts include_re = re.compile(r'include!\(\s*"([^"]+\.rs)"\s*\)') diff --git a/scripts/swagger_assets.py b/scripts/swagger_assets.py index 0a4c06d..03aa585 100755 --- a/scripts/swagger_assets.py +++ b/scripts/swagger_assets.py @@ -85,7 +85,7 @@ def download(destination: Path) -> None: """TLS verification uses Python's default trust store; never executes a shell.""" started = time.monotonic() opener = build_opener(HttpsRedirects()) - request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.25.6"}) + request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.25.7"}) with opener.open(request, timeout=30) as response, destination.open("wb") as output: length = response.headers.get("Content-Length") if length and int(length) > MAX_ARCHIVE: diff --git a/scripts/upgrade.py b/scripts/upgrade.py index b459c92..8f70969 100755 --- a/scripts/upgrade.py +++ b/scripts/upgrade.py @@ -46,7 +46,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None for name in MANAGED: if (target / name).is_symlink(): raise ValueError(f"Managed target {name} is a symlink; refusing to replace it.") - backup = target / ".upgrade-backup" / ("before-0.25.6-" + uuid.uuid4().hex[:12]) + backup = target / ".upgrade-backup" / ("before-0.25.7-" + uuid.uuid4().hex[:12]) backup.mkdir(parents=True, mode=0o700) installed: list[str] = [] moved: list[str] = [] @@ -84,7 +84,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None remove_legacy = legacy.exists() if remove_legacy and (legacy.is_symlink() or not legacy.is_file()): raise ValueError("Obsolete renewal observation sidecar must be a regular file.") - (backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.25.6", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8") + (backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.25.7", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8") if remove_legacy: legacy.unlink() except BaseException: @@ -115,7 +115,7 @@ def main() -> None: backup = upgrade(Path(__file__).resolve().parents[1], args.target, stopped=args.stopped, data_dir=data_dir) except (OSError, ValueError) as error: parser.exit(2, f"Upgrade refused or rolled back: {error}\n") - print(f"Installed RustProxy 0.25.6. Previous managed source files: {backup}") + print(f"Installed RustProxy 0.25.7. Previous managed source files: {backup}") print("Preserved data, .env, .git, target and other unmanaged files. No database migration was run.") print(f"Next: cd {args.target}; ./dev.sh test; ./dev.sh") diff --git a/scripts/web_server_contracts.py b/scripts/web_server_contracts.py index 20a8cfb..d674e4f 100755 --- a/scripts/web_server_contracts.py +++ b/scripts/web_server_contracts.py @@ -96,7 +96,7 @@ need(web, 'HeaderValue::from_static("no-store")', "builtin_error_response(StatusCode::FORBIDDEN, &method)", "empty_index_can_go_directly_to_directory_listing", - "RustProxy 0.25.6", + "RustProxy 0.25.7", "traversal_and_symlink_escape_are_not_served", "try_files_rewrites_cache_rules_headers_and_downloads_work", "precompressed_sidecars_keep_mime_validators_and_range_semantics", diff --git a/src/admin/documentation.rs b/src/admin/documentation.rs index 254262b..46589b6 100644 --- a/src/admin/documentation.rs +++ b/src/admin/documentation.rs @@ -11,456 +11,8 @@ use std::sync::OnceLock; // Keep Reader input independent from build-script output. `include_str!` makes every // document a direct compiler input, so a clean or partially removed target directory // cannot leave the crate pointing at a missing OUT_DIR artifact. -static READER_DOCUMENTS: &[(&str, &str, &str)] = &[ - ( - "README.md", - "project", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md")), - ), - ( - "ROADMAP.md", - "project", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/ROADMAP.md")), - ), - ( - "CHANGELOG.md", - "project", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/CHANGELOG.md")), - ), - ( - "docs/ACME_PROVIDERS.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/ACME_PROVIDERS.md" - )), - ), - ( - "docs/ACME_RFC2136.md", - "historical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/ACME_RFC2136.md")), - ), - ( - "docs/API.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/API.md")), - ), - ( - "docs/API_ACCESS.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/API_ACCESS.md")), - ), - ( - "docs/ARCHITECTURE.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/ARCHITECTURE.md")), - ), - ( - "docs/CACHE.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/CACHE.md")), - ), - ( - "docs/CACHE_DIAGNOSTICS.md", - "technical", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/CACHE_DIAGNOSTICS.md" - )), - ), - ( - "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", - "historical", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/CHANGELOG_TECHNICAL_ARCHIVE.md" - )), - ), - ( - "docs/CONTAINER.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/CONTAINER.md")), - ), - ( - "docs/CUSTOM_LOCATIONS.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/CUSTOM_LOCATIONS.md" - )), - ), - ( - "docs/DOCKER_DISCOVERY.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/DOCKER_DISCOVERY.md" - )), - ), - ( - "docs/ERROR_LOGGING.md", - "technical", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/ERROR_LOGGING.md" - )), - ), - ( - "docs/HTTP3.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/HTTP3.md")), - ), - ( - "docs/INSTALL.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/INSTALL.md")), - ), - ( - "docs/INTEGRATIONS_040.md", - "historical", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/INTEGRATIONS_040.md" - )), - ), - ( - "docs/LIVE_LOGS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/LIVE_LOGS.md")), - ), - ( - "docs/MANAGEMENT.md", - "historical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MANAGEMENT.md")), - ), - ( - "docs/MIGRATION.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MIGRATION.md")), - ), - ( - "docs/MOCK_AUTH.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MOCK_AUTH.md")), - ), - ( - "docs/MOCK_SERVER.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MOCK_SERVER.md")), - ), - ( - "docs/NOT_FOUND_HOSTS.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/NOT_FOUND_HOSTS.md" - )), - ), - ( - "docs/NPM_MIGRATION.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/NPM_MIGRATION.md" - )), - ), - ( - "docs/PHP_FPM.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/PHP_FPM.md")), - ), - ( - "docs/PROMETHEUS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/PROMETHEUS.md")), - ), - ( - "docs/README.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/README.md")), - ), - ( - "docs/REDIRECTS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/REDIRECTS.md")), - ), - ( - "docs/REFERENCES.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/REFERENCES.md")), - ), - ( - "docs/RENEWAL.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/RENEWAL.md")), - ), - ( - "docs/ROADMAP_HISTORY.md", - "historical", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/ROADMAP_HISTORY.md" - )), - ), - ( - "docs/SECRET_STORE_BACKUP.md", - "guides", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/SECRET_STORE_BACKUP.md" - )), - ), - ( - "docs/SECURITY.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/SECURITY.md")), - ), - ( - "docs/SECURITY_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/SECURITY_AUDIT.md" - )), - ), - ( - "docs/SETTINGS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/SETTINGS.md")), - ), - ( - "docs/STREAMS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/STREAMS.md")), - ), - ( - "docs/TEST_REPORT.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TEST_REPORT.md")), - ), - ( - "docs/TODO.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TODO.md")), - ), - ( - "docs/TRANSFORM.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TRANSFORM.md")), - ), - ( - "docs/TRANSPORT.md", - "technical", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TRANSPORT.md")), - ), - ( - "docs/V0.21.0_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.21.0_AUDIT.md" - )), - ), - ( - "docs/V0.22.0_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.22.0_AUDIT.md" - )), - ), - ( - "docs/V0.22.1_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.22.1_AUDIT.md" - )), - ), - ( - "docs/V0.22.2_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.22.2_AUDIT.md" - )), - ), - ( - "docs/V0.22.3_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.22.3_AUDIT.md" - )), - ), - ( - "docs/V0.23.0_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.23.0_AUDIT.md" - )), - ), - ( - "docs/V0.23.1_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.23.1_AUDIT.md" - )), - ), - ( - "docs/V0.23.2_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.23.2_AUDIT.md" - )), - ), - ( - "docs/V0.23.3_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.23.3_AUDIT.md" - )), - ), - ( - "docs/V0.24.0_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.0_AUDIT.md" - )), - ), - ( - "docs/V0.24.1_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.1_AUDIT.md" - )), - ), - ( - "docs/V0.24.3_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.3_AUDIT.md" - )), - ), - ( - "docs/V0.24.4_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.4_AUDIT.md" - )), - ), - ( - "docs/V0.24.5_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.5_AUDIT.md" - )), - ), - ( - "docs/V0.24.6_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.6_AUDIT.md" - )), - ), - ( - "docs/V0.24.7_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.7_AUDIT.md" - )), - ), - ( - "docs/V0.24.8_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.24.8_AUDIT.md" - )), - ), - ( - "docs/V0.25.0_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.0_AUDIT.md" - )), - ), - ( - "docs/V0.25.1_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.1_AUDIT.md" - )), - ), - ( - "docs/V0.25.5_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.5_AUDIT.md" - )), - ), - ( - "docs/V0.25.4_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.4_AUDIT.md" - )), - ), - ( - "docs/V0.25.3_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.3_AUDIT.md" - )), - ), - ( - "docs/V0.25.2_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.2_AUDIT.md" - )), - ), - ( - "docs/V0.25.0_SECURITY_PREPROD_AUDIT.md", - "audits", - include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/docs/V0.25.0_SECURITY_PREPROD_AUDIT.md" - )), - ), - ( - "docs/VHOSTS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/VHOSTS.md")), - ), - ( - "docs/VHOST_ACCESS.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/VHOST_ACCESS.md")), - ), - ( - "docs/WEB_SERVER.md", - "guides", - include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/WEB_SERVER.md")), - ), -]; +mod documents; +use documents::READER_DOCUMENTS; pub(super) async fn index() -> Html<&'static str> { Html(include_str!("web/docs.html")) diff --git a/src/admin/documentation/documents.rs b/src/admin/documentation/documents.rs new file mode 100644 index 0000000..9f689f5 --- /dev/null +++ b/src/admin/documentation/documents.rs @@ -0,0 +1,452 @@ +//! Embedded Markdown documents for the authenticated Reader. + +pub(super) static READER_DOCUMENTS: &[(&str, &str, &str)] = &[ + ( + "README.md", + "project", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md")), + ), + ( + "ROADMAP.md", + "project", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/ROADMAP.md")), + ), + ( + "CHANGELOG.md", + "project", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/CHANGELOG.md")), + ), + ( + "docs/ACME_PROVIDERS.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/ACME_PROVIDERS.md" + )), + ), + ( + "docs/ACME_RFC2136.md", + "historical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/ACME_RFC2136.md")), + ), + ( + "docs/API.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/API.md")), + ), + ( + "docs/API_ACCESS.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/API_ACCESS.md")), + ), + ( + "docs/ARCHITECTURE.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/ARCHITECTURE.md")), + ), + ( + "docs/CACHE.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/CACHE.md")), + ), + ( + "docs/CACHE_DIAGNOSTICS.md", + "technical", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/CACHE_DIAGNOSTICS.md" + )), + ), + ( + "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", + "historical", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/CHANGELOG_TECHNICAL_ARCHIVE.md" + )), + ), + ( + "docs/CONTAINER.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/CONTAINER.md")), + ), + ( + "docs/CUSTOM_LOCATIONS.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/CUSTOM_LOCATIONS.md" + )), + ), + ( + "docs/DOCKER_DISCOVERY.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/DOCKER_DISCOVERY.md" + )), + ), + ( + "docs/ERROR_LOGGING.md", + "technical", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/ERROR_LOGGING.md" + )), + ), + ( + "docs/HTTP3.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/HTTP3.md")), + ), + ( + "docs/INSTALL.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/INSTALL.md")), + ), + ( + "docs/INTEGRATIONS_040.md", + "historical", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/INTEGRATIONS_040.md" + )), + ), + ( + "docs/LIVE_LOGS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/LIVE_LOGS.md")), + ), + ( + "docs/MANAGEMENT.md", + "historical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MANAGEMENT.md")), + ), + ( + "docs/MIGRATION.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MIGRATION.md")), + ), + ( + "docs/MOCK_AUTH.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MOCK_AUTH.md")), + ), + ( + "docs/MOCK_SERVER.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/MOCK_SERVER.md")), + ), + ( + "docs/NOT_FOUND_HOSTS.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/NOT_FOUND_HOSTS.md" + )), + ), + ( + "docs/NPM_MIGRATION.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/NPM_MIGRATION.md" + )), + ), + ( + "docs/PHP_FPM.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/PHP_FPM.md")), + ), + ( + "docs/PROMETHEUS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/PROMETHEUS.md")), + ), + ( + "docs/README.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/README.md")), + ), + ( + "docs/REDIRECTS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/REDIRECTS.md")), + ), + ( + "docs/REFERENCES.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/REFERENCES.md")), + ), + ( + "docs/RENEWAL.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/RENEWAL.md")), + ), + ( + "docs/ROADMAP_HISTORY.md", + "historical", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/ROADMAP_HISTORY.md" + )), + ), + ( + "docs/SECRET_STORE_BACKUP.md", + "guides", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/SECRET_STORE_BACKUP.md" + )), + ), + ( + "docs/SECURITY.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/SECURITY.md")), + ), + ( + "docs/SECURITY_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/SECURITY_AUDIT.md" + )), + ), + ( + "docs/SETTINGS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/SETTINGS.md")), + ), + ( + "docs/STREAMS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/STREAMS.md")), + ), + ( + "docs/TEST_REPORT.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TEST_REPORT.md")), + ), + ( + "docs/TODO.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TODO.md")), + ), + ( + "docs/TRANSFORM.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TRANSFORM.md")), + ), + ( + "docs/TRANSPORT.md", + "technical", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/TRANSPORT.md")), + ), + ( + "docs/V0.21.0_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.21.0_AUDIT.md" + )), + ), + ( + "docs/V0.22.0_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.22.0_AUDIT.md" + )), + ), + ( + "docs/V0.22.1_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.22.1_AUDIT.md" + )), + ), + ( + "docs/V0.22.2_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.22.2_AUDIT.md" + )), + ), + ( + "docs/V0.22.3_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.22.3_AUDIT.md" + )), + ), + ( + "docs/V0.23.0_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.23.0_AUDIT.md" + )), + ), + ( + "docs/V0.23.1_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.23.1_AUDIT.md" + )), + ), + ( + "docs/V0.23.2_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.23.2_AUDIT.md" + )), + ), + ( + "docs/V0.23.3_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.23.3_AUDIT.md" + )), + ), + ( + "docs/V0.24.0_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.0_AUDIT.md" + )), + ), + ( + "docs/V0.24.1_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.1_AUDIT.md" + )), + ), + ( + "docs/V0.24.3_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.3_AUDIT.md" + )), + ), + ( + "docs/V0.24.4_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.4_AUDIT.md" + )), + ), + ( + "docs/V0.24.5_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.5_AUDIT.md" + )), + ), + ( + "docs/V0.24.6_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.6_AUDIT.md" + )), + ), + ( + "docs/V0.24.7_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.7_AUDIT.md" + )), + ), + ( + "docs/V0.24.8_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.24.8_AUDIT.md" + )), + ), + ( + "docs/V0.25.0_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.0_AUDIT.md" + )), + ), + ( + "docs/V0.25.1_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.1_AUDIT.md" + )), + ), + ( + "docs/V0.25.5_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.5_AUDIT.md" + )), + ), + ( + "docs/V0.25.4_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.4_AUDIT.md" + )), + ), + ( + "docs/V0.25.3_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.3_AUDIT.md" + )), + ), + ( + "docs/V0.25.2_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.2_AUDIT.md" + )), + ), + ( + "docs/V0.25.0_SECURITY_PREPROD_AUDIT.md", + "audits", + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/docs/V0.25.0_SECURITY_PREPROD_AUDIT.md" + )), + ), + ( + "docs/VHOSTS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/VHOSTS.md")), + ), + ( + "docs/VHOST_ACCESS.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/VHOST_ACCESS.md")), + ), + ( + "docs/WEB_SERVER.md", + "guides", + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/docs/WEB_SERVER.md")), + ), +]; diff --git a/src/admin/openapi.json b/src/admin/openapi.json index 88a9b96..d660bcb 100644 --- a/src/admin/openapi.json +++ b/src/admin/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.0.3", "info": { "title": "RustProxy Administration API", - "version": "0.25.6", + "version": "0.25.7", "description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust." }, "servers": [ @@ -2917,6 +2917,74 @@ ], "default": "dark", "description": "Account-scoped administration interface theme. Existing accounts and omitted values default to the current dark theme." + }, + "backend_table_columns": { + "type": "array", + "minItems": 1, + "maxItems": 14, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "vhost", + "backend", + "status", + "active", + "requests", + "errors", + "latency", + "traffic", + "generation", + "generationRequests", + "generationAge", + "rotations", + "lastFailure", + "lastRecovery" + ] + }, + "default": [ + "vhost", + "backend", + "status", + "active", + "requests", + "errors", + "latency", + "traffic", + "generation", + "generationRequests", + "generationAge", + "rotations", + "lastFailure", + "lastRecovery" + ], + "description": "Account-scoped Backends diagnostics columns shown in the dashboard." + }, + "backend_table_sort": { + "type": "string", + "enum": [ + "vhost", + "backend", + "status", + "active", + "requests", + "errors", + "latency", + "traffic", + "generation", + "generationRequests", + "generationAge", + "rotations", + "lastFailure", + "lastRecovery" + ], + "default": "vhost", + "description": "Account-scoped sort key for the Backends diagnostics table." + }, + "backend_table_descending": { + "type": "boolean", + "default": false, + "description": "Account-scoped sort direction for the Backends diagnostics table." } }, "required": [ @@ -5093,7 +5161,7 @@ } } }, - "description": "Sets an HttpOnly SameSite=Strict session cookie. Browser sessions use the configured 7\u201330 day absolute lifetime. Use the panel sign-in page. No bearer token or URL token is accepted.", + "description": "Sets an HttpOnly SameSite=Strict session cookie. Browser sessions use the configured 7–30 day absolute lifetime. Use the panel sign-in page. No bearer token or URL token is accepted.", "security": [], "parameters": [ { diff --git a/src/admin/session.rs b/src/admin/session.rs index 55f0f24..c1caaa9 100644 --- a/src/admin/session.rs +++ b/src/admin/session.rs @@ -267,10 +267,35 @@ const LIVE_LOG_COLUMNS: &[&str] = &[ "websocket", "upstream_error", ]; +const BACKEND_TABLE_COLUMNS: &[&str] = &[ + "vhost", + "backend", + "status", + "active", + "requests", + "errors", + "latency", + "traffic", + "generation", + "generationRequests", + "generationAge", + "rotations", + "lastFailure", + "lastRecovery", +]; fn default_admin_theme() -> String { "dark".to_owned() } +fn default_backend_table_columns() -> Vec { + BACKEND_TABLE_COLUMNS + .iter() + .map(|value| (*value).to_owned()) + .collect() +} +fn default_backend_table_sort() -> String { + "vhost".to_owned() +} #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(deny_unknown_fields)] @@ -278,6 +303,12 @@ struct AdminPreferences { live_log_columns: Vec, #[serde(default = "default_admin_theme")] theme: String, + #[serde(default = "default_backend_table_columns")] + backend_table_columns: Vec, + #[serde(default = "default_backend_table_sort")] + backend_table_sort: String, + #[serde(default)] + backend_table_descending: bool, } impl Default for AdminPreferences { @@ -288,6 +319,9 @@ impl Default for AdminPreferences { .map(|value| (*value).to_owned()) .collect(), theme: default_admin_theme(), + backend_table_columns: default_backend_table_columns(), + backend_table_sort: default_backend_table_sort(), + backend_table_descending: false, } } } @@ -316,6 +350,29 @@ fn validate_admin_preferences(preferences: &AdminPreferences) -> Result<(), ApiE "invalid administration theme preference".into(), )); } + if preferences.backend_table_columns.is_empty() + || preferences.backend_table_columns.len() > BACKEND_TABLE_COLUMNS.len() + { + return Err(ApiError( + StatusCode::UNPROCESSABLE_ENTITY, + "at least one backend table column must be visible".into(), + )); + } + let mut seen = std::collections::HashSet::new(); + for column in &preferences.backend_table_columns { + if !BACKEND_TABLE_COLUMNS.contains(&column.as_str()) || !seen.insert(column.as_str()) { + return Err(ApiError( + StatusCode::UNPROCESSABLE_ENTITY, + "invalid backend table column preference".into(), + )); + } + } + if !BACKEND_TABLE_COLUMNS.contains(&preferences.backend_table_sort.as_str()) { + return Err(ApiError( + StatusCode::UNPROCESSABLE_ENTITY, + "invalid backend table sort preference".into(), + )); + } Ok(()) } diff --git a/src/admin/tests/part_04.rs b/src/admin/tests/part_04.rs index 63ab71a..26458c3 100644 --- a/src/admin/tests/part_04.rs +++ b/src/admin/tests/part_04.rs @@ -20,6 +20,12 @@ LIVE_LOG_COLUMNS.len() ); assert_eq!(initial["theme"], "dark"); + assert_eq!( + initial["backend_table_columns"].as_array().unwrap().len(), + BACKEND_TABLE_COLUMNS.len() + ); + assert_eq!(initial["backend_table_sort"], "vhost"); + assert_eq!(initial["backend_table_descending"], false); assert!(store .save_admin_preferences("owner", r#"{"live_log_columns":["time","status"]}"#) @@ -39,10 +45,19 @@ let legacy = json_body(response).await; assert_eq!(legacy["live_log_columns"], json!(["time", "status"])); assert_eq!(legacy["theme"], "dark"); + assert_eq!( + legacy["backend_table_columns"].as_array().unwrap().len(), + BACKEND_TABLE_COLUMNS.len() + ); + assert_eq!(legacy["backend_table_sort"], "vhost"); + assert_eq!(legacy["backend_table_descending"], false); let selected = json!({ "live_log_columns":["time","request","status","upstream_error"], - "theme":"light" + "theme":"light", + "backend_table_columns":["vhost","backend","status","requests","latency"], + "backend_table_sort":"requests", + "backend_table_descending":true }); let response = router .clone() @@ -101,6 +116,7 @@ assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); let response = router + .clone() .oneshot( request("/api/preferences") .method("PUT") @@ -117,6 +133,24 @@ .await .unwrap(); assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); + + let response = router + .oneshot( + request("/api/preferences") + .method("PUT") + .header("cookie", &cookie) + .header("origin", "http://127.0.0.1:9090") + .header("x-rustproxy-request", "1") + .header("x-csrf-token", &csrf) + .header("content-type", "application/json") + .body(Body::from( + r#"{"live_log_columns":["time"],"backend_table_columns":["unknown"]}"#, + )) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY); store.close().await; } diff --git a/src/admin/web/app/core.js b/src/admin/web/app/core.js index c7e9403..b56fa17 100644 --- a/src/admin/web/app/core.js +++ b/src/admin/web/app/core.js @@ -353,7 +353,7 @@ function lock(notify = true) { if (navigating) { document.documentElement.classList.add("app-loading"); location.replace(destination); } } -async function activate(info) { pendingAuthDestination = null; authMessage(""); $("api-docs").hidden = false; $("logs-open").hidden = false; authEpoch++; sessionInfo = info; csrf = info.csrf_token; authenticated = true; const preferences = await loadAdminPreferences(); window.rustProxyLogs?.applyPreferences(preferences); await loadConfig(); $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("login").hidden = true; $("workspace").hidden = false; $("logout").hidden = false; renderSession(); await refresh(true); startLive(); document.documentElement.classList.remove("app-loading"); } +async function activate(info) { pendingAuthDestination = null; authMessage(""); $("api-docs").hidden = false; $("logs-open").hidden = false; authEpoch++; sessionInfo = info; csrf = info.csrf_token; authenticated = true; const preferences = await loadAdminPreferences(); window.rustProxyLogs?.applyPreferences(preferences); window.rustProxyVhosts?.applyPreferences(preferences); await loadConfig(); $("password").value = ""; $("password-confirm").value = ""; $("setup-token").value = ""; $("login").hidden = true; $("workspace").hidden = false; $("logout").hidden = false; renderSession(); await refresh(true); startLive(); document.documentElement.classList.remove("app-loading"); } async function loadAudit() { if (!authenticated) return; const epoch = authEpoch; try { const data = await api("/api/audit"); if (!authenticated || epoch !== authEpoch) return; const rows = data.entries.map(item => { const tr = el("tr"); for (const value of [new Date(item.time * 1000).toLocaleString(locale()), item.actor, item.action, item.detail]) { const td = el("td", value); td.title = value; tr.append(td); } return tr; }); $("audit-rows").replaceChildren(...rows); $("empty-audit").hidden = rows.length > 0; } catch (e) { toast(e.message, true); } } let tunnelRefreshTimer = null; function tunnelMessage(value = "", error = false) { const node = $("tunnels-status"); if (!node) return; node.textContent = value; node.classList.toggle("error", !!error); } diff --git a/src/admin/web/app/settings.js b/src/admin/web/app/settings.js index 1345bd4..ae11e23 100644 --- a/src/admin/web/app/settings.js +++ b/src/admin/web/app/settings.js @@ -6,7 +6,7 @@ function renderSettings() { if (!settingsDirty.has("response-form")) { const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {}; $("expose-request-id").checked = !!diagnostics.request_id; - $("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.6"; + $("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.7"; for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name]; $("compress-min").value = compression.min_bytes ?? 1024; syncServerMode(); } diff --git a/src/admin/web/index.html b/src/admin/web/index.html index bf04d33..dc7ceef 100644 --- a/src/admin/web/index.html +++ b/src/admin/web/index.html @@ -523,9 +523,75 @@
-
-

Backends

+
+

Backends

+
+ + + + +
+ Columns +
+ + + + + + + + + + + + + + +
+
+ +

Live state: leases cover the entire exchange; traffic is an EWMA of payload bytes.

@@ -533,20 +599,23 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -1598,7 +1667,7 @@

Diagnostic headers

@@ -2386,7 +2455,7 @@
-
RustProxy 0.25.6API - / +
RustProxy 0.25.7API - / dropped: 0
@@ -3097,7 +3166,7 @@ max_execution_time = 30
-
RustProxy0.25.6
+
RustProxy0.25.7
diff --git a/src/admin/web/style.css b/src/admin/web/style.css index d8d2855..83bda04 100644 --- a/src/admin/web/style.css +++ b/src/admin/web/style.css @@ -50,6 +50,9 @@ --shadow-mid: #0006; --shadow-strong: #0009; --neutral-soft: rgba(127, 127, 127, .05); + --scrollbar-track: #151a16; + --scrollbar-thumb: #4f5d50; + --scrollbar-thumb-hover: #6b7b69; --mono: ui-monospace, SFMono-Regular, Consolas, monospace; --sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif } @@ -97,11 +100,39 @@ html[data-theme="light"] { --transform-chart: #7d4fa3; --shadow-mid: rgb(31 39 33 / .16); --shadow-strong: rgb(31 39 33 / .26); - --neutral-soft: rgba(70, 78, 72, .05) + --neutral-soft: rgba(70, 78, 72, .05); + --scrollbar-track: #e7ece4; + --scrollbar-thumb: #a9b5a6; + --scrollbar-thumb-hover: #879684 } * { - box-sizing: border-box + box-sizing: border-box; + scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); + scrollbar-width: thin +} + +*::-webkit-scrollbar { + width: 10px; + height: 10px +} + +*::-webkit-scrollbar-track { + background: var(--scrollbar-track) +} + +*::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border: 2px solid var(--scrollbar-track); + border-radius: 999px +} + +*::-webkit-scrollbar-thumb:hover { + background: var(--scrollbar-thumb-hover) +} + +*::-webkit-scrollbar-corner { + background: var(--scrollbar-track) } html.app-loading { @@ -2463,6 +2494,63 @@ td { flex: 0 0 auto } +.vh-enable-control { + display: grid !important; + grid-template-columns: auto minmax(0, 1fr) auto; + grid-template-rows: auto auto; + align-items: center; + gap: 2px 10px; + margin-top: 5px !important; + padding: 11px 12px; + border: 1px solid var(--pill-live-line); + background: var(--panel2); + box-shadow: inset 3px 0 0 var(--green) +} + +.vh-enable-control>input { + grid-column: 1; + grid-row: 1/3; + width: 18px; + height: 18px; + accent-color: var(--green) +} + +.vh-enable-control>span { + grid-column: 2; + grid-row: 1; + color: var(--text); + font-size: 12px; + font-weight: 700 +} + +.vh-enable-hint { + grid-column: 2; + grid-row: 2; + color: var(--muted); + font-size: 10px +} + +.vh-enable-state { + grid-column: 3; + grid-row: 1/3; + padding: 3px 7px; + border: 1px solid var(--pill-live-line); + color: var(--green); + font: 600 10px var(--mono); + text-transform: uppercase; + letter-spacing: .04em +} + +.vh-enable-control.is-disabled { + border-color: var(--danger-line-strong); + box-shadow: inset 3px 0 0 var(--red) +} + +.vh-enable-control.is-disabled .vh-enable-state { + border-color: var(--danger-line); + color: var(--red) +} + .vh-wide { grid-column: 1/-1; min-width: 0 @@ -2524,6 +2612,78 @@ td { margin-bottom: 12px } +.backend-card-heading { + align-items: flex-start; + gap: 10px +} + +.backend-table-tools { + display: flex; + align-items: center; + justify-content: flex-end; + flex-wrap: wrap; + gap: 7px; + margin-left: auto +} + +#pool-search { + width: min(250px, 30vw); + min-width: 170px +} + +.backend-sort-control { + display: flex; + align-items: center; + gap: 6px; + color: var(--muted); + font-size: 11px +} + +.backend-sort-control select { + width: auto; + min-width: 120px +} + +.backend-sort-direction { + min-width: 48px +} + +.backend-column-picker { + position: relative +} + +.backend-column-picker>summary { + list-style: none; + cursor: pointer; + user-select: none +} + +.backend-column-picker>summary::-webkit-details-marker { + display: none +} + +.backend-column-options { + position: absolute; + z-index: 20; + top: calc(100% + 6px); + right: 0; + display: grid; + grid-template-columns: repeat(2, minmax(145px, 1fr)); + gap: 1px 12px; + min-width: 330px; + max-height: 330px; + overflow: auto; + padding: 10px 12px 12px; + border: 1px solid var(--line); + background: var(--panel); + box-shadow: 0 12px 28px var(--shadow-strong) +} + +.backend-column-options .check { + margin-top: 4px !important; + font-size: 11px +} + .pool-card .fine { margin: 0 0 8px } @@ -4861,6 +5021,16 @@ dialog .window-heading { margin-top: 8px } +.vhost-quick-toggle.is-enable { + border-color: var(--pill-live-line); + color: var(--green) +} + +.vhost-quick-toggle.is-disable { + border-color: var(--danger-line); + color: var(--red) +} + @media(max-width:980px) { .logging-grid { grid-template-columns: 1fr @@ -4896,6 +5066,30 @@ dialog .window-heading { min-width: 0 } + .backend-card-heading { + align-items: stretch; + flex-direction: column + } + + .backend-table-tools { + width: 100%; + justify-content: flex-start; + margin-left: 0 + } + + #pool-search { + flex: 1 1 100%; + width: 100%; + min-width: 0 + } + + .backend-column-options { + right: auto; + left: 0; + grid-template-columns: 1fr; + min-width: min(290px, 82vw) + } + .vhost-card-head .entity-actions { width: 100%; justify-content: flex-start diff --git a/src/admin/web/vhosts/editor.js b/src/admin/web/vhosts/editor.js index 5c4c4b6..4ba59b1 100644 --- a/src/admin/web/vhosts/editor.js +++ b/src/admin/web/vhosts/editor.js @@ -38,7 +38,11 @@ editing = value.id || null; revision = envelope?.revision ?? null; dirty = false; initialized = true; container.replaceChildren(); $("vhost-editing").textContent = t(editing ? "vhEditLabel" : "vhNewLabel"); let g = group("vhEditor"); field(g, "id", "vhId", value.id, "text", { required: true, maxLength: 64, pattern: "[A-Za-z0-9_-]{1,64}" }); if (editing) note(g, "vhIdRenameHelp"); - readHosts = hostTagEditor(g, value.frontend?.hosts || []); field(g, "enabled", "vhEnabled", value.enabled !== false, "checkbox"); + readHosts = hostTagEditor(g, value.frontend?.hosts || []); + const enabledControl = field(g, "enabled", "vhEnabled", value.enabled !== false, "checkbox"), enabledLabel = enabledControl.closest("label"), enabledState = el("strong", "", "vh-enable-state"); + if (enabledLabel) { enabledLabel.classList.add("vh-enable-control", "vh-wide"); enabledLabel.append(text("small", "vhEnableHint", "vh-enable-hint"), enabledState); } + const syncEnabledState = () => { const key = enabledControl.checked ? "vhEnabled" : "vhDisabled"; enabledLabel?.classList.toggle("is-disabled", !enabledControl.checked); enabledLabel?.classList.toggle("is-enabled", enabledControl.checked); enabledState.dataset.i18n = key; enabledState.textContent = t(key); }; + enabledControl.addEventListener("change", syncEnabledState); syncEnabledState(); const mainSource = field(g, "source-type", "sourceType", value.source?.type || "reverse_proxy", "select", { values: [["reverse_proxy", "sourceReverseProxy"], ["web_server", "sourceWebServer"]] }); const mainWebService = field(g, "source-web-service", "webService", value.source?.web_service_id || "", "select"); fillWebServices(mainWebService, value.source?.web_service_id || ""); const syncMainSource = () => { const web = mainSource.value === "web_server"; mainWebService.disabled = !web; mainWebService.required = web; }; mainSource.addEventListener("change", syncMainSource); syncMainSource(); diff --git a/src/admin/web/vhosts/render.js b/src/admin/web/vhosts/render.js index 0f2d046..c546493 100644 --- a/src/admin/web/vhosts/render.js +++ b/src/admin/web/vhosts/render.js @@ -1,3 +1,87 @@ + const poolColumns = ["vhost", "backend", "status", "active", "requests", "errors", "latency", "traffic", "generation", "generationRequests", "generationAge", "rotations", "lastFailure", "lastRecovery"]; + const defaultPoolTablePrefs = () => ({ sort: "vhost", descending: false, columns: [...poolColumns] }); + let poolTablePrefs = defaultPoolTablePrefs(), poolPreferenceSaveRunning = false, poolPreferenceSaveQueued = false; + function normalizePoolTablePrefs(preferences) { + const selected = Array.isArray(preferences?.backend_table_columns) ? preferences.backend_table_columns.filter(key => poolColumns.includes(key)) : []; + return { + sort: poolColumns.includes(preferences?.backend_table_sort) ? preferences.backend_table_sort : "vhost", + descending: preferences?.backend_table_descending === true, + columns: selected.length ? selected : [...poolColumns], + }; + } + function applyPoolPreferences(preferences) { + poolTablePrefs = normalizePoolTablePrefs(preferences); + const sort = $("pool-sort"); if (sort) sort.value = poolTablePrefs.sort; + syncPoolColumns(); syncPoolSortDirection(); applyPoolTableView(); + } + async function savePoolTablePrefs() { + if (!authenticated) return; + poolPreferenceSaveQueued = true; + if (poolPreferenceSaveRunning) return; + poolPreferenceSaveRunning = true; + try { + while (poolPreferenceSaveQueued && authenticated) { + poolPreferenceSaveQueued = false; + const saved = await window.rustProxyPreferences.update({ + backend_table_columns: poolColumns.filter(key => poolTablePrefs.columns.includes(key)), + backend_table_sort: poolTablePrefs.sort, + backend_table_descending: poolTablePrefs.descending, + }); + if (!authenticated) return; + if (!poolPreferenceSaveQueued) poolTablePrefs = normalizePoolTablePrefs(saved); + } + syncPoolColumns(); syncPoolSortDirection(); + } catch (error) { if (error.status !== 401) toast(error.message, true); } + finally { poolPreferenceSaveRunning = false; } + } + function syncPoolColumns() { + const visible = new Set(poolTablePrefs.columns); + document.querySelectorAll("[data-pool-column]").forEach(node => { node.hidden = !visible.has(node.dataset.poolColumn); }); + document.querySelectorAll("[data-pool-column-toggle]").forEach(input => { input.checked = visible.has(input.dataset.poolColumnToggle); }); + } + function syncPoolSortDirection() { + const control = $("pool-sort-direction"); if (!control) return; + control.textContent = poolTablePrefs.descending ? "Z-A" : "A-Z"; + control.setAttribute("aria-label", t(poolTablePrefs.descending ? "backendSortDescending" : "backendSortAscending")); + } + function applyPoolTableView() { + const body = $("pool-rows"); if (!body) return; + const query = ($("pool-search")?.value || "").trim().toLowerCase(); + const key = $("pool-sort")?.value || poolTablePrefs.sort; + const rows = [...body.querySelectorAll("tr")]; + rows.sort((left, right) => { + const a = left.poolSort?.[key] ?? "", b = right.poolSort?.[key] ?? ""; + const result = typeof a === "number" && typeof b === "number" ? a - b : String(a).localeCompare(String(b), locale(), { numeric: true, sensitivity: "base" }); + return poolTablePrefs.descending ? -result : result; + }); + body.replaceChildren(...rows); + let visible = 0; + for (const row of rows) { const match = !query || (row.poolSearchValue || "").includes(query); row.hidden = !match; if (match) visible++; } + syncPoolColumns(); syncPoolSortDirection(); + const empty = $("pool-empty"); + if (empty) { empty.textContent = query && rows.length && !visible ? t("backendSearchEmpty") : t("vhHealthEmpty"); empty.hidden = visible > 0 || (!rows.length && !document.querySelector("#backend-diagnostics-card:not([hidden])")); } + } + function initPoolTableTools() { + const sort = $("pool-sort"), direction = $("pool-sort-direction"), search = $("pool-search"); + if (sort) { sort.value = poolTablePrefs.sort; sort.addEventListener("change", () => { poolTablePrefs.sort = sort.value; void savePoolTablePrefs(); applyPoolTableView(); }); } + direction?.addEventListener("click", () => { poolTablePrefs.descending = !poolTablePrefs.descending; void savePoolTablePrefs(); applyPoolTableView(); }); + search?.addEventListener("input", applyPoolTableView); + document.querySelectorAll("[data-pool-column-toggle]").forEach(input => input.addEventListener("change", () => { + const visible = new Set(poolTablePrefs.columns); + if (input.checked) visible.add(input.dataset.poolColumnToggle); else visible.delete(input.dataset.poolColumnToggle); + if (!visible.size) { input.checked = true; toast(t("backendColumnsRequired"), true); return; } + poolTablePrefs.columns = poolColumns.filter(key => visible.has(key)); void savePoolTablePrefs(); syncPoolColumns(); + })); + syncPoolColumns(); syncPoolSortDirection(); + } + async function toggleVhostEnabled(vhost) { + if (!envelope || busy) return; + const next = structuredClone(envelope.config), target = (next.vhosts || []).find(item => item.id === vhost.id); + if (!target) return; + target.enabled = vhost.enabled === false; + if (await saveSection("vhosts", next.vhosts || [])) render(); + } + function render() { if (!envelope) return; if (!initialized) load(defaults(), [], false); @@ -33,7 +117,9 @@ const browseTls = configuredEndpoints.some(endpoint => endpoint.binding?.tls === true); const openButton = button("vhOpenBrowser", () => { if (browseHost) window.open(`${browseTls ? "https" : "http"}://${browseHost}/`, "_blank", "noopener,noreferrer"); }); openButton.disabled = !browseHost || v.enabled === false; - actions.append(openButton, button("edit", async () => { if (await allowDiscard()) load(structuredClone(v)); }), button("remove", async () => { + const quickToggle = button(v.enabled === false ? "vhQuickEnable" : "vhQuickDisable", () => toggleVhostEnabled(v), `quiet vhost-quick-toggle ${v.enabled === false ? "is-enable" : "is-disable"}`); + quickToggle.setAttribute("aria-pressed", String(v.enabled !== false)); + actions.append(quickToggle, openButton, button("edit", async () => { if (await allowDiscard()) load(structuredClone(v)); }), button("remove", async () => { if (busy || !(await appConfirm(t("vhDelete"), { danger: true }))) return; const next = structuredClone(envelope.config); next.vhosts = (next.vhosts || []).filter(item => item.id !== v.id); if (await saveSection("vhosts", next.vhosts || [])) { if (editing === v.id) load(); render(); } @@ -147,7 +233,9 @@ const generationAgeText = generationAgeRaw == null || !Number.isFinite(generationAge) ? "-" : generationAge >= 3600 ? `${Math.floor(generationAge / 3600)}h ${Math.floor((generationAge % 3600) / 60)}m` : generationAge >= 60 ? `${Math.floor(generationAge / 60)}m ${Math.floor(generationAge % 60)}s` : `${Math.floor(generationAge)}s`; const row = el("tr"); if (vhostDisabled) row.classList.add("pool-vhost-disabled"); const poolDomain = status.backend_pool_domains?.[pool.id]; const poolLabel = poolDomain ? `${pool.id} (${poolDomain})` : pool.id; const cells = [poolLabel, `${member.id}${member.backup ? " / " + t("vhBackup") : ""}`, label, activeLimit, member.requests, member.errors, member.ewma_latency_ms > 0 ? `${member.ewma_latency_ms.toFixed(1)} ms` : "-", `${rateBytes(memberTraffic)}/s`, member.upstream_client_generation ?? "-", member.upstream_client_generation_requests ?? "-", generationAgeText, member.upstream_client_rotations_total ?? "-", lastFailure, lastRecovery]; - cells.forEach((value, index) => { const cell = el("td", String(value ?? "-")); cell.title = index === 2 ? (vhostDisabled ? t("vhDisabled") : `${label} · ${healthDetail}`) : index === 12 ? (member.last_failure_detail || lastFailure) : String(value ?? "-"); if (index === 2 && !vhostDisabled) cell.className = member.status === "down" ? "status-error" : member.status === "up" ? "status-good" : ""; if (index === 12 && member.last_failure_at_ms) cell.classList.add("backend-last-failure"); row.append(cell); }); rows.push(row); + const sortValues = { vhost: poolLabel.toLowerCase(), backend: String(member.id || "").toLowerCase(), status: label.toLowerCase(), active: Number(member.active) || 0, requests: Number(member.requests) || 0, errors: Number(member.errors) || 0, latency: Number(member.ewma_latency_ms) || 0, traffic: memberTraffic, generation: Number(member.upstream_client_generation) || 0, generationRequests: Number(member.upstream_client_generation_requests) || 0, generationAge: Number.isFinite(generationAge) ? generationAge : -1, rotations: Number(member.upstream_client_rotations_total) || 0, lastFailure: Number(member.last_failure_at_ms) || 0, lastRecovery: Number(member.last_recovered_ms) || 0 }; + row.poolSort = sortValues; row.poolSearchValue = [poolLabel, member.id, label, member.status, member.last_failure_class, member.last_failure_detail].filter(Boolean).join(" ").toLowerCase(); + cells.forEach((value, index) => { const cell = el("td", String(value ?? "-")); cell.dataset.poolColumn = poolColumns[index]; cell.title = index === 2 ? (vhostDisabled ? t("vhDisabled") : `${label} · ${healthDetail}`) : index === 12 ? (member.last_failure_detail || lastFailure) : String(value ?? "-"); if (index === 2 && !vhostDisabled) cell.className = member.status === "down" ? "status-error" : member.status === "up" ? "status-good" : ""; if (index === 12 && member.last_failure_at_ms) cell.classList.add("backend-last-failure"); row.append(cell); }); rows.push(row); if (!vhostDisabled && member.status === "up") up++; active += Number(member.active) || 0; requests += Number(member.requests) || 0; errors += Number(member.errors) || 0; traffic += memberTraffic; const latency = Number(member.ewma_latency_ms || member.latency_ms) || 0; if (latency > 0) { const weight = Math.max(1, Number(member.requests) || 1); weightedLatency += latency * weight; latencyWeight += weight; } } @@ -190,9 +278,9 @@ vhost.source?.type !== "web_server" || (vhost.routes || []).some(route => !route.response && (route.source?.type || "reverse_proxy") === "reverse_proxy") ); $("pool-rows").replaceChildren(...rows); - $("pool-empty").hidden = rows.length > 0 || !hasConfiguredProxySource; const backendDiagnosticsCard = $("backend-diagnostics-card"); if (backendDiagnosticsCard) backendDiagnosticsCard.hidden = !hasConfiguredProxySource; + applyPoolTableView(); document.querySelectorAll("[data-health-for]").forEach(node => node.textContent = summaries.get(node.dataset.healthFor) || t("vhHealthEmpty")); const fill = (attr, format) => document.querySelectorAll(`[data-${attr.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`)}]`).forEach(node => { const data = aggregate.get(node.dataset[attr]); node.textContent = data ? format(data) : "-"; }); fill("vhostHealth", d => d.disabled ? t("vhDisabled") : d.staticOnly ? t("vhUp") : d.healthMode === "off" ? t("vhHealthDisabled") : `${d.up}/${d.total} ${t("vhUp")}`); @@ -242,6 +330,7 @@ load(saved ? structuredClone(saved) : defaults()); }); $("pool-open").addEventListener("click", () => setPanel("vhosts")); + initPoolTableTools(); $("location-help-close")?.addEventListener("click", () => $("location-help-dialog")?.close()); - window.rustProxyVhosts = { render, renderStatus, reset() { dialog.close(); draftEpoch++; stagedCertificates = []; uploading = false; editing = null; revision = null; dirty = false; initialized = false; chartHistory.clear(); backendTrafficHistory.clear(); vhostTrafficHistory.clear(); container.replaceChildren(); $("vhost-search").value = ""; $("vhost-list").replaceChildren(); $("pool-rows").replaceChildren(); } }; + window.rustProxyVhosts = { render, renderStatus, applyPreferences: applyPoolPreferences, reset() { dialog.close(); draftEpoch++; stagedCertificates = []; uploading = false; editing = null; revision = null; dirty = false; initialized = false; poolTablePrefs = defaultPoolTablePrefs(); poolPreferenceSaveRunning = false; poolPreferenceSaveQueued = false; chartHistory.clear(); backendTrafficHistory.clear(); vhostTrafficHistory.clear(); container.replaceChildren(); $("vhost-search").value = ""; if ($("pool-search")) $("pool-search").value = ""; $("vhost-list").replaceChildren(); $("pool-rows").replaceChildren(); const sort = $("pool-sort"); if (sort) sort.value = poolTablePrefs.sort; applyPoolTableView(); } }; if (envelope) render(); if (latestStatus) renderStatus(latestStatus); diff --git a/src/logging/format.rs b/src/logging/format.rs index d8a7af5..b925a61 100644 --- a/src/logging/format.rs +++ b/src/logging/format.rs @@ -29,7 +29,6 @@ impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for RedactingStderr { } } } - fn redact_regex(pattern: &'static str) -> &'static regex::Regex { static AUTH: OnceLock = OnceLock::new(); static QUERY: OnceLock = OnceLock::new(); diff --git a/src/main/bootstrap.rs b/src/main/bootstrap.rs index b1d7a27..367412d 100644 --- a/src/main/bootstrap.rs +++ b/src/main/bootstrap.rs @@ -41,7 +41,7 @@ use zeroize::Zeroizing; #[command( name = "rust-proxy", version, - about = "RustProxy - independent Rust reverse proxy and static Web Server 0.25.6" + about = "RustProxy - independent Rust reverse proxy and static Web Server 0.25.7" )] struct Cli { #[arg( diff --git a/src/main/tasks.rs b/src/main/tasks.rs index 90e8ef6..a0b00f9 100644 --- a/src/main/tasks.rs +++ b/src/main/tasks.rs @@ -239,7 +239,7 @@ async fn live_logs_command(dir: PathBuf, addr: SocketAddr) -> Result<()> { } }); let interactive = io::stdin().is_terminal() && io::stdout().is_terminal(); - println!("RustProxy live logs 0.25.6 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits."); + println!("RustProxy live logs 0.25.7 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits."); if interactive { print!("> "); io::stdout().flush()?; } let mut filters = LiveLogFilters::default(); let mut history = std::collections::BTreeMap::::new(); diff --git a/src/prometheus/vhosts_backends.rs b/src/prometheus/vhosts_backends.rs index 872a93d..e41023b 100644 --- a/src/prometheus/vhosts_backends.rs +++ b/src/prometheus/vhosts_backends.rs @@ -102,6 +102,8 @@ fn render_backends( ("io_errors_total", "passive_io_errors_total", "counter"), ("slow_responses_total", "slow_responses_total", "counter"), ("slow_responses_total", "passive_slow_total", "counter"), + ("retry_attempts_total", "retry_attempts_total", "counter"), + ("retry_successes_total", "retry_successes_total", "counter"), ( "capacity_rejections_total", "capacity_rejections_total", @@ -117,6 +119,17 @@ fn render_backends( ), ("read_timeouts_total", "read_timeouts_total", "counter"), ("send_timeouts_total", "send_timeouts_total", "counter"), + ("upstream_client_generation", "upstream_client_generation", "gauge"), + ( + "upstream_client_generation_requests", + "upstream_client_generation_requests", + "gauge", + ), + ( + "upstream_client_rotations_total", + "upstream_client_rotations_total", + "counter", + ), ( "max_concurrent_requests", "max_concurrent_requests", @@ -151,6 +164,11 @@ fn render_backends( 1000.0, ), ("traffic_bytes_per_second", "traffic_bytes_per_second", 1.0), + ( + "upstream_client_generation_age_seconds", + "upstream_client_generation_age_seconds", + 1.0, + ), ] { if let Some(n) = member[field].as_f64() { f.add( @@ -379,6 +397,8 @@ fn render_docker( ("io_errors_total", "passive_io_errors_total", "counter"), ("slow_responses_total", "slow_responses_total", "counter"), ("slow_responses_total", "passive_slow_total", "counter"), + ("retry_attempts_total", "retry_attempts_total", "counter"), + ("retry_successes_total", "retry_successes_total", "counter"), ( "capacity_rejections_total", "capacity_rejections_total", @@ -394,6 +414,17 @@ fn render_docker( ), ("read_timeouts_total", "read_timeouts_total", "counter"), ("send_timeouts_total", "send_timeouts_total", "counter"), + ("upstream_client_generation", "upstream_client_generation", "gauge"), + ( + "upstream_client_generation_requests", + "upstream_client_generation_requests", + "gauge", + ), + ( + "upstream_client_rotations_total", + "upstream_client_rotations_total", + "counter", + ), ( "max_concurrent_requests", "max_concurrent_requests", @@ -428,6 +459,11 @@ fn render_docker( 1000.0, ), ("traffic_bytes_per_second", "traffic_bytes_per_second", 1.0), + ( + "upstream_client_generation_age_seconds", + "upstream_client_generation_age_seconds", + 1.0, + ), ] { if let Some(n) = member[field].as_f64() { f.add( diff --git a/src/web_server/fastcgi/protocol.rs b/src/web_server/fastcgi/protocol.rs index 7e60d79..5552742 100644 --- a/src/web_server/fastcgi/protocol.rs +++ b/src/web_server/fastcgi/protocol.rs @@ -156,7 +156,7 @@ pub(super) fn fastcgi_params( } params.insert("HTTPS".into(), if context.tls { "on" } else { "off" }.into()); params.insert("GATEWAY_INTERFACE".into(), "CGI/1.1".into()); - params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.25.6".into()); + params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.25.7".into()); params.insert("REDIRECT_STATUS".into(), "200".into()); if let Some(value) = headers.get(CONTENT_TYPE).and_then(|value| value.to_str().ok()) { params.insert("CONTENT_TYPE".into(), value.into()); diff --git a/src/web_server/response/file.rs b/src/web_server/response/file.rs index ebb9bc5..048ac98 100644 --- a/src/web_server/response/file.rs +++ b/src/web_server/response/file.rs @@ -180,7 +180,7 @@ pub(super) fn directory_listing(path: &str, entries: &[DirectoryEntry]) -> Vec{type_label}{label}{slash}{kind}" )); } - html.push_str(r#"
RustProxy 0.25.6Web Server · Directory listing
"#); + html.push_str(r#"
RustProxy 0.25.7Web Server · Directory listing
"#); html.into_bytes() } diff --git a/src/web_server/tests/part_02.rs b/src/web_server/tests/part_02.rs index b141c71..fbe31fc 100644 --- a/src/web_server/tests/part_02.rs +++ b/src/web_server/tests/part_02.rs @@ -202,7 +202,7 @@ async fn empty_index_can_go_directly_to_directory_listing() { let body = std::str::from_utf8(&body).unwrap(); assert!(body.contains("file.txt")); assert!(body.contains("DIRECTORY LISTING")); - assert!(body.contains("RustProxy 0.25.6")); + assert!(body.contains("RustProxy 0.25.7")); } #[tokio::test]
VhostBackendStatusActiveRequestsErrorsLatencyTraffic/sClient gen.Gen. requestsGen. ageRotationsLast failureLast recoveryVhostBackendStatusActiveRequestsErrorsLatencyTraffic/sClient gen. + Gen. + requestsGen. ageRotationsLast failureLast recovery +