ANAVEM
Languagefr
How to Deploy Bitwarden with Docker for Self-Hosted Password Management

How to Deploy Bitwarden with Docker for Self-Hosted Password Management

Deploy a production-ready Bitwarden password manager using Docker containers with SSL, database configuration, and security hardening for complete control over your credentials.

Evan MaelEvan Mael
March 26, 2026 15 min
mediumbitwarden 10 steps 15 min

Why Deploy Self-Hosted Bitwarden with Docker?

Self-hosting Bitwarden gives you complete control over your password management infrastructure, ensuring your sensitive credentials never leave your servers. Unlike cloud-based solutions, a self-hosted deployment eliminates third-party data access concerns while providing the same robust features as Bitwarden's commercial offering.

Docker containerization makes Bitwarden deployment significantly more manageable than traditional installations. The official Docker setup includes automated SSL certificate management, database orchestration, and service scaling—all managed through a single script interface. This approach reduces configuration complexity while maintaining production-grade security and reliability.

What Makes Docker the Preferred Deployment Method for Bitwarden?

Bitwarden's Docker implementation uses a multi-container architecture that separates concerns effectively. The web vault, API server, identity provider, and database each run in isolated containers, improving security boundaries and making updates safer. The official bitwarden.sh script automates the entire Docker Compose orchestration, handling everything from SSL certificates to database migrations.

The containerized approach also simplifies backup and disaster recovery procedures. Database backups, configuration files, and SSL certificates are contained within predictable directory structures, making it straightforward to implement automated backup strategies and restore procedures.

How Does Self-Hosted Bitwarden Compare to Cloud Solutions?

Self-hosted Bitwarden provides identical functionality to the cloud version while offering superior privacy controls and customization options. You can implement custom authentication providers, integrate with existing LDAP systems, and maintain complete audit trails of all access attempts. The trade-off is increased operational responsibility—you handle updates, monitoring, and security hardening rather than relying on Bitwarden's managed infrastructure.

Implementation Guide

Full Procedure

01

Create Bitwarden System User and Directory Structure

First, create a dedicated system user for Bitwarden to avoid running as root. This follows security best practices and prevents permission issues.

sudo useradd -r -m -d /opt/bitwarden -s /bin/false bitwarden
sudo mkdir -p /opt/bitwarden
sudo chown -R bitwarden:bitwarden /opt/bitwarden

Switch to the bitwarden user and navigate to the installation directory:

sudo -u bitwarden -s /bin/bash
cd /opt/bitwarden
Warning: Never install Bitwarden as root user. This creates security vulnerabilities and file permission issues that are difficult to fix later.

Verify the user and directory setup:

whoami
pwd
ls -la /opt/bitwarden

You should see bitwarden as the current user and /opt/bitwarden as the current directory.

02

Download and Install Bitwarden Installation Script

Download the official Bitwarden installation script. This script automates the Docker Compose setup and configuration process.

curl -Lso bitwarden.sh https://go.btwrdn.co/bw-sh
chmod 700 bitwarden.sh

Verify the script downloaded correctly:

ls -la bitwarden.sh
head -5 bitwarden.sh

You should see the script file with execute permissions and the beginning of the shell script content.

Pro tip: Always verify downloaded scripts before execution. The official Bitwarden script is signed and regularly updated from the go.btwrdn.co redirect.
03

Obtain Installation ID and Key from Bitwarden

Before running the installation, you need to register your self-hosted instance with Bitwarden to get an Installation ID and Key. Visit https://bitwarden.com/host in your browser.

Fill out the registration form:

  • Enter your admin email address
  • Select your region (US or EU)
  • Agree to the terms

Copy the Installation ID and Installation Key that are generated. You'll need these in the next step.

Warning: Keep your Installation ID and Key secure. These authenticate your self-hosted instance with Bitwarden's services for license validation and updates.

Store these values temporarily in environment variables for easy access:

export BW_INSTALLATION_ID="your-installation-id-here"
export BW_INSTALLATION_KEY="your-installation-key-here"
04

Run Initial Bitwarden Installation and Configuration

Execute the installation script to set up the initial configuration:

./bitwarden.sh install

The script will prompt you for several configuration values:

  • Domain name: Enter your full domain (e.g., bitwarden.yourdomain.com)
  • Let's Encrypt SSL: Choose 'y' for automatic SSL certificates
  • Installation ID: Paste the ID from step 3
  • Installation Key: Paste the key from step 3
  • Database: Accept default (MSSQL) or specify PostgreSQL

The installation creates the directory structure and downloads Docker images:

ls -la bwdata/
ls -la bwdata/env/

Verify the installation created the necessary files:

