# Vaultwarden — Administrator & Developer Guide

## 1. Architecture Overview

Vaultwarden is an unofficial, lightweight implementation of the Bitwarden server API written in Rust. It replaces the official multi-container .NET Bitwarden server with a single binary that implements the complete Bitwarden client API (268 endpoints), enabling compatibility with all official Bitwarden clients. The project is licensed under AGPL-3.0-only.

The server is built on the Rocket web framework with Diesel ORM for database access and supports SQLite, PostgreSQL, and MySQL/MariaDB backends. All authentication uses RS256 JWT tokens with an auto-generated RSA-2048 key pair. Configuration is driven entirely through environment variables processed by a custom `make_config!` macro that generates a type-safe configuration system with validation, admin panel integration, and runtime updates.

### Architecture Diagram

```text
┌─────────────────────────────────────────────────────────┐
│                    Bitwarden Clients                     │
│  (Browser, Desktop, Mobile, CLI)                        │
└──────────────────────┬──────────────────────────────────┘
                       │ HTTPS (via reverse proxy)
┌──────────────────────▼──────────────────────────────────┐
│                   Vaultwarden Binary                     │
│  ┌─────────────┐  ┌──────────┐  ┌────────────────────┐ │
│  │ Rocket HTTP  │  │ WebSocket│  │ Admin Panel (HBS)  │ │
│  │ Server       │  │ Hub      │  │                    │ │
│  └──────┬──────┘  └────┬─────┘  └────────┬───────────┘ │
│         │              │                  │              │
│  ┌──────▼──────────────▼──────────────────▼───────────┐ │
│  │                   API Layer                         │ │
│  │  /api/* (core)  /identity/* (auth)  /admin/*       │ │
│  │  /icons/*       /notifications/*    /events/*      │ │
│  └──────────────────────┬─────────────────────────────┘ │
│         │               │                │               │
│  ┌──────▼───┐  ┌───────▼────┐  ┌───────▼────────────┐  │
│  │ Auth/JWT  │  │ Diesel ORM │  │ Background Jobs    │  │
│  │ (RS256)   │  │            │  │ (job_scheduler_ng) │  │
│  └──────────┘  └──────┬─────┘  └────────────────────┘  │
│                        │                                 │
└────────────────────────┼─────────────────────────────────┘
                         │
              ┌──────────▼──────────┐
              │   Database Backend   │
              │  SQLite / PostgreSQL │
              │  / MySQL-MariaDB     │
              └─────────────────────┘
```

> [!NOTE]
> Vaultwarden compiles database support via Cargo feature flags. The official Docker images include all three backends. Source builds must choose one: `--features sqlite`, `--features postgresql`, or `--features mysql`.

### Component Inventory

| Component | Path | Role |
|---|---|---|
| `src/main.rs` | Entry point | CLI parsing, startup, signal handling, job scheduling |
| `src/config.rs` | Configuration | `make_config!` macro, env var processing, validation |
| `src/auth.rs` | Authentication | JWT (RS256), RSA key management, request guards |
| `src/crypto.rs` | Cryptography | PBKDF2, HMAC, random generation |
| `src/api/` | API handlers | All HTTP endpoint implementations |
| `src/api/core/` | Core API | Ciphers, folders, collections, organizations, sends |
| `src/api/core/two_factor/` | 2FA | TOTP, WebAuthn, Duo, YubiKey, Email implementations |
| `src/api/identity/` | Identity | Login, token refresh, SSO flows |
| `src/api/admin.rs` | Admin panel | Web-based admin interface |
| `src/api/icons.rs` | Icons | Favicon proxy/cache service |
| `src/api/notifications.rs` | Notifications | WebSocket hub for real-time sync |
| `src/db/` | Database layer | Diesel models, migrations, connection pool |
| `src/db/models/` | Data models | All entity types (User, Cipher, Organization, etc.) |
| `src/mail.rs` | Email | SMTP/sendmail integration, Handlebars templates |
| `src/sso.rs` / `src/sso_client.rs` | SSO | OpenID Connect client implementation |
| `src/http_client.rs` | HTTP client | Outbound requests with IP blocking |
| `src/ratelimit.rs` | Rate limiting | Per-IP rate limiting for auth endpoints |
| `docker/` | Docker | Dockerfiles, build scripts, healthcheck |

### Technology Stack

| Layer | Technology | Version/Notes |
|---|---|---|
| Language | Rust | 1.92.0+ (1.94.1 in Docker builds) |
| Web Framework | Rocket | Async, custom config |
| ORM | Diesel | With r2d2 connection pool |
| Database | SQLite / PostgreSQL / MySQL | Compile-time feature selection |
| JWT | jsonwebtoken | RS256 with 2048-bit RSA |
| 2FA | webauthn-rs, yubico, oath | WebAuthn, YubiKey OTP, TOTP |
| SSO | openidconnect | Full OIDC flow with PKCE |
| Email | lettre | SMTP + sendmail support |
| Templates | Handlebars | Email + admin panel rendering |
| Object Storage | OpenDAL | S3 via AWS credential chain |
| Allocator | mimalloc (optional) | `enable_mimalloc` feature flag |
| Container | Docker | Debian trixie / Alpine 3.23, multi-arch |

---

## 2. System Requirements

### Hardware

