Skip to main content
This guide walks you through the full Certplane setup: running the broker, defining a certificate policy, enrolling a host with its identity certificate, and starting the agent renewal loop. By the end, your host will have a publicly trusted TLS certificate that renews automatically.
Prefer Ansible? Skip ahead to the Ansible roles guide — the certplane_broker and certplane_agent roles automate every step on this page.
1

Prerequisites

Before you begin, make sure you have the following in place:
  • step-ca — A running step-ca instance reachable by your hosts. This is the internal CA that issues agent identity certificates.
  • Let’s Encrypt access — The broker uses ACME to obtain public certificates. You need a valid email address for the ACME account.
  • A DNS provider supported for dns-01 — Currently cloudflare or httpreq. Wildcard profiles require dns-01.
  • The Certplane binariescertplane-broker on your broker host and certplane-agent on each managed host. Build with make from the source repo.
2

Deploy the broker

The broker is the central server that enforces policy and obtains certificates from your public CA. Create /etc/certplane/broker.yml (this mirrors examples/config/broker.yml):
broker.yml
server:
  address: ":8443"
  tls:
    cert: /etc/certplane/broker/broker.crt
    key: /etc/certplane/broker/broker.key
    min_version: "1.2"
  mtls:
    agent_ca_bundle: /etc/certplane/ca/agent-identity-ca-bundle.crt
  read_header_timeout: 5s
  read_timeout: 10s
  write_timeout: 60s
  idle_timeout: 120s

policy:
  path: /etc/certplane/policy.yml
  watch: false

issuer:
  provider: acme
  acme:
    directory_url: https://acme-v02.api.letsencrypt.org/directory
    account_email: admin@example.com
    account_key: /var/lib/certplane/acme/account.key
    dns_provider: cloudflare

secrets:
  provider: env

store:
  driver: sqlite
  path: /var/lib/certplane/broker.db

audit:
  enabled: true
  failure_mode: fail_open
  mirror_to_log: true

rate_limits:
  per_identity_per_hour: 50
  per_identity_profile_per_hour: 20

logging:
  level: info
  format: json
  destination: stdout
The server.mtls.agent_ca_bundle must be the CA bundle that signed (or will sign) your agent identity certificates — typically the step-ca root or intermediate.Start the broker:
certplane-broker -c /etc/certplane/broker.yml serve
The broker listens on :8443 by default and requires mTLS from every connecting agent. For the full configuration reference, see Broker configuration.
3

Create a policy file

The policy file defines which certificate profiles exist and which hosts may request each one. Create /etc/certplane/policy.yml:
policy.yml
version: 1

profiles:
  public_edge_main:
    type: wildcard
    dns_names:
      - "*.example.com"
    acme:
      challenge: dns-01
      credentials: cloudflare/example-com
    renew_before: 720h

hosts:
  edge01:
    identity: edge01.h.int.example.com
    profiles:
      - public_edge_main
  • profiles — Each named profile sets type (wildcard or multi_san), allowed dns_names, ACME settings (acme.challenge and acme.credentials), and an optional renew_before window.
  • hosts — Each entry maps a label to an identity (the CN of the identity certificate issued by step-ca) and lists profiles the host may request. Requests for any other profile are rejected.
Validate before you deploy it:
certplane-broker -c /etc/certplane/broker.yml policy validate --policy /etc/certplane/policy.yml
For the full reference, see Policy overview.
4

Enroll your first host

Enrollment gives a host its identity certificate. The agent contacts step-ca once using a short-lived bootstrap token, generates an ECDSA key pair locally, and stores the resulting identity.crt.Generate a bootstrap token on your step-ca instance:
step ca token edge01.h.int.example.com
Write the token to the host at the path referenced in the agent config (e.g., /etc/certplane/bootstrap-token, mode 0600).Create the agent config at /etc/certplane/agent.yml (mirrors examples/config/agent.yml):
agent.yml
state_dir: /var/lib/certplane/agent

identity:
  name: edge01.h.int.example.com
  provider: step-ca
  cert: /var/lib/certplane/agent/identity.crt
  key: /var/lib/certplane/agent/identity.key
  issuer_ca_bundle: /etc/certplane/ca/agent-identity-ca-bundle.crt
  bootstrap_token: /etc/certplane/bootstrap-token
  renew_before: 8h
  warn_before: 24h
  step_ca:
    url: https://ca.int.example.com
    fingerprint: "sha256:aabbcc..."
    root_ca_bundle: /etc/certplane/ca/step-ca-root.crt
    timeout: 10s

broker:
  url: https://certplane-broker.int.example.com:8443
  server_ca_bundle: /etc/certplane/ca/broker-server-ca-bundle.crt
  timeout: 30s

logging:
  level: info
  format: text
  destination: stderr

certificates:
  - name: edge-wildcard
    profile: public_edge_main
    dns_names:
      - "*.example.com"
    key:       /var/lib/certplane/agent/service.key
    cert:      /var/lib/certplane/agent/service.crt
    chain:     /var/lib/certplane/agent/service.chain.crt
    fullchain: /var/lib/certplane/agent/service.fullchain.crt
    renew_before: 720h
    reload_command: "systemctl reload traefik"
    reload_timeout: 30s
Run enrollment:
certplane-agent -c /etc/certplane/agent.yml enroll
The agent generates identity.key locally, creates a CSR, and submits it to step-ca along with the bootstrap token. On success, identity.crt is written and the bootstrap token file is deleted.
The bootstrap token is consumed during enrollment and cannot be reused. If enrollment fails and you need to retry, generate a new token from step-ca. See Agent enrollment for troubleshooting.
5

Run the agent

Once the host is enrolled, run the renewal loop. The agent is a one-shot binary — run it on a timer (the Ansible role ships a systemd timer; see Running the agent for the standalone unit).
certplane-agent -c /etc/certplane/agent.yml run
On each run, the agent:
  1. Renews the identity certificate if it expires within identity.renew_before.
  2. For each entry under certificates:
    • Ensures a local ECDSA service key exists at key (generated if missing, reused otherwise).
    • Skips the certificate if a valid one exists and is not yet within renew_before of expiry.
    • Otherwise builds a CSR with the configured dns_names, calls the broker over mTLS, validates that the returned bundle matches the local key and requested DNS names, writes cert, chain, and fullchain, and runs reload_command if set.
Validate config and on-disk state without making changes:
certplane-agent -c /etc/certplane/agent.yml check

Next steps