Skip to content

Deploying Bitwarden

Bitwarden is a leading open-source password manager and vault service that enables individuals and organizations to securely store, manage, and share passwords, login credentials, and sensitive information. Built with security as the core principle, Bitwarden provides end-to-end encrypted password management without reliance on proprietary cloud services. Whether you’re managing personal passwords, team credentials, or enterprise-wide secrets, Bitwarden delivers transparent, auditable, and completely self-hosted password management infrastructure.

Why Bitwarden?

Bitwarden stands out as the premier choice for password management with exceptional security and transparency:

  • End-to-End Encryption: All data encrypted on client side before transmission
  • Open Source: Complete source code available for audit and verification
  • Zero-Knowledge Architecture: Server cannot decrypt your data
  • Self-Hosted: Full control over infrastructure and data
  • No Cloud Dependency: Run entirely on your own servers
  • Cross-Platform: Available for Windows, Mac, Linux, iOS, Android
  • Browser Extensions: Native support for Chrome, Firefox, Safari, Edge
  • Organization Management: Create teams and manage shared credentials
  • User Roles and Permissions: Fine-grained access control
  • Two-Factor Authentication: Support for TOTP, WebAuthn, Duo, and more
  • Password Generator: Built-in secure password generation
  • Secure Notes: Store encrypted notes and documents
  • Identity Management: Store and auto-fill identity information
  • Group-Based Access: Collections for organizing shared items
  • Audit Logging: Complete access logs for compliance
  • LDAP/Active Directory: Enterprise authentication integration
  • API Access: Programmatic access to vault data
  • Mobile Apps: Full-featured iOS and Android applications

Bitwarden is ideal for individuals seeking privacy, teams requiring credential sharing, enterprises needing compliance-ready password management, and organizations that want complete infrastructure control. With persistent storage on Klutch.sh, all your password data is permanently secured and backed up.

Prerequisites

Before deploying Bitwarden, ensure you have:

  • A Klutch.sh account
  • A GitHub repository with your Bitwarden deployment configuration
  • Basic familiarity with Docker, Git, and security concepts
  • A custom domain name (recommended for production)
  • SSL/TLS certificate requirements (automatic via Klutch.sh)
  • Understanding of password management best practices
  • Optional: LDAP or Active Directory for enterprise integration

Important Considerations

