Your Reverse Proxy Is Now Your Accidental CA
Public CAs walked away from client auth in February. The trust scope didn't disappear, it moved into whichever box was already terminating TLS.
May 20, 2026 · [cyphrs] Team · 11 min read
"Is it possible to generate and upload client certificates to my mobile device?"
That's a question from r/PangolinReverseProxy this week. It is, on the surface, a small thread. Eight upvotes, four comments, the kind of thing that scrolls past most weeks without anyone noticing. The operator has client mTLS working through Cloudflare's edge as a stopgap and wants to replicate the setup in their self-hosted reverse proxy for Home Assistant and Immich. They want certs they can install on their phone and tablet so the public internet path to their internal apps stays authenticated.
"Is it possible to generate and upload client certificates to my mobile device that then I can use over the public internet?"
r/PangolinReverseProxy, "Client mTls certificate," 2026-05-17
The answer is yes. The longer answer, the one nobody quite says out loud in the replies, is that the moment you do this you are running a private certificate authority. The reverse proxy holds the trust scope. The reverse proxy issues the leaves. The reverse proxy's keys are now a security boundary for everything sitting behind it. There is nothing wrong with any of that, in principle. The problem is that almost no operator who lands on this pattern recognises that they have just stood up a CA, and so almost none of them write down the things you would write down if you were standing one up on purpose.
This is what the post-public-ClientAuth world looks like in 2026. Not a category collapse. A quiet diffusion of trust responsibility into boxes that were never marketed as certificate authorities, owned by people who would not describe themselves as PKI engineers, with the documentation living mostly in someone's Bash history.
Why the trust scope ended up in your reverse proxy
Public CAs stopped issuing certificates with the TLS Client Authentication EKU in February. Let's Encrypt removed it from the default ACME profile on 11 February. The Chrome Root Program deadline in June 2026 requires that client and server authentication live in entirely separate PKI hierarchies, so every other public CA followed suit on their own schedule. We wrote about the why in "Why Public CAs No Longer Issue Client Certificates". The short version: the browser ecosystem decided ambiguity between server and client identity was a security smell, and the public CAs had no economic reason to fight that call.
What the explainers tend to skip is what happened next on the operator side. Lots of organisations were quietly relying on public ClientAuth certs for things that nobody had ever called mTLS in a design document. A vendor portal pinning the leaf for a B2B integration. A mobile app that issued itself a client cert during onboarding. A reverse proxy in front of a SaaS appliance, using ClientAuth as a poor-person's bot-mitigation control. None of those teams woke up on 12 February and said, "we should architect a private CA programme." They reached for whatever was already in the box that could still issue them a cert.
For a meaningful slice of those teams, the thing already in the box was their reverse proxy. Or their edge platform. Or the Compose file with three openssl commands and a comment that says "TODO: rotate before 2027."
Three patterns in the wild
If you spend a couple of hours reading the relevant subreddits this month, you can pick out the three shapes that account for almost all the accidental-CA setups people are landing on. They are not equivalent, and the failure mode each one inherits is different.
Pattern 1 · The edge platform as CA
Cloudflare's ClientAuth feature is the canonical example. You enable the option in the dashboard, Cloudflare provisions an internal CA tied to your zone, you download the client cert, you install it on the device. From the operator's perspective it feels like a setting, not a CA. From a trust-architecture perspective, Cloudflare is now the root of trust for every authenticated session your application accepts.
The failure mode is migration. The day you decide to move off Cloudflare, you re-issue every device. The day Cloudflare changes the feature pricing or scope, you have a one-vendor dependency on a control plane you do not run. Useful as a stopgap, structurally a vendor lock-in if it becomes the long-term answer.
Pattern 2 · ACME-anywhere from the reverse proxy
Traefik and Caddy will both do ACME against a private CA you configure (step-ca being the most common). The reverse proxy holds the relationship with the CA, fetches leaves, hot-reloads them. For server-side TLS this is genuinely a good pattern. For client-side, where you also want to issue mTLS leaves for end-user devices, the reverse proxy is often pressed into being the CA itself rather than just an ACME client.
The failure mode is scope creep. A reverse proxy is software designed to terminate TLS and route requests. It is not designed to be a CA. The audit logs are wrong shape for a CA. The key custody story is wrong shape for a CA. When the proxy host gets compromised, you discover the CA was on the same host.
Pattern 3 · The Compose-file CA
Three openssl commands in a docker-compose.yml. A root key generated once, six months ago. A leaf signing script that gets invoked by hand when a new device joins. There is no rotation. There is no revocation. The trust scope is "every device that someone ran the script for, until the root expires."
The failure mode is everything. This is what the r/selfhosted "how do you manage SSL for internal-only services" thread (64 comments this week) is full of. People know it is wrong. They cannot find an answer that is not either a full PKI deployment or step-ca, both of which feel heavier than the problem they are trying to solve.
All three of these patterns share a common shape, which is the part worth dwelling on. Each one moves the trust scope into a box that was not architected to hold it. The decision to do this is almost never explicit. The diagram on the whiteboard still says "reverse proxy" or "edge" or "this little compose file." The diagram in cryptographic reality says "CA."
A reverse proxy that issues certs is a CA, whether you wrote it down or not
Here is a useful thought experiment. Take whatever box is currently issuing your client certificates and ask, for each of the following questions, what the answer is. Not in theory. In the actual configuration on the actual host, today.
| What a CA has | What your reverse proxy probably has |
|---|---|
| A documented trust scope (who is in, who is out) | An implicit list defined by "whoever has been issued a leaf" |
| A key custody policy (where the root key lives, who can touch it) | The same filesystem as the web-facing process |
| A rotation calendar for the root and intermediates | Whatever the openssl command happened to set, often ten years |
| A revocation mechanism (CRL, OCSP, or short-lived issuance) | None, or a CRL nobody publishes |
| An issuance audit log | Shell history, if you are lucky |
| A named owner who pages when it breaks | Usually whoever set the proxy up, often no longer at the company |
If the right-hand column describes your setup, then the architecture you are running is a CA. It is just a CA whose security properties are accidental rather than designed. Some of those properties will be fine. Some will be fine until they aren't, and then they will be in your incident report.
The thing nobody likes about this framing is that it sounds like a sales pitch for a PKI engineer. It isn't really. It is a request to draw the diagram you actually have, instead of the one on the whiteboard.
Why this is happening now, specifically
The accidental-CA pattern is not new. The new part is the volume. Three things compound in 2026 that did not all overlap before.
The first is the ClientAuth removal. Public CAs have been the path of least resistance for any team that needed a TLS cert for anything for fifteen years. Once that lane closed for client authentication, the demand for client certs did not go down. It just had to go somewhere else.
The second is the SC-081 validity cliff. With 200-day validity now in force and a 47-day window coming in 2029, the cost of an ad-hoc renewal process is going up sharply. The team that used to manually rotate three certs a year is about to be manually rotating thirty, which is the point at which someone reaches for a script, which is the point at which the script becomes the de facto issuing policy.
The third is the rise of OAuth-style preconditions on HTTPS. A whole category of internal tools now refuse to do federated login, or device attestation, or webhooks, unless the endpoint is served over a properly trusted TLS connection. The r/selfhosted operator who opened this week's "internal only services" thread (32 up, 64 comments) named OAuth compatibility as the reason they were trying to solve HTTPS for Prowlarr at home. The same dynamic applies in mid-market enterprises. HTTPS is no longer optional for internal tools, even when the internal tool is, in a network sense, completely private.
Stack those three on top of each other and you get the current moment: thousands of operators independently solving the same problem with whatever tool was on hand, and most of them landing on reverse-proxy-as-CA without a clean alternative in the mid-market.
A note on what the platform vendors are saying about this
CyberArk (carrying the Venafi product line now) published a piece this month called "TLS certificate management in 2026: the endless game of Whack-A-Cert." The framing is honest about the operational burden the 200-day cohort creates. The framing is also revealing about what kind of product is being sold against the problem. Whack-A-Cert is a metaphor about discovery, automation, dashboards. Platform-level certificate lifecycle management for public certs.
That product category is real and the work it does is genuinely useful. It is also not the same product as "give me a small private CA, with sane defaults, that issues mTLS-capable leaves and rotates them, and let me not be the PKI admin." CLM platforms answer the question "is this renewing on time?" They do not answer "is this even on the right trust path?" Those are different products. The first one has incumbents. The second one is the gap the reverse-proxy-as-CA pattern is filling, badly. The Mongoose mTLS bypass earlier this year is the kind of failure mode you get when a box that wasn't designed to be a CA also wasn't designed to enforce client-cert validation, and the two omissions compound.
What drawing the diagram on purpose actually looks like
If you have an accidental CA today and you want to upgrade it into one you can defend, here is the shape of the work, ordered by how cheaply it pays off. None of this requires a procurement cycle. Most of it can be done by the same engineer who set up the reverse proxy.
Start with the inventory. Open the reverse proxy config. List every device, application or partner that currently holds a leaf cert issued out of it. Note the issuance date. Note the expiry. Note what would happen, operationally, if any of those leaves stopped working tomorrow. This step usually surprises people. The set is bigger than they expected, and roughly a third of the entries are things nobody is still using but nobody is willing to delete.
Then move the root off the host that terminates TLS. Even if you stay with the same toolchain (step-ca, Smallstep, or a hand-rolled CA), put the signing key on a different machine, ideally one with no inbound network exposure. If a single compromise of the proxy host today gives an attacker both the running keys and the root, that is the easiest thing to fix in one afternoon.
Write down the rotation calendar. The root probably has a ten-year validity, set when you generated it, which means there is no urgency, which means it will be in a panic in 2032. Write down what you want the rotation to look like. Cross-signing the new root against the old one for an overlap period is the standard play. The hard part is not the cryptography, it is making sure every device that holds the current root trusts the new one before the old one stops being honoured.
And add revocation, even if it is just short-lived issuance. The ability to revoke a leaf is the difference between "we lost a phone" being a paragraph in a runbook versus a paragraph in a postmortem. Short-lived leaves (24 hours, 7 days) with automatic re-issuance against a healthy device-attestation check are operationally simpler than CRL or OCSP for this scale of CA, and they remove the question entirely.
The choice you are actually making
The honest version of this article is shorter than the version you just read. If you are issuing client certificates today out of anything that was not designed to be a CA, you have already made an architectural choice. The choice was made for you when public CAs left the ClientAuth lane and the easiest path forward happened to run through a box that was already on the network. There is no judgment in that. The diffusion was structural.
The choice still in front of you is whether to leave the architecture accidental or to draw it on purpose. The accidental version works most of the time and fails in interesting ways the rest of the time. The on-purpose version takes a couple of weekends of engineering work, asks you to write down things nobody likes writing down, and then mostly disappears into the background.
The reframe
If your reverse proxy issues certificates, it is a certificate authority. Whether or not anybody at your organisation has used those words to describe it. The work is not "should we have one." You have one. The work is whether the one you have is the one you would build if you were starting fresh, knowing what you know now.
The r/PangolinReverseProxy operator will probably figure it out. They will land on step-ca, or smallstep, or they will keep Cloudflare's ClientAuth running as the long-term solution and accept the vendor coupling that comes with it. They will not, statistically, end up writing a runbook for any of it. The accidental CA will keep working, until one day it doesn't.
That is the day the rest of this conversation matters. Better to have it now.
Related reading on the public-to-private trust split: