← back

基于Bitwarden的密码管理方案

Bitwarden+Vaultwarden+CloudflareTunnel+坚果云

前言

本文不做密码管理方案的横向对比,萝卜青菜各有所爱,各个方案的存在肯定是因为其符合了某些人的某些需求

我对密码管理的需求就是:自己掌握数据+生态友好,在满足此前提之下,其他方面更好那就是锦上添花,而Bitwarden就很符合我的需求

简单介绍一下Bitwarden,这是一个开源的密码管理工具,可以使用其官方服务,有免费版也有付费版,此外其可以自己搭建服务,并且生态好,全平台支持

本方案的简单介绍

基本使用

Authentication(TOTP)

在bitwarden中也集成了一般用于2FA验证的Authentication,具体的添加方式入下图,当屏幕上出现用于添加验证的二维码时候,点击步骤3中的照相机图标,即可实现识别并添加。在之后使用的时候也会自动填充

image.png

image.png

image.png

1. 搭建Bitwarden密码服务器:Vaultwarden

vaultwardenbitwarden的密码服务器的一个开源实现,使用rust实现,优点是非常轻量,性能强,与官方的功能几乎无差异,可以很方便的部署在一些性能较弱的设备中,例如树莓派等

1.1 配置 docker-compose.yml

使用docker进行部署,这是最方便的方案,下面是一个具体的docker-compose.yml的示例

# ~/docker/vaultwarden/docker-compose.yml

version: '3.8'

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vw.your.hostname"
      WEBSOCKET_ENABLED: "true"
      SIGNUPS_ALLOWED: "false"
    volumes:
      - ./data/:/data/
    # 这里我们将容器的 80 端口映射到宿主机的 8001 端口,与在cloudflared中的配置一致
    ports:
      - "8001:80"

⚠️ 注意 : SIGNUPS_ALLOWED 这个配置决定是否可以进行账号的注册,第一次使用时候需要设置为true,账号注册完毕后再修改为不可注册即可

1.2 启动

cd ~/docker/vaultwarden
docker compose up -d

1.3 注册/登录

访问指定的IP:PORT,如果是第一次使用,记得修改一下docker-compose.yml中的SIGNUPS_ALLOWED值,从而才能注册账号

1.4 导入其他的密码

登录成功后,可以看到vaultwarden是支持从其他的密码管理器中导入数据的,这一点就各自按照自己的需求进行导入即可

2. 内网穿透+域名解析:Cloudflare配置

建议:对于那些对安全有要求的服务,最好不要在自己服务器上直接暴露IP和端口,通过代理的方式可以大大的提高安全性,个人习惯使用cloudflare的服务,原因是国际大牌+免费+免备案

在本方案中,我是通过cloudflare提供的cloudflare tunnle服务为家庭内网内的所有服务提供代理服务,配合绑定的域名,即可以通过域名直接访问vaultwarden的密码服务了

⚠️注意:前提是你需要有域名或者域名的DNS托管在cloudflare,才能够使用该服务

2.1 安装cloudflared

选择任意一个内网的机器,安装cloudflared,待会用于获取设备的认证密钥等,官方安装文档

2.2 获取认证证书

cloudflared login

登录后选择相应的域名,然后会在~/.cloudflared/cert.pem 位置生成一个证书

2.3 创建 tunnel

cloudflared tunnel create your-tunnel-name

2.4 配置 cloudflared 服务

