Skip to main content

Documentation Index

Fetch the complete documentation index at: https://certplane.kippel.org/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through configuring the Certplane broker to obtain publicly-trusted certificates from Let’s Encrypt using the dns-01 challenge. The dns-01 challenge proves domain ownership by creating a DNS TXT record — it works even for servers not reachable from the internet, and is required for wildcard certificates.
Let’s Encrypt enforces strict rate limits on its production environment. Always validate your setup against the staging environment before switching to production.
1

Get your Cloudflare API token

In the Cloudflare dashboard, create an API token with Zone → DNS → Edit permission scoped to the zone (or zones) you want Certplane to manage. Do not use a Global API Key — a scoped token limits the blast radius if the credential is ever exposed.Once you have the token, note its value. You’ll store it in the next step.
2

Store the token

The simplest approach is the env secrets provider. Export the token as an environment variable before starting the broker:
export CLOUDFLARE_DNS_API_TOKEN="your-token-here"
If you prefer to read the token from a file or from HashiCorp Vault instead, see the Vault Secrets guide and set secrets.provider accordingly. The value of acme.credentials in policy.yml is the name interpreted by whichever provider you configure.
Generate your ACME account key before continuing. Certplane reads this key to sign ACME requests — it is not a certificate, and you should keep it in a secure, backed-up location:
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out /etc/certplane/acme/account.key
3

Configure the broker

Edit your broker.yml to point the issuer block at the Let’s Encrypt staging directory and configure the Cloudflare DNS provider. Start with staging so you can confirm everything works without burning production rate limits.
issuer:
  provider: acme
  acme:
    directory_url: https://acme-staging-v02.api.letsencrypt.org/directory
    account_email: admin@example.com
    account_key: /etc/certplane/acme/account.key
    dns_provider: cloudflare

secrets:
  provider: env
The account_key must be the path to the EC private key you generated above. The account_email is the address Let’s Encrypt uses to send expiry warnings; it does not need to match any DNS record.
4

Create a wildcard profile in policy.yml

Add a profile that requests a wildcard certificate using the dns-01 challenge. The credentials value is the name of the secret as interpreted by your configured secrets provider — for the env provider, this is the environment variable name.
profiles:
  public_wildcard:
    cert_type: wildcard
    dns_names:
      - "*.example.com"
    acme_challenge: dns-01
    renew_before: 720h
Then allow the relevant host to request this profile:
hosts:
  web01:
    identity: web01.internal.example.com
    profiles:
      - public_wildcard
Let’s Encrypt ignores the ttl field at issuance time and always issues certificates valid for 90 days. The renew_before value controls when Certplane proactively renews — the default of 720h (30 days) is a sensible starting point.
5

Test with staging, then switch to production

Restart the broker and trigger a certificate request from an agent. Staging certificates are signed by a fake CA that browsers do not trust, but they are structurally identical to production ones — any configuration errors will surface here.Once the staging certificate is issued successfully, switch the broker to the production directory:
issuer:
  provider: acme
  acme:
    directory_url: https://acme-v02.api.letsencrypt.org/directory
    account_email: admin@example.com
    account_key: /etc/certplane/acme/account.key
    dns_provider: cloudflare
Restart the broker. The next renewal cycle (or a forced re-request) will obtain a production certificate trusted by all major browsers and operating systems.