说实话,我也曾是那种“一个密码走天下”的人,直到某次数据泄露自查,才发现自己的账号密码早就躺在某个公开的泄露库里。从那时候起才认真对待密码管理,先后试过几款在线密码管理器,同步确实方便,但把全家密码交给别人服务器这件事,始终觉得不踏实。后来转向自建服务器方案,一路折腾下来,最顺手、维护成本最低的就是轻量级开源密码管理器 Vaultwarden。自建搞定之后,手机、电脑、浏览器插件都能无缝同步,访问速度不受限,数据完全在自己手里,这就是所谓的密码自由。
这篇文章里,我会把 Vaultwarden 从方案选型、服务器准备、Docker 部署、反向代理配置到数据备份、客户端接入、故障排查的完整过程都梳理出来,适合想摆脱云密码服务依赖、手上有台闲置小主机或云服务器的朋友直接参考复现。不管你会不会写代码,只要具备基本的 Linux 操作能力,跟着步骤走基本都能跑起来。
1. 为什么我最终选择了自建密码库
1.1 云密码服务与自建之间的账
先算一笔账。免费的云密码服务确实方便,但免费方案往往在设备同步数量上有种种限制,跨设备功能也经常被阉割。即使数据加密和隐私政策写得漂亮,作为用户你其实没法真正验证它到底怎么处理你的密码库。我见过有人为了全家人的账号安全买了好几年的付费密码服务,一年几百块,算下来真不便宜,而且你还得一直相信对方不出事。密码库这种东西,一旦服务方出了问题,后果远比丢一个网站账号麻烦。
自建方案的逻辑就是把信任模型掌握在自己手里。用一台每天电费几乎可以忽略的小主机,换来一个只属于自己的密码库,没有设备数量限制,没有同步流量限制,所有数据都在自己的磁盘上。Vaultwarden 的“轻量级”不是随便说说的,它对硬件的要求低到夸张,512MB 内存的小机器都能跑得很稳。这意味着它一旦部署好,维护成本基本趋近于零——这也是我最终选择它的核心原因。
1.2 Vaultwarden 到底是什么
很多人听到 Vaultwarden 会先想到 Bitwarden。Bitwarden 本身是一款全平台密码管理器,客户端覆盖手机、桌面和浏览器,免费且开源。但官方提供的服务端是 .NET 重工程,部署起来既庞大又吃资源,对个人自建来说负担很重。Vaultwarden 是社区用 Rust 重新实现的兼容服务端,API 完全兼容官方客户端,但数据存储只用了一个 SQLite 数据库文件,整个数据目录非常小,备份就是直接拷文件。
Vaultwarden 与官方服务端的关系,可以理解成“官方客户端的自制替代服务端”。官方客户端能连的协议,它几乎都能兼容:端到端加密、组织共享、紧急访问、两步验证登录,这些核心能力都有。而资源占用只有官方服务端的零头。所以它天然就是为个人、家庭或小团队自建场景准备的。
1.3 自建这件事真正的难点在哪
自建密码管理器,很多人第一反应是“我自己有服务器,搭个服务很轻松”。其实真正的难点从来不是跑起一个 Docker 容器,而是怎么保证这个服务长期稳定、数据安全、随时可用。密码管理器是那种平时感觉不到存在、一旦出问题就非常要命的服务。
要做好这件事,至少得覆盖四个维度:第一,服务本身能跑起来,并且跟着容器更新迭代;第二,访问链路是加密的,不能用明文 HTTP 直接裸奔;第三,数据有备份,能应对磁盘损坏和误删;第四,自己有排查问题的基本手段,遇到客户端连不上、同步失败能定位原因。后面的内容我会围绕这四个维度展开,每一步都会说明为什么这么做。
2. 部署前的需求梳理与方案定型
2.1 先想清楚这几个关键问题
动手之前,我强烈建议你先列一张需求清单。比如我自己的清单是这样的:第一,能在我所有设备上装上客户端,包括手机、电脑和浏览器;第二,浏览器里能自动填充网页登录表单;第三,密码库的数据库文件得在我自己手里;第四,遇到问题我能自己排查,而不是找客服;第五,最好不用花额外的服务费。
这张清单直接决定了后续的部署方案。如果你只是收藏几个网址密码,随便用个在线保管就行;但如果你要把银行卡、邮箱、社交账号、甚至家庭成员的密码都放进去,那就必须认真对待。另外,还要想清楚要不要多人共用。Vaultwarden 支持组织共享功能,可以给家人分一个组织,共享家庭共用的账号密码,这个能力在选择时一定要考虑进去。
2.2 服务器与域名准备
Vaultwarden 对服务器的要求是真的低。我用过一台树莓派级别的机器,也用过只有 1 核 1G 内存的云服务器,跑起来都没压力。系统推荐 Debian 或 Ubuntu,因为 Docker 的支持最好,遇到问题也容易搜到答案。
域名这件事,我的建议是尽量准备一个。原因很简单:客户端同步时,Vaultwarden 需要知道自己的访问地址,如果直接暴露 IP 加端口,浏览器扩展和手机 App 的证书信任、地址匹配都会很别扭。有域名之后还能挂自动签发的 HTTPS 证书,访问体验和安全性完全不是一个级别。如果你实在不想买域名,用免费二级域名也凑合,但后面配置反向代理时会麻烦不少。
2.3 备份的基本思想提前定好
备份策略应该在部署之前就想清楚,而不是等数据出问题再补救。Vaultwarden 的设计让备份异常简单:服务运行中产生的所有数据都集中在一个数据目录里,备份就相当于对那个目录做一次快照。这个特性直接决定了它的能维护性——不需要停服务、不需要导出导入,只需要在磁盘上复制文件。
我会在后面专门讲一套可落地的备份脚本。这里先明确思想:密码库数据是不可再生的,一旦丢了,没有任何客服能帮你恢复。所以备份方案宁可冗余,不可缺失。我的习惯是本地定时备份,再往对象存储里同步一份异地的备份,两条腿走路。
3. 完整的 Docker 部署过程
3.1 安装 Docker 与 Compose
部署的第一步是准备 Docker 环境。以 Debian/Ubuntu 为例,最简单的安装方式是用 Docker 官方安装脚本:
curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh脚本执行完会自动安装 Docker 引擎。接着再安装 Compose 插件:
apt install docker-compose-plugin安装完成后验证一下版本:
docker --version docker compose version看到版本号输出就说明环境没问题。这一步我踩过一个坑:网上很多老教程还在用docker-compose命令(中间有个横杠),那是旧版独立的 Compose。新版 Docker 推荐的是docker compose子命令,写配置和执行的逻辑是一样的,但命令名不同,新手照着老教程很容易卡住。
3.2 编写编排文件
Vaultwarden 官方推荐用 Docker Compose 部署。我会把编排文件放在/opt/vaultwarden目录下,下面是完整的内容:
version: "3" services: vaultwarden: image: vaultwarden/server:latest container_name: vaultwarden restart: unless-stopped environment: DOMAIN: "https://vault.example.com" ADMIN_TOKEN: "用openssl生成的随机字符串" SIGNUPS_ALLOWED: "false" WEBSOCKET_ENABLED: "true" SMTP_HOST: "smtp.example.com" SMTP_PORT: "587" SMTP_SECURITY: "starttls" SMTP_FROM: "vaultwarden@example.com" SMTP_USERNAME: "vaultwarden@example.com" SMTP_PASSWORD: "你的SMTP密码" volumes: - ./vw-data:/data ports: - "127.0.0.1:8080:80"这里有几个关键点需要解释一下,否则你只是抄配置,不知道里面在干什么。
restart: unless-stopped让容器在服务器重启后自动拉起,这是密码管理器必须的行为,你总不能每次重启服务器后手动 docker start。ports映射成127.0.0.1:8080:80是把容器内的 80 端口只暴露给本机的 8080 端口,外部网络无法直接访问这个端口,必须经过后面要配置的反向代理。这样做的好处是少一个不设防的攻击面。
DOMAIN这个环境变量特别重要。它告诉 Vaultwarden 自己的公网访问地址,生成二步验证、邀请链接、客户端推送通知的时候都会用到这个地址。如果填错或者漏填,客户端登录后会因为地址不匹配而出现各种诡异问题。ADMIN_TOKEN是管理后台的凭据,建议用openssl rand -base64 48生成,长度足够且完全随机。
3.3 启动容器与初始化
编排文件写好后,在/opt/vaultwarden目录下执行:
docker compose pull docker compose up -dpull是拉取最新镜像,up -d是后台启动容器。启动后可以用下面的命令查看日志:
docker compose logs -f日志里如果出现Vaultwarden is ready!之类的信息,就说明服务已经起来了。这时候在服务器本地访问一下http://127.0.0.1:8080,能看到登录页面就说明 Web 服务器正常。
这里要提醒一句:如果你是在有防火墙的云服务器上操作,记得确认 8080 端口没有对外开放。我用127.0.0.1映射就是为了避免这种情况,如果你不小心写成了8080:80,相当于把 Vaultwarden 整个暴露在公网上,非常危险。
3.4 管理员后台与关闭注册
容器首次启动后,Vaultwarden 默认是允许注册新账号的。这个设置只适合安装测试阶段,正式使用前必须关掉。具体的做法就是前面编排文件里的SIGNUPS_ALLOWED: "false"。但问题来了,注册关掉之后,你自己怎么创建第一个账号?
Vaultwarden 的管理后台提供了解决方案。打开https://你的域名/admin,输入ADMIN_TOKEN的值进入管理页面,然后在“用户管理”里先临时开启注册,注册完自己的账号后再关闭。另一种方式是临时把SIGNUPS_ALLOWED改成true,重启容器,注册完再改回来。两种方法都有人用,我个人更倾向于用管理后台操作,因为不用重启容器,体验更顺。
管理后台里还可以做很多事情:查看用户列表、禁用异常账号、调整组织配额、打开邮件日志等。第一次部署时建议把这里熟悉一下,后面排查问题会经常用到。
4. 反向代理与 HTTPS 配置
4.1 为什么代理层是必须的
Vaultwarden 自带的 Web 服务是纯 HTTP 的,密码数据全都走明文传输,这显然不能用。哪怕只是内网使用,我也建议至少挂一层 TLS。公网环境下,没有 HTTPS 的密码管理器就好比把钥匙挂在大门口。
反向代理的角色就是把外网的 HTTPS 流量接收下来,解密后转发给本机 8080 端口上的 Vaultwarden。域名那边解析到服务器 IP 后,代理层负责自动申请和续期证书。这样一来,客户端始终面对的是合法的 HTTPS 地址,Vaultwarden 本身不需要处理证书逻辑,架构非常干净。
4.2 两套代理方案怎么选
我试过 Nginx 和 Caddy 两种方案,都有各自适合的场景。
如果你希望配置最精简、自动续期证书不用操心,选 Caddy。Caddy 的配置文件极短,反向代理加自动 HTTPS 的写法就几行:
vault.example.com { reverse_proxy 127.0.0.1:8080 }把这段内容保存到Caddyfile,Caddy 会自动申请证书并续期,一条配置搞定。Caddy 的缺点是一些高级流量控制能力不如 Nginx 灵活,但对 Vaultwarden 这种简单场景完全够用。
如果你服务器上已经跑了 Nginx,或者你喜欢传统 Nginx 的生态,那用 Nginx 也没问题。完整配置如下:
server { listen 443 ssl; server_name vault.example.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/privkey.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /notifications/hub { proxy_pass http://127.0.0.1:8080; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } }注意第二个location是给 WebSocket 用的。Vaultwarden 的实时通知功能依赖 WebSocket 连接,如果代理层不特殊处理升级请求,客户端会一直显示掉线或同步失败。
4.3 验证代理配置是否正确
配置完反向代理后,需要检查几件事。第一,浏览器访问https://你的域名能正常打开登录页,浏览器地址栏显示锁标志。第二,打开浏览器的开发者工具,切到 Network 面板,随便触发一次登录操作,确认请求都是 HTTPS 且没有混合内容警告。第三,如果客户端已经装好,登录后确认可以正常同步。
关于证书续期,Caddy 会自动处理。Nginx 配合官方签发工具的话,要设置定时任务自动更新证书。我见过不少人 Nginx 配置写好后就忘了证书这回事,三个月后证书过期,客户端全线罢工。如果 Nginx 用的是自动续期方案,建议隔几个月确认一次续期任务有没有正常执行。
5. 数据备份与恢复实操
5.1 数据目录里到底有什么
Vaultwarden 的所有数据都在挂载的vw-data目录里。第一次启动后,目录下会逐步生成以下内容:
| 文件或目录 | 作用 | 优先级 |
|---|---|---|
db.sqlite3 | 核心数据库,账号、密码库条目、组织关系的唯一存储位置 | 必须备份 |
config.json | 服务配置,包含安装时的随机密钥、加密参数 | 必须备份 |
rsa_key/ | RSA 密钥对,用于某些加密数据和邀请令牌的签名验证 | 必须备份 |
attachments/ | 密码库条目中附带的安全附件,加密后存储 | 按需备份 |
icon_cache/ | 网站图标缓存,属于可再生成数据 | 无需备份 |
备份时最核心的是前三个。尤其是rsa_key这个目录,很多人会忽略,结果密钥丢了以后部分加密数据无法解析,悔都来不及。icon_cache丢了会自动重建,不值得占备份空间。
5.2 一套可以落地的备份脚本
我平时使用的备份脚本逻辑很简单:先停掉容器(保证数据文件一致),然后把整个数据目录打成压缩包,最后和之前的每日备份一起做轮换。脚本如下:
#!/bin/bash # 备份目录 BACKUP_DIR=/backup/vaultwarden DATA_DIR=/opt/vaultwarden/vw-data DATE=$(date +%Y%m%d_%H%M%S) mkdir -p "$BACKUP_DIR" # 停止容器,确保数据一致 docker compose -f /opt/vaultwarden/docker-compose.yml stop # 压缩数据目录 tar -czf "$BACKUP_DIR/vaultwarden_$DATE.tar.gz" -C /opt/vaultwarden vw-data # 恢复容器运行 docker compose -f /opt/vaultwarden/docker-compose.yml start # 清理超过30天的备份 find "$BACKUP_DIR" -name "vaultwarden_*.tar.gz" -mtime +30 -delete把脚本存到/usr/local/bin/backup-vaultwarden.sh,加执行权限,然后加进 crontab:
0 3 * * * /usr/local/bin/backup-vaultwarden.sh >> /var/log/vaultwarden_backup.log 2>&1每天凌晨三点自动执行备份。这样即使服务器断电、磁盘损坏,最多丢一天的密码变更。
这里我要强调一个细节:尽量不要直接拷贝运行中的 SQLite 数据库文件。SQLite 在没有 WAL 模式时,拷贝过程中可能遇到写入事务,导致备份文件损坏。所以我上面脚本选择先stop容器再打包,虽然会中断几秒服务,但换来的是一份一致可靠的数据。凌晨三点中断几秒,几乎没有任何用户能感知到。
5.3 模拟一次完整恢复
备份只是手段,能恢复才算真正安全。我建议你部署完成后,做一个模拟恢复演练。操作流程是这样:准备一台新机器,装上 Docker,创建/opt/vaultwarden目录,把备份的压缩包解压进去,确认数据目录结构齐全,然后启动同样的 Docker Compose 配置。
启动完成后,浏览器访问地址并用账号登录,确认所有密码条目都还在,附件可以正常下载。这个演练不复杂,半个小时就能走完,但能暴露备份文件不完整、路径错误、证书配置遗漏等各种问题。别偷懒,密码管理器这种服务,恢复演练就是一次保险理赔的提前演习。
6. 客户端接入与日常使用
6.1 全平台客户端的兼容性
Vaultwarden 最大的兼容性优势在于,它可以直接使用官方发布的客户端。包括 Windows、macOS、Linux 桌面端,iOS 和 Android 端,以及 Chrome、Firefox、Edge 的浏览器扩展。这些客户端默认连接官方服务器,但在登录界面都有一个“服务器地址”输入框,把它改成你的 Vaultwarden 地址即可。
这个兼容性意味着你不需要为 Vaultwarden 单独安装任何专用客户端,也不用担心客户端更新后接口不兼容的问题。官方客户端是持续维护的,Vaultwarden 社区也一直紧跟接口变化。
6.2 浏览器扩展配置细节
浏览器扩展是我个人使用频率最高的入口。安装官方扩展后,点击扩展图标,进入设置,找到服务器地址字段,把https://你的域名填进去,保存后重新打开扩展页面,就能看到登录界面。
有个小细节容易踩坑:服务器地址千万不要加路径。很多人习惯性填成https://你的域名/admin,结果扩展一直提示服务器地址无效。正确填法就是域名根路径。
填好地址登录一次后,扩展会把密码库缓存在本地。之后每次浏览器启动,扩展会自动向服务器同步一次。配合主密码或者指纹解锁,日常使用体验和在线密码服务没有差别。
6.3 值得特别注意的功能开关
Vaultwarden 管理后台可以细调很多参数。我这里挑几个日常使用中影響最大的开关说明一下。
首先是“注册开放”开关,正式使用后必须保持关闭。如果家里人有新成员要加入,管理后台临时打开注册,注册完再关闭,这个操作要熟练掌握。
其次是两步验证登录。Vaultwarden 支持为账号开启 TOTP 验证,开启后每次登录除了密码,还需要输入验证码。这个功能一旦开启,别人拿到主密码也进不了你的密码库。密码管理器的账号安全层级,要比普通网站账号更高,开启两步验证的优先级非常高。
最后是紧急访问功能。如果你担心自己某天意外没法登录,可以为信任的设备开启紧急访问,设置一个等待期,到期后联系人可以申请访问你的密码库。这个功能对家庭共享场景特别实用。
7. 常见问题与排查技巧实录
7.1 忘记管理员令牌怎么办
ADMIN_TOKEN是进入管理后台的唯一凭证,但很多时候配置完就忘了。遇到这种情况,直接编辑服务器上的docker-compose.yml,把ADMIN_TOKEN改成新生成的随机值,然后重新创建容器:
docker compose up -d --force-recreate注意--force-recreate会基于新配置重建容器,但数据目录里的数据不会丢失。改完令牌后,旧的管理登录会话会失效,重新登录即可。
7.2 更新镜像后数据会不会丢
不会。更新只涉及镜像层,data volume 里的数据完全不触碰。标准更新流程是:
cd /opt/vaultwarden docker compose pull docker compose up -d执行前建议先做一次手工备份,万一新版本有兼容问题,可以立刻回滚到旧镜像。docker compose本身不会自动删掉旧镜像,所以回滚也很简单:
docker compose up -d --no-deps vaultwarden:上一个版本号更新这件事最怕的是有人直接在未备份的情况下pull latest后启动,结果遇到 bug 再想回退,发现旧镜像已经被覆盖了。养成更新前备份的习惯,能省去很多不必要的惊吓。
7.3 客户端提示同步失败
同步失败通常有两个原因。一是反向代理没配置 WebSocket 升级,客户端无法维持长连接状态。检查 Nginx 或 Caddy 配置里有没有对应规则,按前面的配置补上就好。二是服务器时间不正确,TLS 握手会因证书时间校验失败而中断。
排查思路是先看容器日志:
docker compose logs --tail=50日志里如果出现WebSocket connection相关错误,优先去检查代理层。如果是证书校验错误,检查服务器系统时间和证书有效期。
7.4 SMTP 始终发不出去
开启 SMTP 后,最常见的错误是SMTP_SECURITY设置不对。不同的邮件服务商支持的加密方式不同,有的用 STARTTLS 在 587 端口,有的用隐式 TLS 在 465 端口。Vaultwarden 里这三个参数要配套:
SMTP_PORT=587时,SMTP_SECURITY通常填starttlsSMTP_PORT=465时,SMTP_SECURITY填tls
如果填反了,会在日志里看到 SSL 握手失败之类的报错。另外注意,有些服务商要求SMTP_HOST填域名而非 IP,填错了也会导致认证失败。
7.5 磁盘空间被图标缓存撑爆
icon_cache目录会缓存所有登录网站用到的站点图标。如果密码库里收藏的网站很多,图标数量会比较大。正常情况下这个目录能通过配置限制最大容量,但如果你发现磁盘快满了,最快的清理方式是删除icon_cache目录后重启容器。Vaultwarden 会自动重新生成图标缓存,不会影响密码数据。
我建议在管理后台开启图标缓存限制,或者在容器创建时用 Docker 卷限制挂载目录大小。老设备磁盘本来就小,这个细节值得留意。
最后说点个人感受。Vaultwarden 跑起来以后,给我的感觉就是安静地待在角落,几乎不需要存在感。真正需要你操心的无非两件事:定时备份,以及更新镜像前先看一眼变更说明。如果你手头刚好有一台连图形界面都跑不动的旧电脑,或者一块几百兆内存的小主机,用它来干这件事,可以说是物尽其用。一个下午的折腾,换回来日后每一刻的密码自由,这笔买卖很划算。