This guide enables ACME v2 on an existing Smallstep Step CA deployment, then shows how a host like test.maksonlee.com can trust your private CA, request/renew TLS certificates with Certbot, and let Certbot’s NGINX plugin automatically enable HTTPS on the default NGINX site.
This Post Is Based On
Lab Context
- Step CA host:
stepca.maksonlee.com - Client host:
test.maksonlee.com - OS: Ubuntu 24.04
- Step CA server path:
/etc/step-ca - Step CA config:
/etc/step-ca/config/ca.json - ACME provisioner name:
acme-internal - ACME directory URL:
https://stepca.maksonlee.com/acme/acme-internal/directory
What You’ll Build
- Enable ACME v2 on Step CA
- Install
step-clion the client and trust the Root CA - Install NGINX (default site)
- Use Certbot + NGINX plugin to:
- register an ACME account,
- request a TLS certificate from Step CA,
- and automatically configure NGINX for HTTPS + HTTP→HTTPS redirect
- Confirm Certbot’s auto-renewal timer and test renewal
- Verify the certificate chain and SAN using OpenSSL
Prerequisites
- Step CA is already running and reachable at:
https://stepca.maksonlee.com
- DNS:
test.maksonlee.comresolves to the client host. - This post uses HTTP-01 challenges.
test.maksonlee.commust accept inbound TCP/80 during issuance/renewal.
If you can’t expose port 80, use DNS-01 instead.
- Enable ACME on Step CA
Run on stepca.maksonlee.com:
sudo -i
export STEPPATH=/etc/step-ca
step ca provisioner add acme-internal --type ACME \
--ca-config /etc/step-ca/config/ca.json \
--ca-url https://stepca.maksonlee.com \
--root /etc/step-ca/certs/root_ca.crt \
--password-file /etc/step-ca/password.txt
sudo systemctl kill -s HUP step-ca
ACME Directory URL (clients will use this):
https://stepca.maksonlee.com/acme/acme-internal/directory
- Install step-cli on the Client
Run on test.maksonlee.com.
Install dependencies:
sudo apt update && sudo apt install -y --no-install-recommends curl gpg ca-certificates
Add Smallstep’s apt signing key:
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsSL https://packages.smallstep.com/keys/apt/repo-signing-key.gpg \
-o /etc/apt/keyrings/smallstep.asc
sudo chmod 0644 /etc/apt/keyrings/smallstep.asc
Add the Smallstep apt repository:
sudo tee /etc/apt/sources.list.d/smallstep.sources >/dev/null <<'EOF'
Types: deb
URIs: https://packages.smallstep.com/stable/debian
Suites: debs
Components: main
Signed-By: /etc/apt/keyrings/smallstep.asc
EOF
Install step-cli:
sudo apt update && sudo apt install -y step-cli
- Bootstrap Trust on the Client and Install the Root CA
Get the Root CA fingerprint:
curl -fsSk https://stepca.maksonlee.com/roots.pem | step certificate fingerprint
Bootstrap the client context (replace <FINGERPRINT> with the value above):
step ca bootstrap \
--ca-url https://stepca.maksonlee.com \
--fingerprint <FINGERPRINT>
Install the Root CA into the OS trust store:
sudo step certificate install ~/.step/certs/root_ca.crt
Verify the ACME directory endpoint from the client:
curl -fsS https://stepca.maksonlee.com/acme/acme-internal/directory | head
Expected output: JSON containing endpoints like newNonce, newAccount, newOrder, etc.
- Install NGINX
sudo apt update
sudo apt install -y nginx
sudo systemctl enable --now nginx
Confirm HTTP works (default page):
curl -fsS http://127.0.0.1/ | head
- Install Certbot + NGINX Plugin
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
- Request a Certificate from Step CA and Let Certbot Configure NGINX
This command:
- registers an ACME account (first run),
- requests the certificate from Step CA,
- enables HTTPS in NGINX,
- and configures HTTP → HTTPS redirect.
Replace the email address:
sudo certbot --nginx -n \
-d test.maksonlee.com \
--server https://stepca.maksonlee.com/acme/acme-internal/directory \
--agree-tos --email you@maksonlee.com \
--redirect
Certificates are stored at:
/etc/letsencrypt/live/test.maksonlee.com/fullchain.pem
/etc/letsencrypt/live/test.maksonlee.com/privkey.pem
Verify HTTPS:
curl -fsS https://test.maksonlee.com/ | head
Expected: HTML for the default “Welcome to nginx!” page.
- Verify Renewal and the Issued Certificate
Confirm Certbot auto-renewal is scheduled (systemd timer)
systemctl status certbot.timer --no-pager
systemctl list-timers | grep certbot || true
Expected: certbot.timer is active (waiting) and has a future trigger time.
Simulate renewal against your Step CA ACME directory
sudo certbot renew --dry-run \
--server https://stepca.maksonlee.com/acme/acme-internal/directory
Expected: “all simulated renewals succeeded”.
Verify the certificate chain (client-side)
sudo openssl verify \
-CApath /etc/ssl/certs \
-untrusted /etc/letsencrypt/live/test.maksonlee.com/chain.pem \
/etc/letsencrypt/live/test.maksonlee.com/cert.pem
Expected: cert.pem: OK
Show issuer, validity period, and SAN
sudo openssl x509 -in /etc/letsencrypt/live/test.maksonlee.com/cert.pem \
-noout -issuer -dates -ext subjectAltName
Expected:
- Issuer = your Step CA Intermediate
- SAN includes
DNS:test.maksonlee.com notAftermatches your short-lived policy
Confirm NGINX is presenting the expected certificate
echo | openssl s_client -connect test.maksonlee.com:443 -servername test.maksonlee.com 2>/dev/null | \
openssl x509 -noout -issuer -dates -ext subjectAltName
Expected: same issuer / dates / SAN as the cert.pem output above.
Summary
You now have Step CA acting as an ACME v2 server, a client host that trusts your private PKI, Certbot issuing and renewing certs, and NGINX automatically configured for HTTPS using your Step CA-issued certificate:
https://stepca.maksonlee.com/acme/acme-internal/directory
Did this guide save you time?
Support this site