Bitwarden Self-Hosted Deployment

6 October 2025 · Updated 6 October 2025

Notes on running the official Bitwarden server on your own infrastructure. Covers installation, configuration, updates, and backup.

Overview

Bitwarden sells a self-hosted option that keeps all vault data on your own servers. It’s the heavier counterpart to Vaultwarden — same compatible client apps, but more moving parts, more RAM, and SSO/SCIM on the paid tier. If you want a lightweight setup for personal or small-team use, Vaultwarden is usually the better call. Bitwarden proper is the one to reach for when you need the enterprise features, the compliance paperwork, or full control over the MS SQL database underneath.

The trade-off is real: you now own patching, backups, TLS, SMTP, and everything else. If you’re not ready for that responsibility, the hosted version is still the right answer.

System Requirements

Minimum Requirements

  • CPU: 2 cores
  • RAM: 4 GB
  • Storage: 25 GB
  • OS: Ubuntu 20.04+ LTS, Debian 10+, CentOS/RHEL 8+
  • Docker: 20.10.x or later
  • Docker Compose: 1.29.x or later
  • CPU: 4 cores
  • RAM: 8 GB
  • Storage: 50 GB SSD
  • OS: Ubuntu 22.04 LTS (EOL: April 2027)
  • Dedicated server or VM (not shared hosting)

Network Requirements

  • Inbound: HTTPS (443)
  • Outbound: Internet access for license validation (can be proxied)
  • DNS: Resolvable hostname
  • SSL Certificate: Valid certificate (Let’s Encrypt or commercial)

Installation

Prerequisites

Install Docker:

# Ubuntu/Debian
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Install Docker Compose:

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Obtain Installation ID and Key

  1. Visit: https://bitwarden.com/host/
  2. Enter email address
  3. Receive Installation ID and Installation Key via email
  4. Save these securely (required for installation)

Download and Run Installer

Create Bitwarden user:

sudo adduser bitwarden
sudo usermod -aG docker bitwarden
su - bitwarden

Download installer:

curl -Lso bitwarden.sh "https://func.bitwarden.com/api/dl/?app=self-host&platform=linux" && chmod +x bitwarden.sh

Run installation:

./bitwarden.sh install

Installation Prompts

The installer will ask:

  1. Domain name: vault.example.com
  2. Let’s Encrypt certificate: Yes/No
    • If Yes: Enter email for Let’s Encrypt notifications
    • If No: Provide your own SSL certificate
  3. Database name: vault (default, can customize)
  4. Installation ID: From email
  5. Installation Key: From email

Configuration

Main Configuration File

Location: ./bwdata/config.yml

Key settings:

# Domain configuration
url: https://vault.example.com
domain: vault.example.com

# SSL/TLS
https_port: 443
http_port: 80

# Database
database:
  type: mssql  # or postgres
  name: vault
  username: bitwarden
  # Password generated during install

# SMTP (for email)
mail:
  replyToEmail: no-reply@example.com
  smtp:
    host: smtp.example.com
    port: 587
    ssl: false
    startTls: true
    username: bitwarden@example.com
    # Password in environment variables

# Admin panel
adminSettings:
  admins: admin@example.com

Environment Variables

Location: ./bwdata/env/global.override.env

Common overrides:

# Admin email
globalSettings__mail__replyToEmail=no-reply@example.com

# SMTP settings
globalSettings__mail__smtp__host=smtp.example.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__username=bitwarden@example.com
globalSettings__mail__smtp__password=smtp_password

# Database connection
globalSettings__sqlServer__connectionString=Data Source=mssql;Initial Catalog=vault;User ID=bitwarden;Password=db_password

# Disable user registration (for private instances)
globalSettings__disableUserRegistration=true

# Logging
globalSettings__logLevel__default=Information

SSL Certificate Configuration

Using Let’s Encrypt (Automatic)

Already configured during installation if selected.

Manual renewal:

./bitwarden.sh renewcert

Using Custom Certificate

Place certificate files:

# Certificate and key
./bwdata/ssl/your-domain/certificate.crt
./bwdata/ssl/your-domain/private.key

# CA bundle
./bwdata/ssl/your-domain/ca.crt

Update config.yml:

ssl:
  certificate_path: /etc/bitwarden/ssl/your-domain
  certificate_name: certificate.crt
  key_name: private.key
  ca_name: ca.crt

