TLS Certificates for System DNS
Overview
A System DNS base domain can hold a wildcard TLS certificate covering every resource named under it. Managed databases with a public IP receive that certificate automatically, so a customer connecting to db-prod-mysql.cloud1.example.com can verify it against the public trust store rather than trusting a self-signed certificate or turning verification off.
One certificate per base domain covers everything:
*.cloud1.example.com and cloud1.example.com
Both names are on the certificate. A wildcard does not match the bare domain, so the apex is included separately.
Why a wildcard
Let's Encrypt limits issuance to 50 certificates per week per registered domain. A certificate per database would burn that budget quickly on a busy fleet and then block new issuance for a week. One wildcard covers every resource under the domain and renews once per cycle.
Wildcards can only be issued using the DNS-01 challenge, which means proving control by writing a DNS record rather than by answering an HTTP request. The panel already owns the zone, so it writes the challenge record itself with the same credentials it uses for every other record. Nothing needs to be installed on a database, no ports need to be open to the internet, and no DNS credentials ever leave the panel.
This is a different mechanism from load balancer certificates, which use HTTP-01 against a customer's own domain. Both continue to work; they solve different problems.
Prerequisites
- A System DNS base domain in the active state. Verification must have passed, because issuance depends on the same delegation. See System DNS.
- The domain's PowerDNS provider reachable from the panel. See PowerDNS Cluster Deployment.
Issuing a certificate
Go to DNS > System Domains and choose Issue certificate on an active domain.
Issuance runs while you wait, normally around a minute. The panel writes the challenge record, waits for your own nameserver to serve it, asks Let's Encrypt to check, and stores the result. The challenge record is removed afterwards.
If it fails, the reason from the certificate authority is shown on the row. Common causes:
| Reason | What to do |
|---|---|
| The domain is not active | Verify the delegation first. Issuance needs the same delegation that verification proves. |
| The challenge record was not visible in time | Your nameserver did not serve the record. Check the provider is reachable and the zone exists. |
| The provider is disabled | Re-enable it under DNS > Providers. |
| Rate limited | You have issued 50 certificates for this registered domain this week. Wait, or use a different base domain. |
Testing without spending your rate limit
Set ACME_DIRECTORY_URL to the Let's Encrypt staging directory before issuing:
ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory
Staging certificates are not trusted by clients, so connections will still warn, but the whole path is exercised and the staging limits are far looser. Remove the variable for real certificates. A burned production limit blocks new issuance for a week, so test here first.
What happens to databases
When a certificate is issued or renewed, it is pushed to every public managed database already named under that domain. When a database gains a name later, it receives the certificate then.
On each database the panel writes the material, checks the certificate and key are actually a pair, then reloads the engine without restarting it:
| Engine | Reload |
|---|---|
| MySQL 8+ | ALTER INSTANCE RELOAD TLS |
| MariaDB 10.4+ | FLUSH SSL |
| PostgreSQL | pg_reload_conf() |
Older MySQL and MariaDB releases have no reload statement. There the certificate is installed and the database is marked pending restart: it keeps serving the previous certificate until someone restarts the engine. That is shown distinctly from success on purpose, so a database still presenting an expiring certificate is visible rather than hidden behind a green tick.
The certificate and private key are sent in a file that is deleted from the database immediately afterwards, including when installation fails. They are never passed as command arguments, where any local user could read them from the process list.
Connecting with verification
Once installed, customers can verify the connection properly.
MySQL and MariaDB
mysql -h db-prod-mysql.cloud1.example.com -u appuser -p \
--ssl-mode=VERIFY_IDENTITY
PostgreSQL
psql "host=db-prod-pg.cloud1.example.com user=appuser sslmode=verify-full dbname=app"
Both must connect by the hostname, not the IP address. The certificate is issued for the name, so verification against an IP will always fail.
No CA file is needed. The certificate chains to a public root that operating systems and language runtimes already trust.
Renewal
Certificates are valid for 90 days. A scheduled job renews them at 30 days remaining and runs daily, so a failed attempt has a month of retries behind it rather than being a countdown. Each renewal is pushed to the databases automatically.
A failed renewal never removes the existing certificate. The current one keeps working while retries continue, and the failure is recorded on the domain.
To renew early, issue again from the panel. Re-issuing is safe at any time.
Scope and limitations
Public-IP databases only. A wildcard certificate only helps if the client connects by a name that matches it, and System DNS only names resources that have a public IPv4. A database on a private VPC subnet has no such name, so it does not receive a certificate. Publishing the name inside the VPC's own DNS would make this work and is not implemented yet.
Databases only, for now. Load balancers keep their own certificate flow, which handles customer-owned domains. Instances do not receive the certificate: the private key belongs to a name in your zone, and handing it to a customer's virtual machine is a trust decision rather than a technical one.
Kubernetes control planes are unaffected. Their certificates come from the cluster's own certificate authority, which is how Kubernetes expects it to work.