Deploying Bitwarden

  1. Create a New Project

    Log in to your Klutch.sh dashboard and create a new project for your Bitwarden deployment.

  2. Prepare Your Repository

    Create a GitHub repository with the following structure for your Bitwarden deployment:

    bitwarden-deploy/
    ├─ Dockerfile
    ├─ .env.example
    ├─ docker-entrypoint.sh
    ├─ nginx.conf
    ├─ .gitignore
    └─ README.md

    Here’s a Dockerfile for Bitwarden:

    FROM node:18-alpine AS builder
    # Install build dependencies
    RUN apk add --no-cache \
    python3 \
    make \
    g++ \
    curl \
    git
    WORKDIR /app
    # Clone Bitwarden repository
    RUN git clone https://github.com/bitwarden/server.git . && \
    git checkout master
    # Build the application (Node.js components)
    RUN npm ci && npm run build
    FROM node:18-alpine
    # Install runtime dependencies
    RUN apk add --no-cache \
    curl \
    ca-certificates \
    openssl \
    postgresql-client
    WORKDIR /app
    # Copy built application from builder
    COPY --from=builder /app /app
    # Create necessary directories
    RUN mkdir -p /app/data \
    /app/logs \
    /app/attachments \
    /app/keys && \
    chmod -R 755 /app
    # Copy entrypoint script
    COPY docker-entrypoint.sh /
    RUN chmod +x /docker-entrypoint.sh
    # Expose port
    EXPOSE 8000
    # Health check
    HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:8000/alive || exit 1
    # Run entrypoint
    ENTRYPOINT ["/docker-entrypoint.sh"]
    CMD ["start"]

    Create a docker-entrypoint.sh file:

    #!/bin/bash
    set -e
    # Wait for database if configured
    if [ -n "$DATABASE_URL" ]; then
    echo "Waiting for database connection..."
    MAX_ATTEMPTS=30
    ATTEMPTS=0
    while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
    if pg_isready -h $(echo $DATABASE_URL | cut -d/ -f3 | cut -d@ -f2 | cut -d: -f1) \
    -p $(echo $DATABASE_URL | cut -d: -f4 | cut -d/ -f1) 2>/dev/null; then
    echo "Database is ready!"
    break
    fi
    ATTEMPTS=$((ATTEMPTS + 1))
    sleep 1
    done
    fi
    # Generate encryption keys if not present
    if [ ! -f /app/keys/encryption.key ]; then
    echo "Generating encryption keys..."
    openssl rand -out /app/keys/encryption.key 32
    chmod 600 /app/keys/encryption.key
    fi
    # Initialize database
    if [ ! -f /app/data/initialized ]; then
    echo "Initializing database..."
    npm run db:migrate || true
    touch /app/data/initialized
    fi
    # Set permissions
    chmod -R 755 /app
    if [ "$1" = "start" ]; then
    # Start the application
    npm start
    else
    exec "$@"
    fi

    Create a .env.example file:

    Terminal window
    # Application Configuration
    NODE_ENV=production
    APP_PORT=8000
    APP_URL=https://vault.yourdomain.com
    DOMAIN=yourdomain.com
    LOG_LEVEL=info
    # Database Configuration
    DATABASE_URL=postgresql://bitwarden_user:password@db:5432/bitwarden
    DATABASE_TYPE=postgresql
    DATABASE_POOL_SIZE=20
    # Encryption Configuration
    ENCRYPTION_KEY_PATH=/app/keys/encryption.key
    JWT_SECRET=your-jwt-secret-key-here
    ADMIN_TOKEN=your-secure-admin-token
    # Admin Settings
    ADMIN_PASSWORD=secure_password_here
    ADMIN_EMAIL=admin@yourdomain.com
    # User Registration
    ALLOW_USER_REGISTRATION=true
    ALLOW_ORGANIZATION_CREATION=true
    INVITE_EXPIRES_DAYS=7
    # Email Configuration
    MAIL_FROM=noreply@yourdomain.com
    MAIL_FROM_NAME=Bitwarden Vault
    SMTP_HOST=smtp.gmail.com
    SMTP_PORT=587
    SMTP_USERNAME=your-email@gmail.com
    SMTP_PASSWORD=your-app-password
    SMTP_SECURE=true
    SMTP_TIMEOUT=10
    # Security Configuration
    REQUIRE_HTTPS=true
    SESSION_TIMEOUT_MINUTES=30
    MASTER_PASSWORD_MINIMUM_LENGTH=8
    PASSWORD_COMPLEXITY=true
    REQUIRE_TWO_FACTOR=false
    # Two-Factor Authentication
    ENABLE_TOTP=true
    ENABLE_WEBAUTHN=true
    ENABLE_DUO=false
    # LDAP Configuration (Optional)
    LDAP_ENABLED=false
    LDAP_SERVER=ldap://ldap.yourdomain.com
    LDAP_BASE_DN=dc=yourdomain,dc=com
    LDAP_BIND_DN=cn=admin,dc=yourdomain,dc=com
    LDAP_BIND_PASSWORD=password
    # Organization Settings
    MAX_USERS_PER_ORGANIZATION=1000
    MAX_ORGANIZATIONS_PER_USER=10
    # API Configuration
    API_ENABLED=true
    API_KEY_ENABLED=true
    # Logging
    LOG_FILE=/app/logs/bitwarden.log
    LOG_SIZE_LIMIT=104857600
    LOG_RETENTION_DAYS=30
    # Backup
    BACKUP_ENABLED=true
    BACKUP_SCHEDULE=0 2 * * *
    BACKUP_RETENTION_DAYS=30

    Commit and push to your GitHub repository:

    Terminal window
    git init
    git add .
    git commit -m "Initial Bitwarden deployment"
    git remote add origin https://github.com/yourusername/bitwarden-deploy.git
    git push -u origin main
  3. Create a New App

    In the Klutch.sh dashboard:

    • Click “Create New App”
    • Select your GitHub repository containing the Dockerfile
    • Choose the branch (typically main or master)
    • Klutch.sh will automatically detect the Dockerfile in the root directory
  4. Configure Environment Variables

    Set up these essential environment variables in your Klutch.sh dashboard:

    VariableDescriptionExample
    APP_URLYour Bitwarden domainhttps://vault.yourdomain.com
    APP_PORTApplication port8000
    NODE_ENVEnvironment typeproduction
    DATABASE_URLDatabase connectionpostgresql://user:pass@host/db
    JWT_SECRETJWT signing secretsecure-random-string
    ADMIN_TOKENAdmin API token (generate secure)secure-token
    ADMIN_PASSWORDAdmin account passwordsecure_password
    ADMIN_EMAILAdmin email addressadmin@yourdomain.com
    ENCRYPTION_KEY_PATHPath to encryption key/app/keys/encryption.key
    ALLOW_USER_REGISTRATIONAllow new user signupstrue
    SMTP_HOSTSMTP server hostnamesmtp.gmail.com
    SMTP_PORTSMTP port587
    SMTP_USERNAMESMTP usernameyour-email@gmail.com
    SMTP_PASSWORDSMTP passwordapp_password
    MAIL_FROMEmail sender addressnoreply@yourdomain.com
    SESSION_TIMEOUT_MINUTESSession timeout duration30
    ENABLE_TOTPEnable TOTP 2FAtrue
    ENABLE_WEBAUTHNEnable WebAuthn/FIDO2true
    LOG_LEVELLogging verbosityinfo
  5. Configure Persistent Storage

    Bitwarden requires persistent storage for vault data, attachments, and keys. Add persistent volumes:

    Mount PathDescriptionRecommended Size
    /app/dataVault database and configuration100GB+
    /app/keysEncryption keys and certificates5GB
    /app/attachmentsUser file attachments500GB+
    /app/logsApplication logs20GB

    In the Klutch.sh dashboard:

    • Navigate to your app settings
    • Go to the “Volumes” section
    • Click “Add Volume” for each mount path
    • Set mount paths and sizes as specified above
  6. Set Network Configuration

    Configure your app’s network settings:

    • Select traffic type: HTTP (Bitwarden uses standard web ports)
    • Recommended internal port: 8000 (as specified in Dockerfile)
    • Klutch.sh will automatically handle HTTPS termination via reverse proxy
    • Ensure ports 80 and 443 are accessible from your domain
  7. Configure Custom Domain

    Bitwarden requires a custom domain for secure operation:

    • Navigate to your app’s “Domains” section in Klutch.sh
    • Click “Add Custom Domain”
    • Enter your domain (e.g., vault.yourdomain.com)
    • Configure DNS with a CNAME record to point to your Klutch.sh app
    • Update APP_URL environment variable to match your domain
    • Klutch.sh will automatically provision SSL certificates
  8. Deploy Your App

    • Review all settings and environment variables
    • Click “Deploy”
    • Klutch.sh will build the Docker image and start your Bitwarden instance
    • Wait for the deployment to complete (typically 5-10 minutes)
    • Access your Bitwarden instance at your configured domain
    • Create your admin account and begin configuring users

