一句话结论: 密码是最不该交给别人保管的资产。Vaultwarden 让你用一台 1C1G 的小鸡跑起与 Bitwarden 官方客户端完全兼容的密码服务,本文手把手带你从零部署、上 HTTPS、关闭注册、做自动备份,所有命令均在 Debian 12 实测通过。

为什么要自建一个密码库?
先说背景:Bitwarden 是目前开源密码管理器里生态最完整的一个——浏览器插件、桌面端、移动端、CLI 全平台覆盖。但官方托管有两件让人不放心的事:
- 免费版限制:附件、TOTP(两步验证码)、企业集合等功能藏在付费墙后;
- 信任问题:主密码由你保管没错,但密码库本体躺在别人服务器上。
自建有两个主流选择,先看对比:
| 方案 | 资源占用 | 功能 | 适用场景 |
|---|---|---|---|
| Bitwarden 官方 Server(自托管) | 2GB+ 内存起步,MS SQL 极重 | 全功能 | 团队/企业 |
| Vaultwarden(本文) | 50MB 内存即可跑 | 几乎全部免费版付费功能 | 个人/小团队 |
| KeePass 系纯文件同步 | 无服务 | 无在线访问体验 | 极客单机党 |
关于版本:Vaultwarden 是 Rust 重写的 Bitwarden 服务端实现,长期活跃维护,官方 Bitwarden 客户端无需任何修改即可直连。本文以 Docker 部署 + Caddy 反代为路线,这也是官方 Wiki 推荐的组合。
部署前准备
- 一台有公网 IP 的 VPS(Debian 12 / Ubuntu 22.04 均可);
- 一个域名(如
vault.example.com),A 记录指到 VPS——强烈建议上 HTTPS,官方客户端在非 HTTPS 环境下功能受限; - Docker 与 Docker Compose 插件:
# 安装 Docker(官方脚本,实测一条命令搞定)
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker
docker --version # 本文实测:Docker 27.x
一、用 Compose 拉起 Vaultwarden
建一个工作目录,写 docker-compose.yml:
mkdir -p /opt/vaultwarden && cd /opt/vaultwarden
mkdir vw-data
# /opt/vaultwarden/docker-compose.yml
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
DOMAIN: "https://vault.example.com" # 换成你的域名,必须与实际访问地址一致
SIGNUPS_ALLOWED: "true" # 先开注册,建完自己的账号后改回 false
volumes:
- ./vw-data:/data
ports:
- "127.0.0.1:8080:80" # 只绑回环,外网流量交给 Caddy
注意
DOMAIN这个坑:它必须与你最终访问的域名一字不差(含 https://)。实测如果这里填错,会出现附件上传失败、WebAuthn 登录异常等诡异问题,且日志里没有任何明确报错。
启动并确认健康:
docker compose up -d
docker logs -f vaultwarden # 看到 "Rocket has launched" 即启动成功
curl -s http://127.0.0.1:8080/alive # 返回 {"version":"..."} 即正常
二、用 Caddy 上 HTTPS
Caddy 的好处是自动申请、续期 Let's Encrypt 证书,零配置维护。安装后写一个 Caddyfile:
sudo apt install -y caddy
# /etc/caddy/Caddyfile
vault.example.com {
encode gzip
reverse_proxy 127.0.0.1:8080
}
sudo systemctl reload caddy
关于 WebSocket:老教程会让你把
/notifications/hub单独反代到 3012 端口。实测 Vaultwarden 1.29.0 之后 WebSocket 已合并进主端口,一条reverse_proxy就够了,无需再做区分(WEBSOCKET_ENABLED环境变量也已废弃,配了会被日志警告)。
此时浏览器访问 https://vault.example.com 应能看到登录页。
三、管理面板与初始安全配置
1. 生成管理面板令牌(argon2 哈希,不要用明文):
docker exec -it vaultwarden /vaultwarden hash
# 按提示输入两遍密码,输出类似:
# ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$xxxxx$yyyyy'
把整行(含引号)写进 compose 的 environment 后重启:
ADMIN_TOKEN: '$argon2id$v=19$m=65540,t=3,p=4$xxxxx$yyyyy'
docker compose up -d # 配置变更后重建容器
访问 https://vault.example.com/admin 即可进入管理面板(用你刚才设置的密码登录)。
2. 注册自己的账号,然后立刻关闭公开注册——这是自建密码库最关键的一步,否则任何人都能往你的库塞垃圾账号:
- 首页 Create Account 建好自己的账号(主密码务必够强,它不参与服务端任何存储,忘了就是真丢了);
- 修改 compose:
SIGNUPS_ALLOWED: "false",docker compose up -d生效。
3. 管理面板里再加固两项(Admin → General settings):
Allow new signups取消勾选(双保险);- 如需邀请制小团队,只把
Invitations allowed打开。
四、客户端接入
用 Bitwarden 官方客户端(浏览器插件 / 手机 App 均可),在登录页点右上角齿轮,把 Server URL 填为 https://vault.example.com,然后正常登录即可。所有官方客户端特性(自动填充、TOTP、密码报告)在 Vaultwarden 下全部可用——这部分功能是免费的,也是 Vaultwarden 最大的价值点。
五、备份与恢复(实测脚本)
密码库这种数据,备份策略必须是「机器炸了也能原样恢复」。数据目录里真正要备份的东西:
| 文件/目录 | 作用 | 是否必需 |
|---|---|---|
db.sqlite3 | 密码库主数据库 | ✅ |
attachments/ | 加密附件 | 有附件就必需 |
sends/ | Bitwarden Send 文件 | 用了 Send 就必需 |
rsa_key.pem | 附件加密密钥 | ✅(漏掉它附件将永久无法解密) |
自动备份脚本(放在 /opt/vaultwarden/backup.sh):
#!/usr/bin/env bash
set -euo pipefail
DATA_DIR="/opt/vaultwarden/vw-data"
BACKUP_DIR="/opt/vaultwarden/backups"
STAMP=$(date +%Y%m%d-%H%M%S)
KEEP=14 # 本地保留 14 份
mkdir -p "$BACKUP_DIR"
# 1. 在线一致性备份 SQLite:不能直接 cp 运行中的 db,用 sqlite3 自带命令
docker exec vaultwarden sqlite3 /data/db.sqlite3 ".backup '/data/db-${STAMP}.sqlite3'"
mv "${DATA_DIR}/db-${STAMP}.sqlite3" "${BACKUP_DIR}/db-${STAMP}.sqlite3"
# 2. 打包附件、Send 与密钥文件
tar -czf "${BACKUP_DIR}/files-${STAMP}.tar.gz" \
-C "$DATA_DIR" attachments sends rsa_key.pem 2>/dev/null || true
# 3. 清理过期备份
find "$BACKUP_DIR" -name 'db-*.sqlite3' -mtime +${KEEP} -delete
find "$BACKUP_DIR" -name 'files-*.tar.gz' -mtime +${KEEP} -delete
echo "[$(date)] backup done: $BACKUP_DIR"
chmod +x /opt/vaultwarden/backup.sh
# 每天凌晨 3:20 执行
sudo crontab -e # 追加一行:
# 20 3 * * * /opt/vaultwarden/backup.sh >> /var/log/vw-backup.log 2>&1
容器内自带 sqlite3 客户端,
.backup命令保证拿到的是一致性快照,不用停机。异地容灾再用rsync把backups/推到另一台机器或对象存储即可,一行命令的事:rsync -az --delete /opt/vaultwarden/backups/ backup@nas:/volume1/vw-backups/
恢复流程(换机重建实测可行):
# 新机器上先按上文装好 Docker 并拉起一个空 Vaultwarden,然后停掉
docker compose down
# 用备份覆盖数据目录
cp backups/db-20260101-032000.sqlite3 vw-data/db.sqlite3
tar -xzf backups/files-20260101-032000.tar.gz -C vw-data/
docker compose up -d
# 登录验证一下账号密码条目是否完整
六、实测踩坑记录
DOMAIN与实际访问地址不一致 → 附件上传失败、客户端握手报错,日志无明确提示。改对后重建容器即恢复。- 明文
ADMIN_TOKEN→ 面板会警告。务必用容器内/vaultwarden hash生成 argon2 串,且整体带单引号写入 compose(串里有$,YAML 双引号会触发变量解析)。 - 忘了关注册 → 公网密码库几天就被扫出来注册了一堆垃圾账号。装完第一时间
SIGNUPS_ALLOWED=false。 - 备份只拷了 db 没拷
rsa_key.pem→ 恢复后附件全部解密失败。这张表建议抄进你的运维文档。 - 8080 端口直接暴露公网 → 完全没必要,绑
127.0.0.1让 Caddy 统一入口,少开一个攻击面。
小结
整套方案的日常维护成本约等于零:docker compose pull && docker compose up -d 一月跑一次升级,备份脚本自己照顾自己。与其把全部身家托付给某家网盘和 SaaS,不如花一个下午把它握在自己手里——毕竟和 TeamSpeak 一样,这类「一装永逸」的自建服务,装好之后能安分陪你很多年。
