Pure git mv operations; no content edits. Internal links remain pointing
at old paths and will be fixed in Phase 11. Per the Phase 1 audit
recommendations at cowork/docs-overhaul-phase-1-audit-2026-05-04/.
35 files moved across 8 audience-organized subdirectories:
docs/getting-started/ (5):
quickstart.md, concepts.md, examples.md, advanced-demo.md (was
demo-advanced.md), why-certctl.md
docs/reference/ (6):
architecture.md, api.md (was openapi.md), mcp.md,
intermediate-ca-hierarchy.md, deployment-model.md (was
deployment-atomicity.md), vendor-matrix.md (was
deployment-vendor-matrix.md)
docs/reference/protocols/ (6):
acme-server.md, acme-server-threat-model.md, scep-intune.md,
est.md, crl-ocsp.md, async-ca-polling.md (was async-polling.md)
docs/operator/ (4):
security.md, tls.md, database-tls.md, approval-workflow.md
docs/operator/runbooks/ (3):
cloud-targets.md (was runbook-cloud-targets.md), expiry-alerts.md
(was runbook-expiry-alerts.md), disaster-recovery.md
docs/migration/ (3):
from-certbot.md (was migrate-from-certbot.md), from-acmesh.md
(was migrate-from-acmesh.md), cert-manager-coexistence.md (was
certctl-for-cert-manager-users.md)
docs/compliance/ (4):
index.md (was compliance.md), soc2.md (was compliance-soc2.md),
pci-dss.md (was compliance-pci-dss.md), nist-sp-800-57.md (was
compliance-nist.md)
docs/contributor/ (4):
testing-strategy.md, test-environment.md (was test-env.md),
ci-pipeline.md, qa-test-suite.md (was qa-test-guide.md)
Deferred to later Phase 2 sub-phases:
- connectors.md split (Phase 4): docs/connectors.md +
docs/connector-{apache,f5,iis,k8s,nginx}.md still at top level
- testing-guide.md prune (Phase 5): docs/testing-guide.md still
at top level
- features.md disperse (Phase 6): docs/features.md still at top
level
- legacy-est-scep.md split (Phase 7): docs/legacy-est-scep.md
still at top level
- ACME walkthrough re-homing (Phase 8): three
docs/acme-*-walkthrough.md still at top level
- Upgrade docs archive (Phase 3): two docs/upgrade-*.md still
at top level
Cross-reference updates (Phase 11) will happen after all moves and
content edits land. Internal links to docs/* paths are temporarily
broken until that phase completes.
7.2 KiB
Deployment Examples
Five turnkey docker-compose scenarios, each runnable in under 5 minutes. Pick the one closest to your setup.
Which Example Should I Use?
| I need to... | Example | Issuer | Target |
|---|---|---|---|
| Get Let's Encrypt certs for NGINX on a public server | ACME + NGINX | ACME (HTTP-01) | NGINX |
| Issue wildcard certs without opening port 80 | Wildcard DNS-01 | ACME (DNS-01) | Any |
| Run an internal CA for services behind a firewall | Private CA + Traefik | Local CA | Traefik |
| Use Smallstep step-ca as my PKI backend | step-ca + HAProxy | step-ca | HAProxy |
| Manage both public and internal certs from one dashboard | Multi-Issuer | ACME + Local CA | Mixed |
Already using another tool? See the migration sections below each example for Certbot, acme.sh, and cert-manager users.
ACME + NGINX
Scenario: You have one or more public-facing domains, NGINX as the reverse proxy, and want automated Let's Encrypt certificates with HTTP-01 challenges.
What it deploys: certctl server + PostgreSQL + certctl agent + NGINX, all on one Docker network. The agent generates keys locally (ECDSA P-256), submits CSRs to the server, receives signed certs from Let's Encrypt, and deploys them to NGINX with automatic reload.
Prerequisites: A domain pointing to your server, ports 80 and 443 open, Docker Compose v20.10+.
cd examples/acme-nginx
cp .env.example .env # Edit with your domain and email
docker compose up -d
The full walkthrough — including how HTTP-01 challenges work, adding multiple domains, switching to staging for testing, and a production checklist — is in the example README.
Migrating from Certbot? certctl discovers your existing /etc/letsencrypt/live/ certificates automatically. You keep your ACME account, disable the Certbot cron, and certctl takes over renewal with centralized visibility and deployment verification. The step-by-step process is in Migrating from Certbot.
Wildcard DNS-01
Scenario: You need wildcard certificates (*.example.com) or your servers aren't reachable from the internet (no port 80). DNS-01 validates ownership by creating a TXT record at your DNS provider.
What it deploys: certctl server + PostgreSQL + certctl agent. Includes a Cloudflare DNS hook script as a working reference — swap in your own DNS provider (Route53, Azure DNS, Google Cloud DNS, or any provider with an API).
Prerequisites: A domain, API credentials for your DNS provider, Docker Compose.
cd examples/acme-wildcard-dns01
cp .env.example .env # Edit with domain, email, DNS provider credentials
docker compose up -d
The full walkthrough — including DNS-PERSIST-01 (set a TXT record once, never touch DNS again on renewals), adapting scripts for other providers, and propagation troubleshooting — is in the example README.
Migrating from acme.sh? Your existing dns_* hook scripts are compatible with certctl's DNS-01 — they use the same pattern (shell scripts creating TXT records). The migration guide covers script adaptation, discovery of existing acme.sh certificates, and phasing out the acme.sh cron. See Migrating from acme.sh.
Private CA + Traefik
Scenario: Internal services that don't need public CA validation. You run your own certificate authority — either a self-signed root for development, or a subordinate CA chained to your enterprise root (e.g., Active Directory Certificate Services).
What it deploys: certctl server + PostgreSQL + certctl agent + Traefik. The Local CA issuer signs certificates directly. Traefik watches a cert directory and auto-reloads when new files appear.
Prerequisites: Docker Compose. For sub-CA mode, you'll need a CA certificate and key signed by your enterprise root.
cd examples/private-ca-traefik
docker compose up -d # Self-signed mode (no .env needed for demo)
The full walkthrough — including sub-CA setup with CERTCTL_CA_CERT_PATH and CERTCTL_CA_KEY_PATH, creating certificates via the API, monitoring deployments, and production hardening — is in the example README.
step-ca + HAProxy
Scenario: You use Smallstep's step-ca as your private PKI and want automated lifecycle management for certificates deployed to HAProxy load balancers.
What it deploys: certctl server + PostgreSQL + certctl agent + step-ca (with JWK provisioner) + HAProxy. certctl issues certs via step-ca's native /sign API, combines them into HAProxy's expected PEM format (cert + chain + key in one file), and reloads HAProxy.
Prerequisites: Docker Compose.
cd examples/step-ca-haproxy
docker compose up -d
The full walkthrough — including step-ca provisioner configuration, integrating with an existing step-ca instance, HAProxy PEM format details, and advanced features (approval workflows, policy-based renewal, multi-instance HAProxy) — is in the example README.
Multi-Issuer
Scenario: You manage both public-facing services (needing Let's Encrypt or another public CA) and internal services (using a private CA) and want a single dashboard for everything.
What it deploys: certctl server + PostgreSQL + certctl agent configured with both an ACME issuer and a Local CA issuer. Demonstrates issuer assignment via profiles — public services get ACME certs, internal services get Local CA certs, all visible in one inventory.
Prerequisites: Docker Compose. For real ACME certs, a public domain and port 80 access.
cd examples/multi-issuer
docker compose up -d
The full walkthrough — including profile-based issuer assignment, testing with ACME staging, Local CA enterprise sub-CA mode, and scaling beyond Docker Compose — is in the example README.
Using cert-manager for Kubernetes? certctl complements cert-manager — cert-manager handles in-cluster certs, certctl handles everything outside: VMs, bare metal, network appliances, Windows servers. They can share the same CA (ACME, step-ca, Vault PKI). See certctl for cert-manager Users.
Beyond These Examples
These 5 scenarios cover the most common deployment patterns, but certctl supports a broader set of issuer and target backends — see docs/features.md's Issuer Connectors and Target Connectors sections for the live catalogs (rebuild via ls -d internal/connector/issuer/*/ | wc -l and ls -d internal/connector/target/*/ | wc -l). Once you have the basics running, you can mix and match:
Issuers: ACME (Let's Encrypt, ZeroSSL, Buypass, Google Trust Services), Local CA (self-signed or sub-CA), step-ca, Vault PKI, DigiCert CertCentral, OpenSSL/Custom CA script, Sectigo (coming soon).
Targets: NGINX, Apache, HAProxy, Traefik, Caddy, Envoy, IIS (local PowerShell or WinRM proxy), Postfix, Dovecot, F5 BIG-IP (coming soon).
See Connector Reference for configuration details on every issuer and target.