Published on

部署基于 Rust 的第三方 Bitwarden 服务端容器

Authors
  • avatar
    Name
    ttyS3
    Twitter

更新

2021-06-30 更新: 项目名称现在更改为 vaultwarden 了, 详情见 https://github.com/dani-garcia/vaultwarden/discussions/1642

缘由

1password太贵, 关键是这类软件好像以前还有数据泄露事例。

在此之前老灯用的是Firefox Lockwise , 只能说基本上够用吧。管理密码功能在Firefox上操作。其实就是Firefox本身的功能。 Lockwise app 只是协助在手机端给你自动填充密码。

这次Google 停止Chromium账号同步功能事件,使得我重新花时间思考了一下,我要切换浏览器的事情。

这一年多以来,老灯重回Firefox, 刚开始真的很不适应,你们懂的。唯一不适应的就是:慢。打开网页超级慢。

(因为习惯了Chrome和Chromium的快)

然而一年过去了,Firefox打开页面的速度并不见得有什么提升。同时有一些在任何其它浏览器都没有的问题,

在Firefox会出现。fix: (native wayland硬件加速的支持 已经和 Chromium 一样可以试验性开启了。) , 最明显的可能是 4K 屏下打开Firefox 要按两次 F11 解决窗口大小问题吧(用过的就懂我在说什么)。

不过,一个Firefox进程打开4000多个tab不会炸机(没错,我真的有四千个tab没关),这一点 Firefox 确实比 吃内存狂魔 Chrome 要好。

切换掉Firefox 对于我来说,等于要卸载 Firefox Lockwise . 因此得找个替代的app.

为什么是Bitwarden

综合考虑之下,选择了 Bitwarden.

  1. 全套开源(desktop, mobile, server)
  2. 官方同时提供付费服务(有商业支持,能确保开源项目持续)
  3. 其实官方的 free 版也足够大部分人使用,比如我。

唯一我不太喜欢的可能是,server端是基于C#实现了,同时要mssql 数据库的支持。

虽然官方有提供docker compose 文件,可以一键 up. 但是对于个人需求来说,为了一个server api, 起一堆的容器,我也不太喜欢。另外,起这么多容器,vps的配置也是要相应的跟得上的。

不过,翻看博客,找到了一个基于Rust 实现的all in one 的 Bitwarden server:

https://github.com/dani-garcia/vaultwarden

这个版本相对于官方的C#版有什么区别?

  1. 除了一些企业版的功能,其它的应该有的都有。可以说对于个人用户是没有影响的。
  2. 小巧啊,all in one 啊,只要跑一个容器。据说只需要10M左右的内存给它跑!

自己构建 Bitwarden 容器镜像

如果不想使用默认的镜像,可以自己构建,很简单。

# 构建 docker 镜像:
docker build -t bitwarden_rs .

# 要使用 MySQL 后端, 则
docker build -t bitwarden_rs --build-arg DB=mysql .

# 要使用 Postgresql 后端
docker build -t bitwarden_rs --build-arg DB=postgresql .

当然也可以直接用Rust toolchain编译二进制:

# 使用所有后端编译(二进制位于 target/release/bitwarden_rs)
cargo build --features sqlite,mysql,postgresql --release

#仅使用 sqlite 编译(二进制位于 target/release/bitwarden_rs)
cargo build --features sqlite --release

# 仅使用 mysql 编译(二进制位于 target/release/bitwarden_rs)
cargo build --features mysql --release

# 仅使用 postgresql 编译(二进制位于 target/release/bitwarden_rs)
cargo build --features postgresql --release

构建web ui (web-vault)

可以直接从 dani-garcia/bw_web_builds 下载web-vault的编译版本。

*注意:构建密码库需要约 1.5GB 的 RAM。在具有 1GB 或更小容量的 RaspberryPI 之类的系统上,请启用交换功能或在功能更强大的计算机上构建,然后从那里将文件复制过来。仅构建时需要大量内存,而运行带密码库的 bitwarden_rs 仅需要***约 10MB** 的 RAM。

1、克隆 bitwarden/web git 库,并检查最新的发行标签(例如 v2.18.2):

# 克隆库
git clone https://github.com/bitwarden/web.git web-vault
cd web-vault
# 切换到最新的标签
git checkout "$(git tag --sort=v:refname | tail -n1)"

2、从 dani-garcia/bw_web_builds 下载补丁文件并将其复制到 web-vault 文件夹。选择要使用的补丁文件的版本(假设网页密码库版本为 vX.Y.Z):

  • 如果有版本为 vX.Y.Z 的补丁,则使用该版本
  • 否则,选择小于 vX.Y.Z 的最大的那一个版本

3、应用补丁:

