Debian自建vaultwarden密码管理器
此前使用chrome和Firefox自带的密码管理器,此外还有keepass作为备份。因为管理不变,最终迁移到了vaultwarden上实现全平台通用。最终目标是后台使用docker运行vaultwarden,前台使用Nginx反代,并且使用https加密通讯过程,且能自动更新为最新版本。
以下教程无论是否有sudo,都建议使用root权限执行。
准备工作
以Debian 13为例,vaultwarden运行时需要至少200M内存,一般而言1G内存的VPS就够了。
首先,安装docker环境,将docker加入apt更新源:
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
安装相关软件:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
配置vaultwarden
创建数据目录
官方推荐直接新建/vw-data
文件夹,但并不建议这么干,最好是遵循Linux的标准习惯,在/opt
文件夹下实现。sudo mkdir -p /opt/vaultwarden sudo chown root:root /opt/vaultwarden sudo chmod 750 /opt/vaultwarden
让容器内的 UID 1000 可写
sudo chown -R 1000:1000 /opt/vaultwarden sudo chmod -R u+rwX,go-rwx /opt/vaultwarden
准备 Compose 与环境变量
在/opt/vaultwarden
目录下创建两个文件。
首先是/opt/vaultwarden/compose.yaml
,注意其中的password.example.com
改为实际的域名,"127.0.0.1:28080:80"中的28080
是对外的端口,不建议遵循官方教程的80
负责将导致与Nginx默认监听端口冲突。SIGNUPS_ALLOWED
当前是true
,等后续注册完了就需要改为false
以禁止其他人注册和使用。services: vaultwarden: image: vaultwarden/server:latest container_name: vaultwarden restart: unless-stopped env_file: - /opt/vaultwarden/vw.env environment: DOMAIN: "https://password.example.com" SIGNUPS_ALLOWED: "true" volumes: - /opt/vaultwarden:/data labels: - "com.centurylinklabs.watchtower.enable=true" ports: - "127.0.0.1:28080:80" watchtower: image: containrrr/watchtower container_name: watchtower restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock command: --label-enable --schedule "0 0 4 * * *" environment: - TZ=Asia/Shanghai
其次是
/opt/vaultwarden/vw.env
文件,用以保存域名信息和密码。首先安装apt install argon2
,并生成符合 PHC 字符串的密码:echo -n "example-passwaord" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4 # example-passwaord 改为实际密码
虽后将获得
$argon2id$v=19$m=65540,t=3,p=4$THTRFZzRVWHZaTlRNRFJrVT0$RVWORVWOZz+nhHnhHFop1+0QzS+cw0QHEIKrZidfw
输出,将其中的每个$
都再添加一个$
,并写入/opt/vaultwarden/vw.env
中,最终如下:DOMAIN=https://password.example.com ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$THTRFZzRVWHZaTlRNRFJrVT0$$RVWORVWOZz+nhHnhHFop1+0QzS+cw0QHEIKrZidfw
启动并运行
cd /opt/vaultwarden sudo docker compose pull sudo docker compose up -d
常用运维命令
停止 vaultwarden 容器 sudo docker compose stop vaultwarden 启动 vaultwarden 容器 docker compose up -d # 查看容器状态与日志 sudo docker compose ps sudo docker compose logs -f vaultwarden # 手动更新(Watchtower 之外,临时手动) sudo docker compose pull && sudo docker compose up -d # 备份(SQLite 数据在 /opt/vaultwarden,热备可直接打包整个目录) sudo tar -czf /opt/vaultwarden-backup-$(date +%F).tar.gz -C /opt vaultwarden
设置Nginx反代
完整的配置文件如下,注意其中的SSL证书路径,以下例子是使用acme.sh实现的SSL证书。
upstream vaultwarden-default {
zone vaultwarden-default 64k;
server 127.0.0.1:28080;
keepalive 2;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' "";
}
server {
listen 80; #default_server;
listen [::]:80; #default_server;
server_name password.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name password.example.com; # 改成你的域名
client_max_body_size 525M;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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;
location / {
proxy_pass http://vaultwarden-default;
}
ssl_certificate /opt/website/certificate/password.example.com_bundle.crt; # SSL证书
ssl_certificate_key /opt/website/certificate/password.example.com.key; # SSL 证书
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
access_log /var/log/nginx/access.password.example.com.log; # Nginx日志
error_log /var/log/nginx/error.password.example.com.log; # Nginx日志
}