A project can accumulate app, staging, beta and marketing subdomains long before anyone plans certificate management. A wildcard certificate can simplify that work for services within the same trust boundary. Sharing its private key across many servers also increases the impact of a key leak; separate certificates may be preferable for unrelated customers or teams.
This guide covers DNS-01 validation and wildcard certificate automation on cPanel, Plesk and Nginx on a VPS. It separates DNS control, certificate issuance, installation and renewal monitoring. The right workflow depends on who manages authoritative DNS and which account can install the certificate; obtaining a wildcard does not secure the application itself.
Why Wildcard SSL + DNS‑01 Is the Sanity Saver
A certificate for *.example.com covers one label, such as www.example.com or app.example.com. It does not cover example.com or api.app.example.com; request those names separately if needed. Let’s Encrypt requires DNS-01 for wildcard issuance. This demonstrates control of the relevant DNS, not legal ownership of a domain or the security of every application under it.
An automated DNS-01 client creates the required TXT value, waits for DNS publication, completes validation and removes its challenge data. Certificate installation is a separate operation: the renewed certificate must reach every service that uses it. Keep failure alerts and external expiry monitoring even when the scheduled tasks normally succeed.
If you’re newer to SSL in general and want a refresher, see this explanation of what an SSL certificate actually does and how it secures your site. It pairs nicely with this guide.
DNS‑01 Without the Headache: What’s Really Happening
For DNS-01, the ACME client derives a TXT value from the challenge token and account key and publishes it at _acme-challenge.example.com. Let’s Encrypt queries public DNS to check the value. The web service itself may be private, but its challenge DNS must be publicly resolvable. Apex and wildcard validation can require multiple TXT values at the same owner name; do not overwrite another active challenge.
Use a supported DNS plugin or hook to add the record and remove only its own value after validation. Certbot and acme.sh provide integrations for many DNS providers. Verify every authoritative nameserver and set the client’s propagation wait for the provider; an API success response does not prove all nameservers already serve the change.
If TXT records, CNAMEs, and AAAA glue your brain into knots, see this guide to DNS records and the little gotchas. It explains the record types used in this workflow.
cPanel: From “Please Renew” Emails to Fully Automated Wildcards
cPanel’s Let’s Encrypt AutoSSL provider supports wildcards when authoritative DNS is managed locally by cPanel/WHM or its DNS cluster. It cannot perform that wildcard validation through an unsupported external DNS provider. Check the AutoSSL provider and DNS arrangement first. If needed, use a separate DNS-aware ACME client and an installation hook for the existing cPanel virtual hosts.
The external-DNS workflow
Choose a client with an integration for your DNS provider, restrict its credentials, and explicitly request the names you use. After DNS-01 succeeds, install the certificate into the relevant cPanel account and virtual hosts. Scheduled renewal must run as the same client identity, retain access to credentials and repeat deployment. The examples below are alternatives: do not let two clients manage the same certificate files.
Option A: acme.sh with your DNS provider’s API
This Cloudflare example assumes acme.sh is installed for the cPanel account using the upstream installation instructions and that the account has local shell access. Load the token from a protected source; the placeholders below are not real credentials. Scope it to the target zone with required DNS permissions. Explicitly choosing Let’s Encrypt avoids relying on the client’s default CA; a consistent RSA key type avoids mixing RSA and ECC certificate stores.
# Run as the cPanel account that will own this acme.sh installation.
# Install acme.sh using its upstream instructions before this example.
export CF_Token="<restricted_cloudflare_token>"
export CF_Account_ID="<cloudflare_account_id>"
export CF_Zone_ID="<cloudflare_zone_id>"
# First test DNS validation with --staging in a separate test setup.
# Do not deploy a staging certificate to the live website.
# Production issuance:
~/.acme.sh/acme.sh --issue --server letsencrypt --keylength 2048 \
--dns dns_cf \
-d example.com -d '*.example.com'
The cpanel_uapi deploy hook runs the local uapi executable on the cPanel server; it is not a remote API-token client. Run it as the cPanel account, with uapi available in PATH. When an administrator runs the whole acme.sh installation as root instead, the hook supports DEPLOY_CPANEL_USER to select the target account. Keep that choice consistent through issuance and renewal.
# Run in the same cPanel account and acme.sh installation as issuance.
export PATH="/usr/local/cpanel/bin:$PATH"
command -v uapi
~/.acme.sh/acme.sh --deploy -d example.com \
--deploy-hook cpanel_uapi
# Verify the installer-created schedule for this account.
crontab -l
# For an administrator's separate root-run setup only:
# export DEPLOY_CPANEL_USER="cpanel_username"
# Do not invent DEPLOY_CPanel_TOKEN or DEPLOY_CPanel_SERVER settings.
Check the deployment result and confirm the certificate actually served by each required hostname. The hook can identify matching hosted domains, but certificate coverage does not create missing sites or DNS records. If local shell access or UAPI is unavailable, use the host’s supported installation method and arrange a matching renewal-deployment mechanism.
Option B: Certbot with a DNS plugin, then install via cPanel UAPI
Certbot is an EFF ACME client with separately installed DNS plugins. On the cPanel server, install Certbot and the Cloudflare plugin using the instructions for the supported operating system; do not assume a package command works on every AlmaLinux, Rocky Linux or older CentOS release. The following root-run example also requires local UAPI access and an existing cPanel account/domain.
# Certbot and its Cloudflare DNS plugin must already be installed.
# Preserve existing credentials; create and protect the file before editing.
sudo install -d -m 700 /etc/letsencrypt
if ! sudo test -e /etc/letsencrypt/cloudflare.ini; then
sudo install -m 600 /dev/null /etc/letsencrypt/cloudflare.ini
fi
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudoedit /etc/letsencrypt/cloudflare.ini
# File content: dns_cloudflare_api_token = <restricted_token>
# Test this certonly request with --dry-run first; it does not save a cert.
# Then issue the production certificate under an explicit name:
sudo certbot certonly --cert-name example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d example.com -d '*.example.com' \
-m you@example.com --agree-tos --non-interactive
# Install the production certificate into the target existing vhost.
# Replace the account name; inspect status/errors in the JSON response.
sudo /usr/local/cpanel/bin/uapi --output=json --user=cpanel_username \
SSL install_ssl domain=example.com \
cert="$(sudo cat /etc/letsencrypt/live/example.com/cert.pem)" \
key="$(sudo cat /etc/letsencrypt/live/example.com/privkey.pem)" \
cabundle="$(sudo cat /etc/letsencrypt/live/example.com/chain.pem)"
Verify whether your Certbot installation provides a systemd timer or cron task before adding a schedule. Add a deploy hook for the matching certificate and account, and make it fail when UAPI reports an error. The example needs jq installed and uses a quoted heredoc so RENEWED_LINEAGE and file reads happen during renewal, not while the hook is created. Repeat installation for other required cPanel virtual hosts; the example targets only example.com.
sudo install -d -m 700 /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/10-install-cpanel.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
# Restrict this hook to the certificate and account configured below.
[ "${RENEWED_LINEAGE:-}" = "/etc/letsencrypt/live/example.com" ] || exit 0
/usr/local/cpanel/bin/uapi --output=json --user=cpanel_username \
SSL install_ssl domain=example.com \
cert="$(cat "$RENEWED_LINEAGE/cert.pem")" \
key="$(cat "$RENEWED_LINEAGE/privkey.pem")" \
cabundle="$(cat "$RENEWED_LINEAGE/chain.pem")" \
| jq -e '.result.status == 1' >/dev/null
EOF
sudo chmod 700 /etc/letsencrypt/renewal-hooks/deploy/10-install-cpanel.sh
Run a renewal dry-run to check DNS authentication and inspect its result. Deploy hooks do not run by default during that test, so validate installation separately against the production certificate and monitor what the server actually presents. Never replace a live certificate with a staging certificate merely to test automation.
Plesk: Built‑In Wildcard, If DNS Is in the Right Place
Plesk’s Let’s Encrypt workflow supports DNS-01 wildcard certificates. Unattended renewal requires Plesk to update the authoritative challenge records, either through its own DNS service or a supported, working integration. A local zone that is not authoritative and is not synchronized externally is insufficient.
When DNS lives in Plesk
Open the domain’s SSL/TLS Certificates page and select the Let’s Encrypt wildcard option. Include example.com when you also use the apex. With authoritative DNS managed by Plesk, the required TXT update can be automated. After issuance, check certificate assignment in each subdomain’s Hosting Settings; adding a new subdomain may still require selecting the existing wildcard certificate.
When DNS lives elsewhere
For external DNS, manual TXT entry can complete issuance but is not unattended renewal. Use a supported integration and verify its synchronization of challenge records. Plesk specifically documents the DNS Integration for Cloudflare extension with domain synchronization enabled for this purpose. Check current support and renewal behavior for Route53, Google Cloud DNS or another provider individually rather than assuming every DNS extension supports the same workflow.
Check the authoritative nameservers before validation and allow time for provider publication and resolver caching. Lowering a new TXT TTL cannot clear a previously cached negative response. The DNS TTL migration guide explains why preparation and cache expiry matter more than changing a value after a failed lookup.
Renewals and the “invisible” factor
Keep Plesk renewal notifications and external certificate-expiry monitoring active. DNS moves, expired credentials or a broken synchronization can stop renewal even when earlier issuance succeeded. After changing DNS or credentials, verify both validation and the certificate presented by the intended service.
Nginx on a VPS: Certbot or acme.sh, and a Clean Reload
For Nginx on a VPS, choose Certbot or acme.sh according to OS support and the DNS plugin you need. The process identity must be able to read DNS credentials, write the selected certificate files and reload Nginx. A working DNS challenge alone does not establish those permissions.
Certbot example with a DNS plugin (Cloudflare)
For the Certbot Cloudflare plugin, use a token with Zone:DNS:Edit for only the necessary zones. Install Certbot and the plugin for your OS first. Prepare the protected INI file described in the cPanel example, even when using Nginx, and adjust the propagation wait to the DNS provider. The example uses an explicit certificate name so the expected file paths are clear.
# Certbot, its DNS plugin and the protected credentials file are prerequisites.
# Test with --dry-run first, then run production issuance:
sudo certbot certonly --cert-name example.com \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
-d example.com -d '*.example.com' \
-m you@example.com --agree-tos --non-interactive
# Edit the intended Nginx HTTPS server block, preserving the site configuration:
# ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# After saving the configuration:
sudo nginx -t && sudo systemctl reload nginx
Verify Certbot’s timer or cron task for your installation. A deploy hook can test and reload Nginx after successful renewal. Check executable paths on your OS and keep hook failures visible in logs and alerts. A reload is preferable to an unnecessary restart, but is not an unconditional zero-downtime guarantee.
sudo install -d -m 700 /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/20-reload-nginx.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
/usr/sbin/nginx -t
/bin/systemctl reload nginx
EOF
sudo chmod 700 /etc/letsencrypt/renewal-hooks/deploy/20-reload-nginx.sh
acme.sh example with Route 53
The following acme.sh Route53 alternative assumes a root-owned installation because it writes under /etc/nginx and reloads the service. Run every command and the renewal schedule with that same identity, or design a limited privileged deployment step instead. Restrict Route53 record changes to the relevant hosted zone and challenge name; the plugin may also need account-level discovery permissions such as ListHostedZones. Load keys securely, or use a supported IAM role.
# Root-run example: install acme.sh for root using upstream instructions first.
# Run in a root shell; do not mix this with another user's acme.sh state.
# Load these placeholders from a protected source, not a shared command history.
export AWS_ACCESS_KEY_ID="<restricted_access_key_id>"
export AWS_SECRET_ACCESS_KEY="<restricted_secret_key>"
umask 077
~/.acme.sh/acme.sh --issue --server letsencrypt --keylength 2048 \
--dns dns_aws \
-d example.com -d '*.example.com'
# Use --install-cert, not the client's internal storage paths.
install -d -m 700 /etc/nginx/ssl/example.com
~/.acme.sh/acme.sh --install-cert -d example.com \
--fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
--key-file /etc/nginx/ssl/example.com/privkey.pem \
--reloadcmd '/usr/sbin/nginx -t && /bin/systemctl reload nginx'
# In the intended HTTPS server block, configure:
# ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
# ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;
# Then test and reload after saving that configuration.
/usr/sbin/nginx -t && /bin/systemctl reload nginx
Confirm the root account’s acme.sh cron task exists and that the saved installation paths and reload command are retained. Check client logs and scheduler output; logging locations and whether logging is enabled depend on installation settings. Monitor external expiry and the certificate presented by Nginx so a failed deployment is not hidden by successful issuance.
Little Things That Make the Whole Setup Rock‑Solid
The following checks address common failure points in DNS validation and certificate deployment.
Use staging while you wire it up
Use Let’s Encrypt staging to test validation without repeatedly consuming production issuance limits. Certbot certonly –dry-run or renew –dry-run performs a test without saving a production certificate; deploy hooks are not run by default. With acme.sh, select the Let’s Encrypt CA and use –staging in an isolated test setup. Keep test certificates out of production and verify deployment separately.
Mind your CAA records
For CAA, an issuewild record controls wildcard issuance when present; otherwise issue applies. Make sure the effective wildcard policy and the apex’s normal policy allow letsencrypt.org. Adding issue alone cannot override a restrictive issuewild policy. Misconfigured DNSSEC can also prevent valid DNS answers; see the DNSSEC guide for the trust-chain context.
Keep DNS API tokens tight and quiet
Give tokens only the DNS changes and discovery permissions required by the chosen plugin. Keep secret files readable only by the renewal identity, usually with mode600, and protect acme.sh’s stored account configuration too. Track expiry and rotation; after replacing a token, validate the new credentials and revoke the old token. Avoid recording secret values in shell history, tickets or debug logs.
Low TTLs help “manual” paths
For manual or synchronized TXT changes, a suitably low TTL can help with later cache expiry, but cannot flush existing cached data or negative answers. Wait for provider publication and the relevant cache lifetimes, and do not remove another active challenge value. See the DNS TTL migration guide for the preparation involved.
Chain files and reloads
Supply certificate chains in the format the server expects. Nginx uses fullchain.pem for ssl_certificate and the private key separately; cPanel’s UAPI accepts the leaf certificate and CA bundle in separate parameters. After renewal, confirm successful installation and reload. The private key should be readable only by the required service identity; root-run Nginx normally does not need its worker account to read the key directly.
Don’t forget the rest of your security posture
TLS is one layer: keep redirects correct and remove mixed content. Enable HSTS only after HTTPS is reliable across its intended scope; includeSubDomains and preload require checking the affected subdomains. The HTTP security headers guide covers the next configuration decisions.
Common “Why Is This Failing?” Moments (And Quick Fixes)
Troubleshoot validation, renewal scheduling and installation separately so the repair matches the failing step.
“Validating the TXT record is failing”
Confirm the exact TXT name and value, check for an accidentally repeated suffix such as _acme-challenge.example.com.example.com, and query all authoritative nameservers as well as a public resolver. Verify the actual NS delegation after a DNS move. Allow for negative caching and provider publication; keep concurrent apex/wildcard TXT values intact.
“It worked yesterday, now renewals are broken”
Inspect renewal logs for expired credentials, changed permissions, DNS moves and API limits. Confirm the current plugin and authoritative provider agree. Authentication failures need credential repair; rate limits need appropriate backoff. If using debug output, keep secrets private and remove them before sharing logs.
“The site still shows the old certificate”
A newly issued certificate may not have reached the service, or the service may not have reloaded. Check the cPanel UAPI or deploy-hook result and the Nginx certificate paths. A CDN or reverse proxy that terminates TLS presents its own edge certificate, independently of the origin certificate; this is not ordinary HTTP content caching. Check both TLS endpoints and the hostname/SNI selection.
“Wildcard works, but the apex domain is missing”
Remember that wildcard *.example.com does not cover example.com. Always include both the apex and the wildcard in your request. It’s a small oversight that happens to everyone once.
“We use DNSSEC—does it matter for ACME?”
It matters in the best way when configured right. Signed zones help protect the integrity of your TXT validation. Misconfigured DNSSEC, however, can block resolution. If validation mysteriously fails yet your TXT record exists, test DNSSEC health and check the DS record chain. If you need a refresher, see this explanation of how DNSSEC works and why it matters.
Putting It All Together: A Quick, Real‑World Blueprint
Use a DNS-aware client or supported panel automation, request the actual names needed, restrict credentials, and install the certificate in the format required by each service. Include a tested deployment step in renewal and monitor the externally served certificate. This applies across cPanel, Plesk and Nginx even though their DNS and installation mechanisms differ.
These primary documentation starting points describe ACME validation, DNS plugins and deployment options. Check the instructions for your installed version and provider.
• The Let’s Encrypt documentation on wildcard certificates for the DNS‑01 basics and caveats.
• The Certbot documentation about DNS plugins to pick your provider module and credential format.
• The acme.sh project documentation for provider variable names and deploy hooks.
For panel-specific requirements, also consult current cPanel AutoSSL and Plesk DNS-integration documentation; general ACME client support does not imply that every panel can automate the same provider.
Wrap‑Up: Make Renewals Boring Again
A reliable renewal process produces evidence: successful DNS validation, a successful installation result and a fresh certificate presented by the intended service. Keep these checks and failure notifications active even after the first renewal succeeds. Automation reduces repetitive work; it does not eliminate changes in DNS permissions, software or certificate deployment.
On cPanel, start with Let’s Encrypt AutoSSL when authoritative DNS is local or clustered; otherwise use a supported external-DNS client and installation path. On Plesk, confirm DNS control or synchronization and certificate assignment. On Nginx, use the right chain and key paths, then test and reload. Validate in staging without deploying its certificates live. Once HTTPS is reliable, review HSTS, CSP and related headers for your application’s scope.
Hope this was helpful! If there’s a stack you want me to cover next—HAProxy, Traefik, Kubernetes Ingress—I’m game. Until then, may your certificates auto‑renew quietly and your dashboards stay gloriously boring.