为了稳定性以及数据的备份方便,依然通过 docker 来使用 cloudflared 服务

  1. 新建文件夹 : mkdir -p ~/docker/cloudflared

  2. 拷贝 <TUNNEL_UUID>.json

    cp ~/.cloudflared/
    <TUNNEL_UUID>.json 
    ~/docker/cloudflared
  3. 配置config.yml文件:修改相关的TUNNEL_UUIDhostnameservice

    # ~/docker/cloudflared/config.yml
    
    tunnel: <TUNNEL_UUID>
    # 这里是容器内的路径,不要修改,只更改 TUNNEL_UUID 即可
    credentials-file: /etc/cloudflared/<TUNNEL_UUID>.json
    loglevel: info
    
    ingress:
      # 规则一:代理 Vaultwarden
      # service 指向 Vaultwarden 暴露在宿主机上的 IP 和端口
      - hostname: vw.your.hostname
        service: http://192.168.1.100:8080 # 假设 Vaultwarden 映射到了宿主机的 8080 端口
    
      # 规则二:代理另一台设备上的服务(例如一台 NAS)
      - hostname: nas.your.hostname
        service: http://192.168.1.150:5000 # NAS 的局域网 IP 和端口
    
      # 规则三:使用 host.docker.internal 访问宿主机服务 (推荐)
      # 如果服务和 cloudflared 在同一台物理机上,用这个特殊域名更稳健,即使宿主机 IP 变了也不影响
      - hostname: jellyfin.your.hostname
        service: http://host.docker.internal:8096 # 假设 Jellyfin 映射到了宿主机的 8096 端口
    
      # 兜底规则,保持不变
      - service: http_status:404
  4. 配置 docker-compose.yml

    # ~/docker/cloudflared/docker-compose.yml
    
    version: '3.8'
    
    services:
      cloudflared:
        image: cloudflare/cloudflared:latest
        container_name: cloudflared-gateway # 换个名字以示区分
        restart: unless-stopped
        command: tunnel --config /etc/cloudflared/config.yml run
        volumes:
          # 将当前目录下的所有文件挂载进去
          - ./:/etc/cloudflared/
        # 添加 extra_hosts 使得 host.docker.internal 生效
        # 这是让容器内能解析 host.docker.internal 到宿主机的关键
        extra_hosts:
          - "host.docker.internal:host-gateway"
        # 使用 http2 访问速度会快很多
        environment:
          - TUNNEL_TRANSPORT=http2
  5. 启动

  6. cloudflare 配置DNS解析记录:需要在所使用的域名下添加对应的DNS解析,cloudflare不会自动的完成这个操作

  7. 访问:此时应该就可以通过域名访问对应的服务了

3. 数据备份

因为vaultwarden使用的是数据库进行的存储,所以使用坚果云的自动同步是不合适的,甚至可能会破化数据库文件,并且我们的核心目标通过云存储来避免自托管数据的丢失,所以只需要定期备份即可

3.1 创建备份脚本

mkdir -p ~/script
cd ~/script
touch vaultwarden_backup.sh

下面是脚本的模板,有几个注意事项

#!/bin/bash

# --- 请根据您的实际情况修改以下配置 ---

# Vaultwarden 数据目录 (包含 db.sqlite3, attachments, sends, rsa_key.pem 等)
VAULTWARDEN_DATA_DIR="~/docker/vaultwarden/data/"

# 备份文件存放的临时目录
BACKUP_TEMP_DIR="/tmp/vaultwarden_backup"

# 坚果云 WebDAV 配置
WEBDAV_URL="https://dav.jianguoyun.com/dav"
WEBDAV_USER="你的坚果云邮箱@example.com"
WEBDAV_PASSWORD="你刚才生成的应用密码"

# 在坚果云上存放备份的文件夹名称 (脚本会自动创建)
WEBDAV_REMOTE_DIR="VaultwardenBackup"

# --- 配置结束 ---


# --- 脚本主体,通常无需修改 ---

# 备份文件的名称,包含日期和时间
BACKUP_FILENAME="vaultwarden-backup-$(date +%Y-%m-%d-%H%M%S).tar.gz"
BACKUP_TEMP_FILE="${BACKUP_TEMP_DIR}/${BACKUP_FILENAME}"

echo "开始备份 Vaultwarden..."

