[pbs-devel] superseded: [PATCH proxmox{-backup, } v4 0/8] fix #6939: acme: support servers returning 204 for nonce requests

Samuel Rufinatscha s.rufinatscha at proxmox.com
Thu Jan 8 12:48:43 CET 2026


https://lore.proxmox.com/pbs-devel/20260108112629.189670-1-s.rufinatscha@proxmox.com/T/#t

On 12/3/25 11:21 AM, Samuel Rufinatscha wrote:
> Hi,
> 
> this series fixes account registration for ACME providers that return
> HTTP 204 No Content to the newNonce request. Currently, both the PBS
> ACME client and the shared ACME client in proxmox-acme only accept
> HTTP 200 OK for this request. The issue was observed in PBS against a
> custom ACME deployment and reported as bug #6939 [1].
> 
> ## Problem
> 
> During ACME account registration, PBS first fetches an anti-replay
> nonce by sending a HEAD request to the CA’s newNonce URL.
> RFC 8555 §7.2 [2] states that:
> 
> * the server MUST include a Replay-Nonce header with a fresh nonce,
> * the server SHOULD use status 200 OK for the HEAD request,
> * the server MUST also handle GET on the same resource and may return
>    204 No Content with an empty body.
> 
> The reporter observed the following error message:
> 
>    *ACME server responded with unexpected status code: 204*
> 
> and mentioned that the issue did not appear with PVE 9 [1]. Looking at
> PVE’s Perl ACME client [3], it uses a GET request instead of HEAD and
> accepts any 2xx success code when retrieving the nonce. This difference
> in behavior does not affect functionality but is worth noting for
> consistency across implementations.
> 
> ## Approach
> 
> To support ACME providers which return 204 No Content, the Rust ACME
> clients in proxmox-backup and proxmox need to treat both 200 OK and 204
> No Content as valid responses for the nonce request, as long as a
> Replay-Nonce header is present.
> 
> This series changes the expected field of the internal Request type
> from a single u16 to a list of allowed status codes
> (e.g. &'static [u16]), so one request can explicitly accept multiple
> success codes.
> 
> To avoid fixing the issue twice (once in PBS’ own ACME client and once
> in the shared Rust client), this series first refactors PBS to use the
> shared AcmeClient from proxmox-acme / proxmox-acme-api, similar to PDM,
> and then applies the bug fix in that shared implementation so that all
> consumers benefit from the more tolerant behavior.
> 
> ## Testing
> 
> *Testing the refactor*
> 
> To test the refactor, I
> (1) installed latest stable PBS on a VM
> (2) created .deb package from latest PBS (master), containing the
>   refactor
> (3) installed created .deb package
> (4) installed Pebble from Let's Encrypt [5] on the same VM
> (5) created an ACME account and ordered the new certificate for the
>   host domain.
> 
> Steps to reproduce:
> 
> (1) install latest stable PBS on a VM, create .deb package from latest
>   PBS (master) containing the refactor, install created .deb package
> (2) install Pebble from Let's Encrypt [5] on the same VM:
> 
>      cd
>      apt update
>      apt install -y golang git
>      git clone https://github.com/letsencrypt/pebble
>      cd pebble
>      go build ./cmd/pebble
> 
> then, download and trust the Pebble cert:
> 
>      wget https://raw.githubusercontent.com/letsencrypt/pebble/main/test/certs/pebble.minica.pem
>      cp pebble.minica.pem /usr/local/share/ca-certificates/pebble.minica.crt
>      update-ca-certificates
> 
> We want Pebble to perform HTTP-01 validation against port 80, because
> PBS’s standalone plugin will bind port 80. Set httpPort to 80.
> 
>      nano ./test/config/pebble-config.json
> 
> Start the Pebble server in the background:
> 
>      ./pebble -config ./test/config/pebble-config.json &
> 
> Create a Pebble ACME account:
> 
>      proxmox-backup-manager acme account register default admin at example.com --directory 'https://127.0.0.1:14000/dir'
> 
> To verify persistence of the account I checked
> 
>      ls /etc/proxmox-backup/acme/accounts
> 
> Verified if update-account works
> 
>      proxmox-backup-manager acme account update default --contact "a at example.com,b at example.com"
>      proxmox-backup-manager acme account info default
> 
> In the PBS GUI, you can create a new domain. You can use your host
> domain name (see /etc/hosts). Select the created account and order the
> certificate.
> 
> After a page reload, you might need to accept the new certificate in the browser.
> In the PBS dashboard, you should see the new Pebble certificate.
> 
> *Note: on reboot, the created Pebble ACME account will be gone and you
> will need to create a new one. Pebble does not persist account info.
> In that case remove the previously created account in
> /etc/proxmox-backup/acme/accounts.
> 
> *Testing the newNonce fix*
> 
> To prove the ACME newNonce fix, I put nginx in front of Pebble, to
> intercept the newNonce request in order to return 204 No Content
> instead of 200 OK, all other requests are unchanged and forwarded to
> Pebble. Requires trusting the nginx CAs via
> /usr/local/share/ca-certificates + update-ca-certificates on the VM.
> 
> Then I ran following command against nginx:
> 
> proxmox-backup-manager acme account register proxytest root at backup.local --directory 'https://nginx-address/dir
> 
> The account could be created successfully. When adjusting the nginx
> configuration to return any other non-expected success status code,
> PBS rejects as expected.
> 
> ## Patch summary
> 
> 0001 – acme: include proxmox-acme-api dependency
>   Adds proxmox-acme-api as a new dependency for the ACME code. This
>   prepares the codebase to use the shared ACME API instead of local
>   implementations.
> 
> 0002 – acme: drop local AcmeClient
>   Removes the local AcmeClient implementation. Minimal changes
>   required to support the removal.
> 
> 0003 – acme: change API impls to use proxmox-acme-api handler
>   Updates existing ACME API implementations to use the handlers provided
>   by proxmox-acme-api.
> 
> 0004 – acme: certificate ordering through proxmox-acme-api
>   Perform certificate ordering through proxmox-acme-api instead of local
>   logic.
> 
> 0005 – acme api: add helper to load client for an account
>   Introduces a helper function to load an ACME client instance for a
>   given account. Required for the PBS refactor.
> 
> 0006 – acme: reduce visibility of Request type
>   Restricts the visibility of the internal Request type.
> 
> 0007 – acme: introduce http_status module
>   Adds a dedicated http_status module for handling common HTTP status
>   codes.
> 
> 0008 – fix #6939: acme: support servers returning 204 for nonce
>   Adjusts nonce handling to support ACME servers that return HTTP 204
>   (No Content) for new-nonce requests.
> 
> Thanks for considering this patch series, I look forward to your
> feedback.
> 
> Best,
> Samuel Rufinatscha
> 
> ## Changelog
> 
> Changes from v3 to v4:
> 
> Removed: [PATCH proxmox-backup v3 1/1].
> 
> Added:
> 
> [PATCH proxmox-backup v4 1/4] acme: include proxmox-acme-api dependency
>      * New: add proxmox-acme-api as a dependency and initialize it in
>        PBS so PBS can use the shared ACME API instead.
> 
> [PATCH proxmox-backup v4 2/4] acme: drop local AcmeClient
>      * New: remove the PBS-local AcmeClient implementation and switch PBS
>        over to the shared proxmox-acme async client.
> 
> [PATCH proxmox-backup v4 3/4] acme: change API impls to use proxmox-acme-api
> handlers
>      * New: rework PBS’ ACME API endpoints to delegate to
>        proxmox-acme-api handlers instead of duplicating logic locally.
> 
> [PATCH proxmox-backup v4 4/4] acme: certificate ordering through
> proxmox-acme-api
>      * New: move PBS’ ACME certificate ordering logic over to
>        proxmox-acme-api, keeping only certificate installation/reload in
>        PBS.
> 
> [PATCH proxmox v4 1/4] acme-api: add helper to load client for an account
>      * New: add a load_client_with_account helper in proxmox-acme-api so
>        PBS (and others) can construct an AcmeClient for a configured account
>        without duplicating boilerplate.
> 
> [PATCH proxmox v4 2/4] acme: reduce visibility of Request type
>      * New: hide the low-level Request type and its fields behind
>        constructors / reduced visibility so changes to “expected” no longer
>        affect the public API as they did in v3.
> 
> [PATCH proxmox v4 3/4] acme: introduce http_status module
>      * New: split out the HTTP status constants into an internal
>        http_status module as a separate preparatory cleanup before the bug
>        fix, instead of doing this inline like in v3.
> 
> Changed:
> 
> [PATCH proxmox v3 1/1] -> [PATCH proxmox v4 4/4]
> fix #6939: acme: support server returning 204 for nonce requests
>      * Rebased on top of the refactor: keep the same behavioural fix as in v3
>        (accept 204 for newNonce with Replay-Nonce present), but implement it
>        on top of the http_status module that is part of the refactor.
> 
> Changes from v2 to v3:
> 
> [PATCH proxmox v3 1/1] fix #6939: support providers returning 204 for nonce
> requests
>      * Rename `http_success` module to `http_status`
> 
> [PATCH proxmox-backup v3 1/1] acme: accept HTTP 204 from newNonce endpoint
>      * Replace `http_success` usage
> 
> Changes from v1 to v2:
> 
> [PATCH proxmox v2 1/1] fix #6939: support providers returning 204 for nonce
> requests
>      * Introduced `http_success` module to contain the http success codes
>      * Replaced `Vec<u16>` with `&[u16]` for expected codes to avoid
>        allocations.
>      * Clarified the PVEs Perl ACME client behaviour in the commit message.
> 
> [PATCH proxmox-backup v2 1/1] acme: accept HTTP 204 from newNonce endpoint
>      * Integrated the `http_success` module, replacing `Vec<u16>` with `&[u16]`
>      * Clarified the PVEs Perl ACME client behaviour in the commit message.
> 
> [1] Bugzilla report #6939:
> [https://bugzilla.proxmox.com/show_bug.cgi?id=6939](https://bugzilla.proxmox.com/show_bug.cgi?id=6939)
> [2] RFC 8555 (ACME):
> [https://datatracker.ietf.org/doc/html/rfc8555/#section-7.2](https://datatracker.ietf.org/doc/html/rfc8555/#section-7.2)
> [3] PVE’s Perl ACME client (allow 2xx codes for nonce requests):
> [https://git.proxmox.com/?p=proxmox-acme.git;a=blob;f=src/PVE/ACME.pm;h=f1e9bb7d316e3cea1e376c610b0479119217aecc;hb=HEAD#l597](https://git.proxmox.com/?p=proxmox-acme.git;a=blob;f=src/PVE/ACME.pm;h=f1e9bb7d316e3cea1e376c610b0479119217aecc;hb=HEAD#l597)
> [4] Pebble ACME server:
> [https://github.com/letsencrypt/pebble](https://github.com/letsencrypt/pebble)
> [5] Pebble ACME server (perform GET request:
> [https://git.proxmox.com/?p=proxmox-acme.git;a=blob;f=src/PVE/ACME.pm;h=f1e9bb7d316e3cea1e376c610b0479119217aecc;hb=HEAD#l219](https://git.proxmox.com/?p=proxmox-acme.git;a=blob;f=src/PVE/ACME.pm;h=f1e9bb7d316e3cea1e376c610b0479119217aecc;hb=HEAD#l219)
> 
> proxmox-backup:
> 
> Samuel Rufinatscha (4):
>    acme: include proxmox-acme-api dependency
>    acme: drop local AcmeClient
>    acme: change API impls to use proxmox-acme-api handlers
>    acme: certificate ordering through proxmox-acme-api
> 
>   Cargo.toml                             |   3 +
>   src/acme/client.rs                     | 691 -------------------------
>   src/acme/mod.rs                        |   5 -
>   src/acme/plugin.rs                     | 336 ------------
>   src/api2/config/acme.rs                | 407 ++-------------
>   src/api2/node/certificates.rs          | 240 ++-------
>   src/api2/types/acme.rs                 |  98 ----
>   src/api2/types/mod.rs                  |   3 -
>   src/bin/proxmox-backup-api.rs          |   2 +
>   src/bin/proxmox-backup-manager.rs      |   2 +
>   src/bin/proxmox-backup-proxy.rs        |   1 +
>   src/bin/proxmox_backup_manager/acme.rs |  21 +-
>   src/config/acme/mod.rs                 |  51 +-
>   src/config/acme/plugin.rs              |  99 +---
>   src/config/node.rs                     |  29 +-
>   src/lib.rs                             |   2 -
>   16 files changed, 103 insertions(+), 1887 deletions(-)
>   delete mode 100644 src/acme/client.rs
>   delete mode 100644 src/acme/mod.rs
>   delete mode 100644 src/acme/plugin.rs
>   delete mode 100644 src/api2/types/acme.rs
> 
> 
> proxmox:
> 
> Samuel Rufinatscha (4):
>    acme-api: add helper to load client for an account
>    acme: reduce visibility of Request type
>    acme: introduce http_status module
>    fix #6939: acme: support servers returning 204 for nonce requests
> 
>   proxmox-acme-api/src/account_api_impl.rs |  5 +++++
>   proxmox-acme-api/src/lib.rs              |  3 ++-
>   proxmox-acme/src/account.rs              | 27 +++++++++++++-----------
>   proxmox-acme/src/async_client.rs         |  8 +++----
>   proxmox-acme/src/authorization.rs        |  2 +-
>   proxmox-acme/src/client.rs               |  8 +++----
>   proxmox-acme/src/lib.rs                  |  6 ++----
>   proxmox-acme/src/order.rs                |  2 +-
>   proxmox-acme/src/request.rs              | 25 +++++++++++++++-------
>   9 files changed, 51 insertions(+), 35 deletions(-)
> 
> 
> Summary over all repositories:
>    25 files changed, 154 insertions(+), 1922 deletions(-)
> 





More information about the pbs-devel mailing list