# 在'web-vault'目录中运行命令
git apply vX.Y.Z.patch

4、然后,构建

npm install
# Read the note below (we do use this for our docker builds).
# 运行 npm audit fix 以修复漏洞。这将自动尝试将软件包升级到较新的版本,
# 该版本可能不兼容并破坏web-vault功能。
# 如果知道自己在做什么,请自行承担风险。
# npm audit fix
npm run dist

5、最后将 build 文件夹的内容复制到目标文件夹中:

  • 如果与 cargo run --release 一起运行,则目标文件夹为 bitwarden_rs/web-vault。
  • 如果直接运行已编译的二进制,则它位于二进制旁,为 bitwarden_rs/target/release/web-vault

老灯构建完已经推到docker hub了:

https://hub.docker.com/r/80x86/vaultwarden

启动 Bitwarden 容器

# 删除旧的容器,如果有
docker stop bitwarden && docker rm bitwarden

# 准备数据目录,你也可以存别的地方, vps 没有额外的数据盘的可以直接这样
mkdir /bw-data/

# 先拉一下,方便run 顺利执行
docker pull 80x86/vaultwarden:latest

# 创建并启动容器
docker run -d --name bitwarden \
--restart unless-stopped \
-e WEBSOCKET_ENABLED=true \
-e ROCKET_WORKERS=20 \
-e SIGNUPS_ALLOWED=false \
-e INVITATIONS_ALLOWED=false \
-p 3012:3012 \
-p 2052:80 \
-v /bw-data/:/data/ \
80x86/vaultwarden:latest

# by the way, rs的是这个
#bitwardenrs/server:latest

# 启动后,可以用以下命令观察日志有没有错误 
docker logs -f bitwarden

解释: -e SIGNUPS_ALLOWED=false 禁用新用户注册,如果只准备给自己使用,则可以用这个选项禁止其它人注册。注意,容器第一次启动时,请将这个选项设置成 true 开启注册,等你注册完了自己的账号,就可以关闭注册 了。当然,如果你开启了admin后台,也可以通过admin发起邀请注册。

-e INVITATIONS_ALLOWED=false 禁用(普通用户的)邀请权限

如果机器有开 firewalld 防火墙的,注意开放 443 端口,等会我们要用到。

# 防火墙配置
firewall-cmd --zone=public --permanent --add-port=443/tcp

# 看看现在开放的端口
firewall-cmd --zone=public --permanent --list-ports

# 重载配置(注意,如果有其它容器在跑,这个会影响nat转发规则)
# 对于podman 可以用 network reload 命令修复 iptables 规则。
firewall-cmd --reload

nginx反向代理+启用https

因为 Bitwarden web vault UI 使用的 Web Crypto API,大多数浏览器只有在 HTTPS 环境下才能正常工作。

(推荐)把 bitwarden_rs 放在一个反向代理后面。比如用nginx来处理 HTTPS 连接

(不推荐)启用 bitwarden_rs 内置的 HTTPS 功能(通过 Rocket 网络框架)。Rocket 的 HTTPS 实现相对不成熟且有限。此方式也不支持 WebSocket 通知。

有关这些选项的更多细节,请参考启用 HTTPS 部分。

这里老灯选择最简单的方案:

nginx反向代理 + Cloudflare 代理

Cloudflare 里面的tls 配置成 full 模式。然后nginx使用自签名的证书就OK了(cf的 full 模式不会校验 origin server之间的ca 证书, 因此可以放心地用自签名证书)

由于前置了cf, 真正的证书是cf自动分发的。因此 origin server (也就是我们的nginx反向代理)自签名证书完全不会给浏览器红色警告。

当然,也可以使用 ACME 客户端获取 Let's Encrypt 证书。一些反向代理(例如 Caddy)也内置支持使用 ACME 协议获取证书。

老灯这里用nginx,是因为服务器上已经有nginx在跑了,并且占用了80和443端口。

如果是全新的服务器,并且80和443没有被占用,我建议使用 Caddy 配置起来 更简单。

启用 WebSocket 通知

要启用 WebSockets 通知,必须使用外部反向代理,并且必须执行以下配置操作:

  1. 将 /notifications/hub 端点路由到 WebSocket 服务器,默认在 3012 端口,确保传递 Connection 和 Upgrade 头。(提示:可以使用 WEBSOCKET_PORT 变量来更改端口)
  2. 将所有其他(包括 /notifications/hub/negotiate)路由到标准 Rocket 服务器,默认在 80 端口上。
  3. 如果使用 Docker,则可能还需要使用 -p 标识来映射两个端口。

tips: 由于 Rocket (荒野注: 这个server api是基于Rust生态一个叫Rocket的框架开发的) 缺乏对 WebSockets 的支持(尽管这是计划的功能),因此要在单独的端口上启动ws服务器。

