Running Your Own Internal Certificate Authority With step-ca

Home server rack representing a private certificate authority with a root CA certificate on screen

Running your own certificate authority with step-ca gives you an ACME server you fully control — the same automated workflow as Let’s Encrypt, but the certificates never touch a third party and can live for hours instead of months. It is the right tool when you want total ownership of your PKI: air-gapped segments, zero-trust access, or certificates for names and IPs a public CA will never sign. For most homelabs it is a deliberate step up, not the default.

On my network step-ca runs in its own LXC container on the management VLAN, deliberately walled off, issuing short-lived certificates to the services that need them. The trade is stark and worth stating up front: you gain complete control and lose the free “already trusted everywhere” property of a public CA. Everything below is about earning back that trust cleanly.

Home server rack representing a private certificate authority with a monitor showing a root CA certificate

When Does Running Your Own CA Make More Sense Than Let’s Encrypt?

Run your own CA when you need certificates a public CA cannot or will not issue — for raw IP addresses, for a truly air-gapped network, or with lifetimes measured in hours for a zero-trust model. If none of those apply, the Let’s Encrypt wildcard over DNS-01 is simpler and I would reach for it first. An internal CA is power you should only take on with a reason.

The concrete cases where a private CA wins: a lab segment with no internet access at all, where even the DNS-01 challenge to Let’s Encrypt is impossible; a desire for certificates that expire in an hour so a stolen key is worthless almost immediately; or the need to issue for names that are not under any domain you own. A public CA is bound by rules — it validates public domains and issues 90-day certificates, full stop. Your own CA answers only to you.

The cost is trust distribution. A Let’s Encrypt certificate works on a brand-new phone the instant it connects. A step-ca certificate is rejected by that same phone until you install your CA’s root, which is the whole subject of trusting your own CA on phones, laptops, and browsers. Many homelabs end up running both: Let’s Encrypt for the general case, an internal CA for the handful of services with special needs. That is exactly the split I run, and I mapped the full decision in the internal HTTPS guide.

What Is step-ca and Why Use It Over openssl?

step-ca is an open-source online certificate authority from Smallstep that speaks ACME (RFC 8555), so your internal services renew certificates automatically using the exact same clients they would use for Let’s Encrypt — instead of you hand-signing certificates with openssl forever. That automation is the entire reason to choose it. A hand-rolled openssl CA works for one certificate and becomes a chore by the fifth.

Close-up of a terminal issuing an internal certificate with a command-line CA tool

The elegant part is protocol compatibility. Because step-ca exposes an ACME endpoint, a service running Caddy, certbot, or acme.sh can point at your CA and enrol with no special code — it just uses a different directory URL. step-ca also supports other provisioner types (token-based, OIDC, and more), but ACME is the one that makes it feel like a private Let’s Encrypt. The companion step CLI handles bootstrapping and manual issuance when you need it.

Compared to a pile of openssl commands, step-ca gives you automated renewal, a real intermediate-CA structure, configurable certificate policies, and short-lived certificates without manual effort. openssl is fine for generating a one-off key or inspecting a certificate — I still use it daily for that — but it is not a CA you would want to operate. step-ca is built to be operated. That difference is the whole point.

How Do You Deploy step-ca Safely in a Homelab?

Deploy step-ca in an isolated container on your management segment, protect the CA private key above all else, and use a two-tier root-and-intermediate structure so the root can stay offline. The CA key is the master key to your entire internal trust, so its handling is the single most important security decision in this whole setup. Treat it accordingly.

A single small isolated server node on a management network segment with a labeled ethernet cable

The structure step-ca sets up by default is the right one: a root CA that signs a single intermediate CA, and the intermediate is what actually issues your service certificates. This matters because you can keep the root key offline — encrypted, off the running server, ideally on separate media — while only the intermediate stays online to do daily issuance. If the online intermediate is ever compromised, you revoke it and re-issue from the still-safe root, rather than rebuilding your entire trust from scratch. That is the reason PKI uses intermediates at all.

