自建vaultwarden,实现自动同步与镜像更新

在ChatGPT的辅助下完成了自建vaultwarden,多次修改后终于有个能用的了,具体操作有:

  • 容器采用目录挂载方式启动,这样方便备份和更新
  • 保留90天备份,将整个挂载目录压缩加密备份,每天5点自动备份到onedrive
  • 备份使用GPG加密存储
    • 其实本地密码文件本身是加密存储的,但是配置文件会泄露一点信息,故我再次加密
  • 每天自动检测vaultwarden镜像是否有更新,有的话自动更新并启动(有佬推荐使用watchower自动更新镜像)

  • 实现这些需要的:
    • 一台vps
    • 一个域名,这个域名解析到你的vps上, 本文假设域名为 my.com

  • 服务器或VPS挂了怎么办:
    • vaultwarden支持离线使用,密码在本地会存一份,即使bitwarden插件现在连不上VPS也可以继续使用密码
    • 本地存的那份密码可以导出

  • bitwarden官方不是有自己的镜像吗? 为什么要使用vaultwarden?
    • bitwarden官方占用比vaultwarden大,如果你的VPS空间紧张,那vaultwarden很适合你


目录结构

为组织脚本和相关文件,建议使用以下目录结构:

/vaultwarden_backup/

├── admin_token_hash
├── backup  
│   ├── backup_2024-10-19.tar.gz.gpg
│   ├── backup_2024-10-20.tar.gz.gpg
│   ├── backup_2024-10-21.tar.gz.gpg
│   ├── backup_2024-10-22.tar.gz.gpg
│   └── backup_2024-10-24.tar.gz.gpg
├── backup.log
├── backup_update_script.sh
└── gpg_passphrase_file

文件名 描述
admin_token_hash 保存 Vaultwarden 后台密码 Hash
backup 存放每天自动备份文件
backup.log 存放脚本 backup_update_script.sh 执行时输出的日志
backup_update_script.sh 自动备份和镜像更新脚本
gpg_passphrase_file GPG 加密文件

环境准备

1. 必要工具

确保您的系统已经安装以下工具:

  • Docker:用于运行 Vaultwarden。
  • Rclone:用于将备份文件上传到 OneDrive。
  • GPG:用于加密备份文件。
  • Argon2:用于生成 ADMIN_TOKEN 的哈希值。
  • Cron:用于定时执行备份和更新脚本。
sudo apt update
sudo apt install docker.io rclone gpg argon2 
sudo systemctl start docker 
sudo systemctl enable docker

在远程Linux服务器上安装并配置rclone (配置rclone流程我记不清了,这个是我找的)

1 安装rclone

如果你的Linux服务器还没有安装rclone,可以按照以下步骤安装:

  1. 通过SSH连接到你的远程Linux服务器。

  2. 运行以下命令来下载并安装rclone

    curl https://rclone.org/install.sh | sudo bash
    
  3. 安装完成后,可以通过以下命令确认安装是否成功:

    rclone version
    

