This commit is contained in:
Mateusz Gruszczyński committed 2026-10-07 13:40:21 +02:00
1 parent 3a2eb4fe79
commit e0194fbaff
63 files changed
+1553 -379

No files matched your search

+16 -9
View File
@@ -26,16 +26,23 @@ certificate to a vhost. No CA operation occurs on startup or merely opening a fo
| PEM import | Upload fullchain/certificate and corresponding private key, then validate |
| Existing server files | Advanced: reference a PEM pair already in the certificate directory |
Python 3 and Certbot must be executable by the RustProxy service user. Install
plugins in that SAME Certbot environment. The application does not install packages
or execute sudo. Check the CLI installation with `bash dev.sh acme --doctor` and
`certbot plugins`; this does not validate provider credentials or DNS reachability.
DNS uses the API/plugin appropriate to the selected provider, not a Cloudflare
Tunnel integration or a hand-written replacement for ACME.
RustProxy now owns its preferred Certbot environment under `<data-dir>/acme-python`.
When it is missing, RustProxy creates a virtual environment and installs pinned Certbot
5.8.0 plus `certbot-dns-cloudflare`, `certbot-dns-ovh` and
`certbot-dns-rfc2136` 5.8.0 with pip. No distribution Python files are modified and
RustProxy never executes sudo. If the stdlib `venv` module is unavailable but system
pip works, `virtualenv` is bootstrapped only inside the RustProxy data directory.
The shipped OCI image already contains Certbot plus the Cloudflare, OVH and RFC2136
plugins in one dedicated Python environment. Host/source installations remain under
the operator's package-management policy and must provide the plugins they use.
If local setup fails, a runnable system `certbot` from `PATH` is used as fallback. The
Certificates panel reports whether the managed environment, the system fallback, or no
ACME runtime is active. Systems without Python (for example some appliance layouts)
retain PEM import and existing-file certificate modes even though ACME issuance/renewal
is unavailable. `bash dev.sh acme --doctor` and `certbot plugins` inspect only the
current shell/system fallback; they do not validate provider credentials or DNS reachability.
The shipped OCI image contains Python, venv/pip and distribution Certbot packages as an
offline fallback. Its preferred managed environment is still created in the persisted
`/var/lib/rustproxy` data volume.
## HTTP-01 requirements and scope
+2 -2
View File
@@ -406,7 +406,7 @@ For a certificate owned by a local external issuer such as system Certbot, prefe
CLI deploy hook, which calls that loopback API after bounded local file checks:
```bash
rust-proxy tls deploy --id shared-cert \
/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert \
--cert /etc/letsencrypt/live/example/fullchain.pem \
--key /etc/letsencrypt/live/example/privkey.pem
```
@@ -444,7 +444,7 @@ curl --fail --show-error \
For an on-host Certbot hook, a token is optional: invoke the installed binary directly instead:
```bash
rust-proxy tls deploy --id shared-cert \
/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert \
--cert /etc/letsencrypt/live/example/fullchain.pem \
--key /etc/letsencrypt/live/example/privkey.pem
```
+1 -1
View File
@@ -1,4 +1,4 @@
# Administration API access - 0.27.0
# Administration API access - 0.27.1
## Sign-in boundary
+7 -7
View File
@@ -9,7 +9,7 @@ each Docker host, so the proxy container never needs Docker-socket access. See
Build locally with a normal OCI builder:
```bash
docker build -t rustproxy:0.27.0 .
docker build -t rustproxy:0.27.1 .
```
Persist `/var/lib/rustproxy`; it contains the SQLite database, certificates and the
@@ -22,7 +22,7 @@ docker volume create rustproxy-data
docker run --rm -d --name rustproxy \
-p 8080:8080 \
-v rustproxy-data:/var/lib/rustproxy \
rustproxy:0.27.0
rustproxy:0.27.1
docker exec rustproxy rust-proxy admin setup-token
```
@@ -32,11 +32,11 @@ RustProxy configuration and choose a certificate, then bind the administration
listener to a non-loopback address. Publish the admin port only after HTTPS is
active. Plain remote HTTP keeps the legacy explicit risk gate.
The runtime image includes Python, OpenSSL and a dedicated Certbot environment with
all DNS plugins currently supported by RustProxy: Cloudflare, OVH and RFC2136.
HTTP-01 needs no DNS plugin. The Certbot core and all three DNS plugins are pinned to
the same release so they stay in one compatible Python environment; no image extension
is required for the built-in certificate providers.
The runtime image includes Python, venv/pip, OpenSSL and distribution Certbot packages
for Cloudflare, OVH and RFC2136 fallback. RustProxy prefers its own pinned Certbot
environment under `/var/lib/rustproxy/acme-python`; because `/var/lib/rustproxy` is the
persisted volume, that environment survives container replacement. If pip setup is not
possible, the image can fall back to the distribution Certbot binaries already in `PATH`.
For access-log files, prefer a writable path under `/var/lib/rustproxy` or mount a
separate writable log volume. The built-in JSON file sink is disabled by default.
+1 -1
View File
@@ -1,6 +1,6 @@
# Stored log explorer
RustProxy 0.27.0 provides an authenticated, read-only **Logs** workspace at `/logs`. The top bar has one **Logs** menu with separate **Stored logs** and **Live Logs** actions; the two data paths remain independent.
RustProxy 0.27.1 provides an authenticated, read-only **Logs** workspace at `/logs`. The top bar has one **Logs** menu with separate **Stored logs** and **Live Logs** actions; the two data paths remain independent.
## Separation from Live Logs
+27 -17
View File
@@ -1,4 +1,4 @@
# Installing and updating RustProxy 0.27.0
# Installing and updating RustProxy 0.27.1
The scripts prepare a Linux/systemd installation. This source archive is **not a
verified production build**: Rust/Cargo, real CA operations, live systemd startup
@@ -31,7 +31,7 @@ Plain remote HTTP requires both an explicit non-loopback `RUSTPROXY_ADMIN_LISTEN
Equivalent prerequisite commands are:
```bash
apt install -y build-essential gcc git ca-certificates python3 pkg-config wget sudo python3-certbot-dns-rfc2136 python3-certbot-dns-cloudflare
apt install -y build-essential gcc git ca-certificates python3 python3-venv python3-pip pkg-config wget sudo certbot python3-certbot-dns-rfc2136 python3-certbot-dns-cloudflare python3-certbot-dns-ovh
wget -qO- --https-only --secure-protocol=TLSv1_2 https://sh.rustup.rs | sh
```
@@ -154,25 +154,35 @@ editable desired-state entries.
## ACME prerequisites
Automatic renewal runs inside RustProxy, not a separately installed cron timer.
Install `certbot`, the DNS plugins you use (`certbot-dns-cloudflare`,
`certbot-dns-ovh`, `certbot-dns-rfc2136`), Python and OpenSSL on the server. HTTP-01
uses Certbot's webroot authenticator, not a competing standalone web server.
Certbot and its plugins must be in the **same Python environment**. An optional
root-owned virtual environment at `/opt/rustproxy-certbot` is on the service PATH;
otherwise use `/usr/local/bin` or `/usr/bin`. Avoid an executable under an
administrator's home directory: the unit uses `ProtectHome=true`.
Automatic renewal runs inside RustProxy, not a separately installed cron timer. RustProxy
prefers a private Python environment at `<data-dir>/acme-python`. When that environment is
missing or incomplete, the service creates it automatically and installs the pinned Certbot
core plus the Cloudflare, OVH and RFC2136 plugins with `pip`. The application never executes
`sudo` and never modifies distribution-owned Python site-packages.
Check the effective service account's environment rather than only your shell:
The host should provide Python 3 with either the standard `venv` module or `pip`; RustProxy can
bootstrap `virtualenv` into its own data directory when a distribution splits `venv` into a
separate package. OpenSSL remains a local certificate-inspection fallback. If the private
environment cannot be created, RustProxy uses a runnable distribution `certbot` from `PATH`
when one is available.
If Python is absent (a possible layout on appliances such as OPNsense), or Python is present
but no local environment can be created and no system Certbot exists, the Certificates panel
shows ACME as unavailable. PEM upload and references to existing certificate files remain
available.
On the standard service installation the managed environment therefore lives at
`/var/lib/rustproxy/acme-python`. Do not run a second Certbot renewal timer over RustProxy's
`certs/acme` profiles. See [renewal](RENEWAL.md).
A source-tree preflight can still inspect a distribution-provided fallback environment with:
```bash
sudo -u rustproxy env PATH=/opt/rustproxy-certbot/bin:/usr/local/bin:/usr/bin:/bin \
sudo -u rustproxy env PATH=/usr/local/bin:/usr/bin:/bin \
python3 scripts/acme_provider.py --doctor
```
The provider scripts are embedded in the binary; the source file above is just a
preflight command. The service owns its complete private `certs/acme` tree. Do not
run a second Certbot renewal timer over those same profiles. See [renewal](RENEWAL.md).
The provider script is embedded in the RustProxy binary; this command is diagnostic only.
### Using a separate system Certbot
@@ -182,14 +192,14 @@ A Certbot deploy hook can publish every successful renewal to all vhosts that al
that id:
```bash
/usr/bin/rust-proxy tls deploy --id shared-cert \
/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert \
--cert /etc/letsencrypt/live/example/fullchain.pem \
--key /etc/letsencrypt/live/example/privkey.pem
```
The command reads the Certbot files locally and sends them to the authenticated loopback `POST /api/certificates/deploy` endpoint. The running RustProxy service writes the private generation with its own filesystem identity and hot-publishes it for new public TLS/H2/H3 handshakes. No per-vhost edit is needed. If another
local process instead replaces the exact files already referenced by RustProxy, run
`/usr/bin/rust-proxy tls reload` (or authenticated `POST /api/certificates/reload`) afterward. If the replacement belongs to one configured manual certificate ID, automation may instead call `POST /api/certificates/{certificate_id}/reload`; the same endpoint accepts a scoped Certificate API Key ID + Bearer token and does not change the configuration revision.
`/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls reload` (or authenticated `POST /api/certificates/reload`) afterward. If the replacement belongs to one configured manual certificate ID, automation may instead call `POST /api/certificates/{certificate_id}/reload`; the same endpoint accepts a scoped Certificate API Key ID + Bearer token and does not change the configuration revision.
Administration TLS is startup-fixed and may still require a service restart.
Optional environment overrides go in a root-owned `/etc/rustproxy/environment`
+2 -1
View File
@@ -15,6 +15,7 @@ This is the canonical index for the current project documentation. The authentic
- [0.25.1 release audit](V0.25.1_AUDIT.md) - historical Traffic/module-split release scope and compiler-regression guards.
- [0.25.0 specification audit](V0.25.0_AUDIT.md) - Web Server foundation point-by-point implementation status.
- [0.25.0 pre-production security audit](V0.25.0_SECURITY_PREPROD_AUDIT.md) - threat-oriented source/configuration review, fixes made in-session and mandatory runtime security gates.
- [0.27.1 implementation note](V0.27.1_IMPLEMENTATION.md) - first-admin command, managed/fallback certificate runtime and account-scoped route-list sorting.
- [0.27.0 implementation note](V0.27.0_IMPLEMENTATION.md) - compression defaults/scoped policy, persistent Docker publications and visible cache occupancy meter fill.
- [0.26.7 implementation note](V0.26.7_IMPLEMENTATION.md) - HOT/COLD occupancy meters, backend rotation continuity and container Certbot packaging.
- [0.26.6 implementation note](V0.26.6_IMPLEMENTATION.md) - composed ACL allow semantics, certificate-form reset, backend table preferences and NPM migration helper documentation.
@@ -68,7 +69,7 @@ This is the canonical index for the current project documentation. The authentic
## Historical or version-labelled context
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [V0.27.0_IMPLEMENTATION.md](V0.27.0_IMPLEMENTATION.md); [V0.26.7_IMPLEMENTATION.md](V0.26.7_IMPLEMENTATION.md) is retained as the prior cache/backend/container milestone; [V0.26.6_IMPLEMENTATION.md](V0.26.6_IMPLEMENTATION.md) is retained as the prior access-policy/administration milestone; [V0.26.5_IMPLEMENTATION.md](V0.26.5_IMPLEMENTATION.md) is retained as the prior interface-scaling/listener-navigation milestone, [V0.26.4_IMPLEMENTATION.md](V0.26.4_IMPLEMENTATION.md) as the prior administration/backend-lifecycle milestone, [V0.26.3_IMPLEMENTATION.md](V0.26.3_IMPLEMENTATION.md) as the prior appearance/UI milestone, [V0.26.2_IMPLEMENTATION.md](V0.26.2_IMPLEMENTATION.md) as the prior Logs/UI milestone and [V0.26.1_IMPLEMENTATION.md](V0.26.1_IMPLEMENTATION.md) as the prior protocol-attribution milestone. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain historical evidence.
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md); [V0.27.0_IMPLEMENTATION.md](V0.27.0_IMPLEMENTATION.md) is retained as the prior compression/Docker-publication milestone; [V0.26.7_IMPLEMENTATION.md](V0.26.7_IMPLEMENTATION.md) is retained as the prior cache/backend/container milestone; [V0.26.6_IMPLEMENTATION.md](V0.26.6_IMPLEMENTATION.md) is retained as the prior access-policy/administration milestone; [V0.26.5_IMPLEMENTATION.md](V0.26.5_IMPLEMENTATION.md) is retained as the prior interface-scaling/listener-navigation milestone, [V0.26.4_IMPLEMENTATION.md](V0.26.4_IMPLEMENTATION.md) as the prior administration/backend-lifecycle milestone, [V0.26.3_IMPLEMENTATION.md](V0.26.3_IMPLEMENTATION.md) as the prior appearance/UI milestone, [V0.26.2_IMPLEMENTATION.md](V0.26.2_IMPLEMENTATION.md) as the prior Logs/UI milestone and [V0.26.1_IMPLEMENTATION.md](V0.26.1_IMPLEMENTATION.md) as the prior protocol-attribution milestone. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain historical evidence.
Older context documents such as [INTEGRATIONS_040](INTEGRATIONS_040.md), [MANAGEMENT](MANAGEMENT.md), [SECURITY_AUDIT](SECURITY_AUDIT.md), [ACME_RFC2136](ACME_RFC2136.md) and older version audits remain available for traceability but should not override the current functional/technical documents above.
+1 -1
View File
@@ -82,7 +82,7 @@ For a certificate intentionally owned by a separate system Certbot instead of th
renewal subsystem, use a manual certificate id and a Certbot deploy hook that runs, for example:
```bash
/usr/bin/rust-proxy tls deploy --id shared-cert \
/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy --id shared-cert \
--cert /etc/letsencrypt/live/example/fullchain.pem \
--key /etc/letsencrypt/live/example/privkey.pem
```
+8 -10
View File
@@ -1,24 +1,22 @@
# Verification report - RustProxy 0.27.0
# Verification report - RustProxy 0.27.1
## Scope
RustProxy 0.27.0 changes downstream compression policy, Docker-vhost publication continuity, cache-meter rendering, fresh-install response identity and source-package layout while keeping SQLite schema 8.
RustProxy 0.27.1 changes first-administrator onboarding, ACME/Certbot runtime preparation and account-scoped sorting for vhosts, Docker vhosts, redirects, 404 hosts and streams while keeping SQLite schema 8.
Dynamic response compression defaults to zstd, Brotli and gzip enabled, with deflate opt-in. Client `Accept-Encoding` quality values are authoritative; equal quality uses deterministic `zstd -> br -> gzip -> deflate` server preference. Existing `Content-Encoding`, `no-transform`, range responses/requests, SSE and upgrades remain excluded. Cookie, authorization, `Set-Cookie`, `private` and `no-store` no longer disable compression as blanket rules.
The first-run administrator screen now presents a complete command using the default `./data` directory and a second standard-service example using `/var/lib/rustproxy`.
Ordinary vhosts and Web Server services can inherit, enable or disable dynamic compression and independently inherit/enable/disable zstd, Brotli, gzip and deflate. Docker vhosts expose one Compression checkbox only and use the codec set/priorities from global **Settings -> Response**. Global codec switches remain the hard availability ceiling and `min_bytes` remains global.
Certificate automation now prefers a RustProxy-owned Python environment at `<data-dir>/acme-python`. Missing environments are prepared with `venv` and pip; when a distribution omits the stdlib `venv` module but provides pip, RustProxy can bootstrap `virtualenv` into its own data directory rather than changing distribution site-packages. Certbot 5.8.0 and the Cloudflare, OVH and RFC2136 plugins are installed into that managed environment. A runnable distribution Certbot remains the fallback. The Certificates panel reports managed/system/preparing/unavailable state and missing Python/pip diagnostics; manual PEM import and existing-file workflows do not depend on ACME runtime availability.
An explicitly published Docker assignment keeps its generated hostname even when its service disappears. A successful inventory without the assigned service materializes an unavailable route that returns HTTP 503 instead of removing the hostname. Agent polling errors retain the previous successful inventory when one exists, and a returning service is reconciled automatically. The cache overview progress elements have explicit WebKit/Chromium and Firefox progress-value styling so their visual fill follows the numeric meter value.
Fresh installations now default the response `Server` policy to `custom` with the exact value `RustProxy`. Existing stored settings are not rewritten, and a configuration document predating the `server_header` field still deserializes with the historical preserve behavior. Debian package-build metadata is no longer shipped in the main source tree; ready packages are maintained separately at `https://rustproxy.linuxiarz.pl`.
The route/list pages gain feature-specific sort-column and sort-direction controls. Their values are saved in the existing account-scoped administrator preferences and default safely when absent. Redirects and 404 hosts use the same search/sort/action toolbar structure as Vhosts.
## Regression coverage
Compression unit coverage checks defaults, q-value negotiation, equal-quality priority, each supported codec, existing-encoding passthrough, scoped per-codec resolution and the revised cookie/auth/cache-privacy policy. Docker unit coverage checks missing published service -> retained 503, failed agent observation -> retained last-known backend, the single compression switch and ignoring legacy Docker per-codec values. Settings coverage checks the fresh-install `Server: RustProxy` default and legacy missing-field compatibility. Static/UI contracts require ordinary-vhost and Web-Service codec controls to hide/disable when their scope is explicitly OFF, require Docker vhosts to expose only the single Compression checkbox, and retain the 503 path, visible cache progress styling, external Debian-packaging separation and reproducible archives without a `debian/` tree.
Static/source contracts cover the new first-run commands, ACME runtime status UI/API, managed environment path and pinned package set, distro fallback markers, preference fields and list-specific sort controls. They also reject the development-only `./dev.sh tls deploy` UI hook and require the production binary/data-directory example, both official repository links and Python/pip/Certbot runtime metadata in the startup banner and authenticated application information. Existing release-smoke, language/OpenAPI, source-module, security, web-server, browser-service and Docker-agent gates remain part of the Rust-independent verification set.
## Verification status in this workspace
Rust/Cargo is not installed in this workspace. Rust-independent checks pass here; compiler/type/runtime gates remain explicitly open until this source is checked on a Rust-enabled release host.
Rust/Cargo is not installed in this workspace. Rust-independent checks are run here; compiler/type/runtime gates remain explicitly open until this source is checked on a Rust-enabled release host.
| Check | Status |
|---|---|
@@ -43,4 +41,4 @@ Rust/Cargo is not installed in this workspace. Rust-independent checks pass here
| `cargo test --all-targets --all-features` | BLOCKED: Rust/Cargo toolchain unavailable |
| complete release build | BLOCKED at Rust compilation: Rust/Cargo toolchain unavailable |
The 0.27.0 source archive must not be described as compiler-verified or production-ready until the Rust-enabled release-host gates pass. Static/source contracts do not substitute for Rust parsing, type checking, Clippy, unit tests or real protocol runtime tests.
The 0.27.1 source archive must not be described as compiler-verified or production-ready until the Rust-enabled release-host gates pass. Static/source contracts do not substitute for Rust parsing, type checking, Clippy, unit tests or real protocol runtime tests.
+41
View File
@@ -0,0 +1,41 @@
# RustProxy 0.27.1 implementation note
## Scope
0.27.1 improves first-run administration, makes ACME/Certbot setup independent of one distribution packaging layout, and adds per-user list sorting to the main routing views. SQLite remains schema 8; the saved administrator-preference document gains only defaulted fields.
## First administrator
The initial login/setup screen now shows a directly runnable token command for the default data path:
```bash
rust-proxy --data-dir ./data admin setup-token
```
A standard service-installation example is shown below it:
```bash
rust-proxy --data-dir /var/lib/rustproxy admin setup-token
```
This removes the previous `DATA_DIR` placeholder from the primary command while still documenting the installed-service path.
## Managed certificate runtime
RustProxy now prefers a private Python environment at `<data-dir>/acme-python`. On startup, and again on demand before an ACME job, it validates that environment and initializes it when missing. The managed environment pins Certbot 5.8.0 plus the Cloudflare, OVH and RFC2136 plugins.
Initialization first uses the available `python3`/`python` stdlib `venv`. If a distribution separates `venv` but provides pip, RustProxy installs `virtualenv` only into a temporary directory below its own data directory and uses it to create the managed environment; it does not modify distribution-owned site-packages. The managed environment receives its own pip packages.
If managed setup cannot be completed, RustProxy tests a distribution `certbot` from `PATH` and uses it as the fallback when runnable. If Python is unavailable, or neither managed nor system Certbot can be used, the Certificates panel shows an unavailable state and a specific diagnostic. Manual PEM import and use of existing certificate files remain independent of the ACME runtime. This makes minimal systems, including appliances that intentionally omit Python/pip, fail visibly instead of silently.
## List sorting
The administrator preference document now stores sort column and direction separately for ordinary vhosts, Docker vhosts, 404 hosts and streams. Each page exposes only columns meaningful to that feature and reuses the backend-table column/direction selection pattern. Preferences are account-scoped and reapplied when the administrator session/preferences are loaded.
## Compatibility
No SQLite migration is required. Schema 8 remains current. Existing saved configuration continues to load; missing sort preferences receive defaults. Historical distribution Certbot packages remain useful as an offline/runtime fallback, while the application-owned environment is the preferred path.
## Verification limitation
This workspace does not provide Cargo/Rust, so compiler/type/Clippy/unit-test gates must still be run on a Rust-enabled release host. Rust-independent source, JavaScript, documentation, packaging and Go-agent checks are tracked in [TEST_REPORT](TEST_REPORT.md).