📜 Recent release history (last 2 versions)
[2.247] - 2026-10-30
Added
-
HSM: a connection test records what a PKCS#11 module reports (library, manufacturer, library and firmware versions), shown on the provider's page. In FIPS mode a new SoftHSM provider is refused, since SoftHSM is not a validated module;
UCM_FIPS_ALLOW_SOFTHSM=1allows one for tests. -
Users: an administrator lists another user's API keys in their details and revokes a leaked or unused one, which stops working at once; a revoked or expired key can then be deleted. Each action is audited.
-
CAs: a CA can carry cross-certificates (same subject and key, another issuer) beside its own certificate: attach one, serve it in the default chain, export it, or cross-sign a held CA's key with another from the CA details; revoking one at its issuer is done through the API. Its expiry raises the usual alerts and its revocation follows the approval policies (#400).
-
Chains: exports, deployments, TLS, PKCS#12, ACME, WSTEP and TSA use one chain builder that follows the served cross-certificate;
chain_variant(auto,primary,cross:<id>) picks another chain on CA and certificate exports and on a deploy binding, and EST/cacertsadds the served cross-certificates (#400). -
ACME: the server offers the other chains of an order as RFC 8555 §7.4.2 alternates for
certbot --preferred-chain. AIA serves/ca/{ref}.p7cand/ca/{ref}/cross/{id}.cer, and.cerand.pemfollow the served cross-certificate (#400). -
Import: a certificate that re-certifies a held CA's key is attached as a cross-certificate on a self-signed root, and on an intermediate after the Attach as cross certificate choice (
cross_mode). Smart Import attaches one next to a held root and reportscross_certificate_attached(#400). -
CAs: a CA's details list the certificates and deploy bindings that still chain to it, directly or through a cross-certificate, to show when an old root can be retired;
GET /api/v2/cas/{id}/chain-usage(#400). -
CAs: the chain repair bar lists records damaged before cross-certificates were modelled, with Convert to cross-certificate and Restore as primary; nothing is changed without a click (#400).
Fixed
- Import: a CA certificate re-issued by another CA over the same key overwrote the self-signed root and re-parented it. An intermediate in that case now answers 409
cross_certificate_detected, and so does installing it after Renew via CSR, with Attach as cross certificate and Replace offered; a root rollover under the same issuer name still replaces the certificate (#400). - Smart Import: a cross-certificate in a bundle replaced the self-signed root or was dropped under a generic duplicate warning depending on file order. The root is kept and the result reports
cross_certificate_attachedorcross_certificate_skipped(#400). - CAs: the hourly chain repair deleted a self-signed root when a second record shared its key. It now merges only identical certificates and reports the rest (#400).
- ACME client:
preferred_chainmatched the subject or issuer of the last certificate and preferred an alternate, so a cross-certificate could win a request for the other root. It now follows certbot: the issuer CN of the topmost certificate, default chain first (#400). - OCSP, mTLS and renewal resolved a CA through whichever record shared its key, so a cross-certificate could stand in for the self-signed root. They now prefer the self-signed record (#400).
- DEB and RPM: an upgrade stopped UCM while it rebuilt the Python environment, about five minutes with
UCM_FIPS_BUILD=1. The new environment is now built next to the running one, and the service stops only to switch to it. - UI: 17 badges asked for a size that does not exist and rendered without padding, and a few for a colour that does not exist (About, SSO tests, Smart Import, failed webhook deliveries, ACME order status). They now use defined ones, and a test refuses an unknown size or colour.
- UI: a stat card clicked to filter a list (Certificates, SSH and user certificates, Policies, Discovery, Approvals) showed no active state on desktop, so nothing said which filters were on. Active cards are outlined again.
- CSRs: the Pending and History tabs showed at most 20 requests and every count stopped at 20; both lists now page, search and sort on the server, and History also searches by signing CA (#424, thanks @clinde04).
- ACME client: an order for a domain and its wildcard kept only one of its two authorizations, which both name the base domain, so it never completed. Each now gets its own TXT value and challenge.
- ACME DNS-01: the Route 53, Azure, Gandi, deSEC, PowerDNS and NS1 providers replaced the TXT record with the new value, or refused it, so a domain and its wildcard could not both validate; they now add it to the existing values (Route 53 now needs
route53:ListResourceRecordSets, which cleanup already used). DuckDNS, Hurricane Electric and the FreeDNS provider still keep one TXT value per name. - ACME DNS-01: the Hetzner provider added a TXT value to an existing record with a PATCH the Hetzner Cloud API does not offer, so a domain with its wildcard, or a retry after a leftover value, failed. It now uses
add_recordsand keeps the record's TTL. - CAs: a root imported without its private key showed as active but was silently left out of every CA picker. It is now marked No private key with an Import private key action, and the pickers (issuing, signing, cross-signing, ACME, SCEP, EST, TSA, Windows enrollment, mTLS enrollment) say how many CAs they leave out; the API refuses a CA that cannot sign as SCEP default (an HSM-backed one too, which SCEP cannot use) or EST label, the default SCEP CA can be cleared and can no longer be deleted while set, and a policy can target any CA again (#426).
[2.246] - 2026-10-27
Added
- ACME proxy: optional DNS UPDATE (RFC 2136) listener, off by default, so standard rfc2136 solvers can answer DNS-01 through the proxy with per-account TSIG keys (#416).
Fixed
- PostgreSQL: the web worker reused the database connections that the main process opened at startup and kept using for scheduled tasks, so the replies of both could interleave (intermittent
PGRES_TUPLES_OKerrors, rows of another query, an unhealthy container). Each worker now opens its own. - The HTTP protocol server (CDP, OCSP, AIA, HTTP-01) stopped after
systemctl reload ucmuntil the next restart, because the new worker could not take the port from the old one; it now waits for the port to be released. - ACME proxy: a challenge response now carries
Link: rel="up"even when the upstream CA omits it (Pebble), which certbot and lego require (#420, reported by @WMP). - ACME: deactivating an authorization (RFC 8555 §7.5.2), as lego does after a failed validation, got
malformedfrom the native server and the proxy. Both now accept it; the proxy deactivates the upstream authorization only when no other pending order shares it (#422, reported by @WMP). - ACME:
newAccountwith an already registered key gotexternalAccountRequired, or a refusal of its used EAB, when EAB is required. The native server and the proxy now return the existing account, as RFC 8555 §7.3.1 requires (reported by @WMP). - UI: the
danger-softandwarning-softbuttons, the red icon tiles, the outline button hover and a few tinted panels (CA details, login, reports) referred to colour tokens that were never defined and rendered without their colour. A test now fails the suite when the source uses an undeclared token.
Documentation
- New guide
docs/integrations/acme-proxy-clients.md: how to use the ACME proxy from hosts without DNS API access, with a no-op DNS-01 step for certbot, acme.sh, lego, cert-manager (stub acme-dns example inexamples/kubernetes/cert-manager/), win-acme and Posh-ACME, and the DNS resolver limits of each client (#416).
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.248-rc1
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.248-rc1
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.248-rc1Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.248-rc1/ucm_2.248.rc1_all.deb
sudo dpkg -i ucm_2.248.rc1_all.deb
sudo apt-get install -fFedora
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.248-rc1/ucm-2.248.rc1-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.248.rc1-1.fc43.noarch.rpmRHEL, AlmaLinux, Rocky Linux 9
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.248-rc1/ucm-el9-2.248.rc1-1.el9.noarch.rpm
sudo dnf install ./ucm-el9-2.248.rc1-1.el9.noarch.rpmFIPS mode (preview)
FIPS mode is a preview: feedback is welcome on #399. Full guide: FIPS Mode.
Docker, any Linux host (amd64, arm64):
docker run -d -p 8443:8443 -e UCM_FIPS=1 \
-v ucm-data:/opt/ucm/data -v ucm-config:/etc/ucm \
--name ucm neyslim/ultimate-ca-manager:2.248-rc1-fipsUbuntu 24.04 with Ubuntu Pro (sudo pro enable fips-updates, then reboot):
sudo apt-get install -y gcc pkg-config python3-dev python3-venv libpq-dev libxml2-dev libxslt1-dev \
zlib1g-dev libssl-dev libxmlsec1-dev libxmlsec1t64-openssl rustc-1.91 cargo-1.91
sudo install -d -m 750 /etc/ucm && echo 'UCM_FIPS_BUILD=1' | sudo tee /etc/ucm/ucm.env
sudo apt install ./ucm_2.248.rc1_all.debRHEL, AlmaLinux, Rocky Linux 9 (sudo fips-mode-setup --enable, then reboot; on RHEL, enable CodeReady Builder instead of CRB):
sudo dnf config-manager --set-enabled crb
sudo dnf install -y python3.12-devel gcc pkgconf-pkg-config libpq-devel libxml2-devel libxslt-devel \
openssl-devel xmlsec1-devel xmlsec1-openssl libtool-ltdl-devel rust cargo
sudo install -d -m 750 /etc/ucm && echo 'UCM_FIPS_BUILD=1' | sudo tee /etc/ucm/ucm.env
sudo dnf install ./ucm-el9-2.248.rc1-1.el9.noarch.rpmThe package builds its crypto libraries against the system OpenSSL (about five minutes), sets UCM_FIPS=1 on a host in FIPS mode and prints a readiness report. Fedora, Debian and other distributions are not supported in FIPS mode: use the Docker image.
Silent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.248.rc1_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!
Documentation
- Installation Guide
- API Documentation