| Deployment | CPU | RAM | Disk |
|---|---|---|---|
| Personal (1-5 users) | 1 core | 64 MB | 500 MB |
| Small team (5-50 users) | 1-2 cores | 256 MB | 2 GB |
| Organization (50+ users) | 2+ cores | 512 MB+ | 10 GB+ |

### Software

| Dependency | Requirement |
|---|---|
| Docker | 20.10+ (for container deployment) |
| Rust | 1.92.0+ (for source builds) |
| OpenSSL | Required for TLS and crypto operations |
| Web Vault | v2026.2.0 (must match server version) |

### Supported Platforms

| Architecture | Debian | Alpine |
|---|---|---|
| linux/amd64 | Yes | Yes |
| linux/arm64 | Yes | Yes |
| linux/arm/v7 | Yes | Yes |
| linux/arm/v6 | Yes | Yes |

---

## 3. Configuration Reference

Vaultwarden uses a custom `make_config!` macro that generates a type-safe configuration system. All settings are environment variables (uppercased). Settings can also be modified at runtime through the admin panel (editable settings only) and are persisted to `config.json` in the data folder.

> [!IMPORTANT]
> Environment variables set at startup take precedence initially, but admin panel changes are persisted to `config.json` which overrides environment variables on subsequent startups. If a setting appears in both, the `config.json` value wins and a warning is logged listing the overridden variables.

### Folders

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `DATA_FOLDER` | String | `data` | No | Main data directory |
| `DATABASE_URL` | String | `{DATA_FOLDER}/db.sqlite3` | No | Database connection string |
| `ICON_CACHE_FOLDER` | String | `{DATA_FOLDER}/icon_cache` | No | Icon cache directory |
| `ATTACHMENTS_FOLDER` | String | `{DATA_FOLDER}/attachments` | No | File attachments directory |
| `SENDS_FOLDER` | String | `{DATA_FOLDER}/sends` | No | Send files directory |
| `TMP_FOLDER` | String | `{DATA_FOLDER}/tmp` | No | Temporary upload directory |
| `TEMPLATES_FOLDER` | String | `{DATA_FOLDER}/templates` | No | Custom template overrides |
| `RSA_KEY_FILENAME` | String | `{DATA_FOLDER}/rsa_key` | No | RSA key file path (without `.pem`) |
| `WEB_VAULT_FOLDER` | String | `web-vault/` | No | Web vault static files |

### WebSocket

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `ENABLE_WEBSOCKET` | bool | `true` | No | Enable WebSocket notifications |

### Push Notifications

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `PUSH_ENABLED` | bool | `false` | No | Enable push notifications |
| `PUSH_RELAY_URI` | String | `https://push.bitwarden.com` | No | Push relay server URL |
| `PUSH_IDENTITY_URI` | String | `https://identity.bitwarden.com` | No | Push identity server URL |
| `PUSH_INSTALLATION_ID` | Password | *(empty)* | No | Installation ID from bitwarden.com/host |
| `PUSH_INSTALLATION_KEY` | Password | *(empty)* | No | Installation key from bitwarden.com/host |

> [!IMPORTANT]
> Push relay and identity URIs must start with `https://`. All three push settings (enabled, ID, key) must be configured together.

### Scheduled Jobs

All cron schedules use 6-field cron syntax (sec min hour day month weekday). Set a schedule to empty string to disable that job. Set `JOB_POLL_INTERVAL_MS=0` to disable all scheduled jobs.

| Variable | Type | Default | Description |
|---|---|---|---|
| `JOB_POLL_INTERVAL_MS` | u64 | `30000` | How often the scheduler checks for jobs (ms). 0 = disable all. |
| `SEND_PURGE_SCHEDULE` | String | `0 5 * * * *` | Purge expired Sends (hourly) |
| `TRASH_PURGE_SCHEDULE` | String | `0 5 0 * * *` | Delete trashed items past retention (daily) |
| `INCOMPLETE_2FA_SCHEDULE` | String | `30 * * * * *` | Check for incomplete 2FA logins (every minute) |
| `EMERGENCY_NOTIFICATION_REMINDER_SCHEDULE` | String | `0 3 * * * *` | Send emergency access reminders (hourly) |
| `EMERGENCY_REQUEST_TIMEOUT_SCHEDULE` | String | `0 7 * * * *` | Grant timed-out emergency requests (hourly) |
| `EVENT_CLEANUP_SCHEDULE` | String | `0 10 0 * * *` | Clean old events (daily) |
| `AUTH_REQUEST_PURGE_SCHEDULE` | String | `30 * * * * *` | Clean old auth requests (every minute) |
| `DUO_CONTEXT_PURGE_SCHEDULE` | String | `30 * * * * *` | Clean expired Duo contexts (every minute) |
| `PURGE_INCOMPLETE_SSO_AUTH` | String | `0 20 0 * * *` | Clean incomplete SSO auth records (daily) |

