v0.24.5
This commit is contained in:
commit
5e23e9af02
240 files changed
+99957
No files matched your search
+118
@@ -0,0 +1,118 @@
|
||||
# Automatic certificate renewal
|
||||
|
||||
## Scope and defaults
|
||||
|
||||
RustProxy 0.7.0 renews **configured managed certificates** whose `issuer` metadata
|
||||
identifies an existing HTTP-01, Cloudflare, OVH or RFC2136 Certbot profile. Issuance
|
||||
and initial library import are still explicit, staging-first operations. Importing
|
||||
a PEM pair alone does not create a managed lineage or authorize CA requests.
|
||||
|
||||
For managed certificates, `issuer.auto_renew` defaults to `true`, including saved
|
||||
0.6 metadata lacking that field. Explicit `false` opts out. Therefore upgrading
|
||||
an already configured managed certificate can enable scheduled CA checks; review
|
||||
this before starting the new binary. Missing profiles fail closed with an error;
|
||||
there is no silent recreation, provider switch or production issuance.
|
||||
|
||||
Certificates shows an independent enable/disable action, Check now and Dry run,
|
||||
last check, next check, expiry and result. Expiry is populated after a worker check;
|
||||
it is not a pre-existing inventory of every manually imported certificate. Renewal
|
||||
is not a configurable new ACME account lifecycle or revocation feature.
|
||||
|
||||
## Schedule and recovery
|
||||
|
||||
Saved renewal observations are loaded from SQLite **before administration listeners are
|
||||
exposed**, so last check, next check, expiry and result are available immediately after a
|
||||
restart without pressing **Check now**. RustProxy then waits 5-10 minutes before the first
|
||||
automatic CA check, avoiding a renewal burst during startup. Successful checks are scheduled
|
||||
approximately every 12 hours with up to 30 minutes of additional jitter. Only one issue/renew
|
||||
worker runs at once. Failures back off from one to six hours; a missing/invalid profile is
|
||||
checked again after one hour. Observation rows contain non-secret status/timestamps only and
|
||||
are stored only in `config.sqlite3`. RustProxy 0.15.0 no longer reads or imports historical JSON
|
||||
observation sidecars at runtime. When SQLite has no observation row, the normal scheduler safely
|
||||
reconstructs status on its next automatic check; this does not replace or regenerate certificate,
|
||||
key, account or renewal-profile material. A manual dry run does not postpone a real due check. The
|
||||
service must be running; this is not an independent timer that works while RustProxy is stopped.
|
||||
|
||||
The helper runs `certbot renew --cert-name rustproxy` in the original isolated
|
||||
lineage, reusing saved authenticator/account/credential settings. It does not use
|
||||
`--force-renewal`, change the CA or run directory hooks. Do not add shell hooks
|
||||
to the private Certbot renewal configuration: hooks already saved by an operator
|
||||
are still part of Certbot's trusted configuration. Certbot decides when the
|
||||
certificate needs renewal. A successful exit can mean nothing was due: actual
|
||||
certificate and key bytes are compared with the currently installed generation.
|
||||
|
||||
For changed material, the helper verifies validity times using OpenSSL and creates
|
||||
private immutable, content-addressed staging files. Rust validates the certificate/
|
||||
key match and requested domain coverage, then validates a complete new snapshot
|
||||
including current vhost assignments. Only a successful revisioned SQLite write
|
||||
publishes that snapshot. New TCP and QUIC TLS handshakes use the new certificate;
|
||||
existing connections are not restarted. A simultaneous manual replacement/removal
|
||||
or automatic-renewal disable wins over an older automatic worker result.
|
||||
|
||||
Worker failure, invalid PEM/SANs, expiry regression or configuration conflict leaves
|
||||
the previously active generation intact. If Certbot succeeded but publication did
|
||||
not, the next check compares files again and can retry the same staged generation.
|
||||
Unchanged checks do not write a new configuration revision. Changed certificate publications
|
||||
use the ordinary revisioned configuration path, but certificate inventory changes are not part
|
||||
of cache compatibility and therefore do not discard otherwise compatible hot/cold objects.
|
||||
|
||||
Private profile/file checks, single-worker and per-profile locks, bounded subprocess
|
||||
timeouts and process-group cancellation constrain work. Original certificate files
|
||||
and Certbot archives are retained, not automatically deleted. Immutable renewal
|
||||
staging is limited to 1024 keys; initial issuance staging remains limited to 128.
|
||||
Plan monitored disk space and controlled offline cleanup after verified backups;
|
||||
there is no automatic certificate garbage collector or external expiry alert yet.
|
||||
|
||||
## Provider-specific prerequisites
|
||||
|
||||
HTTP-01 still requires public TCP port 80 to reach an active plaintext RustProxy
|
||||
listener for every name. The reserved challenge handler exposes only bounded tokens
|
||||
for the current worker's domains, before application auth/ACL/cache. It is not a
|
||||
public file browser. Wildcard certificates use DNS-01, not HTTP-01.
|
||||
|
||||
Cloudflare, OVH and RFC2136 need their original DNS permissions, credentials and
|
||||
propagation settings. Secrets are stored in private files, not returned by the
|
||||
renew endpoint or included in desired configuration. They are not encrypted at
|
||||
rest. The helper, Certbot, plugins and OpenSSL must be usable by the service user.
|
||||
Keep absolute profile paths stable; moving the Certbot directory requires explicit
|
||||
migration of its stored paths. A system-wide timer should not also manage these
|
||||
RustProxy-isolated profiles.
|
||||
|
||||
For a certificate intentionally owned by a separate system Certbot instead of this managed
|
||||
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 \
|
||||
--cert /etc/letsencrypt/live/example/fullchain.pem \
|
||||
--key /etc/letsencrypt/live/example/privkey.pem
|
||||
```
|
||||
|
||||
The command resolves Certbot's `live/` symlinks locally, validates and stages a new pair, then
|
||||
publishes the existing id through the normal revisioned configuration path. Do not point this
|
||||
workflow at a certificate carrying RustProxy `issuer` metadata; one lineage must have one owner.
|
||||
|
||||
Staging certificates are not trusted by browsers. A Dry run checks renewal
|
||||
validation but does not deploy the staging result. Only an explicit production
|
||||
issuance creates a production profile; renewal never upgrades staging implicitly.
|
||||
|
||||
## API
|
||||
|
||||
All routes below require the existing local administrator session and CSRF checks.
|
||||
|
||||
- `GET /api/acme`: current job, provider names, nominal interval and renewal states.
|
||||
- `POST /api/acme/renew`: `{"certificate_id":"site","dry_run":false}`; returns 202
|
||||
and a job. Only identity/options, no API credential resubmission.
|
||||
- Certificate opt-out is a revisioned config update setting
|
||||
`tls.certificates[].issuer.auto_renew` to `false`.
|
||||
|
||||
`--dry-run` is **not** a claim of live CA validation in this release's test report:
|
||||
packaging tests used a simulated Certbot. Run a real staging/production-lineage
|
||||
validation on your server. Full runtime scheduler/publication acceptance is pending.
|
||||
|
||||
## Primary references
|
||||
|
||||
Certbot renewal behavior and flags:
|
||||
https://eff-certbot.readthedocs.io/en/stable/using.html#renewing-certificates
|
||||
https://eff-certbot.readthedocs.io/en/stable/man/certbot.html
|
||||
|
||||
Challenge types: https://letsencrypt.org/docs/challenge-types/
|
||||
Reference in new issue
Block a user