On the network side, I run the CA in its own LXC container on the MANAGEMENT VLAN with default-deny firewall rules: only the reverse proxy and the specific hosts that enrol may reach the ACME port, and nothing on the IoT or guest segments can touch it. Issuance and use are separated by firewall rule. A device on a locked-down VLAN can present a certificate my proxy trusts, but it can never reach the CA to request a new one. Same instinct I apply to every hobby on the rack — scope access to exactly what needs it, deny the rest.

How Short Should Internal Certificate Lifetimes Be?

Short — hours, not months — because the entire security advantage of running your own CA is that a leaked certificate becomes useless almost immediately. step-ca’s automated provisioners default to a 24-hour certificate lifetime for exactly this reason. When renewal is fully automated, a short lifetime costs you nothing and buys you a tiny blast radius.

The logic is the reverse of the public-CA world. Let’s Encrypt issues 90-day certificates partly because manual renewal at shorter intervals would be painful. But when your own ACME server renews certificates automatically many times a day, there is no operational reason to let a certificate live for months — and every reason not to. A 24-hour certificate that leaks is worthless by tomorrow; a 90-day one is a 90-day liability. You can tune step-ca’s default, minimum, and maximum durations per provisioner to match how aggressive you want to be.

My rule: automate renewal first, then shorten lifetimes as far as your services tolerate. A service that renews cleanly on a schedule can happily run 24-hour certificates. If something cannot renew reliably that often, that is a signal the automation needs fixing, not that the lifetime should be long. Short-lived certificates turn “revocation” — which is notoriously hard to make work in practice — into simply “wait for it to expire,” which always works.

Frequently Asked Questions

Can step-ca issue certificates for IP addresses and internal names?

Yes. Because it is your own certificate authority, step-ca can issue certificates for raw IP addresses and any internal name you choose, which public authorities like Let’s Encrypt cannot do. This is one of the main reasons to run a private CA instead of, or alongside, a public one.

Do services need special software to use step-ca?

No. Because step-ca exposes an ACME endpoint, standard ACME clients such as Caddy, certbot, and acme.sh can enrol against it by pointing at its directory URL. Your services use the same automated renewal workflow they would use with Let’s Encrypt, just aimed at your own CA.

What is the single most important thing to protect when running my own CA?

The CA private key. It is the master key to your entire internal trust, so anyone who steals it can impersonate any service. Use a root-and-intermediate structure so the root key can stay offline, keep the CA on an isolated network segment, and restrict who can reach its issuance endpoint.

Why would I want certificates that only last 24 hours?

Because a short lifetime shrinks the damage a leaked certificate can do. When your own CA renews certificates automatically, a 24-hour certificate that is stolen becomes useless by the next day, whereas a long-lived one is a lasting liability. Short lifetimes also make revocation a non-issue, since certificates simply expire.

The Mistake: I Put the Root Key on the Running Server

My first step-ca deployment kept everything — root key, intermediate key, running service — in one place, because it was easier and it worked. It did work, right up until I thought hard about what would happen if that container were compromised. The answer was ugly: an attacker would hold the root key, and with it the ability to mint a trusted certificate for anything on my network, forever. There is no clean recovery from a stolen root except rebuilding trust on every device.

I rebuilt it properly: root key generated, used to sign the intermediate, then encrypted and moved off the server entirely, leaving only the intermediate online for daily issuance. The relief was physical — the quiet knowledge that the worst-case blast radius had shrunk from “total compromise” to “revoke the intermediate and re-issue.” The lesson is the oldest one in PKI: the root exists to be protected, not to be online. Keep it offline from day one and you never have to do the anxious rebuild I did.

What I’d Do Starting Today

Only stand up an internal CA if you have a real reason — an air-gapped segment, a zero-trust goal, or a need for certificates a public CA won’t sign. If you do, deploy step-ca in an isolated container on your management network, generate a root-and-intermediate pair, move the root key offline immediately, and enrol services over ACME with 24-hour lifetimes. Then budget the afternoon to install the root on your devices — because until you do, nothing you issue is trusted.

Keep Building

Leave a Comment

Your email address will not be published. Required fields are marked *