find bwdata/ -name "*.yml" -o -name "*.env" | head -10

You should see docker-compose files and environment configuration files.

05

Configure Environment Variables and Database Settings

Edit the global environment configuration to customize your deployment:

nano bwdata/env/global.override.env

Add or modify these essential settings:

# Domain configuration
BW_DOMAIN=bitwarden.yourdomain.com

# Database settings (PostgreSQL example)
BW_DB_PROVIDER=postgresql
BW_DB_SERVER=db
BW_DB_DATABASE=bitwarden
BW_DB_USERNAME=bitwarden
BW_DB_PASSWORD=your-strong-database-password

# Installation credentials
BW_INSTALLATION_ID=your-installation-id
BW_INSTALLATION_KEY=your-installation-key

# SMTP configuration for email notifications
globalSettings__mail__smtp__host=smtp.yourdomain.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__ssl=false
globalSettings__mail__smtp__username=bitwarden@yourdomain.com
globalSettings__mail__smtp__password=your-smtp-password

# Security settings
globalSettings__disableUserRegistration=true
globalSettings__requireHttps=true
Pro tip: Use PostgreSQL instead of MSSQL for better resource usage and easier backup management. PostgreSQL typically uses 50% less memory than MSSQL in Bitwarden deployments.

Save the file and verify the configuration:

cat bwdata/env/global.override.env | grep -E "BW_DOMAIN|BW_DB_PROVIDER"
06

Configure SSL Certificates and Reverse Proxy

If you're using Let's Encrypt (recommended), ensure your domain DNS is properly configured and ports 80/443 are accessible. The installation script handles certificate generation automatically.

For custom SSL certificates, place them in the SSL directory:

mkdir -p bwdata/ssl/bitwarden.yourdomain.com/
# Copy your certificate files:
# cp your-cert.crt bwdata/ssl/bitwarden.yourdomain.com/certificate.crt
# cp your-private.key bwdata/ssl/bitwarden.yourdomain.com/private.key

Configure the nginx settings if needed:

nano bwdata/nginx/default.conf
Warning: If using Cloudflare, disable the proxy (set to DNS only) during initial SSL certificate generation. Re-enable after certificates are issued to prevent Let's Encrypt validation failures.

Test the SSL configuration will work:

openssl s_client -connect bitwarden.yourdomain.com:443 -servername bitwarden.yourdomain.com < /dev/null
07

Start Bitwarden Services and Verify Deployment

Start all Bitwarden services using the management script:

./bitwarden.sh start

Monitor the startup process and check container status:

docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker logs bitwarden-api
docker logs bitwarden-web

Verify all containers are running healthy:

docker ps | grep -E "bitwarden|postgres|mssql" | wc -l

You should see 6-8 containers running (web, api, identity, admin, icons, notifications, events, database).

Test the web interface by visiting your domain:

curl -I https://bitwarden.yourdomain.com
echo "Visit https://bitwarden.yourdomain.com in your browser"

The response should show HTTP 200 OK and you should see the Bitwarden login page in your browser.

08

Create Admin Account and Configure Organization Settings

Access the admin panel to create your first user account. Navigate to https://bitwarden.yourdomain.com/admin in your browser.

If admin registration is disabled, temporarily enable it:

echo "globalSettings__disableUserRegistration=false" >> bwdata/env/global.override.env
./bitwarden.sh restart

Create your admin account through the web interface, then immediately disable registration:

sed -i 's/globalSettings__disableUserRegistration=false/globalSettings__disableUserRegistration=true/' bwdata/env/global.override.env
./bitwarden.sh restart

Verify your account creation and admin access:

docker logs bitwarden-api | grep -i "user.*created"
docker logs bitwarden-identity | tail -20
Pro tip: Set up organization policies immediately after account creation. Enable two-factor authentication requirement and set password complexity rules to maintain security standards.

Test login functionality by accessing the vault and creating a test entry to ensure everything works correctly.

09

Implement Security Hardening and Backup Strategy

Configure fail2ban to protect against brute force attacks:

sudo apt install fail2ban -y
sudo nano /etc/fail2ban/jail.local

Add Bitwarden-specific jail configuration:

