Skip to main content

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:

ReasonWhat to do
The domain is not activeVerify the delegation first. Issuance needs the same delegation that verification proves.
The challenge record was not visible in timeYour nameserver did not serve the record. Check the provider is reachable and the zone exists.
The provider is disabledRe-enable it under DNS > Providers.
Rate limitedYou 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:

EngineReload
MySQL 8+ALTER INSTANCE RELOAD TLS
MariaDB 10.4+FLUSH SSL
PostgreSQLpg_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.