Initial Setup and Configuration

After deployment completes, access your Bitwarden instance to complete setup.

Accessing Bitwarden Admin Panel

Navigate to your domain with /admin path: https://vault.yourdomain.com/admin/

Log in with the admin token or admin account you configured.

Creating Your First User Account

  1. Navigate to your Bitwarden instance: https://vault.yourdomain.com
  2. Click “Create Account”
  3. Enter email and strong master password
  4. Confirm your email address
  5. Log in with your credentials
  6. Set up two-factor authentication for security

Setting Up Two-Factor Authentication

Enhance security with multiple authentication methods:

  1. Log in to your account
  2. Navigate to “Settings” → “Two-step Login”
  3. Choose authentication method:
    • Authenticator (TOTP): Use apps like Google Authenticator
    • WebAuthn/FIDO2: Use hardware security keys
    • Email: Receive codes via email
    • Remember device: Optional trusted device tracking
  4. Complete setup process and save backup codes
  5. Logout and re-login to verify 2FA works

Importing Passwords

Migrate existing passwords to Bitwarden:

  1. Export passwords from your existing password manager
  2. Log in to Bitwarden
  3. Navigate to “Tools” → “Import Data”
  4. Select your source password manager
  5. Upload exported file
  6. Review and confirm import
  7. Organize imported items into collections

