Deine Compose-Datei ist eine gute Grundlage. Ein paar Dinge darin machen allerdings Probleme. Die habe ich in der Anleitung korrigiert und unten am Ende erklärt.
1. Voraussetzungen
Docker und das Docker-Compose-Plugin sind installiert (docker compose version).
Es gibt einen DNS-Eintrag, z. B. bitwarden.domain.com, der auf deinen Reverse Proxy zeigt.
Das externe Netz docknet existiert. Prüfen kannst du das mit docker network ls. Falls es fehlt:
bash
docker network create --subnet 172.16.0.0/24 docknet
2. Verzeichnis anlegen
bash
mkdir -p /opt/vaultwarden && cd /opt/vaultwarden
3. Admin-Token als Hash erzeugen
bash
docker run --rm -it vaultwarden/server:latest /vaultwarden hash
Gib zweimal ein starkes Passwort ein und kopiere den Hash, der mit $argon2id$… beginnt. Mit diesem Passwort (nicht mit dem Hash) meldest du dich später unter /admin an.
4. .env mit den Geheimnissen anlegen
So stehen keine Passwörter direkt in der Compose-Datei.
bash
nano .env
env
# Einfache Anführungszeichen sind wichtig, damit die $-Zeichen im Hash nicht ersetzt werden
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$...'
DB_NAME=vaultdb
DB_USER=vaultuser
DB_PASSWORD=EinLangesPasswortOhneSonderzeichen
DB_ROOT_PASSWORD=NochEinLangesPasswort
SMTP_PASSWORD='dein-smtp-passwort'
bash
chmod 600 .env
Tipp: Nimm für DB_PASSWORD nur Buchstaben und Zahlen. Es landet in einer URL, und Zeichen wie @ : / # ? müssten dort sonst kodiert werden.
5. docker-compose.yml
yaml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: bitwarden_web
restart: always
depends_on:
- dbvault8
environment:
DOMAIN: "https://bitwarden.domain.com"
ADMIN_TOKEN: ${ADMIN_TOKEN}
DATABASE_URL: "mysql://${DB_USER}:${DB_PASSWORD}@172.16.0.53:3306/${DB_NAME}"
TZ: "Europe/Vienna"
LOG_LEVEL: "info"
SIGNUPS_ALLOWED: "false"
SIGNUPS_VERIFY: "true"
INVITATIONS_ALLOWED: "false"
SHOW_PASSWORD_HINT: "false"
WEB_VAULT_ENABLED: "true"
SMTP_HOST: "mail.your-server.de"
SMTP_PORT: "587"
SMTP_SECURITY: "starttls"
SMTP_FROM: "no-reply@domain.com"
SMTP_FROM_NAME: "Bitwarden"
SMTP_USERNAME: "no-reply@domain.com"
SMTP_PASSWORD: ${SMTP_PASSWORD}
volumes:
- ./data:/data
networks:
docknet:
ipv4_address: 172.16.0.3
dbvault8:
image: mysql:8.4
container_name: bitwarden_db_8
restart: always
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- ./db-data_8:/var/lib/mysql
networks:
docknet:
ipv4_address: 172.16.0.53
networks:
docknet:
external: true
6. Starten und Logs prüfen
bash
docker compose config # zeigt, ob die Variablen korrekt eingesetzt werden
docker compose up -d
docker compose logs -f vaultwarden
Beim ersten Start kann Vaultwarden ein paar Mal melden, dass die Datenbank nicht erreichbar ist, solange MySQL noch initialisiert. Das ist normal, weil es automatisch neu versucht. Fertig ist es, wenn Rocket has launched im Log steht.
7. Reverse Proxy (Nginx Proxy Manager)
Lege einen neuen Proxy Host an:
Domain: bitwarden.domain.com
Scheme / Forward IP / Port: http · 172.16.0.3 · 80
Websockets Support: an (wird für die Live-Synchronisation gebraucht)
Block Common Exploits: an
SSL-Tab: Let’s-Encrypt-Zertifikat, Force SSL, HTTP/2 und HSTS aktivieren
Ports musst du am Container keine freigeben, weil NPM ihn direkt über docknet erreicht.
8. Ersten Benutzer anlegen
Da die Registrierung gesperrt ist, hast du zwei Möglichkeiten:
Über das Admin-Panel: Öffne https://bitwarden.domain.com/admin, melde dich mit dem Passwort aus Schritt 3 an und lade dich unter Users → Invite User selbst ein. Dafür muss SMTP funktionieren.
Ohne SMTP: Setze kurzzeitig SIGNUPS_ALLOWED: "true" und starte mit docker compose up -d neu. Dann registrierst du dich, stellst den Wert wieder auf "false" und startest erneut.
9. SMTP testen
Im Admin-Panel findest du unter SMTP Email Settings den Punkt Send test email .
⚠️ Wichtig: Was du im Admin-Panel speicherst, landet in data/config.json und überschreibt von da an die Werte aus der Compose-Datei. Wenn eine Änderung an der Compose-Datei scheinbar nichts bewirkt, liegt es fast immer daran.
10. Backup
bash
# Datenbank sichern
docker exec bitwarden_db_8 sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" vaultdb' > vaultdb_$(date +%F).sql
# data-Ordner sichern (Anhänge, Sends, RSA-Schlüssel, config.json)
tar czf vw-data_$(date +%F).tar.gz data/
Die Dateien data/rsa_key* gehören unbedingt ins Backup. Fehlen sie, sind nach einer Wiederherstellung alle Sitzungen ungültig.
11. Updates
bash
docker compose pull && docker compose up -d && docker image prune -f
Was ich an deiner Vorlage geändert habe
Original Problem Lösung ports: ":80", ":443"Damit werden zufällige Host-Ports veröffentlicht. Vaultwarden selbst spricht außerdem nur HTTP auf Port 80. Ports entfernt, NPM regelt den Zugriff über docknet ADMIN_TOKEN=""In der Listen-Schreibweise werden Anführungszeichen Teil des Werts. Der Token ist dann buchstäblich "" und das Admin-Panel ist mit "" offen. Argon2-Hash aus der .env SMTP_FROM_NAME="bitwarden"Gleiches Problem: Die Anführungszeichen landen im Absendernamen. Map-Schreibweise verwendet DOMAIN=[https://…](…)Das ist durch Kopieren als Markdown-Link kaputtgegangen. https://bitwarden.domain.comWEBSOCKET_ENABLEDSeit Version 1.29 veraltet, Websockets laufen jetzt direkt über Port 80. entfernt PUID / PGIDDiese Variablen nutzen nur Images von linuxserver.io, Vaultwarden ignoriert sie. entfernt (bei Bedarf stattdessen user: "1000:1000") kein depends_on Vaultwarden kann vor der Datenbank starten. depends_on ergänztmysql:8Ein schwammiger Tag, der sich bei einem pull unbemerkt ändern kann. auf mysql:8.4 (LTS) festgelegt Passwörter in der YAML-Datei Sie landen leicht in Backups oder Git. in die .env ausgelagert
Admin-Token für Vaultwarden erstellen
Vaultwarden erwartet als ADMIN_TOKEN keinen Klartext, sondern einen Argon2-Hash deines Admin-Passworts. Beim Anmelden unter /admin tippst du das Passwort ein, und Vaultwarden vergleicht es mit dem Hash.
Schritt 1: Hash erzeugen
Variante A: Container läuft noch nicht
bash
docker run --rm -it vaultwarden/server:latest /vaultwarden hash
Variante B: Container läuft bereits
bash
docker exec -it bitwarden_web /vaultwarden hash
Du wirst zweimal nach dem Passwort gefragt:
Password:
Confirm Password:
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$Zk9xT2...$q8Hk3...'
Generation of the Argon2id PHC string took: 512ms
Kopiere die komplette Zeile mit ADMIN_TOKEN='…'.
Standardmäßig nutzt der Befehl die Bitwarden-Voreinstellung. Mit /vaultwarden hash --preset owasp bekommst du die etwas strengeren OWASP-Parameter. Beides ist sicher.
Schritt 2: Hash eintragen, auf die $-Zeichen achten
Im Hash stehen mehrere $-Zeichen. Docker Compose hält sie für Variablen und würde den Hash kaputt machen. Je nachdem, wo du ihn einträgst, gehst du anders vor:
In der .env (empfohlen): Übernimm die Zeile genau so, wie sie ausgegeben wurde, mit einfachen Anführungszeichen:
env
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$Zk9xT2...$q8Hk3...'
In der docker-compose.yml steht dann:
yaml
ADMIN_TOKEN: ${ADMIN_TOKEN}
Direkt in der docker-compose.yml: Hier musst du jedes $ verdoppeln:
yaml
ADMIN_TOKEN: "$$argon2id$$v=19$$m=65540,t=3,p=4$$Zk9xT2...$$q8Hk3..."
Schritt 3: Prüfen und neu starten
bash
docker compose config | grep ADMIN_TOKEN # der Hash muss vollständig mit allen $ erscheinen
docker compose up -d
docker compose logs vaultwarden | grep -i admin
Erscheint im Log keine Warnung wie You are using a plain text ADMIN_TOKEN, hat es geklappt. Dann meldest du dich unter https://bitwarden.domain.com/admin mit dem Passwort an, nicht mit dem Hash.
Typische Stolperfallen
Login klappt nicht, obwohl der Hash stimmt: Wurde im Admin-Panel schon einmal gespeichert, steht in data/config.json ein eigener admin_token. Der hat Vorrang vor der Compose-Datei. Ändere ihn entweder im Admin-Panel unter General Settings → Admin token oder entferne die Zeile aus config.json und starte den Container neu.
Hash wirkt abgeschnitten: Die $-Zeichen wurden nicht maskiert (siehe Schritt 2). docker compose config zeigt dir das sofort.
Admin-Panel abschalten: Lässt du ADMIN_TOKEN ganz weg, ist /admin deaktiviert. Das ist sinnvoll, wenn alles eingerichtet ist und du das Panel nicht mehr brauchst.