当 bitwarden_rs 运行时,默认它会产生 2 * <cpu 核心数> 个 worker 来处理请求。在某些系统上,这可能会由于 worker 数量太少,从而导致性能降低,因此在 docker 镜像中更改为默认产生 10 个线程。可以通过设置ROCKET_WORKERS变量来增加或减少 worker 数量以覆盖此默认设置。

最后,老灯的配置如下:

server {
        listen 443 ssl http2;
        server_name 你的域名填写在这里;

        # Allow large attachments
        client_max_body_size 128M;

        ssl_certificate    ssl/证书文件名.crt;
        ssl_certificate_key ssl/私钥文件名.key;

        limit_conn conn_limit_per_ip 4;
        limit_req zone=req_limit_per_ip burst=4 nodelay;
        limit_rate 256k;

        access_log  /var/log/nginx/bw.access.log;
        error_log  /var/log/nginx/bw.error.log;

        location / {
            proxy_pass http://127.0.0.1:2052;
            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:3012;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }

        location /notifications/hub/negotiate {
        proxy_pass http://127.0.0.1:2052;
        }
}

TLS 检测

TLS 检测工具:

可以使用 https://comodosslstore.com/ssltools/ssl-checker.php 网站来检查 SSL 证书是否包含证书链。缺少证书链,Android 设备将无法连接。

也可以使用 https://www.ssllabs.com/ssltest/analyze.html 网站进行检查,但是它不支持自定义端口。一定要记住选中“Do not show the results on the boards”复选框,不然你的网址就在“Recently Seen”列表中公开暴露了。

也可以使用 openssl 工具来验证

openssl s_client -showcerts -connect vault.domain.com:443

# 或者使用的其他端口,比如 7070
openssl s_client -showcerts -connect vault.domain.com:7070

# 输出的开头应类似于以下内容(使用 Let's Encrypt 证书):
# 有 3 个不同depth(注意,它是从 0 开始的)级别的验证
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = vault.domain.com
verify return:1

Web Vault Admin界面

这里主要是给管理人员用的,对于个人用户单用户来说,就没有必要打开这里了。

启动管理界面,需要在创建容器时指定环境变量: -e ADMIN_TOKEN=一个超级复杂的密码

有关这些选项的更多细节,请参考启用管理页面 部分。

这个密码可以直接用命令生成: openssl rand -base64 48

测试一下禁止注册功能是否正常:

用户Web Vault界面

支持上游发展

最后,开源不易,有能力的大家尽量支持Bitwarden官方:8bit Solutions LLC 公司 毕竟,开源项目要是脱离了商业支持,基本上活下去的都是奇迹。

bitwarden_rs 仅提供 API(服务器)端实现,用户仍依赖来自上游的客户端程序(移动应用程序、桌面应用程序和网页密码库),这些都是 8bit Solutions LLC 公司在上游完成的许多工作。

同时 bitwarden_rs 支持上游的某些付费功能并免费提供该功能。这就提出了一些有关维持和支持上游发展的问题。许多用户提出了这个问题,并咨询他们如何在使用 bitwarden_rs 的同时支持上游的发展。

您可以通过 PayPal 直接捐赠给上游以支持他们的发展。

https://github.com/dani-garcia/vaultwarden/wiki/Supporting-upstream

https://rs.bitwarden.in/other-information/supporting-upstream-development

refs

构建容器镜像--中文文档: https://rs.bitwarden.in/deployment/building-your-own-docker-image

构建容器镜像--英文文档 https://github.com/dani-garcia/vaultwarden/wiki/Building-your-own-docker-image

启用https https://rs.bitwarden.in/deployment/https/enabling-https

https://github.com/dani-garcia/vaultwarden/wiki/Enabling-WebSocket-notifications

https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS

备份密码库 https://rs.bitwarden.in/other-information/backing-up-your-vault

反向代理教程: https://rs.bitwarden.in/deployment/proxy-examples

禁用新用户注册 https://rs.bitwarden.in/configuration/disable-registration-of-new-users

启用管理页面 https://rs.bitwarden.in/configuration/enabling-admin-page

Warning: Rocket's built-in TLS is not considered ready for production use. It is intended for development use only.

https://rocket.rs/v0.4/guide/configuration/#configuring-tls

https://github.com/dani-garcia/vaultwarden/wiki

https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples

https://bitwarden.com/help/article/import-from-firefox/

https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef

https://www.techempower.com/benchmarks/#section=data-r20

https://github.com/flosse/rust-web-framework-comparison#high-level-server-frameworks

对比:https://www.iamzs.top/archives/comparison-among-three-password-managers.html