Skip to content

SSL/TLS Certificates

CorePanel issues and renews SSL/TLS certificates automatically, with no manual ACME client to run. Understanding how it issues them explains an important operational detail: some hostnames (like mail.example.com) are secured differently from the website, and a domain whose DNS lives on an external provider (Cloudflare, Route 53, etc.) needs specific handling for its mail certificate.

This page is for server administrators. It covers the issuance model, the delegation requirement, why web and mail behave differently, and the concrete setups that produce a valid certificate on mail.<domain>.

CorePanel’s certificate manager (part of corepanel-sys) obtains certificates from an ACME CA (Let’s Encrypt by default) using the DNS-01 challenge only. It never uses HTTP-01.

For each domain it requests a single wildcard certificate covering the wildcard plus the apex:

*.example.com
example.com

That one certificate covers every direct hostname of the domain — www, mail, webmail, ftp, and so on — from a single issuance. There is no separate certificate per service hostname.

PropertyValue
Challenge typeDNS-01 (only)
CALet’s Encrypt (ACME endpoint is configurable)
Coverage*.example.com + example.com
DNS providerLocal PowerDNS (via its HTTP API)
Store path/var/lib/cp-sys/ssl/certs/<domain>/{fullchain,privkey}.pem
RenewalAutomatic (background worker; renews before expiry)

Because issuance is DNS-01 through the server’s own PowerDNS, CorePanel can only complete the challenge when it is authoritative for the domain — that is, when the domain’s nameservers are delegated to this server.

Before every DNS-01 order, the certificate manager runs an authority pre-check: it resolves the domain’s NS records through public resolvers (Cloudflare, Google, Quad9) and confirms they point back to this server’s configured public IP addresses.

When a domain is not delegated to the server, CorePanel does not fire a failing ACME order (that would burn the CA’s failed-validation rate limit). Instead it parks the domain and re-checks delegation every 30 minutes, waiting indefinitely without consuming the retry budget. The moment you point the domain’s NS at the server, the certificate is issued on the next check.

The IPs used for this check are the server’s own public IPs. They are configured automatically during initial setupcorepanel system init detects the main public IP (plus any additional IPs) and records them in the certificate manager. If the server’s public IP later changes, re-run initial setup so the delegation check compares against the correct addresses: a nameserver that resolves to an IP not in this list is treated as not pointing here.

CorePanel uses two independent issuance paths with different triggers. Knowing which one fires — and when — explains why a freshly added site is already on HTTPS while its mail hostname may not be.

The wildcard (DNS-01) — issued proactively when the domain is added

Section titled “The wildcard (DNS-01) — issued proactively when the domain is added”

The certificate manager does not wait for a visit. The moment a domain is provisioned (account creation, or adding a domain to an account) it queues an issuance attempt in the background:

  • Delegated → it publishes the _acme-challenge TXT record in the server’s PowerDNS, waits for it to propagate, and obtains the *.example.com + apex wildcard — typically within seconds to a couple of minutes of adding the domain, with no traffic required. As soon as it lands, every hostname (www, mail, webmail, ftp) is covered and Dovecot’s per-domain SNI block is generated.
  • Not delegated → no ACME order is fired. The domain is parked and re-checked every 30 minutes; issuance happens automatically on the first re-check after you point the domain’s NS at the server.

There is no visit-triggered issuance for the wildcard and no manual “issue now” step: once the domain is delegated to the server, the next 30-minute delegation re-check obtains the certificate on its own.

The web certificate (TLS-ALPN-01) — issued on the first HTTPS request

Section titled “The web certificate (TLS-ALPN-01) — issued on the first HTTPS request”

Independently, CoreHttpd obtains the website’s certificate on demand, at the first HTTPS (port 443) handshake for a hostname it serves:

  1. A browser opens the first https:// connection to the host.
  2. CoreHttpd asks the CA for a certificate and answers the CA’s acme-tls/1 validation probe inside that same handshake (TLS-ALPN-01).
  3. The original handshake then completes with the just-issued certificate — the first HTTPS hit is what triggers issuance.

That first handshake blocks for up to ~30 s while issuing. If it takes longer, the connection falls back to the default certificate and issuance continues in the background, so a retry a few seconds later succeeds. Issuance is gated to hostnames CoreHttpd actually serves (a site must exist) — the abuse guard against ACME orders for arbitrary names.

This path:

  • fires on the first HTTPS request only — a plain HTTP (port 80) visit does not trigger it;
  • covers the web hostname that was hit, nothing else — it never produces a certificate for mail.* or an FTP hostname;
  • needs port 443 for the host to terminate on this server (an external proxy in front breaks it — see the caution in the next section).

For a delegated domain the wildcard usually issues before anyone visits, so the site serves its real certificate from the first hit and mail is covered by the same wildcard. For a non-delegated domain the wildcard never issues, so the website is carried entirely by the on-demand path (first HTTPS visit) while mail and FTP have no automatic certificate — the gap the next sections address.

certmanager (DNS-01) has preference: when it later issues a wildcard, that certificate takes over and owns renewal. Renewals are automatic on both paths — certmanager renews before expiry on its schedule, and CoreHttpd proactively renews its cached web certificates in the background (re-armed on startup, so a certificate issued in a previous run is renewed on schedule rather than only when traffic next arrives).

Two layers: the website vs. everything else

