密码是所有账号的总钥匙。密码管理器我用了很久,之前一直用的官方云服务,没出过什么问题,但心里总有个疙瘩:这么要命的数据,能不能放在自己手里?

研究了一圈,最后选了 Vaultwarden——它是 Bitwarden 官方服务端的一个轻量开源实现,兼容 Bitwarden 全套客户端(浏览器插件、手机 App、桌面端都有),自己部署只需要一个小小的容器,一台配置很低的 VPS 就能跑。说干就干。

准备

  • 一台 VPS(配置不用高,我用的就是手边现成的)

  • 一个域名,用来给密码库留一个子域名入口

  • 机器上装好 Docker

整体思路先说清:密码库本体只监听服务器本机,外面的人连端口都摸不到;对外访问走 Cloudflare 隧道,既有 HTTPS,又不用在服务器上开放任何新端口。

部署

先确认机器上有 Docker,没有的话用官方一键脚本装上:

curl -fsSL https://get.docker.com | sh

再建好数据目录,这个目录就是密码库的全部家当(数据库和附件都在里面):

mkdir -p /opt/vaultwarden

然后一条命令把容器拉起来:

docker run -d --name vaultwarden \
  --restart unless-stopped \
  -e SIGNUPS_ALLOWED=true \
  -e DOMAIN=https://pass.你的域名 \
  -v /opt/vaultwarden:/data \
  -p 127.0.0.1:本地端口:80 \
  vaultwarden/server:latest

几个关键点解释一下:

  • -p 127.0.0.1:本地端口:80:只绑本机地址,外网扫不到这个端口

  • DOMAIN:填密码库对外访问的完整地址,客户端同步要靠它认门

  • SIGNUPS_ALLOWED=true:先开着注册,等会儿要用它注册自己的账号。注册完第一件事就是关掉它(见下文),别让自家密码库变成谁都能注册的公共服务

容器起来之后,先在本机验一下活:容器在运行、健康检查接口有返回,就说明服务本身没问题:

docker ps
curl -s http://127.0.0.1:本地端口/alive

再到 Cloudflare 那边建一条隧道,给隧道添加一条路由:子域名填密码库的域名,服务地址指向 http://localhost:本地端口。隧道如果也用 Docker 容器跑,启动命令是这样(注意带上 --network host,原因见后面搬家那一节踩的坑):

docker run -d --name cloudflared \
  --restart unless-stopped \
  --network host \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run --token 你的隧道令牌

配好之后,打开域名就能看到登录页,全程 HTTPS,服务器防火墙一个新端口都不用开。

打开登录页,先把自己的账号注册好。注册完马上关掉注册:删掉容器、用同一条命令重新拉起(数据都在 /opt/vaultwarden 目录里,删容器不丢数据):

docker stop vaultwarden
docker rm vaultwarden

重新执行上面那条 docker run,只把 SIGNUPS_ALLOWED 的值改成 false。重启完再打开页面试着注册一下,注册入口没了,才算关严实。

最后是客户端:浏览器插件和手机 App 里,把服务器地址从官方默认改成自己的域名,再用刚才注册的账号登录,所有条目就同步过来了。

每日备份

密码库的数据全在那一个目录里,备份也就简单粗暴:每天定时打包一份,保留 7 天——哪天改错删错了,都还有前几天的包能捞回来。脚本核心就两行:

tar czf /opt/backup/vaultwarden-$(date +%F).tar.gz -C /opt vaultwarden
find /opt/backup -name "vaultwarden-*.tar.gz" -mtime +6 -delete

扔进 crontab 每天凌晨跑一次就行。备份文件装的是密码库的全量数据,是敏感东西,只留在服务器本机,哪儿都不传——这一条要划重点。

附带一场搬家

用了没多久,密码库经历了一次搬家:原来那台机器的隧道线路不稳定,登录页时不时打不开。密码库是关键时刻要用的东西,不能将就,于是我把它迁到了另一台更稳的机器上。整个过程大概四十分钟,步骤拆开是这样:

  1. 老机器停容器、打包:先把 Vaultwarden 容器停掉,保证打包时数据不再写入:

docker stop vaultwarden

再把整个数据目录打成一个压缩包。密码库数据量很小,包还不到 2 MB:

tar czf /root/vaultwarden-migrate.tar.gz -C /opt vaultwarden
  1. 中转拷贝:把压缩包下载到自己的电脑,再上传到新机器。中间有个小插曲:中转时压缩包被多套了一层,解压要解两层才见到正主——以后遇到"文件对不上",先看看是不是这种套娃。

  2. 新机器装 Docker、建隧道:新机器先装好 Docker,官方一键脚本就行:

curl -fsSL https://get.docker.com | sh

再新建一条 Cloudflare 隧道,隧道同样用 Docker 容器运行。这里有个大坑:隧道死活连不上本机的密码库,网页报 502,折腾半天才发现,容器里的 localhost 指的是容器自己,不是宿主机。解决办法就写在启动命令里——加上 --network host,让隧道容器跟宿主机共用网络,立刻就通了。凡是"服务在本机、隧道在容器"的组合,都记着这一条:

docker run -d --name cloudflared \
  --restart unless-stopped \
  --network host \
  cloudflare/cloudflared:latest \
  tunnel --no-autoupdate run --token 你的隧道令牌
  1. 解压数据、原样启动:把数据目录解压到新机器同样的位置:

tar xzf /root/vaultwarden-migrate.tar.gz -C /opt

然后用部署一节里那条 docker run 命令原样启动容器(只监听本机、关闭注册、域名不变),这里就不重复贴了。域名不变很关键:客户端认的还是老地址,手机和浏览器插件什么都不用改。 5. 域名改道:在 Cloudflare 里把密码库域名的路由从老隧道删掉、加到新隧道上,服务地址指向新机器的 http://localhost:本地端口。 6. 验收:自己亲自登录一遍——网页能打开、条目一条不少、新存一条记录能保存、手机 App 同步正常,四样都过了才算搬完。 7. 给新家配备份:在新机器上把每日打包备份重新挂好,还是打包数据目录、保留 7 天。定时任务就是这一行(时间是 UTC,相当于北京时间凌晨 3 点):

0 19 * * * tar czf /opt/backup/vaultwarden-$(date +\%F).tar.gz -C /opt vaultwarden; find /opt/backup -name "vaultwarden-*.tar.gz" -mtime +6 -delete
  1. 老机器留冷备:老机器上的容器保持停止、数据目录原样不动,当一份冷备份留着。万一新机器出岔子,老机器上一条命令就能把服务拉回来:

docker start vaultwarden

再把域名路由改回去,十分钟就能回滚;等新机器稳定跑上一阵子,这份冷备再考虑删不删。

搬完最大的感受是:自建的好处在这里体现得淋漓尽致——数据就是一个文件夹,搬家就是搬文件夹,全程自己说了算。

现在的状态和小结

现在密码库住在一台线路稳定的机器上:只监听本机、隧道对外、注册关闭、每天自动备份。手机、电脑、浏览器插件都连它,改一条密码处处同步,跟用官方服务没什么区别,区别只在数据躺在自己的硬盘上。

自建密码库的意义,我觉得不在省钱(官方免费版其实够用),而在于两点:一是数据归属清楚,谁也别想碰;二是搬家、备份全自己说了算,不用看任何平台的脸色。代价则是机器和备份要自己上心——所以它值得放在你最稳的那台机器上,并且配好每日备份。这两点做到,自建就是安心的。