2 初始化rclone配置

  1. 运行rclone config命令启动配置过程:

    rclone config
    
  2. 输入n来创建一个新的remote。

  3. 输入remote的名称(例如onedrive

  4. 继续按提示操作,直到要求进行OAuth认证的步骤。

在这一步,通常rclone会自动打开浏览器来完成OAuth认证,但由于我们是在远程服务器上,这就需要在本地的Windows机器上进行认证。

在本地Windows机器上完成OAuth认证

1 获取认证URL

  1. rclone提示你需要在浏览器中打开一个URL来完成认证时,它会输出一个类似于下面的链接:

    https://accounts.google.com/o/oauth2/auth?client_id=XXXXXXX&response_type=code&scope=XXXXX
    
  2. 复制这个链接,你需要将它复制到本地的机器。

2 在Windows机器上打开浏览器并完成认证

  1. 在本地Windows电脑上,打开浏览器,并粘贴刚才从远程服务器上复制的OAuth认证URL。

  2. 按照浏览器中的指示进行登录,并授权rclone访问你的云存储账户。

  3. 完成认证后,浏览器将返回一个包含认证代码的页面。这时候会显示一段长的代码。

3 将认证代码粘贴回远程Linux服务器

  1. 复制认证完成后页面中显示的授权代码。

  2. 回到你连接远程Linux服务器的终端,在rclone提示你输入认证代码的地方,粘贴该代码并按回车。

完成rclone配置

  1. 继续完成后续的配置。通常是选择默认值(除非你有其他自定义需求),然后保存并退出。

  2. 你可以通过以下命令测试配置是否成功(以Google Drive为例):

    rclone lsd onedrive:vaultwarden_backup
    

    如果能够列出你的云存储目录结构,说明配置成功。
    如果目录不存在,可以手动创建:

    rclone mkdir onedrive:vaultwarden_backup
    

配置GPG

1:生成一个随机密码

我们可以使用 opensslpwgen 生成一个强密码:

# 使用 openssl 生成随机密码
openssl rand -base64 32 > /vaultwarden_backup/gpg_passphrase_file

# 确保文件权限是 600
chmod 600 /vaultwarden_backup/gpg_passphrase_file

这样会在 /vaultwarden_backup/gpg_passphrase_file 中生成一个 32 字节的随机密码,并设置为仅当前用户可读。


2:安装 GPG

如果你的系统上还没有 GPG,请进行安装:

sudo apt update
sudo apt install gnupg -y

3:使用 GPG 创建加密测试文件

你可以测试一下这个 GPG 密码文件是否正常工作:

# 读取生成的密码到变量
GPG_PASSPHRASE=$(< /vaultwarden_backup/gpg_passphrase_file)

# 创建一个测试文件
echo "This is a test backup file." > test_file.txt

# 使用 GPG 加密测试文件
gpg --batch --yes --symmetric --cipher-algo AES256 --passphrase "$GPG_PASSPHRASE" -o test_file.txt.gpg test_file.txt

# 检查是否生成了加密文件
ls test_file.txt.gpg

4:解密文件测试

确保可以使用相同的密码文件解密:

# 解密文件
gpg --batch --yes --passphrase "$GPG_PASSPHRASE" -o decrypted_test_file.txt -d test_file.txt.gpg

# 检查解密结果
cat decrypted_test_file.txt

5:清理测试文件

如果一切正常,可以删除测试文件:

rm test_file.txt test_file.txt.gpg decrypted_test_file.txt

注意事项

  1. 文件权限:确保 /vaultwarden_backup/gpg_passphrase_file 的权限是 600,以保证安全:
    chmod 600 /vaultwarden_backup/gpg_passphrase_file
    
  2. 备份密码文件:将该密码文件妥善保存(例如在安全的地方备份),因为如果丢失,将无法解密备份文件。可以存到onedrive的保险库中.

生成 ADMIN_TOKEN 的哈希值

Vaultwarden 官方推荐使用 argon2 生成 ADMIN_TOKEN 的哈希值。请按照以下步骤操作:

生成哈希值并保存

使用以下命令生成 ADMIN_TOKEN 的哈希值,并将其保存到 /vaultwarden_backup/admin_token_hash 文件中:

# 替换 "123456789" 为您实际的管理员密码
echo -n "123456789" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4 > /vaultwarden_backup/admin_token_hash

# 设置文件权限,确保只有授权用户可以读取
sudo chmod 600 /vaultwarden_backup/admin_token_hash

示例输出(保存在 /vaultwarden_backup/admin_token_hash 文件中):

$argon2id$v=19$m=65540,t=3,p=4$bXBGMENBZUVzT3VUSFErTzQzK25Jck1BN2Z0amFuWjdSdVlIQVZqYzAzYz0$T9m73OdD2mz9+aJKLuOAdbvoARdaKxtOZ+jZcSL9/N0

注意:将 "123456789" 替换为您的实际管理员密码,确保密码足够强壮。

备份和镜像更新脚本

1. 设置备份目录和权限

确保备份目录存在,并设置正确的权限:

sudo mkdir -p /vaultwarden_backup
sudo chmod -R 700 /vaultwarden_backup

2. 完整备份与更新脚本

将以下脚本保存为 /vaultwarden_backup/backup_update_script.sh,并赋予可执行权限。

#!/bin/bash

# ================== 配置部分 ==================

BACKUP_DIR="/vaultwarden_backup/backup"       # 本地备份存储路径
SOURCE_DIR="/VM_data"                         # 需要备份的源目录
REMOTE="onedrive:vaultwarden_backup"          # rclone 远程 OneDrive 目录
DATE=$(date +"%Y-%m-%d")                      # 当前日期
BACKUP_FILE="backup_$DATE.tar.gz"             # 备份文件名
GPG_FILE="$BACKUP_FILE.gpg"                   # 加密后的备份文件名
GPG_PASSPHRASE_FILE="/vaultwarden_backup/gpg_passphrase_file"   # GPG 加密密码文件
RETENTION_DAYS=90                             # 保留的天数
LOG_FILE="/vaultwarden_backup/backup_update_script.log"         # 日志文件

# Docker 配置
IMAGE_NAME="vaultwarden/server:latest"        # 镜像名称
CONTAINER_NAME="vaultwarden"                  # 容器名称

# 日志函数
log() {
    echo "$(date +"%Y-%m-%d %H:%M:%S") - $1" | tee -a $LOG_FILE
}

# 检查 GPG 密码文件是否存在
if [ ! -f "$GPG_PASSPHRASE_FILE" ]; then
    log "GPG 密码文件不存在,备份终止"
    exit 1
fi

# 读取 GPG 密码
GPG_PASSPHRASE=$(< "$GPG_PASSPHRASE_FILE")

# 创建备份
log "开始备份"
if tar -czf "$BACKUP_DIR/$BACKUP_FILE" -C "$SOURCE_DIR" .; then
    log "备份文件已创建: $BACKUP_FILE"
else
    log "备份失败"
    exit 1
fi

# GPG 加密
if gpg --batch --yes --passphrase "$GPG_PASSPHRASE" -c "$BACKUP_DIR/$BACKUP_FILE"; then
    log "备份文件已加密: $GPG_FILE"
else
    log "加密失败,备份终止"
    exit 1
fi

# 删除未加密的文件
rm "$BACKUP_DIR/$BACKUP_FILE"
log "未加密的备份文件已删除"

# 同步到 OneDrive
if rclone copy "$BACKUP_DIR/$GPG_FILE" "$REMOTE"; then
    log "已同步到 OneDrive: $GPG_FILE"
else
    log "同步到 OneDrive 失败"
    exit 1
fi

# 清理本地和远程超过保留期的备份
find "$BACKUP_DIR" -name "backup_*.tar.gz.gpg" -type f -mtime +$RETENTION_DAYS -delete
rclone delete --min-age ${RETENTION_DAYS}d "$REMOTE"
log "超过 $RETENTION_DAYS 天的旧备份已删除"

log "备份完成"


# ================== Docker 镜像更新 ==================

log "开始检查 Docker 镜像更新"

# 拉取最新镜像
if docker pull $IMAGE_NAME; then
    log "拉取最新镜像成功: $IMAGE_NAME"
else
    log "拉取镜像失败"
    exit 1
fi

# 获取最新镜像的 ID
LATEST_IMAGE_ID=$(docker inspect --format='{{.Id}}' $IMAGE_NAME)

# 获取当前运行容器的镜像 ID
CURRENT_IMAGE_ID=$(docker inspect --format='{{.Image}}' $CONTAINER_NAME)

# 检查是否有更新
if [ "$LATEST_IMAGE_ID" != "$CURRENT_IMAGE_ID" ]; then
    log "有新镜像,更新容器..."

    # 停止并移除旧容器
    if docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME; then
        log "旧容器已停止并移除"
    else
        log "停止或移除旧容器失败"
        exit 1
    fi

    # 重新启动容器
    if docker run -d --name $CONTAINER_NAME \
        -v /VM_data:/data \
        -e ADMIN_TOKEN="$(cat /vaultwarden_backup/admin_token_hash)" \
        -e INVITATIONS_ALLOWED=false \
        -p 80:80 \
        --restart unless-stopped \
        $IMAGE_NAME; then
        log "容器已更新并重新启动"
    else
        log "容器启动失败"
        exit 1
    fi
else
    log "镜像没有更新,不执行操作"
fi

log "Docker 镜像检查完成"


3. 设置脚本执行权限

确保脚本具有可执行权限,并设置正确的所有者和权限:

sudo chmod +x /vaultwarden_backup/backup_update_script.sh
sudo chown your_backup_user:your_backup_group /vaultwarden_backup/backup_update_script.sh

注意:将 your_backup_useryour_backup_group 替换为实际的用户和组,确保只有授权用户可以执行和修改脚本。我使用的是chown vaultwarden:vaultwarden /vaultwarden_backup/backup_update_script.sh

4. 配置定时任务(Cron)

使用 cron 定期执行备份和更新脚本。以下示例将脚本设置为每天凌晨2点执行。

  1. 编辑 Crontab

    sudo crontab -e
    
  2. 添加以下行

    # 每天凌晨5点执行备份与更新脚本
    0 5 * * * /vaultwarden_backup/backup_update_script.sh >> /vaultwarden_backup/backup.log 2>&1
    
  3. 保存并退出

5. 验证脚本

在首次运行脚本之前,建议手动执行一次以确保一切正常:

sudo /vaultwarden_backup/backup_update_script.sh

检查日志文件 /vaultwarden_backup/backup.log 以确保所有步骤顺利完成。

bitwarden配置

1. 选自托管

2. 填解析到这个vps的域名

3. 注册第一个用户,第一个注册用户就是管理员

4. 进入后台管理,关闭新用户注册,因为这只是我们自己用

后台网址为 https://域名/admin, 这里密码填上面使用 argon2中的密码(例子中为123456789)

安全提示

  • 密码安全:确保 /vaultwarden_backup/gpg_passphrase_file/vaultwarden_backup/admin_token_hash 文件的权限为 600,且仅限授权用户访问。
  • 脚本权限:确保脚本拥有适当的执行权限,并且只有授权用户可以修改。
  • 定期检查:定期检查备份日志,确保备份和更新过程正常运行。
  • 套CDN: 给解析到VPS的域名套上CDN,防止泄露VPSIP,这个可以在Cloudcone中打开
  • 开防火墙: 注意放行443和80端口

至此,已经结束,下面都是一些佬推荐的,不属于上面教程的一部分,感兴趣的可以看看


其他佬倾情推荐

docker compose一把梭, 注意他使用的是alpine系统镜像

services:

  vault:
    image: vaultwarden/server:alpine
    container_name: vault
    network_mode: host
    restart: always
    volumes: [ "./data/:/data" ]
    environment:
      # Vault
      - DOMAIN=https://vault.xxx.com
      - SIGNUPS_ALLOWED=false
      - SIGNUPS_VERIFY=true
      - INVITATIONS_ALLOWED=false
      # Rocket
      - ROCKET_ADDRESS=127.0.0.1
      - ROCKET_PORT=3018
      # Websocket
      - WEBSOCKET_ENABLED=true
      - WEBSOCKET_ADDRESS=127.0.0.1
      - WEBSOCKET_PORT=3019
      # SMTP
      - SMTP_HOST=smtp.gmail.com
      - SMTP_PORT=587
      - SMTP_SECURITY=starttls
      - [email protected]
      - [email protected]
      - SMTP_PASSWORD=xxx
165 个赞

大佬厉害 :tieba_087:

5 个赞

你特么绝对是脚本,住在这了是吧 :tieba_006: :tieba_006:

3 个赞

论坛买房了 :tieba_087:

3 个赞

辛苦了,看完之后还是先用着官方的吧

4 个赞

之前弄了个,现在用着官方服务,和2fa分开了

3 个赞

逆天住户 太强了

4 个赞

资源荟萃文档共建

fufu 好厉害哟

你是做个人密码管理器用的吗?感觉有点重

4 个赞

对的,做个人密码管理器,通用性号,不需要来回导入导出密码.
另外,还用这个VPS科学上网,一机两用,省钱王 :tieba_025:

2 个赞

算了,还是继续10u一年吧

4 个赞

可以的佬!!!
我挂了个 SD 卡,每隔几天自动打包备份到卡上
有空了手动再备份一下到移动硬盘

4 个赞

插个眼,后面有时间搞一下做个自动备份
我现在就是单纯在用vaultwarden做密码记录,其他的啥也没搞,就是怕服务器出问题了,密码没了就完蛋.

3 个赞

不用担心,他这个密码在本地浏览器中还有一份,即使你VPS挂了,还可以把浏览器中密码导入 :tieba_095:

4 个赞

最好每天保存吧,这个文件小得很,不过我还是建议云端备份一个

2 个赞

嗯,我是整个 docker 文件夹备份了
晚点加个单独的备份

5 个赞

最好弄个挂载目录,把重要目录映射出来,这样好备份,出了问题好恢复

2 个赞

嗯嗯,懂!感谢大佬

3 个赞

直接基于官方的 docker 镜像构建一个内置 rclone 和备份计划任务的镜像,使用不同的参数启动就行了

1 个赞

官方那个占用有点高,我的垃圾VPS跑不动 :tieba_087: