Vaultwarden
Vaultwarden is a lightweight Bitwarden-compatible server - team passwords and files like gitlab-secrets.json.
- ~50 MB RAM instead of ~2 GB for the official Bitwarden server
- attachments, organizations and collections are free
- works with the official Bitwarden apps and browser extensions
Runs on the tools server - set it up first.
Install
Part of the tools server compose project - starts with it, behind Caddy for HTTPS. Bitwarden clients refuse plain HTTP.
Environment
In the tools server .env:
VAULTWARDEN_DOMAIN=vault.example.com
VAULTWARDEN_SIGNUPS_ALLOWED=truethe domain goes without
https://, sign-ups staytrueonly until the owner account exists
Configure
All commands run in /opt/homelab/servers/tools.
Owner account
Open the domain, create your account and enable two-step login in Settings → Security → Two-step login.
Sign-ups
Until disabled, anyone on the internet can register. Set in .env:
VAULTWARDEN_SIGNUPS_ALLOWED=falsesudo docker compose up -dInvite the team from an organization: New organization → Members → Invite member.
without SMTP no invitation email is sent - the invited user registers on the domain with the invited email themselves
Organize
Keep team secrets in the organization, not in My vault - they stay when a member leaves.
Collections
One collection per server or service: Admin Console → Collections → New collection. Give access only to the people who run it.
| Collection | Items |
|---|---|
gitlab | root login, gitlab-secrets.json, gitlab.rb |
vault | admin page password and hash, off-site backup credentials |
grafana | admin login, alert notification tokens |
Delete Default collection
it's preselected in every new item, so everything lands there and it turns into a dump
Files
Files like gitlab-secrets.json go into a Secure note with an empty body:
New→Secure note, pick the collection and save →- open the note →
Attachments→ upload the file
the create dialog has no attachments - they appear only on a saved item. Notes text is capped at 10 000 characters, a file isn't
Upgrade
Bump the tag in servers/tools/vaultwarden/compose.yaml - take the latest from releases. Back up before the update:
sudo docker exec vaultwarden /vaultwarden backuptags are pinned -
latestwould upgrade on anypull, without a backup first
Backup
On top of provider VPS backups, the tools server backup snapshots /opt/homelab/servers/tools/vaultwarden/data every night:
db.sqlite3- the vault itselfattachmentsandsends- filesrsa_key*- token signing keys, without them every client is logged outconfig.json- admin page settings, exists only once the admin page was used
A live db.sqlite3 can be caught mid-write, so the snapshot skips it. backup.sh runs /vaultwarden backup first - it writes a consistent copy next to it as db_<date>.sqlite3.
Restore
In /opt/homelab/servers/tools. On a running server, stop Vaultwarden and move its data aside first:
sudo docker compose stop vaultwarden
sudo mv vaultwarden/data /root/vaultwarden-data-old
sudo ./restic.sh restore latest --target / --include /opt/homelab/servers/tools/vaultwarden/dataTurn the copy back into the database, then start:
sudo mv vaultwarden/data/db_*.sqlite3 vaultwarden/data/db.sqlite3
sudo docker compose up -dExport
Once in a while export the vault from a client: Tools → Export vault → .json (Encrypted). It restores into any Bitwarden-compatible server, not only this one.
Admin page
Optional. The server's own /admin page, not the organization Admin Console - users, organizations, SMTP and diagnostics. Disabled while ADMIN_TOKEN is unset.
All commands run in /opt/homelab/servers/tools.
Enable
generate a password in Vaultwarden
Generatorand save it as its own item →hash it and save the hash in the same item →
fishsudo docker exec -it vaultwarden /vaultwarden hashput the hash in
/opt/homelab/servers/tools/vaultwarden/admin.env→iniADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$...'single quotes keep compose from reading every
$as a variablerestart and log in to
/adminwith the password, not the hashfishsudo docker compose up -d
WARNING
settings saved on the admin page go to data/config.json and override the environment - keep each setting either in .env or on the admin page, not both
Disable
Comment out the token - the hash stays in the file for later:
sudo sed -i 's/^ADMIN_TOKEN/#ADMIN_TOKEN/' vaultwarden/admin.env
sudo docker compose up -dTo enable again:
sudo sed -i 's/^#ADMIN_TOKEN/ADMIN_TOKEN/' vaultwarden/admin.env
sudo docker compose up -d