Section titled “Two layers: the website vs. everything else”

The delegation gate matters differently for the website than for mail/FTP, because the website has an on-demand fallback and mail does not.

The origin web server, CoreHttpd, obtains the website’s certificate on demand using TLS-ALPN-01 on port 443. TLS-ALPN-01 is solved inside the TLS handshake itself — it needs no DNS record — so the website gets a valid certificate even when the domain is not delegated to the server, as long as the A record points at the server.

Mail (Postfix/Dovecot), FTP and other service daemons do not have an on-demand challenge. They can only present a certificate that already exists in the store — which means a DNS-01-issued certificate. There is no TLS-ALPN-01 fallback on the mail or FTP ports.

Dovecot selects its certificate by SNI:

  • For each domain that has a certificate in /var/lib/cp-sys/ssl/certs/, a per-domain local_name block is generated in /etc/dovecot/conf.d/99-corepanel-ssl.conf.
  • Connections with no matching SNI fall back to the default host certificate — the server’s own hostname certificate maintained by CoreHttpd at /var/lib/corehttpd/hostcert/. That certificate is self-signed until the server’s hostname itself obtains an ACME certificate.

Postfix selects its certificate in this priority order:

  1. Exact hostname certificate
  2. Wildcard certificate for the parent domain
  3. System default certificate

The practical consequence: mail.example.com presents a valid certificate only when a certificate for example.com exists in the store — i.e. only after DNS-01 has succeeded, i.e. only when the domain is delegated to the server. If it is not, the mail daemons fall back to the server’s host certificate, whose name does not match mail.example.com.

Worked example: external DNS (Cloudflare) with only A + MX

Section titled “Worked example: external DNS (Cloudflare) with only A + MX”

This is the common case: a customer keeps their DNS at Cloudflare and simply adds an A record and an MX record pointing at the CorePanel server. Here is exactly what happens:

EndpointResultWhy
example.com / www (web)✅ Valid certificateCoreHttpd issues it on demand via TLS-ALPN-01 on port 443 (requires DNS-only, not proxied)
mail.example.com (IMAP/POP3/SMTP)⚠️ Certificate name mismatchNo DNS-01 cert in the store (domain not delegated), so mail falls back to the server host certificate
ftp.example.com (FTPS)⚠️ Certificate name mismatchSame reason as mail

So a Cloudflare domain with only A + MX works for the website but produces an untrusted / name-mismatch warning in mail clients that connect to mail.example.com. The website is fine; the mail hostname is the one that needs attention.

Choose one of the following to get a valid certificate on the mail (and FTP) hostname:

1. Delegate the domain’s DNS to CorePanel (full automation)

Section titled “1. Delegate the domain’s DNS to CorePanel (full automation)”

Point the domain’s NS records at the server. Once the delegation is visible in public DNS, the next 30-minute delegation check issues the wildcard, the per-domain Dovecot local_name block is generated, and mail.example.com presents a valid certificate automatically. This is the intended, zero-maintenance path.

2. Keep external DNS, but use the server’s canonical hostname for mail

Section titled “2. Keep external DNS, but use the server’s canonical hostname for mail”

If the customer must keep DNS at Cloudflare (or another external provider), configure mail clients to use the server’s own hostname (for example mail.yourhosting.tld) as the incoming/outgoing server, instead of mail.customerdomain.tld. The server hostname always has a matching, valid certificate (the host certificate), so clients connect without warnings. This is the standard “one mail hostname for all accounts” model and needs no per-domain delegation.

3. Migration preserves an existing certificate

Section titled “3. Migration preserves an existing certificate”

When you migrate an account from cPanel, a still-valid certificate found in the archive is imported verbatim (sys.ImportCertificate) and tracked for renewal, so the site keeps serving TLS through the cutover without a re-issue.

The panel surfaces per-domain certificate status through the certificate manager (internally, the sys.GetDomainSSLStatus / sys.GetDomainSSLCertificates JSON-RPC methods on corepanel-sys). From a shell you can inspect the live certificates directly, which is the most reliable check:

Terminal window
# Web: which certificate the site presents on 443
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -dates
# Mail: which certificate IMAPS presents for the mail hostname
openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -dates

If the mail hostname reports a subject that is the server’s hostname rather than example.com, the domain has no per-domain certificate in the store — the delegation gate. Confirm it:

Terminal window
# The domain's nameservers as seen by the public hierarchy
dig +short NS example.com
# Where those nameservers resolve — must match the server's public IPs
dig +short A ns1.example.com
# Is there a per-domain certificate on disk at all?
ls -l /var/lib/cp-sys/ssl/certs/example.com/

Mail client shows the wrong or untrusted certificate for mail.<domain>

Section titled “Mail client shows the wrong or untrusted certificate for mail.<domain>”

This is expected when the domain is not delegated to the server (see the Worked example above); apply one of the recommended setups. To confirm which certificate Dovecot is configured to serve:

Terminal window
# Per-domain SNI (local_name) blocks + the default (host) certificate
cat /etc/dovecot/conf.d/99-corepanel-ssl.conf

When a certificate is issued, CorePanel regenerates that SNI config and reloads Postfix and Dovecot automatically (internally, via sys.ReloadMailTLS), so a valid mail.<domain> certificate is picked up without manual steps. To force the running daemons to re-read their configuration yourself:

Terminal window
systemctl reload dovecot postfix