Issue real Let's Encrypt & ZeroSSL wildcard certificates inside WHM/cPanel over the Cloudflare DNS-01 challenge — a dependency-free, pure-PHP ACME client that works even on networks where the CA is blocked.
A WHM and cPanel plugin that issues real SSL/TLS certificates — including
wildcards — straight from your control panel, using the Cloudflare DNS-01
challenge and a scoped Cloudflare API token. No acme.sh, no certbot, no
Composer: just a small, hand-rolled ACME v2 (RFC 8555) client written in pure
PHP on top of the openssl and curl extensions that cPanel already ships.
cPanel's AutoSSL is HTTP-validated and can't issue wildcards. The usual
workaround is gluing acme.sh onto the server with cron hacks. I wanted
something that lived inside WHM, spoke ACME natively, and — critically — kept
working on restricted networks. On servers behind a VPN or tunnel (where the
Let's Encrypt and Cloudflare endpoints are blocked on the default route), every
outbound API call can be bound to a specific egress interface, so issuance
succeeds where a normal client just times out.
DNS-01 over Cloudflare. For each domain it publishes the_acme-challenge TXT record through the Cloudflare API, waits for propagation,
answers the challenge, then cleans the records up — even if issuance fails
partway.
Wildcards and SANs. Single-domain, multi-domain (SAN), and *.example.com
wildcards, with selectable RSA-2048 or ECDSA P-256 keys.
Certificate authorities. Let's Encrypt (production + staging) and ZeroSSL
via External Account Binding.
One-click install. WHM installs through whmapi1; cPanel installs through
UAPI for the running user. Raw fullchain.pem / key.pem downloads too.
Token reuse. Shares the scoped token from its companion plugin,
WHM Cloudflare DNS, so you configure Cloudflare
access once.
The interesting part is the ACME client. It's deliberately small: an RSA-2048
account key, RS256 signatures (a single openssl_sign() call — no
DER→raw conversion, which is the most error-prone part of a hand-written ECDSA
ACME client), nonce handling with one automatic retry on badNonce, and
sub-problem surfacing so per-identifier failures are actually readable.
Two bugs from real issuance runs made it into v1.0.1 and are worth remembering:
Apex + wildcard share one TXT name. example.com and *.example.com are
separate ACME authorizations that both validate against_acme-challenge.example.com, with two different values that must coexist.
A naive "delete records by name, then write" loop deletes the sibling value it
just wrote. Clean once per name, before publishing anything.
whmapi1 installssl is fussy. Its parameters are crt / key / cab
(not cert / cabundle), and it URI-unescapes every value — so a raw
multi-line PEM on the command line comes out as "Invalid base64." The fix:
stage each PEM in a private 0600 temp file and pass it with the @<file>
value form.
Pure PHP (cPanel's bundled runtime), the Cloudflare API, and the ACME v2
protocol. MIT licensed.