当初在群晖上自建bitwarden_rs服务器的时候,使用Google搜索出来的结果一概都是使用DSM界面的简单配置,那样倒是能用,但WebSocket不通会导致实时同步不能生效。趁着这次重新规划NAS的机会,我记录一下完整的配置流程。
Bitwarden介绍
Bitwarden本身就不多说了,是个类似于1Password的全平台密码管理器。优势在于代码开源,可以自建服务进一步保证敏感数据私有;缺点呢主要服务端使用.NET和MS SQL,成本对于个人使用无疑太大了。所以社区上有很多活跃人士造轮子来搭配官方客户端,比较活跃的项目有Ruby写的rubywarden和我这里用的Rust版bitwarden_rs。
bitwarden_rs实现了绝大部分官方版本的功能(免费的和收费的),资源占用很低,使用Docker易于部署,数据存储又可以选择SQLite/MySQL/PostgreSQL,非常灵活。
准备工作
群晖的DSM系统基本上就是个魔改的Debian,界面上还好说,想在命令行操作有时候特别麻烦。
在DNS服务商(CloudFlare)配置域名指向。
安装Docker套件
DSM的Package Center里面直接搜索安装,略。
安装Docker Compose
SSH登录群晖终端,执行:
1
2
| $ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
|
生成域名SSL证书
方案一: 使用群晖的DDNS域名+自定义端口
略。
方案二: 使用Certbot获取Let’s Encrypt免费证书
我用的CloudFlare DNS, Certbot直接支持,很方便。
- 创建独立目录,比如
/volume1/docker/certbot
,进去后创建几个子目录: mkdir -p {etc,secrets,log}
,将CloudFlare API Token填入secrets/cloudflare.ini
:
这里还需要收敛文件权限,不然Certbot运行时会给warning:
1
| $ chmod 600 secrets/cloudflare.ini
|
1
2
3
4
5
6
7
8
9
| $ sudo docker run -it --rm --name certbot \
-v /volume1/docker/certbot/etc:/etc/letsencrypt \
-v /volume1/docker/certbot/log:/var/log/letsencrypt \
-v /volume1/docker/certbot/secrets:/.secrets \
certbot/dns-cloudflare certonly \
--dns-cloudflare-credentials /.secrets/cloudflare.ini \
--dns-cloudflare-propagation-seconds 60 \
--server https://acme-v02.api.letsencrypt.org/directory \
-d 'josta.me,*.josta.me'
|
回答几个交互式问题,就可以看到恭喜证书生成的提示了:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/josta.me/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/josta.me/privkey.pem
Your cert will expire on 2020-08-23.
对应的实际位置在 /volume1/docker/certbot/etc/live/josta.me/
,校验下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| $ openssl x509 -in /volume1/docker/certbot/etc/live/josta.me/fullchain.pem -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:94:9f:69:37:e6:d7:7a:78:dd:0d:51:93:98:72:a3:54:c6
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3
Validity
Not Before: May 25 02:18:35 2020 GMT
Not After : Aug 23 02:18:35 2020 GMT
Subject: CN=josta.me
Subject Public Key Info:
...
|
- 定期更新证书
按照上面的提示,拿到的证书会在2020-08-23过期,所以还需要弄个定时任务去刷新,这里就直接用群晖的UI方便些。
- 更新命令,新建个脚本方便使用
/volume1/docker/certbot/certbot_renew.sh
:
1
2
3
4
5
6
7
| #!/bin/bash
sudo docker run -it --rm --name certbot \
-v /volume1/docker/certbot/etc:/etc/letsencrypt \
-v /volume1/docker/certbot/log:/var/log/letsencrypt \
-v /volume1/docker/certbot/secrets:/.secrets \
certbot/dns-cloudflare renew --quiet
|
- DSM桌面 -> Control Panel -> Task Scheduler -> Create -> Scheduled Task -> User-defined script,定义好定时执行计划,script填刚才创建的文件
bash /volume1/docker/certbot/certbot_renew.sh
,确认即可。
Bitwarden服务
Database
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| version: '3'
services:
database.postgres:
image: groonga/pgroonga:latest
container_name: postgres
restart: always
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
- TZ="Asia/Singapore"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
|
- 注意: 应用并不会去pg自动创建用户和db,需要先手动操作,否则启动时会失败。
1
2
3
4
5
6
7
8
| $ sudo docker run -it --rm -e POSTGRES_PASSWORD=${passwd} -e PGPASSWORD=${passwd} --network postgres_default groonga/pgroonga psql -h postgres -U postgres -c "CREATE USER bwuser WITH PASSWORD 'foobar'"
$ sudo docker run -it --rm -e POSTGRES_PASSWORD=${passwd} -e PGPASSWORD=${passwd} --network postgres_default groonga/pgroonga psql -h postgres -U postgres -c "CREATE DATABASE bitwarden"
$ sudo docker run -it --rm -e POSTGRES_PASSWORD=${passwd} -e PGPASSWORD=${passwd} --network postgres_default groonga/pgroonga psql -h postgres -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE bitwarden TO bwuser"
# Chinese full-text search support
$ sudo docker run -it --rm -e POSTGRES_PASSWORD=${passwd} -e PGPASSWORD=${passwd} --network postgres_default groonga/pgroonga psql -h postgres -U postgres bitwarden -c "create extension pgroonga"
|
- bitwarden_rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
| version: '3'
services:
application:
image: bitwardenrs/server-postgresql
container_name: bitwarden
restart: unless-stopped
ports:
- 8080:80
- 3012:3012
volumes:
- ./data:/data
environment:
- TZ="Asia/Singapore"
- DATABASE_URL=postgresql://bwuser:[email protected]:5432/bitwarden?sslmode=disable
- ENABLE_DB_WAL=false
- ADMIN_TOKEN=${ADMINTOKEN}
- WEBSOCKET_ENABLED=true
- WEBSOCKET_ADDRESS=0.0.0.0
- WEBSOCKET_PORT=3012
- INVITATIONS_ALLOWED=true
- SIGNUPS_ALLOWED=true
- SIGNUPS_VERIFY=true
- SIGNUPS_VERIFY_RESEND_TIME=3600
- SIGNUPS_VERIFY_RESEND_LIMIT=6
- DOMAIN=https://barbaz.josta.me
- PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- ROCKET_ENV=production
- ROCKET_PORT=80
- ROCKET_WORKERS=10
- SMTP_HOST=smtp.gmail.com # gmail smtp
- SMTP_FROM=${FROM_MAIL}
- SMTP_FROM_NAME=${FROM_USER}
- SMTP_PORT=587
- SMTP_SSL=true
- SMTP_USERNAME=${FROM_MAIL}
- SMTP_PASSWORD=${SMTP_PASS}
- SMTP_AUTH_MECHANISM="Plain"
- SMTP_TIMEOUT=15
dns:
- 1.1.1.1
- 1.0.0.1
networks:
- postgres_default
networks:
postgres_default:
external: true
|
Nginx反向代理
在 /usr/local/etc/nginx/sites-enabled/
目录新建配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name barbaz.josta.me;
# Certbot申请的证书路径
ssl_certificate /volume1/docker/certbot/etc/live/josta.me/fullchain.pem;
ssl_certificate_key /volume1/docker/certbot/etc/live/josta.me/privkey.pem;
location / {
proxy_connect_timeout 60;
proxy_read_timeout 60;
proxy_send_timeout 60;
proxy_intercept_errors off;
proxy_http_version 1.1;
proxy_set_header Host $http_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://127.0.0.1:8080;
}
# Live sync websocket
location /notifications/hub {
proxy_pass http://127.0.0.1:3012;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /notifications/hub/negotiate {
proxy_pass http://127.0.0.1:8080;
}
error_page 403 404 500 502 503 504 @error_page;
location @error_page {
root /usr/syno/share/nginx;
rewrite (.*) /error.html break;
allow all;
}
}
|
重启Nginx sudo synoservice -restart nginx
,最后在Bitwarden客户端上配置好服务器地址,大功告成。
Alfred workflow
Bitwarden不比1Password,有Alfred官方提供的原生集成,需要安装社区制作的workflow才能配合使用。
brew install bitwarden-cli
安装官方的命令行工具- 下载并安装最新版插件
- 配置:
bwsetemail $email
帐号bwsetserver https://$domain
设置服务地址- 如果帐号有设置2FA验证需要
bwset2fa on
开启,如果是使用YubiKey的话还要 bwset2famethod 3
bwlogin
完成登录后最好再 bwsync
同步一次- 完成,之后就可以在Alfred launcher里使用
bw <query>
命令查询Bitwarden中保存的数据了
信息更新
- 使用非root用户控制权限,提升安全性
- 设置运行容器的用户uid/gid(比如user: 1029:100)
- 设置
ROCKET_PORT
,普通用户需要大于1024
History
Version | Action | Time |
---|
1.0 | Initial commit | May 25, 2020 |
1.1 | Run as non-root user | Jun 11, 2020 |
1.2 | Alfred integration | Jul 08, 2020 |