### General Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `DOMAIN` | String | `http://localhost` | Yes | Full server URL including protocol |
| `WEB_VAULT_ENABLED` | bool | `true` | No | Enable the web vault UI |
| `SENDS_ALLOWED` | bool | `true` | Yes | Allow users to create Sends |
| `HIBP_API_KEY` | Password | *(unset)* | Yes | HaveIBeenPwned API key for breach checking |
| `USER_ATTACHMENT_LIMIT` | i64 | *(unset)* | Yes | Per-user attachment storage limit (KB) |
| `ORG_ATTACHMENT_LIMIT` | i64 | *(unset)* | Yes | Per-org attachment storage limit (KB) |
| `USER_SEND_LIMIT` | i64 | *(unset)* | Yes | Per-user Send storage limit (KB) |
| `TRASH_AUTO_DELETE_DAYS` | i64 | *(unset)* | Yes | Days before trashed items are auto-deleted |
| `INCOMPLETE_2FA_TIME_LIMIT` | i64 | `3` | Yes | Minutes before incomplete 2FA triggers notification (0 = disable) |
| `DISABLE_ICON_DOWNLOAD` | bool | `false` | Yes | Disable icon fetching (serves cached only) |
| `SIGNUPS_ALLOWED` | bool | `true` | Yes | Allow new user self-registration |
| `SIGNUPS_VERIFY` | bool | `false` | Yes | Require email verification for signups |
| `SIGNUPS_VERIFY_RESEND_TIME` | u64 | `3600` | Yes | Seconds between auto-resent verification emails |
| `SIGNUPS_VERIFY_RESEND_LIMIT` | u32 | `6` | Yes | Max auto-resent verification emails (0 = no limit) |
| `SIGNUPS_DOMAINS_WHITELIST` | String | *(empty)* | Yes | Comma-separated allowed signup domains |
| `ORG_EVENTS_ENABLED` | bool | `false` | No | Enable organization event logging |
| `ORG_CREATION_USERS` | String | *(empty)* | Yes | Comma-separated emails allowed to create orgs, `all` or `none` |
| `INVITATIONS_ALLOWED` | bool | `true` | Yes | Allow org admins to invite users |
| `INVITATION_EXPIRATION_HOURS` | u32 | `120` | No | Token expiration for invites, email verify, delete requests (min: 1) |
| `EMERGENCY_ACCESS_ALLOWED` | bool | `true` | Yes | Enable emergency access feature |
| `EMAIL_CHANGE_ALLOWED` | bool | `true` | Yes | Allow users to change their email |
| `PASSWORD_ITERATIONS` | i32 | `600000` | Yes | Server-side PBKDF2 iterations (min: 100,000) |
| `PASSWORD_HINTS_ALLOWED` | bool | `true` | Yes | Allow users to set password hints |
| `SHOW_PASSWORD_HINT` | bool | `false` | Yes | Show hints on login page when SMTP not configured |
| `ADMIN_TOKEN` | Password | *(unset)* | Yes | Admin panel authentication token (Argon2id PHC recommended) |
| `INVITATION_ORG_NAME` | String | `Vaultwarden` | Yes | Organization name in invitation emails |
| `EVENTS_DAYS_RETAIN` | i64 | *(unset)* | No | Days to retain events (unset = indefinite) |

### Advanced Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `IP_HEADER` | String | `X-Real-IP` | Yes | Header for client IP detection (`none` to use remote IP) |
| `ICON_SERVICE` | String | `internal` | No | Icon service: `internal`, `bitwarden`, `duckduckgo`, `google`, or custom URL with `{}` |
| `ICON_REDIRECT_CODE` | u32 | `302` | Yes | HTTP redirect code for external icon services (301/302/307/308) |
| `ICON_CACHE_TTL` | u64 | `2592000` | Yes | Positive icon cache expiry (seconds, default 30 days) |
| `ICON_CACHE_NEGTTL` | u64 | `259200` | Yes | Negative icon cache expiry (seconds, default 3 days) |
| `ICON_DOWNLOAD_TIMEOUT` | u64 | `10` | Yes | Icon download timeout (seconds) |
| `HTTP_REQUEST_BLOCK_REGEX` | String | *(unset)* | Yes | Regex to block internal HTTP requests to specific domains/IPs |
| `HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS` | bool | `true` | Yes | Block HTTP requests to non-global/reserved IPs |
| `DISABLE_2FA_REMEMBER` | bool | `false` | Yes | Force 2FA on every login (ignore "remember" checkbox) |
| `AUTHENTICATOR_DISABLE_TIME_DRIFT` | bool | `false` | Yes | Only accept current TOTP code (no ±30s drift) |
| `EXPERIMENTAL_CLIENT_FEATURE_FLAGS` | String | *(empty)* | No | Comma-separated list of client feature flags to enable |
| `REQUIRE_DEVICE_EMAIL` | bool | `false` | Yes | Require new device email notification on login |
| `RELOAD_TEMPLATES` | bool | `false` | Yes | Reload templates on every request (dev only) |
| `EXTENDED_LOGGING` | bool | `true` | No | Enable timestamp, target, and level in log output |
| `LOG_TIMESTAMP_FORMAT` | String | `%Y-%m-%d %H:%M:%S.%3f` | Yes | Timestamp format for extended logging |
| `USE_SYSLOG` | bool | `false` | No | Log to syslog (Unix only) |
| `LOG_FILE` | String | *(unset)* | No | File path for log output |
| `LOG_LEVEL` | String | `info` | No | Log level: trace/debug/info/warn/error/off (supports per-module overrides) |
| `ENABLE_DB_WAL` | bool | `true` | No | Enable SQLite WAL mode |
| `DB_CONNECTION_RETRIES` | u32 | `15` | No | Database connection retry attempts (0 = infinite) |
| `DATABASE_TIMEOUT` | u64 | `30` | No | Database connection acquisition timeout (seconds) |
| `DATABASE_IDLE_TIMEOUT` | u64 | `600` | No | Idle connection timeout (seconds) |
| `DATABASE_MAX_CONNS` | u32 | `10` | No | Maximum database connection pool size (1-256) |
| `DATABASE_MIN_CONNS` | u32 | `2` | No | Minimum database connection pool size (1-256) |
| `DATABASE_CONN_INIT` | String | *(empty)* | No | SQL statements to run on new connections |
| `DISABLE_ADMIN_TOKEN` | bool | `false` | No | Disable admin token requirement (use external auth) |
| `ALLOWED_IFRAME_ANCESTORS` | String | *(empty)* | Yes | Domains allowed to embed web vault in iframe |
| `ALLOWED_CONNECT_SRC` | String | *(empty)* | Yes | Additional CSP connect-src domains (HTTPS only) |
| `LOGIN_RATELIMIT_SECONDS` | u64 | `60` | No | Seconds between login attempts before rate limiting |
| `LOGIN_RATELIMIT_MAX_BURST` | u32 | `10` | No | Burst size for login rate limiter |
| `ADMIN_RATELIMIT_SECONDS` | u64 | `300` | No | Seconds between admin login attempts before rate limiting |
| `ADMIN_RATELIMIT_MAX_BURST` | u32 | `3` | No | Burst size for admin rate limiter |
| `ADMIN_SESSION_LIFETIME` | i64 | `20` | Yes | Admin session duration (minutes) |
| `ORG_GROUPS_ENABLED` | bool | `false` | No | Enable organization groups (beta) |
| `INCREASE_NOTE_SIZE_LIMIT` | bool | `false` | Yes | Raise secure note limit from 10,000 to 100,000 chars |
| `ENFORCE_SINGLE_ORG_WITH_RESET_PW_POLICY` | bool | `false` | No | Require Single Org policy before Reset Password policy |
| `DNS_PREFER_IPV6` | bool | `false` | Yes | Prefer IPv6 (AAAA) DNS resolution |

