在ChatGPT的辅助下完成了自建vaultwarden,多次修改后终于有个能用的了,具体操作有:
- 容器采用目录挂载方式启动,这样方便备份和更新
- 保留90天备份,将整个挂载目录压缩加密备份,每天5点自动备份到onedrive
- 备份使用GPG加密存储
- 其实本地密码文件本身是加密存储的,但是配置文件会泄露一点信息,故我再次加密
- 每天自动检测vaultwarden镜像是否有更新,有的话自动更新并启动
(有佬推荐使用watchower自动更新镜像)
- 实现这些需要的:
- 一台vps
- 一个域名,这个域名解析到你的vps上, 本文假设域名为
my.com
- 服务器或VPS挂了怎么办:
- vaultwarden支持离线使用,密码在本地会存一份,即使
bitwarden
插件现在连不上VPS也可以继续使用密码 - 本地存的那份密码可以导出
- vaultwarden支持离线使用,密码在本地会存一份,即使
- 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
,可以按照以下步骤安装:
-
通过SSH连接到你的远程Linux服务器。
-
运行以下命令来下载并安装
rclone
:curl https://rclone.org/install.sh | sudo bash
-
安装完成后,可以通过以下命令确认安装是否成功:
rclone version
2 初始化rclone配置
-
运行
rclone config
命令启动配置过程:rclone config
-
输入
n
来创建一个新的remote。 -
输入remote的名称(例如
onedrive
) -
继续按提示操作,直到要求进行OAuth认证的步骤。
在这一步,通常rclone
会自动打开浏览器来完成OAuth认证,但由于我们是在远程服务器上,这就需要在本地的Windows机器上进行认证。
在本地Windows机器上完成OAuth认证
1 获取认证URL
-
当
rclone
提示你需要在浏览器中打开一个URL来完成认证时,它会输出一个类似于下面的链接:https://accounts.google.com/o/oauth2/auth?client_id=XXXXXXX&response_type=code&scope=XXXXX
-
复制这个链接,你需要将它复制到本地的机器。
2 在Windows机器上打开浏览器并完成认证
-
在本地Windows电脑上,打开浏览器,并粘贴刚才从远程服务器上复制的OAuth认证URL。
-
按照浏览器中的指示进行登录,并授权
rclone
访问你的云存储账户。 -
完成认证后,浏览器将返回一个包含认证代码的页面。这时候会显示一段长的代码。
3 将认证代码粘贴回远程Linux服务器
-
复制认证完成后页面中显示的授权代码。
-
回到你连接远程Linux服务器的终端,在
rclone
提示你输入认证代码的地方,粘贴该代码并按回车。
完成rclone配置
-
继续完成后续的配置。通常是选择默认值(除非你有其他自定义需求),然后保存并退出。
-
你可以通过以下命令测试配置是否成功(以Google Drive为例):
rclone lsd onedrive:vaultwarden_backup
如果能够列出你的云存储目录结构,说明配置成功。
如果目录不存在,可以手动创建:rclone mkdir onedrive:vaultwarden_backup
配置GPG
1:生成一个随机密码
我们可以使用 openssl
或 pwgen
生成一个强密码:
# 使用 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
注意事项
- 文件权限:确保
/vaultwarden_backup/gpg_passphrase_file
的权限是600
,以保证安全:chmod 600 /vaultwarden_backup/gpg_passphrase_file
- 备份密码文件:将该密码文件妥善保存(例如在安全的地方备份),因为如果丢失,将无法解密备份文件。可以存到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_user
和 your_backup_group
替换为实际的用户和组,确保只有授权用户可以执行和修改脚本。我使用的是chown vaultwarden:vaultwarden /vaultwarden_backup/backup_update_script.sh
4. 配置定时任务(Cron)
使用 cron
定期执行备份和更新脚本。以下示例将脚本设置为每天凌晨2点执行。
-
编辑 Crontab:
sudo crontab -e
-
添加以下行:
# 每天凌晨5点执行备份与更新脚本 0 5 * * * /vaultwarden_backup/backup_update_script.sh >> /vaultwarden_backup/backup.log 2>&1
-
保存并退出。
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