How to Manage Secrets Without a Cloud Vendor
How to manage secrets and environment variables without a cloud vendor: keep API keys and credentials secure on infrastructure you own, without a hosted vault bill.
You do not need a hosted secrets vault to keep API keys and credentials safe. You can manage secrets securely on infrastructure you own, with encrypted files, tight permissions, and a little discipline, and never send your most sensitive material to a third party at all. For a solo operator or a small team running a fleet, that is both cheaper and, in an important way, safer. Here is how I handle secrets across a portfolio without a vendor holding the keys.
The principle first: a secret should live in as few places as possible, be readable by as few processes as possible, and never sit in plaintext anywhere it does not have to. You can enforce all three on your own boxes.
Why not just use a hosted secrets manager
Hosted secret managers are fine tools, but for an owned stack they bring two problems. The first is philosophical and real: your most sensitive material, the keys that unlock everything else, now lives inside a third party. If the point of owning your stack is that no vendor can hold you hostage, handing them the master keys works against that, the same tension I get into in servers that cannot be held hostage.
The second is practical: another per-request, per-secret bill and another dependency that has to be up for your app to boot. For a fleet where you already control the boxes, you can get strong secret handling without adding either the exposure or the invoice.
Where secrets should actually live
Keep it simple and layered. Most apps need environment variables at runtime: database URLs, API keys, tokens. Those belong in an environment file on the box, owned by the app's user, with permissions locked so only that user can read it. Not in the code, not in the git repo, not in the container image. The file sits on the server, readable by the one process that needs it, and nothing else.
For anything you want encrypted at rest, keep the secrets in an encrypted file that gets decrypted only at deploy or boot time with a key you hold. That way the secret material in your repo or your backups is ciphertext, useless without the key. This pairs directly with owning your deploy pipeline, since the deploy is where secrets get placed on the box, which I cover in own your deploy pipeline.
How to keep secrets out of the places they leak
Secrets rarely leak from a vault. They leak from the careless places, and self-hosting does not exempt you from that discipline. Guard the usual suspects.
Never commit a secret to git, and scan for it so an accidental commit gets caught. Keep secrets out of logs; a framework that prints the full environment on error is a leak waiting to happen. Keep them out of client-side code, where anything shipped to the browser is public. And when you back up a box, make sure the backup is encrypted, because a plaintext env file inside an unencrypted backup is the same secret sitting somewhere new, a point I stressed in own your backups when you self-host.
Most breaches are not clever. They are a key in a public repo or a token in a log. Own those habits and you have handled the majority of the risk.
Rotate and scope like you mean it
Two habits separate a secure setup from a hopeful one. Rotate and scope.
Rotate the keys that matter on a schedule, and immediately if a person with access leaves or a machine is retired. Rotation is only painless if your deploy can push a new value everywhere in one motion, which is another reason to own the pipeline. Scope every credential to the least it needs: a database user that can only touch its own schema, an API key limited to the one service it calls, a token with a short life. Then a single leaked secret unlocks one small thing instead of everything. That least-privilege thinking is the same one behind isolating apps on one Postgres box under every app.
Fold secret handling into the platform
The reason this scales across twenty apps is that secret management is fleet infrastructure, built once. Each app gets its own locked env file, placed by the same deploy process, backed up encrypted by the same job. A new product inherits the pattern the day it ships. There is no per-app vault to configure and no per-app decision about where keys go.
I built that secret-handling flow into my hosting stack, HostSSH, for the same reason I built in shared databases and backups: an operator should not reinvent security every time they ship a company, and should not have to mail their master keys to a vendor to get it. You can manage secrets safely on your own infrastructure. Lock the files, keep them out of the leaky places, rotate and scope, and the keys to your kingdom stay in your hands, which is the whole point of owning your stack.