Installer Bitwarden Self-Hosted sur Ubuntu : Guide Complet avec Docker Compose

Installer Bitwarden Self-Hosted sur Ubuntu : Guide Technique Complet

Bitwarden self-hosted offre un contrôle total sur vos données de mots de passe. Contrairement à la version cloud, vous hébergez le gestionnaire sur votre propre infrastructure. Ce tutoriel couvre l’installation complète sur Ubuntu Server avec Docker Compose, certificats SSL/TLS et stratégie de sauvegarde.

Prérequis Techniques

  • Serveur Ubuntu 20.04 LTS ou 22.04 LTS (minimum 2 vCPU, 2 Go RAM)
  • Nom de domaine pointant vers l’IP du serveur
  • Docker Engine 20.10+ et Docker Compose 2.0+
  • Accès root/sudo au serveur
  • Port 80 et 443 accessibles (HTTP/HTTPS)
  • Certificat SSL/TLS (Let’s Encrypt gratuit recommandé)

Étape 1 : Préparation du Serveur Ubuntu

Mise à jour du système

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git ufw

Installation de Docker et Docker Compose

# Ajouter la clé GPG officielle de Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Configurer le dépôt stable
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Installer Docker
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Ajouter votre utilisateur au groupe docker
sudo usermod -aG docker $USER
newgrp docker

# Vérifier l'installation
docker --version && docker compose version

Configuration du Firewall (UFW)

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp      # SSH
sudo ufw allow 80/tcp      # HTTP (Let's Encrypt)
sudo ufw allow 443/tcp     # HTTPS
sudo ufw enable

Étape 2 : Préparation des Répertoires et Fichiers

Structure des dossiers

mkdir -p ~/bitwarden/{data,certs}
cd ~/bitwarden
ls -la

Créer le fichier .env pour les variables d’environnement

cat > ~/bitwarden/.env << 'EOF'
# Configuration Bitwarden Self-Hosted
DOMAIN=vault.exemple.com
ADMIN_TOKEN=changez_ceci_par_un_token_long_et_complexe
LOG_LEVEL=warn
DATABASE_URL=postgresql://bitwarden:PASSWORD_DB_COMPLEXE@postgres:5432/bitwarden
DUO_IKEY=
DUO_SKEY=
DUO_HOST=
SMTP_HOST=
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_FROM=bitwarden@exemple.com
SMTP_USERNAME=
SMTP_PASSWORD=
REQUIRE_DEVICE_EMAIL=false
DEVICE_TOKEN_DURATION=2592000
REFRESH_TOKEN_LIFETIME=2592000
EOF

Important : Remplacez les valeurs avec vos propres données sécurisées. Générez un token admin robuste :

openssl rand -base64 32

Étape 3 : Configuration Docker Compose

Créer le fichier docker-compose.yml

cat > ~/bitwarden/docker-compose.yml << 'EOF'
version: '3.9'

services:
  postgres:
    image: postgres:15-alpine
    container_name: bitwarden-db
    restart: always
    environment:
      POSTGRES_USER: bitwarden
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-password_db_change_moi}
      POSTGRES_DB: bitwarden
      POSTGRES_INITDB_ARGS: "-c shared_preload_libraries=uuid-ossp"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backups:/backups
    networks:
      - bitwarden-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U bitwarden -d bitwarden"]
      interval: 10s
      timeout: 5s
      retries: 5

  bitwarden:
    image: vaultwarden/server:latest
    container_name: bitwarden-app
    restart: always
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DOMAIN: https://${DOMAIN:-vault.exemple.com}
      DATABASE_URL: postgresql://bitwarden:${DATABASE_PASSWORD:-password_db_change_moi}@postgres:5432/bitwarden
      ADMIN_TOKEN: ${ADMIN_TOKEN}
      LOG_LEVEL: ${LOG_LEVEL:-info}
      SHOW_PASSWORD_HINT: false
      INVITATIONS_ALLOWED: true
      SIGNUPS_ALLOWED: false
      REQUIRE_DEVICE_EMAIL: ${REQUIRE_DEVICE_EMAIL:-false}
      ROCKET_ADDRESS: 0.0.0.0
      ROCKET_PORT: 8000
      ROCKET_TLS: {certs: "/certs/fullchain.pem", key: "/certs/privkey.pem"}
    volumes:
      - ./data:/data
      - ./certs:/certs:ro
    ports:
      - "8000:8000"
    networks:
      - bitwarden-network
    labels:
      - "com.example.description=Bitwarden Self-Hosted"

volumes:
  postgres_data:

networks:
  bitwarden-network:
    driver: bridge