### OpenID Connect SSO Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `SSO_ENABLED` | bool | `false` | Yes | Enable SSO authentication |
| `SSO_ONLY` | bool | `false` | Yes | Disable password login (SSO only) |
| `SSO_SIGNUPS_MATCH_EMAIL` | bool | `true` | Yes | Match existing users by email on SSO login |
| `SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION` | bool | `false` | Yes | Allow SSO users with unknown email verification status |
| `SSO_CLIENT_ID` | String | *(empty)* | Yes | OIDC client ID |
| `SSO_CLIENT_SECRET` | Password | *(empty)* | Yes | OIDC client secret |
| `SSO_AUTHORITY` | String | *(empty)* | Yes | OIDC provider base URL |
| `SSO_SCOPES` | String | `email profile` | Yes | OIDC scopes (openid is implicit) |
| `SSO_AUTHORIZE_EXTRA_PARAMS` | String | *(empty)* | Yes | Extra URL parameters for the authorization request |
| `SSO_PKCE` | bool | `true` | Yes | Use PKCE in OIDC authorization flow |
| `SSO_AUDIENCE_TRUSTED` | String | *(unset)* | Yes | Regex for additional trusted ID token audiences |
| `SSO_MASTER_PASSWORD_POLICY` | String | *(unset)* | Yes | JSON policy object for SSO master password requirements |
| `SSO_AUTH_ONLY_NOT_SESSION` | bool | `false` | Yes | Use SSO only for auth, not session lifecycle |
| `SSO_CLIENT_CACHE_EXPIRATION` | u64 | `0` | Yes | Discovery endpoint cache duration (seconds, 0 = disabled) |
| `SSO_DEBUG_TOKENS` | bool | `false` | Yes | Log SSO tokens (requires debug log level) |

> [!WARNING]
> `SSO_CLIENT_ID`, `SSO_CLIENT_SECRET`, and `SSO_AUTHORITY` must all be set when `SSO_ENABLED=true`. The authority URL must not include `/.well-known/openid-configuration`.

### YubiKey Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `YUBICO_CLIENT_ID` | String | *(unset)* | Yes | YubiCloud API client ID |
| `YUBICO_SECRET_KEY` | Password | *(unset)* | Yes | YubiCloud API secret key |
| `YUBICO_SERVER` | String | *(unset)* | Yes | Custom YubiKey validation server URL (must be HTTPS) |

Both `YUBICO_CLIENT_ID` and `YUBICO_SECRET_KEY` must be set together for custom YubiKey OTP support. Without them, the default YubiCloud service is used.

### Duo Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `DUO_IKEY` | String | *(unset)* | Yes | Duo client/integration key |
| `DUO_SKEY` | Password | *(unset)* | Yes | Duo secret key |
| `DUO_HOST` | String | *(unset)* | Yes | Duo API hostname |
| `DUO_USE_IFRAME` | bool | `false` | No | Use deprecated iframe-based Duo prompt (WebSDK 2) |

All three Duo settings (`DUO_IKEY`, `DUO_SKEY`, `DUO_HOST`) must be set together for global Duo support. Individual users can also configure their own Duo credentials.

