Skip to main content

Step-CA (Internal Certificate Authority)

Overview

Step-CA is an internal ACME-compatible certificate authority that issues TLS certificates for all *.home.local domains. It allows Traefik to provision and auto-renew trusted certificates for internal services without relying on Let's Encrypt or exposing any ports to the internet.

Clients and browsers on the LAN trust *.home.local certificates because the Step-CA root certificate has been manually installed as a trusted CA on each device.

Access

Type URL / Endpoint Notes
ACME API https://ca.home.local:9000/acme/acme/directory Used by Traefik only
Step-CA UI N/A No web UI — CLI managed only

Step-CA does not have a browser-accessible dashboard. Management is via the step CLI tool.

Configuration

Image: smallstep/step-ca:latest Compose project: traefik (same project as traefik container)

Ports

Port Protocol Purpose
9000 TCP ACME API (host-bound: 0.0.0.0:9000)

Port 9000 is bound directly to the host so that Traefik (and any other ACME client on the LAN) can reach it at ca.home.local:9000.

CA Configuration — ca.json

Location: /home/jeeves/docker/step-ca/config/config/ca.json

Key settings (secrets redacted):

{
  "root": "/home/step/certs/root_ca.crt",
  "crt": "/home/step/certs/intermediate_ca.crt",
  "key": "/home/step/secrets/intermediate_ca_key",
  "address": "0.0.0.0:9000",
  "dnsNames": ["ca.home.local"],
  "db": {
    "type": "badger",
    "dataSource": "/home/step/db"
  },
  "authority": {
    "provisioners": [
      {
        "type": "ACME",
        "name": "acme"
      }
    ]
  }
}

Certificate duration for ACME-issued certs is set to 720 hours (30 days) in Traefik's step-ca resolver config. Traefik renews automatically before expiry.

Volumes / Bind Mounts

Host Path Container Path Purpose
/home/jeeves/docker/step-ca/config /home/step CA configuration, certificates, database

Directory Layout Inside the Volume

/home/jeeves/docker/step-ca/config/
├── config/
│   ├── ca.json          ← Main CA configuration
│   └── defaults.json    ← Step CLI defaults
├── certs/
│   ├── root_ca.crt      ← Root CA certificate (install this on client devices)
│   └── intermediate_ca.crt
├── secrets/             ← Private keys — never expose these
│   ├── root_ca_key
│   ├── intermediate_ca_key
│   └── password         ← Key encryption password (REDACTED)
└── db/                  ← BadgerDB certificate issuance database

Dependencies

  • AdGuard Home — ca.home.local must resolve on the LAN for Traefik to reach the ACME endpoint
  • No other service dependencies

Trusting the Root CA on Client Devices

Every device that accesses *.home.local URLs in a browser must trust the Step-CA root certificate. The root cert is at:

/home/jeeves/docker/step-ca/config/certs/root_ca.crt

Also available at /home/jeeves/docker/traefik/step-ca-root.crt (Traefik keeps a copy for its own ACME client trust store).

macOS

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain root_ca.crt

Windows

Import-Certificate -FilePath root_ca.crt -CertStoreLocation Cert:\LocalMachine\Root

Ubuntu / Debian

sudo cp root_ca.crt /usr/local/share/ca-certificates/step-ca.crt
sudo update-ca-certificates

Notes / Gotchas

  • The Step-CA password file (/home/step/secrets/password) is read on startup. If the volume is lost, the CA must be re-initialized and all client devices must re-import the new root certificate.
  • Do not delete the db/ directory — it contains the certificate issuance history. Loss means Step-CA cannot check for revoked certificates.
  • Step-CA is in the same Portainer compose project as Traefik. Restarting the Traefik stack will also restart Step-CA briefly. Schedule this during off-hours.
  • Traefik caches issued certs in its ACME storage file. If Step-CA is temporarily down, Traefik will continue serving existing certs until they near expiry.

Last Updated: 2026-06-16