EOF

Étape 4 : Configuration HTTPS avec Let's Encrypt

Installation de Certbot

sudo apt install -y certbot python3-certbot-dns-digitalocean
# Ou pour autre DNS provider :
# sudo apt install -y certbot python3-certbot-dns-cloudflare

Générer le certificat SSL/TLS

# Vérifiez que les ports 80 et 443 sont libres
sudo lsof -i :80,443

# Générer le certificat (mode standalone)
sudo certbot certonly --standalone \
  -d vault.exemple.com \
  --email admin@exemple.com \
  --agree-tos \
  --non-interactive

Copier les certificats dans le répertoire Bitwarden

sudo cp /etc/letsencrypt/live/vault.exemple.com/fullchain.pem ~/bitwarden/certs/
sudo cp /etc/letsencrypt/live/vault.exemple.com/privkey.pem ~/bitwarden/certs/
sudo chown -R $USER:$USER ~/bitwarden/certs/
sudo chmod 600 ~/bitwarden/certs/*

Configurer le renouvellement automatique

# Créer un script de renouvellement
cat > ~/bitwarden/renew_cert.sh << 'EOF'
#!/bin/bash
sudo certbot renew --quiet
sudo cp /etc/letsencrypt/live/vault.exemple.com/fullchain.pem ~/bitwarden/certs/
sudo cp /etc/letsencrypt/live/vault.exemple.com/privkey.pem ~/bitwarden/certs/
sudo chown -R $USER:$USER ~/bitwarden/certs/
cd ~/bitwarden && docker compose restart bitwarden
EOF

chmod +x ~/bitwarden/renew_cert.sh

# Ajouter à crontab (renouvellement tous les 60 jours)
(crontab -l 2>/dev/null; echo "0 2 1 * * ~/bitwarden/renew_cert.sh") | crontab -

Étape 5 : Lancement des Conteneurs

Démarrer Bitwarden

cd ~/bitwarden
docker compose pull
docker compose up -d

# Vérifier le statut
docker compose ps
docker compose logs -f bitwarden

Vérifier les logs pour les erreurs

docker compose logs --tail=50 bitwarden
docker compose logs --tail=50 postgres

Attendez 30-60 secondes que les conteneurs s'initialisent complètement avant de tester l'accès.

Étape 6 : Configuration Initiale de Bitwarden

Accéder à l'interface d'administration

Ouvrez votre navigateur et accédez à :

https://vault.exemple.com/admin

Entrez votre ADMIN_TOKEN (défini dans .env). Vous devriez voir le tableau de bord d'administration.

Configuration recommandée dans l'admin panel

  • Users : Créer vos comptes utilisateurs
  • Organizations : Créer une organisation si plusieurs utilisateurs
  • Policies : Activer la politique de sécurité (2FA obligatoire si entreprise)
  • Backup : Vérifier la sauvegarde BD régulière

Étape 7 : Stratégie de Sauvegarde Automatisée

Script de sauvegarde PostgreSQL

cat > ~/bitwarden/backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/home/$USER/bitwarden/backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/bitwarden_$DATE.sql.gz"

# Créer le répertoire s'il n'existe pas
mkdir -p "$BACKUP_DIR"

# Effectuer le backup
docker exec bitwarden-db pg_dump -U bitwarden bitwarden | gzip > "$BACKUP_FILE"

# Conserver seulement les 30 derniers backups
find "$BACKUP_DIR" -name "bitwarden_*.sql.gz" -mtime +30 -delete

echo "Backup créé : $BACKUP_FILE"
EOF

chmod +x ~/bitwarden/backup.sh

Planifier les sauvegardes quotidiennes

(crontab -l 2>/dev/null; echo "0 3 * * * ~/bitwarden/backup.sh") | crontab -

# Vérifier
crontab -l

Sauvegarde hors-site (optionnel mais recommandé)

cat > ~/bitwarden/backup_remote.sh << 'EOF'
#!/bin/bash
LOCAL_BACKUP="/home/$USER/bitwarden/backups"
REMOTE_USER="backup_user"
REMOTE_HOST="backup.exemple.com"
REMOTE_PATH="/backups/bitwarden"

rsync -avz --delete "$LOCAL_BACKUP/" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"
EOF

chmod +x ~/bitwarden/backup_remote.sh

# Ajouter à crontab (quotidiennement à 4h du matin)
(crontab -l 2>/dev/null; echo "0 4 * * * ~/bitwarden/backup_remote.sh") | crontab -

Étape 8 : Sécurisation Avancée

Mettre à jour les variables d'environnement sensibles

# Éditer le fichier .env
nano ~/bitwarden/.env

# Variables critiques à configurer :
# - ADMIN_TOKEN : minimum 32 caractères aléatoires
# - DATABASE_PASSWORD : minimum 32 caractères, caractères spéciaux
# - SMTP_PASSWORD : votre mot de passe SMTP (encodé si spéciaux)
# - SIGNUPS_ALLOWED : à false en production
# - SHOW_PASSWORD_HINT : à false pour sécurité accrue

Configuration d'un reverse proxy Nginx (optionnel)

sudo apt install -y nginx

sudo cat > /etc/nginx/sites-available/bitwarden << 'EOF'
server {
    listen 80;
    server_name vault.exemple.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name vault.exemple.com;

    ssl_certificate /etc/letsencrypt/live/vault.exemple.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vault.exemple.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    client_max_body_size 525M;
    proxy_buffering off;

    location / {
        proxy_pass https://localhost:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/bitwarden /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Activer l'authentification 2FA

  • Panel Admin > Organization > Policies > Activate "Two-Step Login"
  • Obligatoire pour tous les utilisateurs en environnement professionnel

Étape 9 : Maintenance et Monitoring

Mettre à jour Bitwarden régulièrement

cd ~/bitwarden

# Arrêter les conteneurs
docker compose down

# Mettre à jour les images
docker compose pull

# Redémarrer
docker compose up -d

# Vérifier les logs
docker compose logs -f bitwarden

Surveillance des ressources

# Vérifier la consommation CPU/RAM
docker stats bitwarden-app bitwarden-db

# Vérifier l'espace disque
du -sh ~/bitwarden/{data,backups}

# Vérifier la taille de la base PostgreSQL
docker exec bitwarden-db psql -U bitwarden -d bitwarden -c "SELECT pg_database.datname, pg_size_pretty(pg_database_size(pg_database.datname)) FROM pg_database;"

Vérifier les logs pour anomalies

# Logs des 100 dernières lignes
docker compose logs --tail=100 bitwarden

# Logs en temps réel
docker compose logs -f --tail=20 bitwarden

Tableau Récapitulatif : Ports et Services

Service Port Interne Port Externe Protocole Description
Bitwarden 8000 443 HTTPS Interface web et API
PostgreSQL 5432 Interne TCP Base de données (réseau Docker)
SSH 22 22 TCP Gestion du serveur

Dépannage Courant

"Connection refused" sur vault.exemple.com

# Vérifier que le conteneur tourne
docker compose ps

# Vérifier la connectivité
curl -k https://localhost:8000

# Vérifier les pare-feu
sudo ufw status
sudo iptables -L

Erreur de certificat SSL

# Vérifier les certificats
ls -la ~/bitwarden/certs/
openssl x509 -in ~/bitwarden/certs/fullchain.pem -text -noout | grep -i "not before\|not after"

# Renouveler manuellement
sudo certbot renew --force-renewal
sudo cp /etc/letsencrypt/live/vault.exemple.com/* ~/bitwarden/certs/

Base de données corrompue

# Vérifier l'intégrité
docker exec bitwarden-db pg_dump -U bitwarden bitwarden > /tmp/test_dump.sql

# Si ça échoue, restaurer depuis le dernier backup
docker compose down
gunzip < ~/bitwarden/backups/bitwarden_YYYYMMDD_HHMMSS.sql.gz | docker exec -i bitwarden-db psql -U bitwarden -d bitwarden
docker compose up -d

Cas d'Usage et Performances

Configuration testée :

  • 2 vCPU, 2 Go RAM : jusqu'à 50 utilisateurs actifs
  • 4 vCPU, 4 Go RAM : jusqu'à 200 utilisateurs actifs
  • 8 vCPU, 8 Go RAM : plus de 500 utilisateurs actifs

Temps de réponse moyen : < 500ms (connexion/synchronisation)

Espace disque : ~2 Go pour 1000 utilisateurs avec 5 ans d'historique

Conclusion et Prochaines Étapes

Votre instance Bitwarden self-hosted est maintenant opérationnelle et sécurisée. Pour aller plus loin :

  • Configurer l'authentification LDAP/Active Directory pour une intégration d'entreprise
  • Mettre en place un monitoring avec Prometheus/Grafana
  • Activer les logs d'audit complets (paramètre EXTENDED_LOGGING)
  • Tester la procédure de récupération sur un serveur de test
  • Documenter vos procédures opérationnelles (runbook)

Les sauvegardes régulières et les mises à jour de sécurité sont critiques. Testez votre processus de restauration au moins deux fois par an.

Similar Posts