我是如何部署 Vaultwarden 的
Update:
vaultwarden 的 wiki 最近基本完工了,内容更详细。
前言
从前,我都是在自己的设备上明文存储密码。
每次忘掉登录凭证的时候,我就得解锁加密的分区,然后复制粘贴密码。从各种意义上都很危险。
我也不知道怎样才能找到一个可信的托管。有些大厂,比如谷歌和苹果,提供了密码管理服务。可是你敢用吗?反正我不。我也不大敢用 1password 和 LastPass 之类的付费/私有密码管理器。
而且 LastPass 一天到晚出事。对此,隔壁的大狐狸苏卡卡表示:
见怪不怪(x)
对 LastPass 时隔数月才爆出安全事故感到震惊,因为 LastPass 本应该每两个月出现一次安全事故(o)
咱是从 ous50 那里听说了 Bitwarden 的存在。
这玩意开源,虽然他们宣称是 zero knowledge 的,其实直接买他们的托管服务也可以,但我还是不想把底裤(付款信息)卖给 Bitwarden, 就打算亲自部署。
关于这玩意的教程很多,我第一次部署的时候是直接对着 ous50 的博客 照搬。
原版的 C# 后端有一堆起夜级功能,又笨又重。ous 在文章里提到了一个用 Rust 重写的实现,名叫 vaultwarden
, 曾用名 bitwarden_rs
. 这玩意轻了不止一点半点,还可以白嫖付费版功能,重要的二步验证手段 TOTP
.
Disclaimer: 将 TOTP 与密码一起存储,会明显削弱二步验证的保护能力。一旦密码管理器遭到未授权访问,存有 TOTP 的登录凭证将直接沦陷。当然,每个人的威胁模型不同,各自斟酌就好。
前置需求
一台可以分出 200MiB 运行内存和 1GiB 硬盘空间的 Linux 服务器。
200MB 的 RAM 能让它长期稳定运行了。另外 1GiB 的硬盘空间是极其保守的估计,如果你不上传大文件,单人实例的数据可能连 10MB 的占用都没有。Docker 镜像自身大小在 250MB 以内。
一个有效的域名。(这边用
bitwarden.example.com
来示例,记得换成你自己的。)带有这个域名的 SSL 证书。如果您不想买,可以 用 acme.sh 脚本免费申请
如果你的机器带不动 docker, 请直接去看 vaultwarden 在 GitHub 的 wiki . 那里有直接安装二进制程序的方法。
安装依赖
需要 nginx
和 docker
.
当然,还有一个你喜欢的文本编辑器。
Debian 11
为了添加 stream_ssl_preread
模块,我们需要 nginx
的版本高于 1.19.2
^1.
把 NGINX 自己维护的镜像源添加进去,以追上主线版本。
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99nginx
sudo apt update
sudo apt install nginx
添加 docker 自有的镜像源
sudo apt-get update
# sudo apt-get install \
# ca-certificates \
# curl \
# gnupg \
# lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Arch Linux
sudo pacman -Syu nginx docker docker-compose
在 CDN 部署防火墙和 TLS 规则
注意:以下配置方法基于极易获得的 CloudFlare 和 Let’s Encrypt 的服务,不保证大陆访问的稳定性,也不能保证对旧设备的兼容性 。
防火墙
防止著名爬虫引擎收录TLS
(自行选择)把最低 TLS 版本设置成 1.3 以防止降级。
俺们觉得 HSTS
有点麻烦,就放最后做。
启动 Docker 容器
把作者在 docker hub 编译好的镜像 pull 下来就能用了。
建议单开一个文件夹存放相关的数据。比如这样:
mkdir vaultwarden-docker
cd vaultwarden-docker
那么里面大概会有这些东西:
vaultwarden-docker
├── docker-compose.yml
└── vw-data
├── attachments
├── config.json
├── db.sqlite3
├── db.sqlite3-shm
├── db.sqlite3-wal
├── icon_cache
├── rsa_key.pem
├── rsa_key.pub.pem
├── sends
└── tmp
使用 docker-compose
Websocket 已经可以在 HTTP 端口上工作,无需额外分配端口用于 即时通知 ,该功能现已默认启用。
ICON_SERVICE
默认为 internal, 为避免服务器下载图标而被目标网站探测,使用 Bitwarden 的图标服务。所有对图标的请求会被服务器 302 到 bitwarden 的 icon server. 不过这也会将你的隐私在一定程度上暴露给 Bitwarden. (某个IP地址请求了哪些网站的图标,可能是在这些网站有凭证)
.env.template 中 ICON_SERVICE 的注释
同时设置 DISABLE_ICON_DOWNLOAD: "true"
禁止服务器自行下载图标。
config.json
或环境变量存在 ADMIN_TOKEN
时,能打开管理面板 /admin
, 且 config.json
优先级更高。两者皆无,则无法打开管理员界面。使用尽可能长而随机的 token 来抵抗暴力破解(比如用 openssl rand -base64 48
来生成)。
现在甚至有 argon2 hash, 不需要明文 token 了。看看官方教你 怎么换成 hash .
TL;DR: 使用 bitwarden 缺省设置,同时将 $
escape 掉,省得 compose 不认。
echo -n "MySecretPassword" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4 | sed 's#\$#\$\$#g'
然后对照这个例子修改 docker-compose.yml
即可。
# docker-compose.yml
version: '3'
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
ports:
- 127.0.0.1:8080:80
# - 127.0.0.1:3012:3012
environment:
# WEBSOCKET_ENABLED: "true"
ICON_SERVICE: "bitwarden"
DISABLE_ICON_DOWNLOAD: "true"
ADMIN_TOKEN: "$$argon2id$$v=19$$m=19456,t=2,p=1$$UUZxK1FZMkZoRHFQRlVrTXZvS0E3bHpNQW55c2dBN2NORzdsa0Nxd1JhND0$$cUoId+JBUsJutlG4rfDZayExfjq4TCt48aBc9qsc3UI"
volumes:
- ./vw-data:/data
然后
docker compose up -d
就会自动拉取映像,启动容器。
自行编译镜像
如果想要自行编译镜像,不妨看看 这里 。但我不推荐这样做。
配置反代
我不怎么喜欢使用 cloudflared, 虽然这样确实能不对外暴露端口。
如果您希望由服务器自身对外暴露端口,那么强烈建议您使用专门的反向代理,以提升安全性和响应性能。
可以直接参考 wiki 中的 反代示例 。
俺们只会 nginx
了。
为避免有人无端扫 443 探测域名,用 stream
模块来复用 443 端口,如果 SNI 不匹配就会被直接无视。
如果您不希望除 CDN 以外的任何访问者知晓您的服务器的真实 IP 地址,可以参考这篇 隐藏源站 IP 的教程。(TL;DR: 使用 IP 白名单和 authenticated pull)
# /etc/nginx/conf.d/stream.conf
stream {
map $ssl_preread_server_name $name {
sub1.example.com svc1;
sub2.example.com svc2;
bitwarden.example.com bw;
}
upstream svc1 {
server 127.0.0.1:PORT_TO_USE_1;
}
upstream svc2 {
server 127.0.0.1:PORT_TO_USE_2;
}
upstream bw {
server 127.0.0.1:PORT_FOR_BW;
}
server {
listen 443 reuseport;
listen [::]:443 reuseport;
proxy_pass $name;
ssl_preread on;
}
}
判断一下 host, 防止有人直接填 IP 访问。这还可以避免证书不匹配的问题(虽然用 stream 挡住以后没有什么必要了)。
注意 SSL 证书和密钥的路径。记得先签证书 。
屏蔽爬虫 bot.
分流 websocket 连接,用于 即时通知 。
proxy_pass
指向容器监听的地址。
另外针对 /admin
管理页面做了额外配置,添加了 basic auth. 不需要使用管理页面时也可以直接 return XXX, 或者直接在配置文件中删去 admin_token
键。
# /etc/nginx/conf.d/bitwarden.example.com.conf
# The `upstream` directives ensure that you have a http/1.1 connection
# This enables the keepalive option and better performance
#
# Define the server IP and ports here.
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080;
keepalive 2;
}
server {
listen 127.0.0.1:PORT_FOR_BW; ssl http2;
server_name bitwarden.example.com;
# block bots
if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot|^$") {
return 404;
}
# Block Direct Access via IP
if ($host != "bitwarden.example.com") {
return 404;
}
# Specify SSL Config when needed
ssl_certificate /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/fullchain.pem;
ssl_certificate_key /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/privkey.pem;
ssl_trusted_certificate /path/to/certificate/letsencrypt/live/vaultwarden.example.tld/fullchain.pem;
client_max_body_size 128M;
location / {
proxy_http_version 1.1;
proxy_set_header "Connection" "";
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;
proxy_pass http://vaultwarden-default;
}
# Optionally add extra authentication besides the ADMIN_TOKEN
# Remove the comments below `#` and create the htpasswd_file to have it active
#
#location /admin {
# # See: https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
# auth_basic "Private";
# auth_basic_user_file /path/to/htpasswd_file;
#
# proxy_http_version 1.1;
# proxy_set_header "Connection" "";
#
# 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;
#
# proxy_pass http://vaultwarden-default;
#}
}
然后在 /etc/nginx/nginx.conf
里面 include 一下这两个文件就行。
配置好以后,记得(重新)起一下服务。
nginx -t
sudo systemctl enable --now nginx
sudo systemctl reload nginx
如果没报错的话应该就能用了。
配置域名解析
服务起来了,就可以暴露到公网了。
给 bitwarden.example.com
解析到你的机器上。
打开云朵减速器是个好主意,可以加快载入,抵抗攻击并隐藏源站。
如果你没有固定的 IP, 那还是用 cloudflared 吧。也可以 CNAME 到你的 DDNS 上面。估计你也会的
…
我知道有人担心安全问题。毕竟 Cloudflare 的 CDN 可以看到 payload.
但据 Bitwarden 宣称,他们的方案是 zero knowledge 的,密码库的数据都是先加密后上传,TLS 是额外保护。对于 Send 同理。我过段时间去审一审代码,看看是不是真的
如果真是这样,那么 Cloudflare 就看不到你的密码,放心吧。
看到原数据的唯一方式是掌握你的主密码。要确保它足够强,能扛过暴力攻击,这才是最重要的。
配置密码仓库
可以用配置文件 config.json
和环境变量去修改设置。
但是初次安装尽量使用环境变量,因为只有登录过 /admin 并保存一次配置以后,才会生成配置文件 config.json
.
vaultwarden
的作者 dani-garcia 在 GitHub 上提供了一个 完整的 .env.template
. 想要更改的环境变量,直接添加到 compose file 就好了。
或者设定好外部 .env 文件,然后把示例拷贝过来,取消掉相应的注释
打开 https://bitwarden.example.com/admin
用之前设定的 ADMIN_TOKEN
登录。
限制注册
若你不希望别人白嫖你自建的服务,那最好就在管理面板设置禁止注册。
拿掉 Allow new signups
的钩子,防止他人注册。
(可选)设置 SMTP 服务
设置一个 SMTP 服务器,可以用来发发验证邮件和密码提示。
Yandex 360 就很不错。它是有免费版的,完全够用
We stand with Ukraine. 鉴于 Yandex 所处的境地,我们不再建议使用它的服务。
若仅使用 SMTP 发件服务,我们推荐使用 zoho , 它可以免费绑定一个自定义域名,无需添加任何付款信息。
当然,注册的事情就不放在这里说了。
您也可以开启 Email 二步验证。
切记!务必保存!
修改了设置以后
务必保存!
务必保存!
务必保存!
否则修改的内容将会丢失!
邀请
若您想拉人进来,大可使用邀请功能。
切换到 Users 然后在 “Invite User” 下输入对方的邮箱地址。这样就可以在数据库增加新的账户,并且是 Verified 状态。然后这个新用户就可以无视 Allow new signups 的限制了。
顺手鲨了所有认不得的申必用户。
等他们创建完帐号,就可以进入自己的仓库,管理面板上的 Invited
标签也会消失。
这样就可以安全地新增用户,包括你自己。
注册新用户
邀请过自己以后,去 bitwarden.example.com
注册一个账户。
牢记你的密码!这玩意可没法找回或者重置! 万一你忘掉了,就只能建立新账户了。
修改用户 KDF 设置
upd: vaultwarden 已在 2023-05-27 添加了对 Argon2id 的支持。在 account settings > security > keys 调整对应设置,work factor 配置顺应 Bitwarden 官方默认值 即可。
目前 Bitwarden 使用 PBKDF2-HMAC-SHA256 作为主要的 KDF, 服务端和客户端的默认循环次数均为 100000 次。
而在 2022 年 12 月,OWASP 建议 将该算法的循环次数提升到 600000 次,以确保面对离线攻击时的安全性。
现在 Bitwarden 的客户端默认 hash 循环次数也已经达到建议值。
vaultwarden 大概会在下一个版本将服务器一侧的 hash iteration 的默认值提升到 600000. 但这仅能保护你的 master password hash.
但客户端一侧的 PBKDF2 目前还只有 100000 次 hash. 如果想要提升 master key 的循环次数,必须在账户设置中修改 KDF 设置。
请直接按照 Bitwarden 的文档来 修改 KDF 循环次数 。同时建议您阅读 Bitwarden 的 安全白皮书 。
启用二步验证
然后去 Settings -> Two-step Login 设置 Authenticator App 启用二步验证。基于 TOTP
的六位验证码有很多玩意都支持。很多平台都有很优秀的应用,别用 Authy
.
首先强烈推荐用 keepass
来存储 TOTP 凭证。各个平台均有适配的客户端,格式统一,加密强度高,单文件密码库备份简易,自动填充功能强大,字段齐全并且还能拓展,又能支持 TOTP/HOTP/STEAM OTP, 是一款优秀的本地密码管理器。
本地用 keepass 应该够了,如果您还想要其他选择:
Android 有 andOTP
和 Aegis
, Google Play 和 F-Droid 上都能下到。
Linux 可以用 OTPClient
. 垃圾玩意一新增就崩溃 已经修好了
备份和还原
你大可完整备份一下自己的数据库。保不准哪天你的机器可能就完蛋,从而丢失数据(真 数据上云),就像 OVH 这样 …
备份
你存放 vaultwarden 数据的文件夹里,大概会有这些东西:
vaultwarden-docker
├── docker-compose.yml
└── vw-data
├── attachments
├── config.json
├── db.sqlite3
├── db.sqlite3-shm
├── db.sqlite3-wal
├── icon_cache
├── rsa_key.pem
├── rsa_key.pub.pem
├── sends
└── tmp
备份用的指令可以用 cron 做成定时任务。
对于数据库,可以用管理面板来备份数据库。备份的数据库会被命名为 db_YYYYMMDD_HHMMSS.sqlite3
.
也可以调用 sqlite3 命令行。 Reference
sqlite3 ./vw-data/db.sqlite3 "VACUUM INTO './vw-data/db_$(date '+%Y%m%d-%H%M').sqlite3'"
这个数据库是不包括密码管理器配置文件以及网站图标的,而附件在 /attachments
, 如果你在密码仓库里加了附件,那必须备份这个文件夹。
Sends 则被存在 /sends
中。
压缩
可以先打包成一个文件。比如这样:
tar --zstd -cvf vw-backup.tar.zst vaultwarden-docker
或者直接在本地使用 rsync
rsync -avP -e "ssh -p$PORT" user@hostname:/path/to/your/vaultwarden-docker vaultwarden-docker
zstd 的压缩效果还不错,比较建议使用。
保存
存放在安全的地方。你能控制的地方。
最好事先再加密一次。
恢复
把你之前备份的文件送上去解压就行。
总结
这款强大的密码仓库,我暂时也只会这些基本的部署和维护。
至于其他的玩法,你不妨自己探索。经过两年多我也折腾了不少,但是真的懒得写啊
祝玩得开心。
致谢
再次感谢 ous50
的教程。我在自建过程中遇见许多问题。仰仗了他的帮助,我才得以成功部署。
同时感谢 billchenchina
对本文结构的改进。