7.3 KiB
0.7 update: configured managed certificates now have automatic renewal and validated hot deployment. Initial issuance/import remains explicit. Read RENEWAL.md for defaults, retained profiles and opt-out.
Certificate providers
Source implementation; real provider/DNS/CA issuance and Rust runtime have not been verified in the packaging environment. Offline tests substitute Certbot, so they cannot establish that a DNS token, zone policy or CA deployment works.
Workflow
Open Certificates -> Add certificate. Choose one provider or import mode, enter the domains and metadata, then request issuance. Production is selected by default in the panel and still requires the separate explicit production confirmation. Staging remains available for testing and its certificates are not browser-trusted. After a successful job, import its validated pair into the library, then assign the certificate to a vhost. No CA operation occurs on startup or merely opening a form.
| Selection | Mechanism and required configuration |
|---|---|
| HTTP-01 / domain validation | Certbot webroot; domain names and a publicly reachable plaintext HTTP listener |
| Cloudflare | DNS-01; scoped API token; certbot-dns-cloudflare installed |
| OVH | DNS-01; ovh-eu or ovh-ca, application key/secret, consumer key; certbot-dns-ovh installed |
| RFC2136 | DNS-01; server/port, TSIG name/secret/algorithm; certbot-dns-rfc2136 installed |
| 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.
HTTP-01 requirements and scope
Public TCP port 80 for every requested name must reach an active plaintext RustProxy listener. NAT from public 80 to a private/custom HTTP port is allowed; setting only port 8080 in public DNS is not sufficient. Check all published A/AAAA addresses and multi-node routing. TLS-only listeners are not enough. There is no TLS-ALPN-01 mode. This implementation accepts DNS names, not IP certificates. Wildcard certificates require one of the DNS-01 providers, not HTTP-01.
During a running HTTP-01 job, RustProxy serves only
/.well-known/acme-challenge/<token> for that job's exact normalized hostnames.
Only GET/HEAD and bounded regular files from certs/acme-http01 are accepted;
queries, traversal, unrelated names, HTTPS requests and inactive jobs cannot read
these files. The reserved path precedes application auth/cache/static pages so a
CA can validate ownership without logging in. This exception does not bypass
application authentication for any other path. Responses are no-store.
A CDN or upstream proxy must forward this path and the correct Host without rewriting it. There is no automatic forwarding configuration at your DNS/CDN vendor. Expired challenge jobs do not leave an open generic file server.
DNS credentials and least privilege
Cloudflare: use an API token with Zone:DNS:Edit restricted to the zones used for
issuance. The adapter intentionally does not accept the account-wide Global API Key.
OVH: use a consumer key allowing GET /domain/zone/ and GET/PUT/POST/DELETE for
/domain/zone/<YOUR_ZONE>/*. Repeat only for required zones, not the whole account.
Choose the region matching the account. Consult the official plugin docs if API
policies change. A domain registered at OVH but DNS hosted elsewhere must use the
actual authoritative DNS provider; registration alone is not sufficient.
RFC2136: retain the TSIG-limited update policy described in ACME_RFC2136.md. DNS provider propagation delay is configurable. The helper rejects malformed tokens, unknown/cross-provider fields and INI injection. It does not test your DNS policy in advance. Wildcard DNS-01 issuance does not add wildcard HOST routing: vhost hostnames remain exact matches.
API input
Common fields: provider, certificate_id, domains (one or more DNS names), email,
environment (staging/production), agree_tos, confirm_production. RustProxy
does not impose its own domain-count ceiling; the selected CA/provider may still
apply its external certificate/SAN policy.
DNS providers accept propagation_seconds.
Provider-specific fields:
http01: none; wildcard domains are rejected.cloudflare:api_token.ovh:endpoint,application_key,application_secret,consumer_key.rfc2136:dns_server,dns_port,key_name,key_secret,key_algorithm,sign_query.
POST /api/acme/issue is authenticated and CSRF-protected; one job runs at a time.
GET /api/acme is safe status metadata only. Job status is process-local; account
and credential files persist. A completed certificate has optional issuer metadata
with provider/environment, not a copy of request credentials.
Secret storage, renewal and limitations
Provider secrets are sent to the private worker on stdin, not command arguments.
They are not stored in exported JSON, SQLite, localStorage or audit records.
Files are private (0600 credentials, 0700 directories); these permissions do NOT
encrypt them. The service user/root can read them. Certbot account/lineage state
and provider credential files persist for managed renewal under
certs/acme/<environment>-<id>-<provider>; RFC2136 keeps its old path without a
provider suffix. Issued PEM outputs use new immutable names before library import.
Back up these private profiles separately while issuance is idle: the standard SQLite/configured-PEM backup does not include every account/credential profile. Do not put real credentials into shell history or source-control examples. Restrict the admin interface and service environment. Rotate exposed API credentials.
Configured managed certificates in 0.7 renew through the shared RustProxy worker;
validated changed material is published automatically while failed checks preserve
the active generation. Use the certificate's toggle to disable scheduled renewal.
PEM-only imports remain manual. A separate system Certbot timer may own a different,
manual RustProxy certificate id and publish it with tls deploy --id ...; it must not
also own a RustProxy-managed ACME profile. There is no external expiry alert, revocation
or certificate garbage collector. Cancellation
kills the worker group; interrupted DNS cleanup can leave TXT records an operator
must remove. See renewal and recovery and test CA staging first.
Primary references
- HTTP-01/DNS-01 constraints: https://letsencrypt.org/docs/challenge-types/
- Certbot webroot and operational use: https://eff-certbot.readthedocs.io/en/latest/using.html
- Cloudflare plugin/API scope: https://certbot-dns-cloudflare.readthedocs.io/en/stable/
- OVH plugin/API scopes: https://certbot-dns-ovh.readthedocs.io/en/latest/
- RFC2136 plugin: https://certbot-dns-rfc2136.readthedocs.io/en/stable/
These document upstream requirements, not evidence that this RustProxy build has passed live provider or CA acceptance.