What's Changed
Changed
- SSO role mapping multi-match resolution is now formalized — when several of a user's external groups match mapping entries, the highest-privilege role wins (admin > operator > auditor > viewer). Previously the result silently depended on the storage order of the mapping entries. Documented in the role mapping help text. (#221)
Security
- ACME proxy no longer echoes upstream failure details — directory, nonce, order, authorization and challenge errors now return a generic message to the ACME client, with the diagnostic kept in the server log. A URL slug matching no enabled proxy endpoint returns 404 instead of a 500.
- ACME proxy finalize fails closed — an order bound to an owner is refused (403) when no requester identity can be derived from the verified JWS, instead of proceeding unbound.
Fixed
- SSO mapping editor row shuffling — editing the external-group name of any row no longer reorders the list on every keystroke, and transiently typing a name that collides with another entry no longer destroys that entry. Rows now keep a stable identity while editing. (#222)
- mTLS certificate PKCS12 export with encryption at rest enabled — the export read the stored private key without decrypting it, so it failed whenever key encryption was active. An unusable stored key now returns a clear error instead of a generic server error.
- dns-01 challenge TXT name for wildcard domains — the wildcard prefix strip removed any leading run of
*and.characters, producing a wrong_acme-challengeowner name for domains whose label started with a dot-adjacent wildcard form. - Certificate requests with an invalid CSR signature are now rejected (400) instead of being accepted for issuance.
- Revocation with a future
invalidity_dateis now rejected (400) — RFC 5280 §5.3.2 defines it as a past compromise time (5 minutes of clock skew allowed). - Removing a certificate hold no longer leaves the certificate mis-staged when the delta CRL
removeFromCRLentry cannot be written; the failure is reported instead of silently continuing, and a failed delta emission no longer aborts the unhold. - EC curve names containing hyphens (
ECDSA-P384,NIST P-521) are now accepted wherever a curve can be specified.
📜 Recent release history (last 2 versions)
[2.197] - 2026-07-19
Added
- Named protocol URLs can be enabled on existing CAs — the opt-in previously available only at CA creation can now be enabled afterwards from the CRL & OCSP page (or
PATCH /api/v2/cas/<id>withnamedUrls). Auto-generated CDP/AIA URLs are rewritten to the slug form and newly issued certificates embed it; already-issued certificates keep their refid URLs, which continue to resolve. Enabling remains irreversible. (#207)
Fixed
- ACME proxy
Link: rel="up"header — the authorization link returned on challenge responses doubled the/acme/proxypath segment, sending clients that re-poll their authorization (Traefik/lego) to a nonexistent URL. (#217) - ACME proxy certificate download latency — DNS-01 TXT cleanup now runs in a background thread instead of blocking the certificate response on live DNS-provider API calls. (#218)
- ACME proxy order lookup on certificate download — the upstream certificate URL is now persisted on the proxy order when it first appears (finalize or order poll), so the download resolves its order with one indexed query instead of a live upstream round-trip per accumulated pending order. (#219)
- ACME proxy no longer forwards the upstream
Linkheader — itsrel="alternate"entries point directly at the real CA and cannot be authenticated by proxy clients; the preferred chain is already resolved server-side and served in the body. (#220) - CRL & OCSP details panel layout — the "Full CRL Schedule" and "Delta CRL" blocks now render as framed sections, consistent with the rest of the panel.
[2.196] - 2026-07-18
Added
- ACME loopback upstream opt-in — a new toggle (Let's Encrypt settings /
acme.client.allow_loopback_upstream, default off) allows the ACME client and proxy to reach an upstream CA on a loopback address (a colocated Pebble/step-ca on 127.0.0.1). Cloud-metadata targets remain blocked unconditionally.
Fixed
- Security-key (WebAuthn) login restored — after the per-user credential count was removed from
/auth/methods(username-enumeration hardening), the login page stopped offering the security-key option and auto-attempt. The UI no longer depends on that count: it auto-attempts based on the device's saved method and always offers the security-key button when the browser supports it. - WebAuthn username-enumeration oracle closed —
POST /auth/login/webauthn/startreturned a challenge only for users with a registered key (200) versus a 401 otherwise, and/verifyused distinguishable errors. Both now return identical, well-formed responses for unknown, credential-less, and real users (a deterministic per-username decoy credential), removing the account-existence oracle. - No default
serverAuthEKU on issuing CAs — intermediate CAs created via the API without an explicitextendedKeyUsagewere given aserverAuthEKU, which (via EKU chaining) invalidated clientAuth / emailProtection / OCSPSigning leafs issued beneath them, including delegated OCSP responders. Issuing CAs now have no EKU by default; constrain them explicitly viaextendedKeyUsage. - ACME proxy serves the preferred certificate chain — the per-account preferred chain was computed and stored but the upstream default chain was returned to the client; the selected chain is now the one delivered.
- ACME proxy order ownership binding — new-order and finalize now bind an order to the account resolved from the request
kid, so a different account can no longer finalize someone else's order. The previous binding only took effect for JWK-signed requests, which RFC 8555 new-order/finalize never are. - ACME DNS-01 self-check is advisory — a local resolver that cannot see the challenge TXT record (split-horizon or filtered egress DNS) no longer aborts renewal or proxy issuance before the challenge is submitted; the CA remains the authority. Set the propagation timeout to 0 to skip the pre-check entirely.
- SAN URI validation — the issuance/CSR forms now accept authority-less URIs (
urn:,mailto:,did:), matching what the API already allowed. - Account page PKCS#12 labels — two missing translation keys rendered as raw identifiers on the mTLS certificate export controls.
- Signed CSR history panel — clicking "View certificate" no longer throws a runtime error.
- ACME auto-renewal toggle persistence — the Let's Encrypt auto-renewal switch sent a field the API did not read, so the setting never saved; it now uses
renewal_enabled.
Translations
- Completed the ACME "verbose logs" label and description across all locales.
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.198
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.198
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.198Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.198/ucm_2.198_all.deb
sudo dpkg -i ucm_2.198_all.deb
sudo apt-get install -fFedora/RHEL
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.198/ucm-2.198-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.198-1.fc43.noarch.rpmSilent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.198_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!
Documentation
- Installation Guide
- API Documentation