[bitwarden]
enabled = true
port = 80,443
filter = bitwarden
logpath = /opt/bitwarden/bwdata/logs/api/*.txt
maxretry = 3
bantime = 3600
findtime = 600

Create the fail2ban filter:

sudo nano /etc/fail2ban/filter.d/bitwarden.conf
[Definition]
failregex = ^.*Invalid username or password.*.*$
ignoreregex =

Set up automated backups of the database and configuration:

mkdir -p /opt/bitwarden/backups
nano /opt/bitwarden/backup.sh
#!/bin/bash
BACKUP_DIR="/opt/bitwarden/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# Backup database
docker exec bitwarden-db pg_dump -U bitwarden bitwarden > "$BACKUP_DIR/db_backup_$DATE.sql"

# Backup configuration
tar -czf "$BACKUP_DIR/config_backup_$DATE.tar.gz" -C /opt/bitwarden bwdata/env bwdata/ssl

# Keep only last 7 days of backups
find "$BACKUP_DIR" -name "*backup*" -mtime +7 -delete

Make the backup script executable and add to crontab:

chmod +x /opt/bitwarden/backup.sh
echo "0 2 * * * /opt/bitwarden/backup.sh" | crontab -

Verify the security configuration:

sudo fail2ban-client status bitwarden
ls -la /opt/bitwarden/backups/
10

Configure Monitoring and Maintenance Procedures

Set up log rotation to prevent disk space issues:

sudo nano /etc/logrotate.d/bitwarden
/opt/bitwarden/bwdata/logs/*/*.txt {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    copytruncate
}

Create a health check script to monitor service status:

nano /opt/bitwarden/health-check.sh
#!/bin/bash
HEALTH_URL="https://bitwarden.yourdomain.com/alive"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL")

if [ "$STATUS" != "200" ]; then
    echo "$(date): Bitwarden health check failed - HTTP $STATUS" >> /var/log/bitwarden-health.log
    # Optional: send alert email or restart services
    /opt/bitwarden/bitwarden.sh restart
else
    echo "$(date): Bitwarden health check passed" >> /var/log/bitwarden-health.log
fi

Set up the health check to run every 5 minutes:

chmod +x /opt/bitwarden/health-check.sh
echo "*/5 * * * * /opt/bitwarden/health-check.sh" | crontab -

Configure update notifications and create an update procedure:

nano /opt/bitwarden/update.sh
#!/bin/bash
echo "Starting Bitwarden update process..."
./bitwarden.sh updateself
./bitwarden.sh update
echo "Update completed. Checking service status..."
docker ps --format "table {{.Names}}\t{{.Status}}"
echo "Update log: $(date)" >> /opt/bitwarden/update.log

Verify monitoring setup:

chmod +x /opt/bitwarden/update.sh
tail -f /var/log/bitwarden-health.log &
./health-check.sh
kill %1
Pro tip: Set up external monitoring with tools like Uptime Robot or StatusCake to get alerts when your Bitwarden instance goes down. Internal monitoring won't help if the entire server fails.

Frequently Asked Questions

What are the minimum system requirements for self-hosted Bitwarden with Docker?+
Bitwarden requires a Linux server with at least 2GB RAM (4GB recommended for production), Docker Engine 20.10+, and ports 80/443 accessible from the internet. The database container (PostgreSQL or MSSQL) typically consumes 1-2GB RAM, while the application containers need another 1-2GB. Storage requirements are minimal initially but grow with vault data and logs.
Can I use PostgreSQL instead of MSSQL with Bitwarden Docker deployment?+
Yes, PostgreSQL is fully supported and often preferred over MSSQL for self-hosted deployments. Set BW_DB_PROVIDER=postgresql in your global.override.env file along with appropriate database credentials. PostgreSQL typically uses less memory and provides better performance for smaller deployments while maintaining full compatibility with all Bitwarden features.
How do I backup and restore a self-hosted Bitwarden Docker installation?+
Backup involves three components: database dump, configuration files, and SSL certificates. Use docker exec to run pg_dump or sqlcmd for database backups, then archive the bwdata/env and bwdata/ssl directories. For restoration, restore the database dump to a fresh database container and copy configuration files to the appropriate bwdata locations before starting services.
What happens if I lose my Bitwarden Installation ID and Key?+
The Installation ID and Key authenticate your self-hosted instance with Bitwarden's licensing servers. If lost, visit https://bitwarden.com/host to generate new credentials using the same email address. You'll need to update the BW_INSTALLATION_ID and BW_INSTALLATION_KEY values in your global.override.env file and restart services. Existing vault data remains unaffected.
How do I update a self-hosted Bitwarden Docker deployment safely?+
Use the built-in update commands: ./bitwarden.sh updateself updates the management script, then ./bitwarden.sh update pulls new container images and applies configuration changes. Always backup your database and configuration before updating. The update process preserves existing data and settings while applying security patches and feature updates automatically.
Evan Mael
Written by

Evan Mael

Microsoft MCSA-certified Cloud Architect | Fortinet-focused. I modernize cloud, hybrid & on-prem infrastructure for reliability, security, performance and cost control - sharing field-tested ops & troubleshooting.

Discussion

Share your thoughts and insights

Sign in to join the discussion