Creating an Organization

Set up team password sharing:

  1. Log in to your account
  2. Navigate to “Organizations” → “New Organization”
  3. Name your organization
  4. Select billing plan
  5. Add organization users
  6. Create collections for shared passwords
  7. Assign users to collections
  8. Configure roles and permissions

Managing Collections

Organize shared passwords with collections:

  1. In organization settings, go to “Collections”
  2. Click “New Collection”
  3. Name the collection
  4. Set collection access:
    • Read-only access
    • Read and write access
    • Admin access
  5. Assign users to collection
  6. Move items to collection
  7. Manage collection permissions

Environment Variable Examples

Basic Configuration

Terminal window
APP_URL=https://vault.yourdomain.com
APP_PORT=8000
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db:5432/bitwarden
JWT_SECRET=your-secure-jwt-secret
ADMIN_TOKEN=your-secure-admin-token
ALLOW_USER_REGISTRATION=true
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587

Complete Production Configuration

Terminal window
# Application Settings
APP_URL=https://vault.yourdomain.com
APP_PORT=8000
NODE_ENV=production
DOMAIN=yourdomain.com
LOG_LEVEL=info
LOG_FILE=/app/logs/bitwarden.log
LOG_RETENTION_DAYS=30
# Database Configuration
DATABASE_URL=postgresql://bitwarden_user:secure_password@db:5432/bitwarden
DATABASE_TYPE=postgresql
DATABASE_POOL_SIZE=20
DATABASE_TIMEOUT=30
# Encryption and Security
ENCRYPTION_KEY_PATH=/app/keys/encryption.key
JWT_SECRET=your-secure-jwt-secret-key
ADMIN_TOKEN=your-secure-admin-api-token
REQUIRE_HTTPS=true
# Admin Configuration
ADMIN_PASSWORD=secure_admin_password
ADMIN_EMAIL=admin@yourdomain.com
# User Management
ALLOW_USER_REGISTRATION=true
ALLOW_ORGANIZATION_CREATION=true
INVITE_EXPIRES_DAYS=7
SESSION_TIMEOUT_MINUTES=30
MASTER_PASSWORD_MINIMUM_LENGTH=8
PASSWORD_COMPLEXITY=true
# Email Configuration
MAIL_FROM=noreply@yourdomain.com
MAIL_FROM_NAME=Bitwarden Vault
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_SECURE=true
SMTP_TIMEOUT=10
# Two-Factor Authentication
ENABLE_TOTP=true
ENABLE_WEBAUTHN=true
ENABLE_BACKUP_CODES=true
# Organization Settings
MAX_USERS_PER_ORGANIZATION=1000
MAX_ORGANIZATIONS_PER_USER=10
# API Configuration
API_ENABLED=true
API_KEY_ENABLED=true
API_RATE_LIMIT=100
# Backup Configuration
BACKUP_ENABLED=true
BACKUP_SCHEDULE=0 2 * * *
BACKUP_RETENTION_DAYS=30
BACKUP_PATH=/app/backups
# LDAP Configuration (Optional)
LDAP_ENABLED=false
LDAP_SERVER=ldap://ldap.yourdomain.com
LDAP_BASE_DN=dc=yourdomain,dc=com
LDAP_BIND_DN=cn=admin,dc=yourdomain,dc=com
LDAP_BIND_PASSWORD=password
LDAP_SYNC_INTERVAL_HOURS=24

Sample Code and Getting Started

Python - Bitwarden API Integration

