为什么要自己搭一台密码管理器
很多人的密码散落在浏览器、聊天记录和 Excel 表格里,一旦某家网站泄露,撞库风险就会连环爆发。用商业云密码库当然省心,但所有密码都存在别人服务器上,总归隔着一层。这篇文章就解决这个两难:如何用一台便宜的 VPS(Virtual Private Server,虚拟专用服务器)跑起 Vaultwarden,把密码库完全握在自己手里,同时把备份做扎实,避免「自建一时爽、数据火葬场」。
Vaultwarden 是 Bitwarden 服务端的轻量开源实现,客户端完全兼容 Bitwarden 官方 App 和浏览器插件。官方 Bitwarden 服务端用 .NET 写的,对 1GB 小鸡(圈内对低配 VPS 的叫法)不太友好;Vaultwarden 用 Rust 实现,512MB 内存就能跑得很稳,这也是它在圈内流行的原因。
方案概览:三个容器解决全部问题
我的测试环境是一台 1 核 1GB 内存、跑 Debian 12 的入门款 VPS。整套方案只涉及三样东西:Vaultwarden 本体、Caddy 反向代理(自动申请续期 SSL 证书)、以及一个每天凌晨跑的备份脚本。全部用 Docker(容器化运行环境)部署,升级就是拉新镜像重建,数据卷不动。
整个部署链路可以概括为:域名解析到 VPS → Docker 启动 Vaultwarden → Caddy 监听 443 端口做 HTTPS(基于 SSL(Secure Sockets Layer,安全传输协议)的加密传输)反代 → 客户端连域名使用。全程命令不超过二十条,新手照抄也能一次过。
部署前的三件准备
动手之前先把三件事定下来,后面会顺很多。
- 一台海外 VPS:密码库对延迟不敏感,但对在线率要求高,建议选有快照功能、支持按月付款的机器。选型逻辑可以参考这篇美国 VPS 选购五大核心指标,或者先看看海外 VPS 与境内 VPS 的性能差异再决定节点;
- 一个域名:不需要多好的域名,重点是把一条 A 记录指到 VPS 的公网 IP,DNS(Domain Name System,域名解析系统)生效通常几分钟;
- 放行 80 和 443 端口:80 用于 Caddy 申请证书,443 用于日常访问,防火墙记得提前开。
关于合规这一点也要提一句:自托管密码库属于自用性质,一般不涉及备案问题,但如果业务上还承载其他站点,建议先弄清楚使用海外服务器的合规边界,避免混淆用途。
第一步:用 Docker 拉起 Vaultwarden
先装 Docker。Debian/Ubuntu 下一行脚本搞定:
curl -fsSL https://get.docker.com | bash
systemctl enable --now docker然后直接跑容器。下面这份 docker-compose.yml 是我在自己环境里验证过的最小可用配置,两个关键环境变量一定要加:
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
- DOMAIN=https://pw.example.com
- SIGNUPS_ALLOWED=true
volumes:
- ./data:/data
networks:
- caddy
networks:
caddy:
external: true两个参数的作用说清楚:DOMAIN 必须写你真实域名且带 https,否则密码库 Web 端会一直报跨域错误;SIGNUPS_ALLOWED 控制是否开放注册,等你自己注册完第一个账号后,强烈建议改回 false 再重建容器,把密码库变成纯私有,不然任何人扫到你的域名都能注册。
数据卷目录 ./data 里放着核心数据库 db.sqlite3,这个目录就是后面整个备份体系的保护对象,记住它的位置。
第二步:Caddy 反代与 HTTPS
密码管理器裸跑 HTTP 等于把密码箱门敞开,HTTPS 不是可选项。Caddy 的好处是证书全自动,申请、部署、续期都不用管。它的 compose 配置同样简单:
services:
caddy:
image: caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
networks:
- caddy
volumes:
caddy_data:
networks:
caddy:
external: trueCaddyfile 只需要四行:
pw.example.com {
reverse_proxy vaultwarden:80
}启动后访问 https://pw.example.com 能看到登录页,就说明反代通了。证书进度可以在 Caddy 日志里看,Let’s Encrypt 的签发记录、续期时间一目了然。如果你习惯用宝塔面板管理站点,也可以让宝塔来做反代和证书,思路一致——宝塔面板一键部署 WordPress 的思路完全可以平移过来。

第三步:注册、加固与客户端接入
浏览器打开域名,创建你的主账号。主密码是整个体系的单点,它丢了没有任何找回手段,建议用长口令而不是复杂乱码,比如四五个无关单词加符号的组合,长度 16 位以上。
注册完成后立即做三件加固,顺序别乱:
- 把 SIGNUPS_ALLOWED 改回 false,重建容器关闭注册入口;
- 在 Web 端设置里开启两步登录,TOTP(基于时间的一次性验证码)或 FIDO2 安全钥匙都可以,验证器丢了记得把恢复码打印出来;
- 装官方浏览器插件和手机 App,服务器地址填你自己的域名,就可以从所有设备同步了。
到这里,你已经拥有一台只有自己能登录的私有密码库。日常延迟表现取决于 VPS 线路,解锁一条记录通常 1 秒内完成,对使用体验几乎没有影响。
第四步:备份——最容易被忽视的一环
自建服务最大的风险不是被黑,而是 VPS 跑路、磁盘损坏或者一次误操作删库。Vaultwarden 的全部数据就是 ./data 目录,备份策略围绕它做三层:
- 每日增量:cron 凌晨 3 点把 data 目录打包成带日期的压缩包,保留最近 7 份,防误删;
- 每日异地:用 rclone 把当天压缩包同步到另一台机器或对象存储,防单机故障;
- 每周全量导出:从 Web 端导出 JSON 明文备份,加密后离线保存一份,这是最后兜底——哪怕整个服务端没了,也能导入任何兼容客户端。
每日增量用官方镜像自带的 SQLite 备份命令最稳妥,直接在宿主机 cron 里跑这个脚本:
#!/bin/bash
BACKUP_DIR=/opt/vw-backup
mkdir -p $BACKUP_DIR
docker exec vaultwarden /usr/bin/sqlite3 /data/db.sqlite3 ".backup '/data/backup-db.sqlite3'"
tar -czf $BACKUP_DIR/vw-$(date +%F).tar.gz -C /opt/vaultwarden data
rm -f /opt/vaultwarden/data/backup-db.sqlite3
find $BACKUP_DIR -name "vw-*.tar.gz" -mtime +7 -delete
rclone copy $BACKUP_DIR remote:vw-backup --max-age 24h注意先用 sqlite3 的 .backup 命令做一致性快照再打包,直接 tar 一个正在写入的数据库文件,恢复时可能损坏。rclone 的 remote 配置一次即可,这块操作和 WordPress 网站迁移到新服务器时的数据同步逻辑是相通的。
备份做了不算完,恢复演练才算闭环。我的验证方式:每月随机挑一天,在本地起一个全新的 Vaultwarden 容器,把某天的备份包解压挂载进去,确认能登录、密码条目完整、附件可下载,全程十分钟以内。没做过恢复演练的备份,本质上等于没有备份。

常见故障与排查思路
部署过程里大部分报错都集中在几类,遇到问题时按这个顺序排:
- 证书申请失败:九成是域名 A 记录没生效或 80 端口没放行,用 dig 确认解析、telnet 确认端口;
- 登录页能开但登录报错:检查 DOMAIN 环境变量是否与访问域名完全一致,包括 https 前缀;
- 手机 App 收不到推送:Vaultwarden 默认不带推送服务,需要在管理面板配置推送中继或改用客户端定时同步;
- 磁盘写满导致数据库锁定:定期清理旧备份包,data 目录所在分区预留至少 2 倍数据库体积。
总结与建议
一台 1 核 1GB 的小鸡、十几条命令、每天一个 cron 任务,就能换来一个完全由自己掌控的密码库。总结一下关键点:注册后立刻关注册、两步验证必开、备份必须异地且有恢复演练。如果你正在选 VPS 但拿不准节点和线路,可以参考这份海外 VPS 推荐榜单再做决定;预算允许的话,建议密码库独占一台机器,不和业务站点混部,把故障面隔离开。另外提一句,如果你想要一台对中文用户友好的机器,Hostease 的美国 VPS 提供中文客服和支付宝付款,拿来做密码库这类长期在线的小服务比较省心。自托管的意义就在于掌控权在你手里——前提是你把备份这件事当真。




