What it is
Vaultwarden is a Rust reimplementation of the Bitwarden server. It speaks the same API as the official one, so all the official Bitwarden clients — desktop app, browser extension, iPhone, CLI — work against it with no patches. It's tiny, fast, and was clearly written by someone who didn't want to run a JVM on a Raspberry Pi.
Why I run it
A password manager is the single piece of infrastructure where "I'd rather not depend on a SaaS" turns into "I'd rather own this completely." Bitwarden the company is reputable. I just don't want my entire credential graph living somewhere I can't physically point at.
Self-hosting also means I can give it a real backup story (PBS snapshots of the whole container, daily), trust it with non-password recovery material and service credentials, and use it as the canonical store for every other service in this catalog. The auth section of every other service doc on this site is, in effect, a pointer to a Vaultwarden entry.
How I use it
The Bitwarden browser extension is open in every browser I use, configured to point at my internal URL. Same with the desktop app and the iOS app. Day to day the experience is identical to using hosted Bitwarden — autofill in the browser, generated passwords on signup, biometric unlock on the phone.
It also stores things that aren't strictly passwords: recovery notes, service credentials, and automation secrets that need to exist somewhere durable without being committed to a repo. Every other service doc references it by entry path.
Setup notes
- Host: a dedicated LXC on the Optiplex node, separate from any other workload. The migration from a shared edge LXC to its own home was deliberate — I want this one container to have the smallest possible blast radius from a neighbour going sideways.
- Reverse proxy: behind NPM. TLS terminates at NPM; the upstream connection is plain HTTP on the internal network. The Vaultwarden web vault uses the browser's Subtle Crypto API, which only works in a "secure context" — meaning HTTPS or localhost. Accessing it over plain HTTP loads the page but throws a Subtle Crypto warning and refuses to do anything useful. Always access via the proxied HTTPS hostname.
- Backups: PBS snapshots the whole container daily. I also keep an ad-hoc tarball script for the Docker volume that I can run before any planned upgrade.
- Update cadence: strictly manual, image strictly pinned. Explained in the runbook — this is the lesson, not a stylistic preference.
Runbook
- Healthy looks like: web vault loads over HTTPS with the padlock, login succeeds, items render. The Bitwarden browser extension autofills on a real site. Uptime Kuma's two monitors (one through the proxy, one direct to the container) are both green.
- Pin the image. Never use
:latest. I learned this loudly during a container migration::latestresolved to a newer version mid-migration, the new web-vault frontend shipped a rendering change that didn't agree with my browser's cached state, and I got a black screen after login. The login itself worked, the sync API returned 1.3 MB of vault data, the browser extension autofilled fine on real sites — but the web UI refused to render any items. Rolling the image back to the previous known-good tag fixed it instantly. For anything stateful,:latestis not a version, it's a surprise generator. Pin the tag, treat upgrades as planned events, test in a private window after every bump. - Browser extension: "Syncing failed": the extension's Server URL doesn't match the cert's name, or the cert isn't trusted by the OS. Check both — extension settings → Server URL should exactly match your Vaultwarden URL, and the system trust store should include your cert.
- Web vault loads but shows the Subtle Crypto warning: you're on plain HTTP. Switch to the HTTPS hostname.
- Login works, then black screen with no items: classic frontend version mismatch. The fast diagnostic is to try the browser extension on a real site — if autofill works, the server is fine and it's a UI cache problem. Clear site data for the vault hostname, hard-reload, or roll the image back.
- Edge / Chrome still says "Not secure" after importing the cert: Chromium browsers cache certificate trust per session aggressively. Close every window and kill any lingering browser process before reopening — restarting from a still-running process doesn't always re-read the trust store.
- Where logs live:
docker logs vaultwardenon the host LXC.
The single most useful diagnostic principle for this service: test the browser extension on a real site first. If autofill works, the server is delivering data correctly and you're chasing a frontend or cert problem, not a server problem. That one check has saved me hours.