

























一直以来为了方便都是用的 Chrome 自带的密码管理器,虽然很早以前就知道 Chrome 密码没有本地加密,似乎谷歌的逻辑是箱子(操作系统)是安全的,箱子里(Chrome 保存的密码)就是安全的,看起来没啥大毛病,但现实是总会被迫安装各种喜欢扫盘的软件,迫于懒,一直没折腾,现在还是下定决心,研究下使用 vaultwarden 自建密码管理器。
想必愿意折腾自建密码管理器的朋友都已经对 vaultwarden (bitwarden_rs) 有所了解,这里不再介绍,直接进入正题。
所有操作来自于官方文档,系统环境为 Debian 11 (Bullseye)。
运行 vaultwarden 一个最简单的方法是使用 Docker 启动一个容器:
docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 vaultwarden/server:latest
Docker 的安装方法可以参考文章: Debian 系统安装 Docker 教程
显然,要自建一个安全可靠的密码管理器没有这么简单,还需要进行一系列的配置,你可以通过设置环境变量或在 admin 管理页面(会将设置写入 data 目录下的 config.json 文件)来配置 vaultwarden。注意,config.json 中的设置会覆盖相应的环境变量设置,因此推荐两种方式二选一。完整的环境变量参数可以参考 .env.example,通过 docker run --env-file <env-file> 或者 docker run -v /path/to/.env:/.env 来使用自定义环境变量,下面是一些我使用到的参数,仅供参考:
SIGNUPS_ALLOWED=false:禁止注册新用户INVITATIONS_ALLOWED=false:禁止邀请用户,即使设置了禁止注册/邀请用户,在 admin 页面仍然可以邀请用户ADMIN_TOKEN=some_long_long_random_token:开启 admin 管理页面,推荐使用 openssl rand -base64 48 命令来生成一个长 token 来保护 admin 页面,开启 admin 页面后会在 DATA_FOLDER 目录下生成一个 config.json 文件,如果后期需要关闭 admin 页面,需要同时删除环境变量和 config.json 文件中的 admin_token 参数LOG_FILE=/data/vaultwarden.log:输出日志,默认使用 stdout 输出日志,可以通过设置该参数输出到文件SHOW_PASSWORD_HINT=false:关闭密码提示为了方便,这里使用 docker-compose.yml 启动服务:
version: '3'
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: always
environment:
- TZ=Asia/Shanghai
- SIGNUPS_ALLOWED=false
- INVITATIONS_ALLOWED=false
- ADMIN_TOKEN=some_long_long_random_token
- LOG_FILE=/data/vaultwarden.log
- LOG_LEVEL=warn
- SHOW_PASSWORD_HINT=false
- DOMAIN=https://vw.domain.tld
volumes:
- ./vw_data:/data
ports:
- 127.0.0.1:8080:80
启动服务:docker compose up -d,其中 SIGNUPS_ALLOWED 和 INVITATIONS_ALLOWED 请在第一次登录创建用户后再添加重启服务。
更新 vaultwarden:
docker compose down
docker compose pull
docker compose up -d
常规的安全设置如关闭注册/邀请、关闭密码提示已经在上面的环境变量中设置。
开启 HTTPS,你可以 使用 acme.sh 自动签发和更新证书 。
禁止 IP 访问,并设置 ssl_reject_handshake (Nginx ≥ 1.19.4) 参数防止通过 HTTPS 访问你的 IP 时暴露证书,配置 nginx.conf 中的默认设置:
server {
listen 80 default_server;
server_name _;
return 444;
}
server {
listen 443 ssl default_server;
ssl_reject_handshake on;
ssl_protocols TLSv1.2 TLSv1.3;
}
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:8080;
keepalive 2;
}
server {
listen 80;
listen [::]:80;
server_name vw.domain.tld;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name vw.domain.tld;
ssl_certificate /path/to/certificate/fullchain.pem;
ssl_certificate_key /path/to/certificate/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;preload" always;
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;
}
}
如果你开启了 Websocket 通知或者需要使用 htpasswd 来为 admin 页面添加额外的保护,请参考完整的配置文件。
你可以通过搭配 fail2ban 来防止暴力破解密码,进一步增加安全性,关于 fail2ban,可以参考: Debian 下 Nginx 配合 Fail2Ban 减少恶意扫描和攻击 ,这里只列出 filter 和 jail 配置。
Filter,进入 /etc/fail2ban/filter.d 目录,新建 vaultwarden.local:
# /etc/fail2ban/filter.d/vaultwarden.local
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$
ignoreregex =
Jail,进入 /etc/fail2ban/jail.d 目录,新建 vaultwarden.local,注意修改日志文件路径:
# /etc/fail2ban/jail.d/vaultwarden.local
[vaultwarden]
enabled = true
port = 80,443,8081
filter = vaultwarden
logpath = /path/to/vaultwarden.log
maxretry = 3
bantime = 30d
findtime = 3h
Filter,进入 /etc/fail2ban/filter.d 目录,新建 vaultwarden-admin.local:
# /etc/fail2ban/filter.d/vaultwarden-admin.local
[INCLUDES]
before = common.conf
[Definition]
failregex = ^.*Invalid admin token\. IP: <ADDR>.*$
ignoreregex =
Jail,进入 /etc/fail2ban/jail.d 目录,新建 vaultwarden-admin.local,同样注意修改日志文件路径:
# /etc/fail2ban/jail.d/vaultwarden-admin.local
[vaultwarden-admin]
enabled = true
port = 80,443
filter = vaultwarden-admin
logpath = /bitwarden/data/vaultwarden.log
maxretry = 3
bantime = 30d
findtime = 3h
重新加载 fail2ban:
systemctl reload fail2ban
vaultwarden 默认将所有数据存储在 data 目录下,使用 SQLite 数据库,文件结构如下:
data
├── attachments # 每一个附件都作为单独的文件存储在此目录下。
│ └── <uuid> # (如果未创建过附件,则此 attachments 目录将不存在)
│ └── <random_id>
├── config.json # 存储管理页面配置;仅在之前已启用管理页面的情况下存在。
├── db.sqlite3 # 主 SQLite 数据库文件。
├── db.sqlite3-shm # SQLite 共享内存文件(并非始终存在)。
├── db.sqlite3-wal # SQLite 预写日志文件(并非始终存在)。
├── icon_cache # 站点图标 (favicon) 缓存在此目录下。
│ ├── <domain>.png
│ ├── example.com.png
│ ├── example.net.png
│ └── example.org.png
├── rsa_key.der # ‘rsa_key.*’ 文件用于签署验证令牌。
├── rsa_key.pem
├── rsa_key.pub.der
└── sends # 每一个 Send 的附件都作为单独的文件存储在此目录下。
└── <uuid> # (如果未创建过 Send 附件,则此 sends 目录将不存在)
└── <random_id>
其中需要备份的有:
db.sqlite3 文件:主数据库,包含所有重要的数据attachments 目录:文件附件,唯一不存储在数据库表中的重要数据建议备份的有
config.json 文件:配置文件rsa_key* 文件:这些文件用于签署当前登录用户的验证令牌,删除这些文件将注销每个用户,迫使他们重新登录可选备份的有:
sends 目录:文件附件,用于暂时存储icon_cache 目录:图标缓存,用于存储网站图标数据库的备份推荐使用下面的命令进行备份:
sqlite3 data/db.sqlite3 ".backup '/path/to/backups/db-$(date '+%Y%m%d-%H%M').sqlite3'"
如果在 2022 年 10 月 6 日 22:26 运行此命令,这将备份 SQLite 数据库文件到 /path/to/backups/db-20221006-2226.sqlite3
备份的文件可以打包加密后通过 rclone 备份到 OneDrive/Google Drive,可以参考文章: Linux 定时自动备份数据到 OneDrive/Google Drive
还原操作很简单,只需要在另一台服务器上重新安装 vaultwarden 并确保未运行,然后简单地将 data 文件夹中的每个文件或目录替换为它的备份版本即可。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。