A password manager server fails quietly. Bitwarden's browser extensions and mobile apps keep a local copy of the vault and go on autofilling from it when the server disappears; the only symptom is a sync error most people never open. So a self-hosted Vaultwarden can be down for days before anyone notices, usually at the worst moment: a new device that cannot log in, or a password saved on the laptop that never reached the phone. This guide sets up external monitoring that catches the outage while it is happening, using the one endpoint Vaultwarden built for the purpose and a few signals around it.
Everything in the first two sections runs on CronAlert's free plan. The keyword check and the backup heartbeat need Pro ($5/month); each is marked.
What Vaultwarden gives you to check
Vaultwarden is a single Rust process serving the Bitwarden API, the web vault, and (if you enable it) the admin panel, usually behind a reverse proxy that terminates TLS. Four URLs matter for monitoring, and they behave differently:
| URL | Auth | What a 200 proves | Use |
|---|---|---|---|
/alive | none | Process up and a database connection was obtained | Primary monitor |
/api/config | none | API routes answering; JSON includes "name":"Vaultwarden" and the version | Keyword check (Pro) |
/ | none | Web vault static files served (if the web vault is enabled) | Optional |
/admin | token | Nothing useful: 200 whether locked, unlocked, or disabled | Inverse monitor |
The one to build on is /alive. In Vaultwarden's source the handler takes a database connection as a parameter purely so that, in the authors' words, "the alive healthcheck also verify the database connection." It returns a JSON string with the server's current time, supports HEAD as well as GET (the HEAD route exists specifically so uptime monitors do not fill the log with "no matching route" errors), and the official Docker image's own healthcheck uses it. A 200 from https://vault.example.com/alive therefore means: DNS resolved, TLS handshake succeeded, the reverse proxy forwarded the request, Vaultwarden is running, and it could reach SQLite, MySQL, or PostgreSQL. That is most of what can break.
Step 1: the /alive monitor
- In CronAlert, add an HTTP monitor with the URL
https://vault.example.com/alive. Use the public hostname your clients use, not an internal one, so the check follows the same path they do. - Leave the method as
GET(or chooseHEAD; both work), expected status200, timeout10seconds. A healthy Vaultwarden answers/alivein a few milliseconds; a ten-second wait means something is wrong. - Name it after the host. If you run Vaultwarden under a sub-path with
DOMAIN=https://example.com/vault, the endpoint is/vault/alive; the Docker healthcheck has the same gotcha.
The check interval is set by your plan: every 3 minutes on Free, every minute on Pro. Alerts go to whichever channels your team has enabled: email, push, Slack, Discord, Telegram, or a webhook. For a vault, push to your phone is the right default, since the person who needs to know is usually the person who runs the box.
If your proxy sits behind a Cloudflare Tunnel with Access in front, add the service-token headers that guide describes, or the monitor will follow the redirect to the Access login page and report green forever. A Vaultwarden behind Access needs to exempt the Bitwarden API paths anyway, since the apps cannot complete an Access login, so /alive is usually open.
Step 2: certificate expiry
Bitwarden clients refuse to talk to a server with an invalid certificate, so an expired certificate is a total outage with a confusing error on every device. SSL monitoring is part of every HTTP monitor on every plan: the /alive monitor you just created already watches the certificate on vault.example.com and alerts before it expires. If your renewal is automated (Caddy, Traefik, certbot), read monitoring Let's Encrypt renewals for what to do when the renewal job itself breaks; if clients also use a second hostname (a separate DOMAIN for the web vault, say), give it its own monitor.
Step 3: prove the admin panel is locked (inverse monitor)
The admin panel at /admin is enabled by setting ADMIN_TOKEN. It is the one page on a Vaultwarden server that can read every user's email, invite accounts, and change configuration, and the wiki is clear that the token should be an argon2 hash and that the page should not be exposed if you can avoid it. Monitoring it for uptime is pointless: with a token set and no session cookie, GET /admin returns a 200 login page; with the panel disabled, it returns a 200 plain-text message saying the panel is disabled. A status check cannot tell the two apart, and neither state is an outage.
What you can monitor is the lock. Most people restrict /admin at the reverse proxy to a LAN range or a VPN, so from the internet the proxy returns 403 (or 404 if you prefer not to admit the path exists). Create a monitor on https://vault.example.com/admin with the expected status set to 403. It stays green as long as the restriction holds and alerts the day a proxy config rewrite drops the rule and your admin login form is suddenly public. The custom-headers guide explains why any exact status between 100 and 599 is allowed and how these inverse monitors work.
If /admin is reachable from the internet by design, at least use a Pro keyword check for the login form so you know the panel is enabled and responding, and consider the restriction anyway.
Step 4: a keyword check on /api/config (Pro)
/alive proves the process and the database. It does not prove the API routes the clients use are being served, which is a different failure when a proxy rule or path prefix is wrong. Vaultwarden exposes GET /api/config without authentication: a JSON document the clients fetch on startup, with a "server" object ("name":"Vaultwarden"), the "version", the URLs the clients should use for the API, identity, and notifications, and "object":"config".
On Pro, add a monitor on https://vault.example.com/api/config with the assertion contains "name":"Vaultwarden". It fails if the proxy serves something else at that path, if a misconfigured DOMAIN makes the URLs wrong (open the body in the check result and read them), or if a reverse proxy in front starts returning its own 200 error page. Keyword monitoring covers the match types; each monitor carries one assertion, so this is a second monitor, not a setting on the first.
One thing not to do with this endpoint: do not use content changed on it. The body includes the version, which changes on every upgrade, and the gitHash, so you would be paging yourself for routine updates.
Step 5: a heartbeat on the backup (Pro)
A vault with no working backup is one disk failure from losing every password you own. Vaultwarden's wiki is specific: with the default SQLite database, use sqlite3's .backup command rather than copying the live file, and also back up attachments/, sends/, the rsa_key* files (they sign the login tokens; lose them and every device logs out), and config.json if you use the admin panel. Then make the job report that it ran:
# /etc/cron.daily/vaultwarden-backup
set -euo pipefail
DATA=/srv/vaultwarden/data
DEST=/srv/backups/vaultwarden/$(date +%F)
mkdir -p "$DEST"
sqlite3 "$DATA/db.sqlite3" ".backup '$DEST/db.sqlite3'"
cp -r "$DATA/attachments" "$DATA/sends" "$DEST"/ 2>/dev/null || true
cp "$DATA"/rsa_key* "$DATA/config.json" "$DEST"/ 2>/dev/null || true
tar -C "$DEST" -czf "$DEST.tar.gz" . && rm -r "$DEST"
# ship it somewhere else: rclone copy "$DEST.tar.gz" remote:vaultwarden/ ...
curl -fsS --max-time 10 --retry 3 https://cronalert.com/api/heartbeat/YOUR-TOKEN Create a heartbeat monitor in CronAlert with an expected interval of 1 day and a grace period of a few hours, and paste its ping URL into the last line. set -e means any failing step aborts the script before the curl, so a missed ping is a failed backup, not just a skipped one. Monitoring database backups goes deeper, including a restore test; heartbeat grace periods explains how to size the window.
If the database is MySQL or PostgreSQL instead, swap the sqlite3 line for mysqldump or pg_dump; the heartbeat is the same.
A vault that is not on the internet
Plenty of people run Vaultwarden only on a Tailscale or WireGuard network or a home LAN, and that is a sound choice. CronAlert's HTTP checks run from Cloudflare's network and cannot reach 100.x.y.z or 192.168.x.y, and a bare IP with no hostname cannot be the target of an HTTP monitor at all. The answer is the same heartbeat pattern, pointed at /alive from inside:
# every 5 minutes on any always-on machine inside the network
*/5 * * * * curl -fsS --max-time 10 http://vault.tailnet.ts.net/alive >/dev/null && curl -fsS --max-time 10 https://cronalert.com/api/heartbeat/YOUR-TOKEN Set the heartbeat's expected interval to 5 minutes and a grace of 5 to 10 minutes. The first curl fails on anything from a dead container to a missing database, the && stops the ping, and the heartbeat alerts. The machine running the cron is now a dependency, which is why you pick one that is always on (a NAS, a Raspberry Pi, the Tailscale exit node), and why that machine should have its own monitor.
What not to monitor
- The login endpoint. Do not script logins against
/identity/connect/tokento "prove" authentication works. Every attempt is a login event in the logs, failed attempts count toward Vaultwarden's login rate limiting, and the health signal you want is already in/alive. - The web vault with a keyword.
/serves a static single-page app whose HTML is mostly script tags. If you want a check on it, a 200 is enough; the useful JSON is at/api/config. - Mobile push. If you enabled push notifications (
PUSH_ENABLED=truewith an installation ID and key from Bitwarden), delivery goes through Bitwarden's relay. A broken relay delays sync notifications but does not affect vault availability, and nothing about it is visible from outside. Not worth a monitor. - SMTP. Vaultwarden emails invitations, verification codes, and email 2FA. A broken mail setup is invisible to HTTP checks; the admin panel's diagnostics page has an SMTP test, and if the relay is one you run, monitor it directly.
Reading an alert
| Alert | Likely cause | First thing to check |
|---|---|---|
/alive timeout or connection error | Host, container, or proxy down | docker ps; proxy logs |
/alive 502 or 503 | Proxy up, Vaultwarden process down or restarting | Container logs; disk space (SQLite needs room to write) |
/alive 500 | Database unreachable: pool exhausted, MySQL/Postgres down, locked SQLite | Database container; DATABASE_URL |
| Certificate alert | Renewal stopped | Caddy/Traefik/certbot logs; DNS for the ACME challenge |
/admin monitor fails (expected 403, got 200) | Proxy allowlist removed | The proxy config; restore the rule, then check the admin log for logins |
/api/config keyword missing | Proxy serving a different app or error page at that path | The response body in the check result |
| Backup heartbeat overdue | Cron not running, sqlite3 missing after an image change, destination full | Run the script by hand |
Frequently asked questions
Does /alive need the web vault enabled?
No. It is registered regardless of WEB_VAULT_ENABLED; only / and the static files depend on the web vault.
Will a 3-minute check interval bother the server?
No. /alive does a pool checkout and returns a timestamp; it is far cheaper than a single client sync, and the Docker healthcheck hits it every 30 seconds anyway.
Can I monitor the WebSocket notifications endpoint?
Since Vaultwarden 1.29 the notifications hub is served on the main port, so a broken WebSocket usually means a proxy upgrade-header problem rather than a server problem. HTTP monitors cannot speak WebSocket; monitoring WebSockets covers the options. In practice, if /alive is green and sync works, the hub is almost always fine.
What about a status page for the people I share the vault with?
Every plan includes a public status page; put the /alive monitor on it and family or team members can see for themselves whether the vault is up before messaging you.
Is any of this on a paid plan?
The /alive monitor, certificate monitoring, the inverse /admin monitor, and the status page are free. The /api/config keyword check and the heartbeats (backup and VPN-only vault) need Pro at $5/month; see monitoring on a budget.
Get started
One monitor on /alive catches the outage your clients hide, the same monitor watches the certificate, an inverse monitor keeps /admin honest, and a heartbeat proves the backup ran. Create a free CronAlert account and add the /alive check first. Related reading: monitoring Docker self-hosted services, monitoring Nextcloud and Immich, monitoring behind a reverse proxy, SSL certificate monitoring, and cron job heartbeats.