# 1. 创建临时备份目录
mkdir -p "$BACKUP_TEMP_DIR"
# 清理旧的临时文件
rm -f "$BACKUP_TEMP_DIR"/*.tar.gz

# 2. 安全地复制数据库文件
# 使用 sqlite3 的 .backup 命令确保数据一致性,避免在服务运行时直接复制文件
echo "正在创建数据库快照..."
sqlite3 "${VAULTWARDEN_DATA_DIR}/db.sqlite3" ".backup '${BACKUP_TEMP_DIR}/db.sqlite3.bak'"

# 检查数据库备份是否成功
if [ $? -ne 0 ]; then
    echo "错误:数据库备份失败!"
    exit 1
fi
# 将备份的数据库文件重命名为原始名称,以便打包
mv "${BACKUP_TEMP_DIR}/db.sqlite3.bak" "${BACKUP_TEMP_DIR}/db.sqlite3"


# 3. 打包所有重要文件
# 我们将数据库备份、附件、发送文件和最重要的 RSA 密钥一起打包
echo "正在打包文件..."
cd "$VAULTWARDEN_DATA_DIR"
tar -czf "$BACKUP_TEMP_FILE" \
    --transform='s|.*/||' \
    "${BACKUP_TEMP_DIR}/db.sqlite3" \
    "attachments" \
    "sends" \
    "rsa_key.pem"

# 检查打包是否成功
if [ $? -ne 0 ]; then
    echo "错误:文件打包失败!"
    rm -rf "$BACKUP_TEMP_DIR"
    exit 1
fi

# 4. 使用 cURL 通过 WebDAV 上传
echo "正在上传备份文件到坚果云..."

# 首先尝试创建远程目录 (如果不存在)
curl -s -u "${WEBDAV_USER}:${WEBDAV_PASSWORD}" -X MKCOL "${WEBDAV_URL}/${WEBDAV_REMOTE_DIR}/" > /dev/null

# 上传文件
curl -s -u "${WEBDAV_USER}:${WEBDAV_PASSWORD}" \
     -T "$BACKUP_TEMP_FILE" \
     "${WEBDAV_URL}/${WEBDAV_REMOTE_DIR}/${BACKUP_FILENAME}"

# 检查上传是否成功
if [ $? -eq 0 ]; then
    echo "成功!备份文件 ${BACKUP_FILENAME} 已上传至坚果云的 ${WEBDAV_REMOTE_DIR} 文件夹。"
else
    echo "错误:上传到坚果云失败!"
    rm -rf "$BACKUP_TEMP_DIR"
    exit 1
fi

# 5. 清理本地临时文件
echo "清理本地临时文件..."
rm -rf "$BACKUP_TEMP_DIR"

echo "备份完成!"
exit 0

脚本创建好之后可以手动执行测试一下,正常情况下会在坚果云目录下出现一个VaultwardenBackup文件夹,里面是备份文件

chmod +x vaultwarden_backup.sh

3.2 定时备份:设置定时任务 (Cron) 自动执行

让服务器每天在固定的时间自动运行这个备份脚本。

  1. 编辑 Crontabcrontab -e (如果是第一次运行,系统可能会让您选择一个默认的文本编辑器,推荐选择 nano 或者vim)

  2. 添加定时任务 在文件的末尾添加一行,设定脚本的执行时间。例如,设置在每天凌晨 3:30 执行备份:

    30 3 * * * /bin/bash /home/你的用户名/script/vaultwarden_backup.sh > /tmp/vaultwarden_backup.log 2>&1

    • 30 3 * * * 表示 “在每天的 3 点 30 分”。
    • /home/你的用户名/script/vaultwarden_backup.sh 是脚本的绝对路径。请确保路径正确。
    • > /tmp/vaultwarden_backup.log 2>&1 是可选的,但这非常推荐。它会将脚本的所有输出(包括成功信息和错误信息)都记录到 /tmp/vaultwarden_backup.log 文件中,方便您排查问题
  3. 退出即可

💡 有关本blog中的问题,欢迎您在底部评论区留言,一起交流~