自建 Vaultwarden 密码管理器
密码管理器是个好东西,我觉得每个人都要有。
开始
在我看来,密码管理器大致可以分为两类,一类是基于客户端本地存储加密数据库,指定云端存储进行多设备同步,比如 Keepass。一类是基于服务器加密存储,比如 Bitwarden。
我个人一直在用基于本地存储的 SafeInCloud,它按移动端平台一次付费,PC 端免费。我在买它之前还用了一段时间的破解版 Android 应用 一直都有在更新,还算比较良心,现在也涨价了。目前遇到的缺点只有没 Linux 桌面程序,好像不支持 Steam 的 OTP。在这一类上,我大概就推荐它和 Keepass。
Bitwarden 是目前较流行的基于服务端存储的密码管理器,官方实例可以免费使用,缺点是没有 2FA OTP,付费才可以,付费一年 $10,价格不算贵。Bitwarden 最大的缺点是由于设计原因,在服务器离线或是设备无网络的情况下,客户端只能浏览密码库,无法进行增删和修改操作。官方提供了自建文档,但它对于系统资源要求过高,且建成后仍然要购买授权,毫无意义可言。更可行的方法是使用非官方实现、兼容官方客户端的 Vaultwarden。总地来说,如果没有 2FA OTP 需求,可以直接免费使用官方实例,适合推荐给朋友;如果有 2FA OTP 需求但没有自建能力或资源,可以付费使用官方实例;如果有自建能力和资源,可以配置 Vaultwarden。
Vaultwarden 在 GitHub wiki 里针对安装和配置的文档写得很详细,可以看看。文档推荐使用 docker 安装,而我采用的是没有 docker、直接运行预编译文件的安装方式。
配置系统 Rust 环境
如果服务器上没有,自然是先用上 rustup.rs 配好环境。
获取预编译程序文件
仓库本身没有提供预编译程序文件,怎么获得呢?我们可以 fork 仓库,新建分支,在 .github/workflows/build.yml
中添加:
- name: release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/${{ matrix.target-triple }}/release/vaultwarden${{ matrix.ext }}
tag: ${{ github.ref }}
asset_name: vaultwarden_$tag
overwrite: true
body: "https://github.com/dani-garcia/vaultwarden/releases"
等待 GitHub Actions 跑完,就能在 Releases 里拿到预编译文件。当然,也可以直接 来我这里拿。不定期更新
获取静态文件
这个直接前往 bw_web_builds 下载压缩包即可,解压后得到的是一个包含文件、名为 web-vault
的文件夹。
获取配置文件
下载 .env.template,保存为 .env
。
创建 data 文件夹
直接 mkdir data
即可。
确认目录结构
把上面四个放在同一目录下:
vaultwarden
# 根目录,命名随意.env
# 环境配置文件data
# 数据文件夹vaultwarden
# 预编译程序文件web-vault
# 静态文件文件夹
弄成这样就行。
配置数据库
Update:Heroku 收费了,以下内容有关 Heroku 的部分大概就算作废了(要是愿意付费的话还是能用),要么换别家托管 PostgreSQL,要么老实本地 SQLite / MySQL 吧。
数据库可以用 SQLite、MySQL 或 PostgreSQL。之前我也建过一次 Vaultwarden,但我想着万一哪天回滚服务器把用户最近添加或修改的密码库给回滚丢了就完蛋了 最后就撤掉了。现在用上了外部数据库服务,选择的是 Heroku Postgres,免费限制一万行,存储 1GB,应该没什么问题。这下就不怕回滚服务器丢掉数据库了
配置 .env
配置文件太长,就只挑重点的放在这里说一下,复制粘贴建议删除我写的包括 #
后的注释。
.env
DATABASE_URL=postgresql://user:password@host[:port]/database_name # 数据库连接信息,填写方法详见 Wiki
DATABASE_MAX_CONNS=20 # 数据库最大连接数,默认 10,Heroku Postgres 限制 20
SENDS_ALLOWED=false # 是否允许 Send 功能,默认 true(我机器空间不多,干掉)
LOG_FILE=/path/to/log # 指定日志路径,不用日志就注释掉
## Log level
## Change the verbosity of the log output
## Valid values are "trace", "debug", "info", "warn", "error" and "off"
## Setting it to "trace" or "debug" would also show logs for mounted
## routes and static file, websocket and alive requests
LOG_LEVEL=error # 日志等级,默认 info(我用 error)
SIGNUPS_ALLOWED=false # 允许注册,默认 true(我只用邀请注册,设置 false)
SIGNUPS_VERIFY=true # 强制注册验证邮箱,提高安全性,有 SMTP 才能开,默认 false
## Controls which users can create new orgs.
## Blank or 'all' means all users can create orgs (this is the default):
# ORG_CREATION_USERS=
## 'none' means no users can create orgs:
ORG_CREATION_USERS=none # 允许用户创建组织,组织管理员可邀请用户,默认留空允许所有用户(设置 none 为不允许)
## A comma-separated list means only those users can create orgs:
# [email protected],[email protected]
ADMIN_TOKEN= # 设置管理员密码,用于登录 /admin,使用 vaultwarden hash 生成
ORG_ATTACHMENT_LIMIT=1 # 限制组织附件大小,单位 KB(我机器空间不多,掐死)
USER_ATTACHMENT_LIMIT=1 # 限制用户附件大小,单位 KB(我机器空间不多,掐死)
DOMAIN=https://bw.domain.tld:443 # 网站地址及端口
ROCKET_ADDRESS=127.0.0.1 # 设置 Vaultwarden 本地监听地址
ROCKET_PORT=3011 # 设置 Vaultwarden 本地监听端口
SMTP_HOST=smtp.domain.tld # SMTP 主机
[email protected] # SMTP 发送邮箱
SMTP_FROM_NAME=Vaultwarden # SMTP 发送用户名
SMTP_SECURITY=starttls # 开启安全连接,默认 starttls,可选 force_tls 和 off
SMTP_PORT=465 # TLS 465,SSL 587
SMTP_USERNAME=username # SMTP 登录用户名
SMTP_PASSWORD=password # SMTP 登录密码
SMTP_TIMEOUT=15
SMTP_AUTH_MECHANISM="Login" # SMTP 认证方式
配置 Nginx
直接整一个虚拟主机反向代理配置文件,照抄 wiki 示例。
vaultwarden.conf
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080; # 指定到 Vaultwarden 本地监听地址及端口
keepalive 2;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' "";
}
server {
server_name bw.domain.tld ; # 网站地址
include redirect.conf; # 重定向 301 到 https
}
server {
listen 443 ssl http2;
#listen [::]:443 ssl http2;
server_name bw.domain.tld ; # 网站地址
client_max_body_size 525M;
# 延长 nginx 超时时间
proxy_connect_timeout 777;
proxy_send_timeout 777;
proxy_read_timeout 777;
send_timeout 777;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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;
}
include ssl-params.conf; # SSL 参数
access_log /path/to/bw.domain.tld.log; # 网站日志
}
redirect.conf
listen 80;
#listen [::]:80;
return 301 https://$server_name$request_uri;
ssl-params.conf
参考 Mozilla SSL Configuration Generator
ssl_certificate /path/to/fullchain.cer;
ssl_certificate_key /path/to/bw.domain.tld.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
# openssl dhparam -out /path/to/dhparam.pem 2048
ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=63072000" always;
ssl_stapling on;
ssl_stapling_verify on;
resolver_timeout 5s;
ssl_early_data on;
proxy_set_header Early-Data $ssl_early_data;
ssl_trusted_certificate /path/to/chain.pem;
add_header X-Frame-Options SAMEORIGIN; # 用 DENY 可能会引发在 Firefox 上的 WebAuthn iframe 加载问题
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
配置 systemd 自启,运行程序
编写 /etc/system/system/vaultwarden.service
:
[Unit]
Description=Vaultwarden
After=network.target
[Service]
Type=simple
WorkingDirectory=/path/to/vaultwarden # 指向 Vaultwarden 存放目录
ExecStart=/path/to/vaultwarden/vaultwarden # 指向 Vaultwarden 预编译程序文件
Restart=on-failure
[Install]
WantedBy=multi-user.target
执行 systemctl daemon-reload
后,执行 systemctl enable vaultwarden
和 systemctl start vaultwarden
,再执行 systemctl status vaultwarden
查看状态,若无故障即为完工。
附加:使用 Heroku Postgres 的情况
Heroku 在数据库信息处指出:
Please note that these credentials are not permanent.
Heroku rotates credentials periodically and updates applications where this database is attached.
Heroku 文档 中也提到不要直接复制数据库信息,需要在程序运行前通过 Heroku CLI 获取最新的数据库信息。
我就瞎糊了一个 bash 脚本,放在 vaultwarden 目录下,使用 systemd 运行。水平有限,能用就行。
vaultwarden.sh
#!bash
pgsqladdr=`heroku config:get DATABASE_URL -a instance_name` # 获取数据库信息保存到变量
pgsqladdr=$(sed 's/postgres/DATABASE_URL=postgresql/g' <<< "$pgsqladdr") # 修改变量符合 .env 格式
sed -i "s|DATABASE_URL=postgresql.*|$pgsqladdr|g" /path/to/vaultwarden/.env # 替换 .env 文件内数据库信息
/path/to/vaultwarden/vaultwarden # 运行 Vaultwarden 程序
/etc/system/system/vaultwarden.service
[Unit]
Description=Vaultwarden
After=network.target
[Service]
Type=simple
User= # 运行用户(大力就上 root)
Group= # 运行用户组(大力就上 root)
WorkingDirectory=/path/to/vaultwarden
ExecStart=/bin/bash /path/to/vaultwarden/vaultwarden.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
每次改完 systemd 文件后记得执行 systemctl daemon-reload
。
这俩文件让我糊了几个小时,啊,人生(望天
登录及使用
登录使用 https://bw.domain.tld
,管理使用 https://bw.domain.tld/admin
。客户端首次使用时需要改掉默认为官方实例的地址再进行注册和登录操作。
结束
试着导入了一下我在 SafeInCloud 的密码库,结果如下:
这样看来,承载十几个用户应该是没什么问题的。
眼熟的朋友有兴趣可以找我要个号(应该不会跑路……吧?
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。