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.