Starting and Managing Bitwarden

Start Bitwarden

./bitwarden.sh start

Stop Bitwarden

./bitwarden.sh stop

Restart Bitwarden

./bitwarden.sh restart

View Status

docker ps

Expected containers:

  • bitwarden-nginx
  • bitwarden-web
  • bitwarden-api
  • bitwarden-identity
  • bitwarden-mssql (or postgres)
  • bitwarden-attachments
  • bitwarden-icons
  • bitwarden-notifications
  • bitwarden-events
  • bitwarden-admin

View Logs

docker logs bitwarden-api
docker logs bitwarden-identity
docker logs -f bitwarden-api  # Follow mode

Initial Setup

Access Web Vault

Navigate to: https://vault.example.com

Create Master Account

  1. Click “Create Account”
  2. Enter email and strong master password
  3. (Optional) Create organization for team sharing

Configure Admin Panel

Access: https://vault.example.com/admin

Important settings:

  1. General Settings

    • Disable user registration (if private)
    • Configure allowed domains
  2. SMTP Settings

    • Test email configuration
  3. Two-Factor Authentication

    • Enforce 2FA for organization
  4. Policies

    • Master password requirements
    • Personal ownership restrictions

Upgrades and Updates

Check for Updates

./bitwarden.sh updateself
./bitwarden.sh update

Upgrade Process

Best practices:

  1. Review release notes: https://bitwarden.com/help/releasenotes/
  2. Create VM snapshot or backup
  3. Schedule maintenance window
  4. Notify users of downtime
  5. Perform upgrade
  6. Test functionality
  7. Notify users of completion

Upgrade steps:

# 1. Stop Bitwarden
./bitwarden.sh stop

# 2. Update script and dependencies
./bitwarden.sh updateself

# 3. Update Bitwarden
./bitwarden.sh update

# 4. Rebuild containers
./bitwarden.sh rebuild

# 5. Start Bitwarden
./bitwarden.sh start

Typical Upgrade Timeline

  • Preparation: 15-30 minutes
  • Downtime: 5-10 minutes
  • Verification: 10-15 minutes

Breaking Changes to Watch

Common breaking changes in updates:

  • SQL Server version support (e.g., dropping SQL Server 2019)
  • Deprecated authentication methods (e.g., Kerberos)
  • Logging method changes (e.g., syslog deprecation)
  • Encryption scheme updates
  • API version changes

Backup and Recovery

Critical Directories to Backup

./bwdata/env/              # Environment variables and secrets
./bwdata/core/attachments/ # Vault attachments
./bwdata/mssql/data/       # Database files
./bwdata/core/aspnet-dataprotection/  # Auth tokens and encrypted columns

Backup Script

#!/bin/bash
# bitwarden-backup.sh

BACKUP_DIR="/backups/bitwarden"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BW_DIR="/home/bitwarden/bwdata"

# Stop Bitwarden
cd /home/bitwarden
./bitwarden.sh stop

# Create backup directory
mkdir -p "$BACKUP_DIR/$TIMESTAMP"

# Backup critical directories
tar -czf "$BACKUP_DIR/$TIMESTAMP/env.tar.gz" -C "$BW_DIR" env
tar -czf "$BACKUP_DIR/$TIMESTAMP/attachments.tar.gz" -C "$BW_DIR/core" attachments
tar -czf "$BACKUP_DIR/$TIMESTAMP/mssql-data.tar.gz" -C "$BW_DIR/mssql" data
tar -czf "$BACKUP_DIR/$TIMESTAMP/aspnet-dataprotection.tar.gz" -C "$BW_DIR/core" aspnet-dataprotection

# Start Bitwarden
./bitwarden.sh start

# Keep last 30 days
find "$BACKUP_DIR" -type d -mtime +30 -exec rm -rf {} +

echo "Backup completed: $BACKUP_DIR/$TIMESTAMP"

Automate Backups

Cron job (monthly):

# Edit crontab
crontab -e

# Add line (runs 1st of month at 2 AM)
0 2 1 * * /home/bitwarden/bitwarden-backup.sh >> /var/log/bitwarden-backup.log 2>&1

Restore from Backup

#!/bin/bash
# bitwarden-restore.sh