import requests
import json
from typing import Optional, List, Dict
class BitwardenClient:
def __init__(self, base_url: str, admin_token: str):
self.base_url = base_url.rstrip('/')
self.admin_token = admin_token
self.api_url = f'{self.base_url}/api'
self.headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {admin_token}'
}
def create_user(self, email: str, password: str,
name: str = None) -> Optional[Dict]:
"""Create a new user account"""
try:
payload = {
'email': email,
'password': password,
'name': name or email.split('@')[0]
}
response = requests.post(
f'{self.api_url}/accounts/register',
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating user: {e}")
return None
def invite_user_to_organization(self, org_id: str,
email: str, role: str = 'User') -> Optional[Dict]:
"""Invite user to organization"""
try:
payload = {
'emails': [email],
'type': self._role_to_type(role)
}
response = requests.post(
f'{self.api_url}/organizations/{org_id}/users/invite',
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error inviting user: {e}")
return None
def list_organizations(self) -> Optional[List[Dict]]:
"""List all organizations"""
try:
response = requests.get(
f'{self.api_url}/organizations',
headers=self.headers
)
response.raise_for_status()
return response.json().get('data', [])
except requests.exceptions.RequestException as e:
print(f"Error listing organizations: {e}")
return None
def create_organization(self, name: str, billing_email: str) -> Optional[Dict]:
"""Create a new organization"""
try:
payload = {
'name': name,
'billingEmail': billing_email
}
response = requests.post(
f'{self.api_url}/organizations',
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating organization: {e}")
return None
def create_collection(self, org_id: str, name: str) -> Optional[Dict]:
"""Create a collection in organization"""
try:
payload = {
'name': name,
'externalId': None
}
response = requests.post(
f'{self.api_url}/organizations/{org_id}/collections',
headers=self.headers,
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating collection: {e}")
return None
def list_users(self) -> Optional[List[Dict]]:
"""List all users in system"""
try:
response = requests.get(
f'{self.api_url}/users',
headers=self.headers
)
response.raise_for_status()
return response.json().get('data', [])
except requests.exceptions.RequestException as e:
print(f"Error listing users: {e}")
return None
def deactivate_user(self, user_id: str) -> bool:
"""Deactivate a user account"""
try:
response = requests.post(
f'{self.api_url}/users/{user_id}/deactivate',
headers=self.headers
)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
print(f"Error deactivating user: {e}")
return False
def export_organization_vault(self, org_id: str, format: str = 'json') -> Optional[bytes]:
"""Export organization vault data"""
try:
response = requests.get(
f'{self.api_url}/organizations/{org_id}/export',
headers=self.headers,
params={'format': format}
)
response.raise_for_status()
return response.content
except requests.exceptions.RequestException as e:
print(f"Error exporting vault: {e}")
return None
@staticmethod
def _role_to_type(role: str) -> int:
"""Convert role name to type integer"""
role_map = {
'Owner': 0,
'Admin': 1,
'User': 2,
'Manager': 3,
'Provider': 4
}
return role_map.get(role, 2)
# Usage example
if __name__ == "__main__":
client = BitwardenClient('https://vault.yourdomain.com', admin_token='your-admin-token')
# Create a new organization
org = client.create_organization('Acme Corp', 'admin@acmecorp.com')
if org:
org_id = org['id']
print(f"Organization created: {org_id}")
# Create a collection
collection = client.create_collection(org_id, 'Engineering Team')
print(f"Collection created: {collection}")
# Invite users
users_to_invite = ['engineer1@acmecorp.com', 'engineer2@acmecorp.com']
for email in users_to_invite:
result = client.invite_user_to_organization(org_id, email, 'User')
print(f"Invited {email}: {result}")
# List all users
all_users = client.list_users()
print(f"Total users: {len(all_users) if all_users else 0}")
# Export vault
vault_export = client.export_organization_vault(org_id)
if vault_export:
with open('vault_backup.json', 'wb') as f:
f.write(vault_export)

JavaScript - Bitwarden Client Setup

const API_BASE_URL = 'https://vault.yourdomain.com/api';
class BitwardenVaultManager {
constructor(email, masterPassword) {
this.email = email;
this.masterPassword = masterPassword;
this.accessToken = null;
this.refreshToken = null;
}
async login() {
try {
const response = await fetch(`${API_BASE_URL}/accounts/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: this.email,
masterPassword: this.masterPassword,
rememberMe: false
})
});
if (!response.ok) throw new Error('Login failed');
const data = await response.json();
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
return true;
} catch (error) {
console.error('Login error:', error);
return false;
}
}
async getVault() {
try {
const response = await fetch(`${API_BASE_URL}/ciphers`, {
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Failed to fetch vault');
const data = await response.json();
return data.data || [];
} catch (error) {
console.error('Vault fetch error:', error);
return [];
}
}
async createCipher(name, login, password, folderId = null) {
try {
const response = await fetch(`${API_BASE_URL}/ciphers`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 1, // Login type
name: name,
login: {
uri: login.uri || null,
username: login.username,
password: password,
totp: login.totp || null
},
folderId: folderId,
favorite: false
})
});
if (!response.ok) throw new Error('Failed to create cipher');
return await response.json();
} catch (error) {
console.error('Create cipher error:', error);
return null;
}
}
async searchVault(query) {
const vault = await this.getVault();
return vault.filter(cipher =>
cipher.name.toLowerCase().includes(query.toLowerCase()) ||
(cipher.login && cipher.login.username.toLowerCase().includes(query.toLowerCase()))
);
}
async generatePassword(length = 16, uppercase = true,
lowercase = true, numbers = true, symbols = true) {
try {
const response = await fetch(`${API_BASE_URL}/tools/password`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
length: length,
uppercase: uppercase,
lowercase: lowercase,
numbers: numbers,
symbols: symbols
})
});
if (!response.ok) throw new Error('Failed to generate password');
const data = await response.json();
return data.password;
} catch (error) {
console.error('Password generation error:', error);
return null;
}
}
async deleteVaultItem(cipherId) {
try {
const response = await fetch(`${API_BASE_URL}/ciphers/${cipherId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Failed to delete item');
return true;
} catch (error) {
console.error('Delete error:', error);
return false;
}
}
}
// Usage example
(async () => {
const manager = new BitwardenVaultManager('user@yourdomain.com', 'masterPassword');
// Login
const loggedIn = await manager.login();
if (!loggedIn) {
console.error('Failed to login');
return;
}
// Get vault items
const vault = await manager.getVault();
console.log(`Vault contains ${vault.length} items`);
// Create new password item
const newPassword = await manager.generatePassword(20);
const cipher = await manager.createCipher(
'GitHub Account',
{ username: 'user@github.com', uri: 'https://github.com' },
newPassword
);
console.log('Created cipher:', cipher);
// Search vault
const results = await manager.searchVault('github');
console.log('Search results:', results);
})();

cURL - API Integration Examples

Terminal window
# Login to Bitwarden
curl -X POST https://vault.yourdomain.com/api/accounts/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@yourdomain.com",
"masterPassword": "your-master-password"
}'
# Create new user
curl -X POST https://vault.yourdomain.com/api/accounts/register \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"email": "newuser@yourdomain.com",
"password": "secure-password",
"name": "New User"
}'
# Get vault items
curl -X GET https://vault.yourdomain.com/api/ciphers \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Create new password item
curl -X POST https://vault.yourdomain.com/api/ciphers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"type": 1,
"name": "Gmail Account",
"login": {
"username": "yourname@gmail.com",
"password": "your-password",
"uri": "https://mail.google.com"
}
}'
# Generate secure password
curl -X POST https://vault.yourdomain.com/api/tools/password \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"length": 20,
"uppercase": true,
"lowercase": true,
"numbers": true,
"symbols": true
}'
# List organizations
curl -X GET https://vault.yourdomain.com/api/organizations \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
# Invite user to organization
curl -X POST https://vault.yourdomain.com/api/organizations/{org-id}/users/invite \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-d '{
"emails": ["user@yourdomain.com"],
"type": 2
}'
# Export organization vault
curl -X GET "https://vault.yourdomain.com/api/organizations/{org-id}/export?format=json" \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
-o vault_backup.json

Bash - Backup Script

#!/bin/bash
# Bitwarden Backup Script
BACKUP_DIR="/backups/bitwarden"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# Create backup directory
mkdir -p $BACKUP_DIR
# Database backup
echo "Backing up Bitwarden database..."
PGPASSWORD="${DATABASE_PASSWORD}" pg_dump -h ${DATABASE_HOST} \
-U ${DATABASE_USER} -d ${DATABASE_NAME} \
> $BACKUP_DIR/bitwarden_db_$TIMESTAMP.sql
# Attachments backup
echo "Backing up vault attachments..."
tar -czf $BACKUP_DIR/bitwarden_attachments_$TIMESTAMP.tar.gz \
/app/attachments
# Configuration backup
echo "Backing up configuration..."
tar -czf $BACKUP_DIR/bitwarden_config_$TIMESTAMP.tar.gz \
/app/keys /app/data
# Encrypt backups
echo "Encrypting backups..."
openssl enc -aes-256-cbc -salt -in \
$BACKUP_DIR/bitwarden_db_$TIMESTAMP.sql \
-out $BACKUP_DIR/bitwarden_db_$TIMESTAMP.sql.enc \
-pass pass:${BACKUP_ENCRYPTION_PASSWORD}
# Remove unencrypted database backup
rm $BACKUP_DIR/bitwarden_db_$TIMESTAMP.sql
# Cleanup old backups
echo "Cleaning up old backups..."
find $BACKUP_DIR -name "bitwarden_*" -mtime +$RETENTION_DAYS -delete
# Backup summary
echo "Backup completed: $TIMESTAMP"
ls -lh $BACKUP_DIR | tail -5
# Optional: Upload to cloud storage (S3 example)
# aws s3 cp $BACKUP_DIR/bitwarden_db_$TIMESTAMP.sql.enc s3://your-bucket/backups/
# aws s3 cp $BACKUP_DIR/bitwarden_attachments_$TIMESTAMP.tar.gz s3://your-bucket/backups/
# aws s3 cp $BACKUP_DIR/bitwarden_config_$TIMESTAMP.tar.gz s3://your-bucket/backups/

Docker Compose for Local Development

For local testing before deploying to Klutch.sh:

version: '3.8'
services:
bitwarden:
build: .
container_name: bitwarden-app
environment:
APP_URL: http://localhost:8000
APP_PORT: 8000
NODE_ENV: development
DATABASE_URL: postgresql://bitwarden:bitwarden@db:5432/bitwarden
JWT_SECRET: dev-secret-key-change-in-production
ADMIN_TOKEN: dev-admin-token-change-in-production
ADMIN_PASSWORD: admin123
ADMIN_EMAIL: admin@localhost
ALLOW_USER_REGISTRATION: "true"
MAIL_FROM: noreply@localhost
SMTP_HOST: mailhog
SMTP_PORT: 1025
ports:
- "8000:8000"
volumes:
- ./:/app
- ./data:/app/data
- ./attachments:/app/attachments
- ./logs:/app/logs
- ./keys:/app/keys
depends_on:
- db
- mailhog
restart: unless-stopped
db:
image: postgres:15-alpine
container_name: bitwarden-db
environment:
POSTGRES_USER: bitwarden
POSTGRES_PASSWORD: bitwarden
POSTGRES_DB: bitwarden
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
mailhog:
image: mailhog/mailhog:latest
container_name: bitwarden-mailhog
ports:
- "1025:1025"
- "8025:8025"
restart: unless-stopped
volumes:
postgres_data:

To run locally:

Terminal window
docker-compose up -d

Access Bitwarden at http://localhost:8000 Access MailHog (test email) at http://localhost:8025

User Management and Administration

Managing User Accounts

Administer users through the admin panel:

  1. Navigate to admin panel: https://vault.yourdomain.com/admin/
  2. Go to “Users” section
  3. View all user accounts and activity
  4. Enable/disable user accounts
  5. Reset user passwords (users can change)
  6. Delete users and their data
  7. View user login history

Organization Administration

Manage organizations and access control:

  1. Create organizations for different teams
  2. Set organization name and settings
  3. Manage organization members
  4. Assign user roles (Owner, Admin, User)
  5. Create and manage collections
  6. Configure collection access permissions
  7. View organization activity logs

User Roles and Permissions

Configure fine-grained access control:

RolePermissions
OwnerFull organization control, user management, billing
AdminManage users, create collections, view logs
ManagerManage collections and users within collections
UserAccess assigned collections, create personal items

Audit Logging

Monitor all vault activity:

  1. Access admin panel logs
  2. Review user login attempts
  3. Track password item access
  4. Monitor organization changes
  5. Audit user invitations and removals
  6. Export audit logs for compliance

Security Best Practices

Master Password Requirements

Enforce strong master passwords:

  • Minimum length: 8-12 characters
  • Require uppercase, lowercase, numbers, symbols
  • Prevent common passwords
  • Force periodic password changes
  • Educate users on password strength

Two-Factor Authentication

Require 2FA for enhanced security:

  • Enable TOTP authenticator apps
  • Enable WebAuthn/FIDO2 security keys
  • Backup codes for account recovery
  • Enforce 2FA for organization admins
  • Optional: Require 2FA for all users

Data Encryption

Bitwarden’s encryption model:

  • Client-side encryption of all vault data
  • Master password never stored on server
  • AES-256 encryption standard
  • RSA 4096 for encryption keys
  • End-to-end encryption for sharing

Access Control

Implement strong access policies:

  • Principle of least privilege
  • LDAP/Active Directory integration
  • Single Sign-On (SSO) for enterprises
  • IP whitelisting for admin access
  • Session timeout configuration
  • Disable user registration if needed

Network Security

Secure your Bitwarden deployment:

  • HTTPS required for all connections
  • Strong SSL/TLS certificates (automatic via Klutch.sh)
  • Firewall rules limiting access
  • Rate limiting on authentication endpoints
  • DDoS protection considerations
  • Regular security patching

Backup Security

Protect your backup data:

  • Encrypt backups with strong passwords
  • Store offline copies for disaster recovery
  • Test restore procedures regularly
  • Maintain backup access logs
  • Secure backup storage location
  • Automated backup retention policies

Monitoring and Performance

Database Optimization

Optimize database performance:

-- Create indexes for common queries
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_cipher_organization ON ciphers(organization_id);
CREATE INDEX idx_folder_user ON folders(user_id);
CREATE INDEX idx_organization_user ON organization_users(user_id);
-- Analyze query performance
ANALYZE;

Performance Monitoring

Monitor application health:

  • Response time metrics
  • Database query performance
  • API endpoint usage
  • User activity metrics
  • Storage utilization
  • CPU and memory usage

Health Checks

Monitor deployment status:

Terminal window
# Check if Bitwarden is responding
curl -s -o /dev/null -w "%{http_code}" https://vault.yourdomain.com/alive
# Expected response: 200

Troubleshooting

Common Issues and Solutions

Issue: Cannot login to vault

Solutions:

  • Verify username/email is correct
  • Ensure master password is correct
  • Check if account is locked
  • Review email for account reset link
  • Verify database connection
  • Check application logs for errors

Issue: 2FA not working

Troubleshooting:

  • Verify TOTP app time is synchronized
  • Generate new backup codes
  • Try alternative 2FA method
  • Check email receiving capability
  • Verify SMTP configuration

Issue: Slow vault access

Solutions:

  • Check database performance
  • Optimize SQL queries
  • Enable caching
  • Review application logs
  • Check system resources
  • Verify network connectivity

Issue: Users cannot register

Solutions:

  • Verify ALLOW_USER_REGISTRATION is true
  • Check email configuration
  • Review registration logs
  • Check SMTP settings
  • Verify email is valid format
  • Check for rate limiting

Updating Bitwarden

To update Bitwarden to a newer version:

  1. Update your Dockerfile:

    RUN git clone https://github.com/bitwarden/server.git . && \
    git checkout latest-version
  2. Commit and push to GitHub

  3. Klutch.sh will automatically rebuild

  4. Always backup database before upgrading

  5. Test in development first

  6. Monitor logs after upgrade

  7. Verify all features working correctly

Use Cases

Individual Password Management

  • Secure personal password storage
  • Password sharing with family
  • Multi-device access
  • Emergency contacts vault items

Team Credential Management

  • Shared password access
  • Role-based access control
  • Secure API key storage
  • Database credential management

Enterprise Deployments

  • Company-wide password management
  • LDAP/AD integration
  • Compliance audit trails
  • Department-based organization structure

Development Team Secrets

  • API key management
  • Database credentials
  • SSH keys storage
  • Environment secrets

Additional Resources

Conclusion

Deploying Bitwarden on Klutch.sh provides you with a secure, transparent, and self-hosted password management solution that maintains complete control over your sensitive credentials. With end-to-end encryption, comprehensive user management, organization support, two-factor authentication, and audit logging, Bitwarden enables organizations and individuals to manage passwords with complete confidence. Klutch.sh’s managed infrastructure ensures your password vault is always available, secure, and performant, while maintaining privacy through open-source code you can audit.

Start hosting your secure password vault today by deploying Bitwarden on Klutch.sh and take control of your credential management.