banner
NEWS LETTER

VaultWarden搭建个人密码管理器

Scroll down

前言

bitWarden是一个开源的密码管理器,支持跨平台使用,包括Window、macOS、Linux、IOS和Android。还提供密码生成、自动填充、云同步等功能。可直接使用官方提供的服务,高级版需要付费。如果密码托管在官方不放心,还支持自己部署服务。

vaultWarden是一个用 Rust 重新编写的非官方 BitWarden 兼容服务器,兼容bitwarden的官方客户端,以前称为 bitwarden_rs,对服务器配置要求更低,更适合用于做自托管。这里有一个VaultWarden的中文Wiki。

鉴于以上,本次使用vaultWarden来搭建一个密码管理器。

准备工作

  • 云服务器,有docker& docker-compose
  • 域名
  • cloudflare 账号

安装

官方推荐一定要用https服务部署,这是因为 Bitwarden 网络密码库使用的 Web Crypto API,大多数浏览器只有在 HTTPS 环境下才能使用。根据官方文档的描述,需要:

  • 在服务器上启用nginx做反向代理
  • 申请创建SSL证书

本次直接交由CloudFlare托管 + Zero Trust隧道来实现处理https的部分,这样我们需要做的就只剩下启动 vaultwarden

cf tunnel 是什么

Cloudflare Tunnel为您提供了一种安全的方式,将您的资源连接到Cloudflare,而无需公共可路由的IP地址。使用Tunnel,您不会将流量发送到外部IP地址,而是在您的基础设施中创建一个轻量级的守护程序,仅向Cloudflare的全球网络创建出站连接。Cloudflare Tunnel可以安全地将HTTP Web服务器、SSH服务器、远程桌面和其他协议连接到Cloudflare。这样,您的源站可以通过Cloudflare提供流量,而不会容易受到绕过Cloudflare的攻击。

cf tunnel 可以做什么
经由tunnel的流量走向大致为:用户 - cf服务器的隧道入口 - 公网 - 运行在服务器上的隧道出口
有了隧道,无需配置SSL证书,无需nginx代理

创建一个cf tunnel
warden-cf-conf0

选择新建一条隧道,选择Cloudflared,并为隧道命名
warden-cf-conf1
推荐使用docker运行环境,复制页面上的命令,其中token参数每个人的不同用于身份校验。在服务器上执行。这条命令会做:

  • 运行 cloudflarecloudflared 容器镜像
  • 使用 cloudflared 工具创建一个tunnel,并禁用自动更新
  • 运行隧道,用指定token进行身份校验
    1
    docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token czODU4MjQ4ZTY0ZWMwM...
    当然也可以写一个docker-compose.yml配置文件来运行容器。

到这一步,我们已经新建好了一条cf tunnel,接下来需要配置一下cf如何做流量代理和转发。

运行vaultwarden
编写docker-compose.yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3"

services:
vaultwarden:
image: vaultwarden/server:latest
ports:
- "8087:80"
restart: unless-stopped
volumes:
- ./data/:/data/
environment:
SIGNUPS_DOMAINS_WHITELIST: "noplace.top" # 注册域名白名单
SIGNUPS_ALLOWED: "false" #禁用注册
SIGNUPS_VERIFY: "true"

执行docker-compose up -d后,vaultwarden 将运行在宿主机的8087端口,接下来配置public hostnames,将流量转发到服务器的8087端口
warden-cf-conf2

配置

vaultwarden提供了三种配置的方式:

  1. 设置环境变量,
  2. 使用 ENV_FILE 以及
  3. 通过 config.json(这可以通过管理页面生成和管理)

推荐使用环境变量的方式,例如上述docker-compose配置已经设置了三个环境变量。具体环境变量名及对应配置项可参考这里

备份与恢复

vaultwarden会将所有数据存在一个 data 目录下,按照上面容器化启动的方式,我们会将这个目录挂载到宿主机运行启动命令的data目录下,目录的内容将会是下面这样
warden-ls
重点需要备份的内容是SQLite数据库文件(db.sqlite3),它几乎存储了所有重要的Vaultwarden 数据/状态(数据库条目、用户/组织/设备元数据等)

使用 sqlite clibackup命令来备份数据库文件

1
sqlite3 $original_filename ".backup $backup_filename"

执行完上述命令,就得到了一个备份文件。如果更进一步,可以将这个备份文件定期上传到云盘,通过脚本定时任务+云盘webdev的方式实现,操作如下。

