# RustProxy 0.28.1 implementation note ## Scope 0.28.1 adds first-class support for certificate/key pairs that are managed outside the RustProxy data directory, with Certbot's `/etc/letsencrypt/live/...` layout as the primary operator case. It retains the managed filename mode under `/certs`, all 0.28.0 GeoIP/listener/cache/UI changes, SQLite schema 8 and COLD cache format 3. ## Certificate file modes Manual certificate entries use the existing `cert_file` and `key_file` fields. Their addressing mode is derived without adding a database/configuration schema field: - two simple filenames, for example `app.pem` and `app.key`, are resolved inside `/certs`; - two absolute paths, for example `/etc/letsencrypt/live/example.com/fullchain.pem` and `/etc/letsencrypt/live/example.com/privkey.pem`, are read in place; - mixed relative/absolute pairs are rejected. Managed filenames retain the existing traversal protection and `O_NOFOLLOW` open behavior. Absolute external paths are bounded to 4096 bytes. Each external path is canonicalized at load/reload time, which intentionally resolves Certbot `live/` symlinks to the current generation under `archive/`; the resolved final file is then opened with `O_NOFOLLOW`, must be a regular file and remains subject to the 128 KiB PEM bound. Managed private keys remain owner-only. External private keys may grant read-only group access (for example `0640`) so the unprivileged `rustproxy` service can use a restricted TLS group, but they may not be executable, group-writable or world-accessible; every parent directory must also be traversable by the service identity. The certificate/key pair is still parsed by rustls and must match. Config publication remains atomic: invalid or unreadable replacement material leaves the previous immutable TLS snapshot active. ## Renewal wrapper workflow For an externally managed certificate, renew the files using Certbot/acme.sh/another issuer and then call: ```text POST /api/certificates/{certificate_id}/reload ``` The endpoint re-reads configured files and republishes the complete immutable TLS/routing snapshot without changing the saved configuration revision. New HTTP/1.1, HTTP/2 and HTTP/3 handshakes use the refreshed certificate; established TLS sessions are not renegotiated. A selected administration certificate remains startup-fixed and reports that process restart is required. Scoped Certificate API credentials can call the targeted reload endpoint. `POST /api/certificates/deploy` remains a PEM-body deployment API and deliberately refuses to overwrite an ID that is configured with absolute external file paths; this prevents a renewal owner from silently switching storage models. ## Backups RustProxy full backups contain managed certificate material under `/certs`. Absolute external certificate/key files are not copied into the backup. Their configured paths remain in SQLite/configuration, so the files or mounts must exist separately on the restored host before TLS can be compiled successfully. ## Administration UI Certificates -> Generate/Add -> Existing server files now has an explicit file-location selector: - **RustProxy certificate directory (`/certs`)** accepts filenames only; - **External files (absolute paths)** accepts complete server paths and shows a Certbot example. English and Polish provider hints also explain that ACME modes generate/manage their own material, Import copies browser-selected PEM files into RustProxy storage, and Existing files references server-side material. Installed-certificate cards mark absolute-path entries as external. ## Compatibility No migration is required from 0.28.0. Existing filename-only certificate entries keep their prior meaning. Existing deploy/upload/ACME flows continue to create RustProxy-managed filenames and never place PEM key bytes in configuration responses.