What's Changed
Added
UCM_TRUSTED_PROXIESaccepts CIDR networks, not only exact IP addresses. Behind an ingress controller or another proxy whose source address is not fixed, every allowed peer had to be listed individually; an entry such as10.42.0.0/16now trusts any peer inside that range, and a peer that arrives as an IPv4-mapped IPv6 address (::ffff:10.42.0.5, as a dual-stack listener reports IPv4 clients) is matched against IPv4 entries and networks as well. An entry that is neither a valid address nor a valid network is ignored with a warning in the log instead of being kept as a literal string that can never match, so a typo cannot silently narrow the trusted set. The Helm chart gainedproxy.behindProxy(setsUCM_BEHIND_PROXY) andproxy.trustedProxies(setsUCM_TRUSTED_PROXIES), neither of which it templated before, so a chart deployment behind an Ingress can honourX-Forwarded-*and proxy-injected client-certificate headers without a hand-writtenextraEnventry (discussion #337, requested by @szechyjs, contributed by @Hemsby)- The certificate template editor can build a Windows smartcard logon template. The Extended Key Usage list gained
msSmartcardLogin(Microsoft Smartcard Logon, 1.3.6.1.4.1.311.20.2.2) and the SAN types gainedupn, both of which the template API and the issuance path already accepted but which the editor's fixed checkbox lists did not offer, so a reusable Smartcard Logon profile could not be clicked together even though the Issue Certificate form could produce one. A built-in Smartcard Logon system template ships alongside the others (clientAuth+msSmartcardLogin, UPN SAN). The SAN type checkboxes now use the same localized labels as the issue form rather than a bare upper-cased token (discussion #336, requested by @szechyjs, contributed by @Hemsby)
Fixed
- With
UCM_BEHIND_PROXY=1,X-Forwarded-*andX-Real-IPheaders are now honoured only when the request's immediate peer is inUCM_TRUSTED_PROXIES; from any other peer they are dropped before the proxy handling runs, with a warning in the log naming the peer. Previously enabling proxy support trusted those headers from every peer, so a client able to reach the backend directly, such as another pod in the same cluster, could choose its apparent IP, rotate past the per-IP rate limits and pollute the audit trail. Upgrade note: a reverse proxy running on another host must be listed inUCM_TRUSTED_PROXIES(IP or CIDR network), as the documentation already required; unset, the variable trusts loopback only, and a proxy that is not listed now sees its own address logged and rate-limited instead of its clients' (discussion #337, follow-up to #339) - Helm chart:
appVersionnow tracks the release the chart ships with. It had stayed at 2.170 while the image tag defaults toappVersion, so a chart install without an explicitimage.tagdeployed that old version - The public port of the admin and protocol URLs can now differ from the port UCM listens on. Settings > General accepted
http://pki.example.com:80as Protocol Base URL but dropped the:80as a default port when saving, then applied the HTTP protocol port (8080 by default, and the field refuses a port below 1024) to every CDP, OCSP and AIA URL it advertised, so a reverse proxy publishing those endpoints on port 80 could not be described; the same happened tohttps://admin.example.com:443and the HTTPS listen port for the admin canonical URL. An explicitly typed port is now kept as typed and honoured in the advertised URLs, while a URL without a port keeps taking the listen port as before (discussion #337, reported by @szechyjs) - ACME: a reused authorization now records the challenge that was performed, at the time it was performed. When an order reused a valid authorization of the same account, the built-in server created the new authorization with all three challenge types (
dns-01,http-01,tls-alpn-01) marked valid and dated to the reuse, so a renewal appeared validated by methods that were never attempted, on an instance with no DNS provider. The reused authorization now carries only the challenge(s) the client completed, with their originalvalidatedtimestamp; its expiry stays that of the original validation, since reuse does not extend a proof of control. The Orders tab of an ACME account derived an order's method from the first challenge row, which is alwaysdns-01, and so reported DNS-01 for the renewal and for a rejected order alike; it now names the validated challenge(s), the challenge the client attempted when validation failed, and N/A for an order whose challenges were never answered; on a multi-identifier order the choice is made per identifier and merged, so a name proved by dns-01 next to one that failed http-01 lists both. Authorizations reused before this fix keep the three validated rows they were given and are listed with all three methods (#338, reported by @JoseGoncalves)
📜 Recent release history (last 2 versions)
[2.223] - 2026-09-06
Fixed
- Automatic updates on the rc channel refused every release candidate with "Release checksum does not cover this package". The checksum file published with a release candidate names the package as built (
ucm_2.223~rc1_all.deb) while GitHub publishes the asset with a dot (ucm_2.223.rc1_all.deb), and the updater compared the two names literally. The updater now matches the names with that transform applied, and the release build writes the published asset name into the checksum file so earlier versions can update to a release candidate too - Startup no longer depends on the HTTPS certificate binding being readable. The one-time backfill that binds a certificate applied before bindings existed runs under its own application context and treats a database error while reading the binding as "no binding" with a warning, instead of aborting application start; a failed read on the first boot after an update, with the database not yet available, could otherwise keep the service down
- Certificate policy Rules are now enforced at issuance. The policy editor's Allowed Key Types and Max SANs were stored but never checked, and Max Validity only applied to requests routed through approval, so a policy shown as active could be ignored entirely. On the issue form and when an approved request is issued, a request whose key type is not in the policy's allowed list or which carries more DNS names than its maximum is refused with the rule named, and the validity is capped by the policy. Rules apply to every role, including administrators, who keep bypassing only the approval workflow; the DNS pattern keeps its role of scoping which requests a policy covers. Requests over ACME, SCEP, EST and WSTEP are not covered by policies, as before (#335, reported by @Hemsby)
- Revoking a certificate from the web UI now asks for the revocation reason. The confirm dialog had no reason field, so every manual revocation was recorded and published on the CRL as
unspecified, with no way to correct it afterwards since revocation is one-way; only automated paths such as ACME renewal recorded a reason. The revoke dialog (certificates page, detail windows, user portal and bulk operations) now offers the RFC 5280 reason codes with a short explanation of each, defaulting to unspecified, and the certificate details show the chosen reason by name. The API rejects an unknownreasonwith 400 instead of storing it, accepts the snake_case spellings older clients used, and the CRL builder now maps the RFC spellingcACompromisethat ACME revocations store (#334, reported by @JoseGoncalves)
[2.222] - 2026-09-06
Added
- PKCS#12 exports gained a compatibility mode. UCM's PKCS#12 archives use the OpenSSL 3 profile (PBES2 with AES-256-CBC, PBKDF2-SHA256 and an HMAC-SHA256 integrity check), which Android 15 and earlier, macOS 14 and earlier, Windows Server 2016 and earlier and Java before 8u301 / 11.0.1 cannot read and report as a wrong password. A Compatibility mode checkbox on the export dialogs (certificates, CAs, the user portal, mTLS downloads and key recovery) switches that archive to the 3DES/SHA-1 profile these importers accept, the same LegacyDES profile cert-manager and go-pkcs12 offer. The API takes it as
legacy: truealongsidepassword. AES-256 stays the default and the checkbox is a per-export choice, since the legacy profile protects the archive less well (#331, requested by @MakosHD)
Fixed
- The certificate template API no longer accepts
ED25519as a key type. It was allowed at save time but the issuance path cannot generate an Edwards key, so every certificate request from such a template failed with a 400.POSTandPUT /api/v2/templatesnow reject it up front, and template import skips anED25519entry with a reason string instead of storing a template that can never issue. An existingED25519template must be switched to an RSA or EC key type before it can be edited again (#321 follow-up, contributed by @Hemsby)
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.224
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.224
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.224Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.224/ucm_2.224_all.deb
sudo dpkg -i ucm_2.224_all.deb
sudo apt-get install -fFedora/RHEL
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.224/ucm-2.224-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.224-1.fc43.noarch.rpmSilent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.224_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!