先了解几种技术

webdav(Web Distributed Authoring and Versioning web分布式编辑和版本管理)是一种基于http的扩展协议,用于对网络上的文档进行协同编辑和文件管理。它允许用户编辑和管理在服务器上存储的文件。

alist是一个支持多种存储,支持网页浏览和 WebDAV 的文件列表程序,由 gin 和 Solidjs 驱动。支持挂载国内绝大多数网盘存储,支持所有webdav存储。

rclone是一个管理云存储文件的命令行工具,支持Google DriveHDFS等,它也支持webdav

通过上面几种技术我们可以实现将网盘挂载在本地,像管理本地文件一样管理网盘的内容。国内支持webdav的网盘较少,我已知的只有坚果云。我选择的网盘是阿里云盘,官方没有提供webdav服务,但可以通过 aliyundrive-webdav这个项目来实现。

准备工作:

  • aliyundrive-webdav部署阿里云盘webdav服务
  • 在服务器上安装好rclone命令行工具,使用rclone同步文件和目录
    下面是一个备份 vaultwarden 数据库文件的脚本样例:
    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
    set -e # 发生错误时终止脚本
    set -o pipefail # 如果任何阶段管道命令发送错误,脚本将退出

    error() {
    printf "Error on line %s: %s\n" "$1" "$2"
    exit 1
    }
    # 使用trap函数在发生错误时调用error函数
    trap 'error ${LINENO} "${BASH_COMMAND}"' ERR

    REMOTE_PAN="aliyundrive"
    REMOTE_BACKUPS_DIR="$REMOTE_PAN:backups"

    LOCAL_BACKUPS_DIR="$HOME/app/vaultwarden/data/backups"
    LOCAL_ORIGINAL_DIR="$HOME/app/vaultwarden/data"
    LOCAL_ORIGINAL_FILENAME="$LOCAL_ORIGINAL_DIR/db.sqlite3"
    export LOCAL_BACKUP_FILENAME="$LOCAL_BACKUPS_DIR/db-$(date +%Y%m%d_%H%M)_backup.sqlite3"
    echo "准备执行备份到云盘...,远程目录为$REMOTE_PAN:$REMOTE_BACKUPS_DIR\n"
    echo "即将执行本地SQLite3备份,从$LOCAL_ORIGINAL_FILENAME$LOCAL_BACKUP_FILENAME\n"

    sqlite3 $LOCAL_ORIGINAL_FILENAME ".backup $LOCAL_BACKUP_FILENAME"
    echo "本地SQLite3备份完成,接下来上传到云盘"

    # 已经生成备份文件,接下来上传到云盘
    existed_file_count=$(rclone ls "$REMOTE_BACKUPS_DIR" | wc -l)
    if((existed_file_count >= 10)); then
    echo "已存在10个备份文件,删除最早的一条"
    oldest_file=$(rclone lsf --format p "$REMOTE_BACKUPS_DIR" | head -1)
    echo "要删除的是$oldest_file"
    rclone delete "$REMOTE_BACKUPS_DIR/$oldest_file"
    echo "$oldest_file已删除"
    fi
    echo "准备上传文件..."
    rclone copy "$LOCAL_BACKUP_FILENAME" "$REMOTE_BACKUPS_DIR" || { echo "Error occured when rclone copy";exit 1; }
    echo "文件备份至云盘完成"

    echo "准备发送通知"
    msg="$(date '+%Y-%m-%d %H:%M:%S') vaultwarden文件$LOCAL_BACKUP_FILANEM备份至阿里云盘成功"

    # 备份成功tg机器人通知,其他通知方式亦可
    curl 'https://api.telegram.org/botxx:xxxxxxx/sendMessage' \
    -H 'content-type: application/json' \
    --data-raw "{\"chat_id\": \"xxxx\",\"text\": \"$msg\"}" \
    --max-time 10

保存上述内容为do-backup.sh文件,然后crontab -e 添加定时任务,如下面表示每天的18:00执行备份脚本。

1
0 18 * * * ~/app/vaultwarden/data/do-backup.sh

使用

经过上面步骤,我们已完成自托管vaultwarden服务端的部署,接下来可以从客户端访问vaultwarden,直接用bitwarden的客户端即可,包括桌面端、浏览器插件、移动端等。登录时选择自托管,填入上面配置好的域名(vw.youdomain.xxx),然后登录即可。

至此,vaultwarden个人密码管理器的搭建完毕

其他文章