No description
Find a file
2026-04-25 03:53:26 +00:00
.cargo Login to vault 2025-09-21 11:35:13 +05:30
.github/workflows chore: add read permissions to workflows for backup, deploy, and push actions 2026-04-23 13:32:00 +00:00
docs chore: update Web Vault version to v2026.3.1 in documentation and workflows 2026-04-23 12:09:34 +00:00
migrations feat: add archiving support 2026-04-12 09:04:53 +00:00
public/css fix: ensure directory creation before copying vaultwarden.css in deployment scripts and documentation 2026-04-12 09:04:53 +00:00
scripts chore: update Node.js and wrangler version in deployment workflows 2026-04-13 16:08:00 +00:00
sql feat: add archiving support 2026-04-12 09:04:53 +00:00
src fix: update metadata of attachments while updating a cipher 2026-04-25 03:41:44 +00:00
.gitignore chore: update .gitignore 2026-04-12 09:04:53 +00:00
AGENTS.md docs: update project structure in AGENTS.md 2026-04-12 09:04:53 +00:00
Cargo.lock chore: update version to 0.6.1 2026-04-25 03:53:26 +00:00
Cargo.toml chore: update version to 0.6.1 2026-04-25 03:53:26 +00:00
LICENSE Create LICENSE 2025-09-22 03:02:12 +05:30
README.md chore: update Web Vault version to v2026.3.1 in documentation and workflows 2026-04-23 12:09:34 +00:00
rust-toolchain.toml chore: update and lock dependencies 2025-12-14 14:45:31 +00:00
SECURITY.md docs: add SECURITY.md 2026-01-08 08:48:22 +00:00
wrangler.toml chore: update dependencies 2026-04-23 09:10:43 +00:00

Warden: A Bitwarden-compatible server for Cloudflare Workers

Powered by Cloudflare License Deploy to Cloudflare Workers

This project provides a self-hosted, Bitwarden-compatible server that can be deployed to Cloudflare Workers for free. It's designed to be low-maintenance, allowing you to "deploy and forget" without worrying about server management or recurring costs.

Why another Bitwarden server?

While projects like Vaultwarden provide excellent self-hosted solutions, they still require you to manage a server or VPS. This can be a hassle, and if you forget to pay for your server, you could lose access to your passwords.

Warden aims to solve this problem by leveraging the Cloudflare Workers ecosystem. By deploying Warden to a Cloudflare Worker and using Cloudflare D1 for storage, you can have a completely free, serverless, and low-maintenance Bitwarden server.

Features

  • Core Vault Functionality: Create, read, update, and delete ciphers and folders.
  • File Attachments: Optional Cloudflare KV or R2 storage for attachments.
  • Bitwarden Send: Share encrypted text or files via a link.
  • Device Management: View and revoke active sessions.
  • Live Sync & Push Notifications: Real-time vault updates via WebSocket and mobile push.
  • TOTP Support: Store and generate Time-based One-Time Passwords.
  • Bitwarden Compatible: Works with official Bitwarden clients.
  • Free to Host: Runs on Cloudflare's free tier.
  • Low Maintenance: Deploy it once and forget about it.
  • Secure: Your encrypted data lives in your Cloudflare D1 database.
  • Easy to Deploy: Get up and running in minutes with the Wrangler CLI.

Attachments Support

Warden supports file attachments using either Cloudflare KV or Cloudflare R2 as the storage backend:

Feature KV R2
Max file size 25 MB (hard limit) 100 MB (By request body size limit of Workers)
Credit card required No Yes
Streaming I/O Yes Yes

Backend selection: R2 takes priority — if R2 is configured, it will be used. Otherwise, KV is used.

See the deployment guide for setup details. R2 may incur additional costs; see Cloudflare R2 pricing.

Bitwarden Send

  • Text Send: Enabled by default, no extra configuration required.
  • File Send: Requires a storage backend (KV or R2), same as attachments.

Note

Due to the D1 single-row size limit of 2 MB, the maximum text Send size is approximately 1.8 MiB. Additionally, the /api/sync endpoint serializes all of the current user's Sends into the response. A large number of Sends or very large text Sends will significantly increase CPU time and response size.

Current Status

This project is not yet feature-complete, and it may never be. It currently supports the core functionality of a personal vault, including TOTP. However, it does not support the following features:

  • Sharing
  • 2FA login (except TOTP)
  • Emergency access
  • Admin operations
  • Organizations
  • Other Bitwarden advanced features

There are no immediate plans to implement these features. The primary goal of this project is to provide a simple, free, and low-maintenance personal password manager.

Compatibility

  • Browser Extensions: Chrome, Firefox, Safari, etc. (Tested 2026.3.0 on Chrome)
  • Android App: The official Bitwarden Android app. (Tested 2026.4.0)
  • iOS App: The official Bitwarden iOS app. (Tested 2026.4.0)

Demo

A demo instance is available at warden.qqnt.de.

You can register a new account using an email ending with @warden-worker.demo (The email does not need verification).

If you decide to stop using the demo instance, please delete your account to make space for others.

It's highly recommended to deploy your own instance since the demo can hit the rate limit and be disabled by Cloudflare.

Getting Started

Frontend (Web Vault)

The frontend is bundled with the Worker using Cloudflare Workers Static Assets. The GitHub Actions workflows download a pinned bw_web_builds (Vaultwarden web vault) release (default: v2026.3.1) and deploy it together with the backend. You can override it via GitHub Actions Variables (BW_WEB_VERSION for prod, BW_WEB_VERSION_DEV for dev), or set it to latest to follow upstream.

How it works:

  • Static files (HTML, CSS, JS) are served directly by Cloudflare's edge network.
  • API requests (/api/*, /identity/*) are routed to the Rust Worker.
  • No separate Pages deployment or domain configuration needed.

UI overrides (optional):

  • This project ships a small set of "lightweight self-host" UI tweaks in public/css/.
  • In CI/CD (and optionally locally), we apply them after extracting bw_web_builds:
    • mkdir -p public/web-vault/css/ && cp public/css/vaultwarden.css public/web-vault/css/

Note

Migrating from separate frontend deployment? If you previously deployed the frontend separately to Cloudflare Pages, you can delete the warden-frontend Pages project and re-setup the router for the worker. The frontend is now bundled with the Worker and no longer requires a separate deployment.

Warning

The web vault frontend comes from Vaultwarden and therefore exposes many advanced UI features, but most of them are non-functional. See Current Status.

Configure Custom Domain (Optional)

The default *.workers.dev domain is disabled by default, since it may throw 1101 error. You can enable it by setting workers_dev = true in wrangler.toml.

If you want to use a custom domain instead of the default *.workers.dev domain, follow these steps:

Step 1: Add DNS Record

  1. Log in to Cloudflare Dashboard
  2. Select your domain (e.g., example.com)
  3. Go to DNSRecords
  4. Click Add record:
    • Type: A (or AAAA for IPv6)
    • Name: your subdomain (e.g., vault for vault.example.com)
    • IPv4 address: 192.0.2.1 (this is a placeholder, the actual routing is handled by Worker)
    • Proxy status: Proxied (orange cloud icon - this is required!)
    • TTL: Auto
  5. Click Save

Important

The Proxy status must be "Proxied" (orange cloud). If it shows "DNS only" (gray cloud), Worker routes will not work.

Step 2: Add Worker Route

  1. Go to Workers & Pages → Select your warden-worker
  2. Click SettingsDomains & Routes
  3. Click AddRoute
  4. Configure the route:
    • Route: vault.example.com/* (replace with your domain)
    • Zone: Select your domain zone
    • Worker: warden-worker
  5. Click Add route

Built-in Rate Limiting

This project includes rate limiting powered by Cloudflare's Rate Limiting API. Sensitive endpoints are protected:

Endpoint Rate Limit Key Type Purpose
/identity/connect/token 5 req/min Email address Prevent password brute force
/api/accounts/register 5 req/min IP address Prevent mass registration & email enumeration
/api/accounts/prelogin 5 req/min IP address Prevent email enumeration

You can adjust the rate limit settings in wrangler.toml:

[[ratelimits]]
name = "LOGIN_RATE_LIMITER"
namespace_id = "1001"
# Adjust limit (requests) and period (10 or 60 seconds)
simple = { limit = 5, period = 60 }

Note

The period must be either 10 or 60 seconds. See Cloudflare documentation for details.

If the binding is missing, requests proceed without rate limiting (graceful degradation).

Configuration

CPU offloading (via Durable Objects)

Cloudflare Workers Free plan has a very small per-request CPU budget. Two kinds of endpoints are particularly CPU-heavy:

  • import endpoint: large JSON payload (typically 500kB1MB) + parsing + batch inserts.
  • registration, login and password verification endpoint: server-side PBKDF2 for password verification.

To keep the main Worker fast while still supporting these operations, Warden can offload selected endpoints to Durable Objects (DO):

  • Heavy DO (HEAVY_DO): implemented in Rust as HeavyDo (reuses the existing axum router) so CPU-heavy endpoints can run with a higher CPU budget.

How to enable/disable

Whether CPU-heavy endpoints are offloaded is determined by whether the HEAVY_DO Durable Object binding is configured in wrangler.toml.

Note

Durable Objects have much higher CPU budget of 30 seconds per request in free plan(see Cloudflare Durable Objects limits), so we can use it to offload the CPU-heavy endpoints.

Durable Objects can incur two types of billing: compute and storage. Storage is not used in this project, and the free plan allows 100,000 requests and 13,000 GB-s duration per day, which should be more than enough for most users. See Cloudflare Durable Objects pricing for details.

If you choose to disable Durable Objects, you may need subscribe to a paid plan to avoid being throttled by Cloudflare.

Live Sync and Push Notifications

Warden supports live sync for vault data via two mechanisms: WebSocket push (for desktop apps and browser extensions) and Mobile push notifications (for official mobile apps).

WebSocket Push (Desktop & Extensions)

This feature is powered by Durable Objects and enabled by default when the NOTIFY_DO Durable Object binding is configured in wrangler.toml. Removing this binding (and migration) will gracefully disable WebSocket notifications.

Mobile Push Notifications

Warden supports push notifications to official Bitwarden mobile apps via the Bitwarden push relay service.

Setup:

  1. Obtain an installation ID and key from https://bitwarden.com/host/.
  2. Store the credentials as secrets (PUSH_INSTALLATION_ID & PUSH_INSTALLATION_KEY) via the Cloudflare dashboard or wrangler cli.
  3. Enable push by setting PUSH_ENABLED to true in wrangler.toml [vars] or via the Cloudflare dashboard.

Optionally, you can override the default relay endpoints by setting PUSH_RELAY_URI and PUSH_IDENTITY_URI (defaults to https://push.bitwarden.com and https://identity.bitwarden.com).

For detailed configuration and troubleshooting, see the Vaultwarden wiki on push notifications.

Other Environment Variables

Configure environment variables in wrangler.toml under [vars], or set them via Cloudflare Dashboard:

  • BASE_URL (Optional):
    • Overrides the extracted base URL for up/down URLs for files.
    • Format: Include HTTPS protocol, domain, and port (if using non-443 reverse proxy). Do not include any trailing path.
    • Example: https://vault.example.com or https://vault.example.com:8443
    • If not set, falls back to extracting from the incoming request.
  • PASSWORD_ITERATIONS (Optional, Default: 600000):
    • PBKDF2 iterations for server-side password hashing.
    • Minimum is 600000.
  • TRASH_AUTO_DELETE_DAYS (Optional, Default: 30):
    • Days to keep soft-deleted items before purge.
    • Set to 0 or negative to disable.
  • IMPORT_BATCH_SIZE (Optional, Default: 30):
    • Batch size for import/delete operations.
    • 0 disables batching.
  • DISABLE_USER_REGISTRATION (Optional, Default: true):
    • Controls showing the registration button in the client UI (server behavior unchanged).
  • AUTHENTICATOR_DISABLE_TIME_DRIFT (Optional, Default: false):
    • Set to true to disable ±1 time step drift for TOTP validation.
  • ATTACHMENT_MAX_BYTES (Optional):
    • Max size for individual attachment files.
    • Example: 104857600 for 100MB.
  • ATTACHMENT_TOTAL_LIMIT_KB (Optional):
    • Max total attachment storage per user in KB.
    • Example: 1048576 for 1GB.
  • ATTACHMENT_TTL_SECS (Optional, Default: 300, Minimum: 60):
    • TTL for attachment upload/download URLs.
  • SEND_TEXT_MAX_BYTES (Optional, Default: 1887436 ≈ 1.8 MiB):
    • Max size for text Send content. Constrained by D1's 2 MB single-row limit.
  • SEND_MAX_BYTES (Optional, Default: 104857600 = 100 MiB):
    • Max file size for file Sends. Subject to the same KV/R2 limits as attachments.
  • USER_SEND_LIMIT_KB (Optional):
    • Max total Send file storage per user in KB.
  • SEND_TTL_SECS (Optional, Default: 300):
    • TTL for Send file upload/download URLs.

Scheduled Tasks (Cron)

The worker runs a scheduled task to clean up soft-deleted items. By default, it runs daily at 03:00 UTC (wrangler.toml [triggers] cron "0 3 * * *"). Adjust as needed; see Cloudflare Cron Triggers documentation for cron expression syntax.

Database Operations

  • Backup & restore: See Database Backup & Restore for automated backups and manual restoration steps.
  • Time Travel: See D1 Time Travel to restore to a point in time.
  • Seeding Global Equivalent Domains (optional): See docs/deployment.md for seeding in CLI deploy and CI/CD.
  • Local dev with D1:
    • Quick start: wrangler dev --persist
    • Full stack (with web vault): download frontend assets as in deployment doc, then wrangler dev --persist
    • Import a backup locally: wrangler d1 execute vault1 --file=backup.sql
    • Inspect local DB: SQLite file under .wrangler/state/v3/d1/

Local Development with D1

Run the Worker locally with D1 support using Wrangler.

Quick start (API-only):

wrangler dev --persist

Full stack (with Web Vault):

  1. Download the frontend assets (see deployment doc).

  2. Start locally:

    wrangler dev --persist
    
  3. Access the vault at http://localhost:8787.

Using production data temporarily:

  1. Download and decrypt a backup (see backup doc).

  2. Import locally without --remote:

    wrangler d1 execute vault1 --file=backup.sql
    
  3. Start wrangler dev --persist and point clients to http://localhost:8787.

Inspect local SQLite:

ls .wrangler/state/v3/d1/
sqlite3 .wrangler/state/v3/d1/miniflare-D1DatabaseObject/*.sqlite

Note

Local dev requires Node.js and Wrangler. The Worker runs in a simulated environment via workerd.

Updating Your Fork

If you deployed via a GitHub fork, keeping up to date is straightforward:

  1. Watch for new releases — On this repository, click WatchCustom → check Releases. You'll be notified when a new version is published.
  2. Sync your fork — Go to your fork on GitHub, click Sync forkUpdate branch. This pulls the latest changes from upstream into your fork's default branch.
  3. Automatic deployment — If you set up CI/CD via GitHub Actions, the push-to-main workflow will automatically build and deploy the new version to your Cloudflare Worker. No manual steps needed.

Tip

It is recommended to sync your fork when a new release is published in the upstream, so you always have the latest features and security fixes.

Contributing

Issues and PRs are welcome. Please run cargo fmt and cargo clippy --target wasm32-unknown-unknown --no-deps before submitting.

License

This project is licensed under the MIT License. See the LICENSE file for details.