Some shared hosting packages with cPanel don't offer AutoSSL , or only in higher-priced plans. As a result, you can't issue a free Let's Encrypt certificate via the cPanel interface, and all domains are stuck with a self-signed certificate. The browser displays the page as "not secure." The solution: obtain the certificate yourself using acme.sh and install it via the cPanel UAPI – automatically renewing, completely without AutoSSL.
HTTPS has long been mandatory. It's all the more frustrating, then, when your own hosting package doesn't offer a convenient way to obtain a free certificate. This happens more often than you might think, for example with inexpensive entry-level packages or after a plan change where a certificate is suddenly no longer included. However, this gap can be elegantly and permanently closed with just a few lines of code in the shell – the complete process is described below.
1. Log in via SSH
ssh -p <port> <user>@example.com
2. Install acme.sh
curl https://get.acme.sh | sh -s email=me@example.com
source ~/.bashrc
3. Set Let's Encrypt as the CA
acme.sh --set-default-ca --server letsencrypt
4. Issue certificate
acme.sh --issue -d example.com -d www.example.com -w ~/public_html
5. Install into cPanel
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
6. Check
uapi SSL installed_hosts
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -issuer -dates
The hook writes the certificate to the appropriate virtual host via UAPI. The deployment settings are saved – from now on, cron will automatically renew and install everything before expiration. The issuer is "Let's Encrypt," and the expiration date is approximately 90 days in the future. If the old, self-signed certificate still appears, a hard reload in the browser usually helps – the previous certificate may be temporarily cached.
Some hosts run their own cPanel hook. install_ssl and responds with something like adminbin Cpanel/hooks2/...: exit 255. acme.sh still reports "successfully deployed" – and that's correct. In this case, the hook fails due to a subsequent step (such as an internal notify or sync job by the hosting provider), not the actual installation.
For domains with umlauts, acme.sh stores the certificate internally in the Punycode form (xn--…), while the hook's auto-matcher compares the Unicode form. Result: "deployed to 0 of 0 sites" – nothing is installed. The insidious thing is that acme.sh also reports "Success" here, so the error is easily overlooked. Solution: Work directly with the Punycode domain and disable auto-matching.:
python3 -c "import sys;print(sys.argv[1].encode('idna').decode())" hallöle.de
acme.sh --issue -d xn--hallle-zxa.de -d www.xn--hallle-zxa.de -w ~/public_html
export DEPLOY_CPANEL_AUTO_ENABLED='false'
acme.sh --deploy -d xn--hallle-zxa.de --deploy-hook cpanel_uapi
With SSH access, you don't need AutoSSL: acme.sh issues the certificate, which cpanel_uapiThe -Hook installs it, and the included cron job keeps it automatically updated. Once set up, the free HTTPS service runs continuously on its own. Those who invest the initial effort save themselves every manual renewal in the future – and can extend the same solution to any additional domain in the same account with a single command.