BACKUP_DATE="20250101_020000"
BACKUP_DIR="/backups/bitwarden/$BACKUP_DATE"
BW_DIR="/home/bitwarden/bwdata"

# Stop Bitwarden
cd /home/bitwarden
./bitwarden.sh stop

# Restore directories
tar -xzf "$BACKUP_DIR/env.tar.gz" -C "$BW_DIR"
tar -xzf "$BACKUP_DIR/attachments.tar.gz" -C "$BW_DIR/core"
tar -xzf "$BACKUP_DIR/mssql-data.tar.gz" -C "$BW_DIR/mssql"
tar -xzf "$BACKUP_DIR/aspnet-dataprotection.tar.gz" -C "$BW_DIR/core"

# Fix permissions
chown -R bitwarden:bitwarden "$BW_DIR"

# Start Bitwarden
./bitwarden.sh start

echo "Restore completed from: $BACKUP_DIR"

Authentication Integration

Azure AD / Entra ID

Configure in Bitwarden:

  1. Admin Panel → SSOConfigure
  2. Select OpenID Connect
  3. Enter Azure AD details:
    • Authority: https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0
    • Client ID: From Azure App Registration
    • Client Secret: From Azure App Registration

Azure App Registration:

  1. Azure Portal → App registrationsNew registration
  2. Name: Bitwarden SSO
  3. Redirect URI: https://vault.example.com/sso-callback
  4. Create client secret
  5. API permissions: User.Read, profile, email

LDAP / Active Directory

Bitwarden supports LDAP sync for directory integration.

Configure LDAP sync:

# bwdata/env/global.override.env
globalSettings__ldap__server=ldap://dc.example.com
globalSettings__ldap__port=389
globalSettings__ldap__baseDn=DC=example,DC=com
globalSettings__ldap__username=CN=bitwarden,OU=Service Accounts,DC=example,DC=com
globalSettings__ldap__password=ldap_password

Monitoring and Maintenance

Health Check

Check container health:

docker ps --format "table {{.Names}}\t{{.Status}}"

Database connectivity:

docker exec -it bitwarden-mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'your_password' -Q "SELECT @@VERSION"

Log Monitoring

Setup log rotation:

// /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Restart Docker:

sudo systemctl restart docker

Performance Tuning

Database maintenance (SQL Server):

-- Inside bitwarden-mssql container
USE vault;
GO

-- Update statistics
EXEC sp_updatestats;
GO

-- Rebuild indexes
EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REBUILD';
GO

Things worth getting right

Enforce a strong master password policy and require 2FA for every user. These two alone eliminate the vast majority of realistic attack paths.

Run automated backups of the directories listed above and test restore at least once. A backup you’ve never restored from is a backup you don’t have.

HTTPS only. Never expose the web vault over plain HTTP, even briefly. Limit access to management endpoints (admin panel, SSH) to specific source IPs where possible.

Keep the stack on current releases. Bitwarden ships security fixes regularly; running an old version on the open internet is asking for it.

For private instances, disable user registration in the admin panel so the only way in is via an account you create.

Troubleshooting

Common Issues

Container won’t start:

# Check logs
docker logs bitwarden-api

# Check disk space
df -h

# Verify permissions
ls -la ./bwdata

Cannot access web vault:

# Check NGINX logs
docker logs bitwarden-nginx

# Verify SSL certificate
openssl s_client -connect vault.example.com:443

# Check firewall
sudo ufw status

Email not sending:

# Test SMTP from container
docker exec -it bitwarden-api bash
telnet smtp.example.com 587

Database connection errors:

# Check database status
docker exec -it bitwarden-mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa

# Verify connection string
cat ./bwdata/env/global.override.env | grep connectionString

Migration and Disaster Recovery

Migrate to New Server

  1. Prepare new server with same Bitwarden version
  2. Backup current installation
  3. Transfer backup files to new server
  4. Restore using restore script
  5. Update DNS to point to new server
  6. Test functionality thoroughly

High Availability

For mission-critical deployments:

  • Load balancer in front of multiple Bitwarden instances
  • Shared database (Azure SQL, AWS RDS)
  • Shared storage for attachments (S3, Azure Blob)
  • Geographic redundancy for disaster recovery

Additional Resources

Key Topics

Core Configuration