### SMTP Email Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `USE_SENDMAIL` | bool | `false` | Yes | Use sendmail command instead of SMTP |
| `SENDMAIL_COMMAND` | String | *(auto-detect)* | No | Path to sendmail binary |
| `SMTP_HOST` | String | *(unset)* | Yes | SMTP server hostname |
| `SMTP_SECURITY` | String | `starttls` | Yes | `starttls`, `force_tls`, or `off` |
| `SMTP_PORT` | u16 | *(auto)* | Yes | SMTP port (auto: 587/465/25 based on security) |
| `SMTP_FROM` | String | *(empty)* | Yes | Sender email address |
| `SMTP_FROM_NAME` | String | `Vaultwarden` | Yes | Sender display name |
| `SMTP_USERNAME` | String | *(unset)* | Yes | SMTP authentication username |
| `SMTP_PASSWORD` | Password | *(unset)* | Yes | SMTP authentication password |
| `SMTP_AUTH_MECHANISM` | String | *(auto)* | Yes | Auth methods: Plain, Login, Xoauth2 (comma-separated) |
| `SMTP_TIMEOUT` | u64 | `15` | Yes | Connection timeout (seconds) |
| `HELO_NAME` | String | *(hostname)* | Yes | Server name sent during SMTP HELO |
| `SMTP_EMBED_IMAGES` | bool | `true` | Yes | Embed images in emails as attachments |
| `SMTP_DEBUG` | bool | `false` | No | Enable detailed SMTP logging (exposes sensitive data) |
| `SMTP_ACCEPT_INVALID_CERTS` | bool | `false` | Yes | Accept invalid TLS certificates (insecure) |
| `SMTP_ACCEPT_INVALID_HOSTNAMES` | bool | `false` | Yes | Accept invalid TLS hostnames (insecure) |

> [!CAUTION]
> `SMTP_DEBUG=true` outputs full SMTP session data including credentials. Only use during active troubleshooting and disable immediately after.

### Email 2FA Settings

| Variable | Type | Default | Editable | Description |
|---|---|---|---|---|
| `EMAIL_TOKEN_SIZE` | u8 | `6` | Yes | Number of digits in email 2FA token (min: 6, max: 255) |
| `EMAIL_EXPIRATION_TIME` | u64 | `600` | Yes | Token validity duration (seconds) |
| `EMAIL_ATTEMPTS_LIMIT` | u64 | `3` | Yes | Max attempts before token is reset |
| `EMAIL_2FA_ENFORCE_ON_VERIFIED_INVITE` | bool | `false` | Yes | Auto-setup email 2FA on registration |
| `EMAIL_2FA_AUTO_FALLBACK` | bool | `false` | Yes | Auto-enable email 2FA as fallback when needed |

Email 2FA requires a working mail transport (`SMTP_HOST` or `USE_SENDMAIL`). It is automatically enabled when SMTP is configured and a mail transport is available.

### Other Environment Variables

| Variable | Description |
|---|---|
| `ENV_FILE` | Path to `.env` file (default: `.env`) |
| `CONFIG_FILE` | Path to config.json (default: `{DATA_FOLDER}/config.json`) |
| `ROCKET_PORT` | Listening port (default: `80`) |
| `ROCKET_ADDRESS` | Bind address (default: `0.0.0.0`) |
| `ROCKET_TLS` | Rocket TLS configuration (use reverse proxy instead) |
| `I_REALLY_WANT_VOLATILE_STORAGE` | Skip persistent volume check in containers |
| `UMASK` | Set umask before starting (Docker start.sh) |

---

## 4. Deployment & Scaling

### Docker Deployment

Official images are built for four architectures from both Debian (trixie-slim) and Alpine (3.23) base images.

**Production Docker Compose:**

```yaml
services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vw.example.com"
      SIGNUPS_ALLOWED: "false"
      ADMIN_TOKEN: "${ADMIN_TOKEN}"
      SMTP_HOST: "smtp.example.com"
      SMTP_FROM: "[email removed]"
      SMTP_PORT: "587"
      SMTP_SECURITY: "starttls"
      SMTP_USERNAME: "${SMTP_USER}"
      SMTP_PASSWORD: "${SMTP_PASS}"
      PUSH_ENABLED: "true"
      PUSH_INSTALLATION_ID: "${PUSH_ID}"
      PUSH_INSTALLATION_KEY: "${PUSH_KEY}"
    volumes:
      - ./vw-data/:/data/
    ports:
      - "127.0.0.1:8080:80"
```

> [!TIP]
> Bind to `127.0.0.1` when running behind a reverse proxy to prevent direct external access to the unencrypted port.

### S3 Storage

Set `DATA_FOLDER` to an S3 URL to store all data (database, attachments, sends, keys) in S3-compatible storage:

```bash
DATA_FOLDER=s3://my-vaultwarden-bucket/data
```

The `s3` feature flag must be enabled (included in official Docker images). Vaultwarden uses the standard AWS credential chain via the official AWS SDK for credential resolution, supporting IAM roles, environment variables, SSO profiles, and credential files.

### Reverse Proxy Configuration

Vaultwarden requires a reverse proxy for production HTTPS. Key considerations:

- Pass the `X-Real-IP` header (or set `IP_HEADER` to your proxy's header name)
- Forward WebSocket connections for real-time notifications
- The `/alive` endpoint is suitable for health checks

**Healthcheck (used in Docker):**

```bash
curl --insecure --fail --silent --show-error \
  "http://localhost:${ROCKET_PORT}/alive"
```

### Source Build for Production

```bash
cargo build --release --features "sqlite,enable_mimalloc"
```

Available feature flags:

| Flag | Purpose |
|---|---|
| `sqlite` | SQLite database backend |
| `postgresql` | PostgreSQL database backend |
| `mysql` | MySQL/MariaDB database backend |
| `s3` | S3-compatible object storage |
| `enable_mimalloc` | Use mimalloc allocator for better performance |
| `vendored_openssl` | Statically link OpenSSL |

---

## 5. Operations

### Background Jobs

Vaultwarden runs 9 scheduled background jobs in a dedicated scheduler thread:

| Job | Default Schedule | Purpose |
|---|---|---|
| Send purge | Hourly (:05) | Delete expired Sends |
| Trash purge | Daily (00:05) | Delete trashed items past retention |
| Incomplete 2FA check | Every minute (:30) | Notify on incomplete 2FA logins |
| Emergency request timeout | Hourly (:07) | Auto-grant emergency access requests |
| Emergency reminder | Hourly (:03) | Remind grantors of pending requests |
| Auth request purge | Every minute (:30) | Clean expired auth requests |
| Duo context purge | Every minute (:30) | Clean expired Duo auth contexts |
| Event cleanup | Daily (00:10) | Remove events older than retention period |
| SSO auth purge | Daily (00:20) | Clean incomplete SSO auth records |

> [!TIP]
> All schedules use 6-field cron syntax (second minute hour day month weekday). Set any schedule to an empty string to disable that specific job. Set `JOB_POLL_INTERVAL_MS=0` to disable all jobs.

### Backup

**SQLite backup methods:**

1. **CLI command:** `./vaultwarden backup` — creates `db_YYYYMMDD_HHMMSS.sqlite3` in the data folder
2. **Signal (Unix):** `kill -USR1 $(pidof vaultwarden)` — triggers hot backup while running
3. **File copy:** Stop the server, copy `db.sqlite3` and related WAL/SHM files

> [!NOTE]
> The `backup` command and USR1 signal are SQLite-only. PostgreSQL and MySQL require native database backup tools (`pg_dump`, `mysqldump`).

**Critical files to back up:**

| Path | Contents |
|---|---|
| `{DATA_FOLDER}/db.sqlite3` | SQLite database (if using SQLite) |
| `{DATA_FOLDER}/attachments/` | Vault item file attachments |
| `{DATA_FOLDER}/sends/` | Bitwarden Send files |
| `{DATA_FOLDER}/rsa_key.pem` | RSA private key for JWT signing |
| `{DATA_FOLDER}/config.json` | Admin panel configuration overrides |

### Monitoring

- **Health endpoint:** `GET /alive` — returns 200 when the server is running
- **Log levels:** Configure via `LOG_LEVEL` with per-module overrides

```bash
# Enable query logging (slow queries only)
LOG_LEVEL=info,vaultwarden::db::query_logger=warn

# Full query logging
LOG_LEVEL=info,vaultwarden::db::query_logger=debug
```

> [!TIP]
> Query logger levels: `warn` = queries over 5 seconds, `info` = queries over 1 second, `debug` = all queries.

### Signal Handling

| Signal | Platform | Action |
|---|---|---|
| SIGINT | Unix | Graceful shutdown |
| SIGTERM | Unix | Graceful shutdown |
| SIGQUIT | Unix | Graceful shutdown |
| SIGUSR1 | Unix (SQLite only) | Trigger SQLite backup |
| SIGHUP | Unix | Reopen log file (for log rotation) |
| Ctrl-C | Windows | Graceful shutdown |

---

## 6. Performance

### Database Tuning

| Variable | Default | Guidance |
|---|---|---|
| `DATABASE_MAX_CONNS` | `10` | Increase for high-concurrency deployments (max: 256) |
| `DATABASE_MIN_CONNS` | `2` | Set to match minimum expected concurrency |
| `DATABASE_TIMEOUT` | `30` | Connection acquisition timeout (seconds) |
| `DATABASE_IDLE_TIMEOUT` | `600` | Close idle connections after this many seconds |
| `DATABASE_CONN_INIT` | *(empty)* | SQL to run on each new connection (e.g., `PRAGMA` statements for SQLite) |
| `ENABLE_DB_WAL` | `true` | SQLite WAL mode (better concurrent read performance) |

### Memory Optimization

- Enable `mimalloc` via the `enable_mimalloc` feature flag for improved memory allocation performance
- The Rocket request limits are fixed: 20 MB for JSON, 525 MB for data-form and file uploads (matches Bitwarden Send max file size)

### Icon Caching

| Variable | Effect |
|---|---|
| `ICON_SERVICE=internal` | Vaultwarden fetches and caches icons locally (default) |
| `ICON_SERVICE=bitwarden` | Redirect to Bitwarden's icon service |
| `ICON_SERVICE=duckduckgo` | Redirect to DuckDuckGo's icon service |
| `ICON_SERVICE=google` | Redirect to Google's favicon service |
| `DISABLE_ICON_DOWNLOAD=true` | Serve cached icons only, no new downloads |

---

## 7. Security

### Authentication Architecture

Vaultwarden uses RS256 JWT tokens signed with an auto-generated RSA-2048 key pair stored at `{DATA_FOLDER}/rsa_key.pem`. If the key file doesn't exist, it is generated automatically on first startup.

**Token types and lifetimes:**

| Token | Lifetime | Purpose |
|---|---|---|
| Access token | 2 hours | API authentication |
| Refresh token (desktop/web) | 30 days | Token renewal |
| Refresh token (mobile) | 90 days | Token renewal (mobile devices) |
| Invite token | `INVITATION_EXPIRATION_HOURS` (120h) | Organization invitations |
| File download token | 5 minutes | Temporary file access |
| Register verify token | 30 minutes | Email verification during registration |
| 2FA remember token | 30 days | Skip 2FA on remembered devices |
| Admin session | `ADMIN_SESSION_LIFETIME` (20 min) | Admin panel access |
| Send access token | 2 minutes | Send file download |

> [!WARNING]
> The RSA private key (`rsa_key.pem`) is the root of trust for all authentication. If this file is compromised, all tokens can be forged. Protect it with restrictive file permissions and include it in backup procedures.

### Rate Limiting

| Endpoint | Seconds Between Requests | Burst Size |
|---|---|---|
| Login / 2FA | `LOGIN_RATELIMIT_SECONDS` (60) | `LOGIN_RATELIMIT_MAX_BURST` (10) |
| Admin panel | `ADMIN_RATELIMIT_SECONDS` (300) | `ADMIN_RATELIMIT_MAX_BURST` (3) |

### Admin Panel Security

The admin token supports two formats:

1. **Argon2id PHC string** (recommended): Generated via `vaultwarden hash`
2. **Plain text** (insecure): Generates a startup warning recommending migration to Argon2id

Set `DISABLE_ADMIN_TOKEN=true` only when the admin panel is protected by an external authentication layer (e.g., reverse proxy auth).

### Network Security

| Setting | Default | Purpose |
|---|---|---|
| `HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS` | `true` | Prevent SSRF by blocking requests to private/reserved IPs |
| `HTTP_REQUEST_BLOCK_REGEX` | *(unset)* | Regex to block specific domains/IPs from internal HTTP requests |
| `IP_HEADER` | `X-Real-IP` | Client IP detection header (set to `none` to use remote IP) |

> [!CAUTION]
> Disabling `HTTP_REQUEST_BLOCK_NON_GLOBAL_IPS` may expose internal network services to SSRF attacks through the icon fetching functionality.

### Password Security

- Server-side hashing uses PBKDF2-SHA256 with `PASSWORD_ITERATIONS` (default: 600,000, minimum: 100,000)
- The iteration count is updated on login if the configured value changes
- `SHOW_PASSWORD_HINT=true` exposes password hints without authentication — not recommended for public instances

### Two-Factor Authentication Security

- `DISABLE_2FA_REMEMBER=true` forces 2FA on every login
- `AUTHENTICATOR_DISABLE_TIME_DRIFT=true` accepts only the current 30-second TOTP window
- Incomplete 2FA attempts (correct password, missing 2FA) trigger email notifications after `INCOMPLETE_2FA_TIME_LIMIT` minutes
- WebAuthn requires `DOMAIN` to be set with an HTTPS scheme and a valid domain name

### SSO Security Considerations

- `SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=true` with `SSO_SIGNUPS_MATCH_EMAIL=true` creates an account takeover risk — only use with trusted identity providers
- `SSO_PKCE=true` (default) adds PKCE protection to the OIDC authorization flow
- `SSO_AUDIENCE_TRUSTED` accepts a regex — validate that it cannot match unintended audiences

---

## 8. Developer Internals

### Repository Structure

```text
vaultwarden/
├── src/
│   ├── main.rs                 Entry point, CLI, startup sequence
│   ├── config.rs               make_config! macro, env var processing
│   ├── auth.rs                 JWT authentication, request guards
│   ├── crypto.rs               PBKDF2, HMAC, random generation
│   ├── error.rs                Error types, API error formatting
│   ├── mail.rs                 Email sending (SMTP/sendmail)
│   ├── http_client.rs          Outbound HTTP with IP blocking
│   ├── ratelimit.rs            Rate limiting implementation
│   ├── sso.rs                  SSO/OIDC flow logic
│   ├── sso_client.rs           OIDC client configuration
│   ├── util.rs                 Shared utilities
│   ├── api/
│   │   ├── mod.rs              Route registration
│   │   ├── admin.rs            Admin panel routes
│   │   ├── icons.rs            Favicon proxy/cache
│   │   ├── notifications.rs    WebSocket hub
│   │   ├── web.rs              Static file serving
│   │   ├── identity/           Login, token, SSO endpoints
│   │   └── core/
│   │       ├── accounts.rs     User account management
│   │       ├── ciphers.rs      Vault item CRUD
│   │       ├── collections.rs  Collection management
│   │       ├── folders.rs      Folder management
│   │       ├── organizations.rs Organization management
│   │       ├── sends.rs        Bitwarden Send
│   │       ├── emergency_access.rs Emergency access
│   │       ├── events.rs       Event logging
│   │       └── two_factor/     2FA implementations
│   │           ├── authenticator.rs  TOTP
│   │           ├── webauthn.rs       WebAuthn/FIDO2
│   │           ├── duo.rs / duo_oidc.rs  Duo Security
│   │           ├── yubikey.rs        YubiKey OTP
│   │           └── email.rs          Email 2FA
│   └── db/
│       ├── mod.rs              Database pool, migrations
│       ├── schemas/            Diesel table schemas
│       └── models/             Entity models (User, Cipher, etc.)
├── migrations/                 Database migration files per backend
├── macros/                     Procedural macros (db_* derives)
├── docker/                     Docker build infrastructure
├── playwright/                 End-to-end browser tests
└── Cargo.toml                  Dependencies and feature flags
```

### Configuration System Deep Dive

The `make_config!` macro in `src/config.rs` is the central configuration mechanism. It generates:

1. **`ConfigBuilder`** — a struct where all fields are `Option<T>`, populated from environment variables and `config.json`
2. **`ConfigItems`** — the resolved configuration with concrete types and defaults applied
3. **`Config`** — the thread-safe wrapper (`RwLock<Inner>`) exposed as a global `CONFIG` static
4. **Admin panel data** — `prepare_json()` serializes all settings for the web admin UI
5. **Support diagnostics** — `get_support_json()` masks sensitive values for diagnostic output

The config loading order is:
1. `.env` file (via dotenvy)
2. Environment variables → `ConfigBuilder::from_env()`
3. `config.json` → `ConfigBuilder::from_file()`
4. Merge: env ← config.json (config.json overrides env for editable settings)
5. Build: apply defaults, auto-computed values, and generated values
6. Validate: `validate_config()` checks constraints

### Request Guard System

Rocket request guards enforce authentication and authorization at the type level:

| Guard | Access Level |
|---|---|
| `Headers` | Authenticated user with valid JWT |
| `OrgHeaders` | Authenticated user who is a member of the requested organization |
| `OrgMemberHeaders` | Non-revoked organization member |
| `ManagerHeaders` | Confirmed manager with collection access |
| `ManagerHeadersLoose` | Confirmed manager (no collection check) |
| `AdminHeaders` | Confirmed admin or owner |
| `OwnerHeaders` | Confirmed owner only |
| `ClientHeaders` | Client IP + device type (no auth required) |
| `ClientIp` | Extracted client IP (honors `IP_HEADER`) |

### API Surface

Vaultwarden implements 268 API endpoints across these mount points:

| Mount | Prefix | Purpose |
|---|---|---|
| Web | `/` | Static files, web vault |
| Core API | `/api` | Vault operations (ciphers, folders, collections, orgs) |
| Admin | `/admin` | Admin panel |
| Events | `/events` | Event logging API |
| Identity | `/identity` | Authentication, token exchange |
| Icons | `/icons` | Favicon proxy |
| Notifications | `/notifications` | WebSocket hub |

### Database Migrations

Diesel migrations are organized per backend in the `migrations/` directory. Migrations run automatically on startup. The application also performs data migrations in code:

- `TwoFactor::migrate_u2f_to_webauthn()` — migrates legacy U2F registrations to WebAuthn
- `TwoFactor::migrate_credential_to_passkey()` — migrates credentials to passkey format

### Testing

End-to-end tests use Playwright in `playwright/` and cover:

- SSO login flows
- 2FA setup and verification (TOTP, Email)
- Organization management
- Collection creation and assignment

### Code Patterns

- **Error handling:** Custom `make_error!` macro generates a unified `Error` type wrapping 20+ source error types with `err!()` / `err_handler!()` macros for ergonomic error creation
- **Lazy statics:** `LazyLock` for global configuration, JWT keys, compiled regexes
- **Atomic operations:** `OnceLock` for RSA keys (initialized once, then immutable)
- **Template rendering:** Handlebars with custom helpers (`case`, `to_json`, `webver`, `vwver`)
- **Feature flags:** Compile-time (`cfg(sqlite)`, `cfg(s3)`) and runtime (`SUPPORTED_FEATURE_FLAGS` for client-side flags)

---

## 9. Integration Points

### Bitwarden Client Compatibility

Vaultwarden implements the Bitwarden API surface to be compatible with all official clients. The web vault version (v2026.2.0) is bundled and served by the server. Client version detection uses the `Bitwarden-Client-Version` header.

### Push Notification Relay

Push notifications require registration with the Bitwarden push relay service:

1. Register at `https://bitwarden.com/host` to get installation ID and key
2. Set `PUSH_ENABLED=true`, `PUSH_INSTALLATION_ID`, and `PUSH_INSTALLATION_KEY`
3. Notifications are relayed through `PUSH_RELAY_URI` (default: `https://push.bitwarden.com`)

### OIDC Identity Providers

Vaultwarden supports any OpenID Connect compliant provider. The callback URL is `{DOMAIN}/identity/connect/oidc-signin`.

### Email Integration

28 email templates (HTML + plain text) are built in, covering all user lifecycle events. Templates use Handlebars and can be overridden by placing `.hbs` files in the templates folder.

### HaveIBeenPwned

Set `HIBP_API_KEY` to enable password breach checking through the HaveIBeenPwned API.

### Container Startup Hooks

Docker containers source shell scripts before starting:

1. `/etc/vaultwarden.sh` — single initialization script
2. `/etc/vaultwarden.d/*.sh` — directory of initialization scripts

Legacy paths (`/etc/bitwarden_rs.sh`, `/etc/bitwarden_rs.d/`) are supported with deprecation warnings.

---

_Generated May 2026 from dani-garcia/vaultwarden at f21a3ad. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
