智能摘要 DeepSeek
本文介绍用Vaultwarden在1C1G小VPS上自建Bitwarden兼容密码库:Docker Compose部署、Caddy自动HTTPS、argon2管理令牌、注册后立即关闭注册,并给出SQLite在线备份脚本(含rsa_key.pem)与恢复流程,附DOMAIN配置、端口暴露等实测踩坑记录。

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

Vaultwarden 自建密码库:从零部署到异地备份的实战记录-缘梦の镇

为什么要自建一个密码库?

先说背景: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. 注册自己的账号,然后立刻关闭公开注册——这是自建密码库最关键的一步,否则任何人都能往你的库塞垃圾账号:

  1. 首页 Create Account 建好自己的账号(主密码务必够强,它不参与服务端任何存储,忘了就是真丢了);
  2. 修改 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
# 登录验证一下账号密码条目是否完整

六、实测踩坑记录

  1. DOMAIN 与实际访问地址不一致 → 附件上传失败、客户端握手报错,日志无明确提示。改对后重建容器即恢复。
  2. 明文 ADMIN_TOKEN → 面板会警告。务必用容器内 /vaultwarden hash 生成 argon2 串,且整体带单引号写入 compose(串里有 $,YAML 双引号会触发变量解析)。
  3. 忘了关注册 → 公网密码库几天就被扫出来注册了一堆垃圾账号。装完第一时间 SIGNUPS_ALLOWED=false。
  4. 备份只拷了 db 没拷 rsa_key.pem → 恢复后附件全部解密失败。这张表建议抄进你的运维文档。
  5. 8080 端口直接暴露公网 → 完全没必要,绑 127.0.0.1 让 Caddy 统一入口,少开一个攻击面。

小结

整套方案的日常维护成本约等于零:docker compose pull && docker compose up -d 一月跑一次升级,备份脚本自己照顾自己。与其把全部身家托付给某家网盘和 SaaS,不如花一个下午把它握在自己手里——毕竟和 TeamSpeak 一样,这类「一装永逸」的自建服务,装好之后能安分陪你很多年。