欢迎光临

VPS 自建密码管理器完全实战:用 Vaultwarden 部署私有 Bitwarden,从安装到生产加固一步到位

在数字化时代,每个人都在数十甚至上百个网站上拥有账号,密码管理已经不再是可选技能,而是每个互联网用户的刚需。市面上的密码管理器不少——1Password、LastPass、Bitwarden……但如果你是一名 VPS 玩家,手里有闲置的服务器资源,为什么不自己搭一个?

今天这篇文章,我们就来完整实战一遍:在一台 VPS 上用 Vaultwarden(原 Bitwarden_RS)自建私有密码管理器。从 Docker 部署、Nginx 反代、HTTPS 证书,到安全加固、备份策略、客户端配置,一条龙搞定。

为什么选择 Vaultwarden 而不是官方 Bitwarden?

Bitwarden 是目前最流行的开源密码管理器之一,官方提供了自托管版本。但官方自托管版本使用 C# 编写,依赖 SQL Server、.NET Core 等重量级组件,光是启动就至少需要 2GB 内存,对于大多数小 VPS 来说根本跑不动。

Vaultwarden(原名 Bitwarden_RS)是用 Rust 重写的非官方 Bitwarden 服务端实现,它 100% 兼容 Bitwarden 官方客户端 API,但资源消耗极低——空闲时仅占用 10-20MB 内存,一台 512MB 的小鸡就能轻松运行。两者对比如下:

特性 官方 Bitwarden Vaultwarden
编写语言 C# / .NET Rust
最低内存 2GB+ 10-20MB
数据库 SQL Server / PostgreSQL SQLite / MySQL / PostgreSQL
客户端兼容 官方客户端 官方客户端完全兼容
部署复杂度 高(多容器编排) 低(单容器)
高级功能 组织、企业功能完整 大部分功能支持,部分企业功能有限

对于个人用户和小团队来说,Vaultwarden 是更务实的选择:资源占用极小、部署简单、更新频繁、社区活跃。唯一需要注意的是,Vaultwarden 默认使用 SQLite 数据库,虽然性能对于个人使用绰绰有余,但如果你有数百人同时使用的场景,建议切换到 MySQL 或 PostgreSQL。

环境准备与基础部署

系统要求

在开始之前,确保你的 VPS 满足以下最低要求:

  • 操作系统:Ubuntu 22.04/24.04 或 Debian 11/12(推荐)
  • 内存:最低 256MB,推荐 512MB 以上
  • 硬盘:10GB 以上可用空间(含数据库和备份)
  • 已安装 Docker 和 Docker Compose
  • 一个指向 VPS IP 的域名(如 vault.example.com)

安装 Docker 和 Docker Compose

如果你的 VPS 还没有安装 Docker,一行命令搞定:


1
2
curl -fsSL https://get.docker.com | sh
systemctl enable docker && systemctl start docker

安装完成后,验证版本:


1
2
docker --version
docker compose version

创建项目目录与配置文件

建一个专门的目录来存放 Vaultwarden 的所有配置和数据:


1
2
mkdir -p /opt/vaultwarden/data
cd /opt/vaultwarden

创建

1
.env

环境变量文件,这是最核心的配置:


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
# /opt/vaultwarden/.env
# ===== 基础配置 =====
DOMAIN=https://vault.example.com

# ===== 数据库配置 =====
# 默认使用 SQLite,数据文件位于 data/db.sqlite3
# 如需 MySQL,取消注释以下行:
# DATABASE_URL=mysql://vaultwarden:password@db:3306/vaultwarden

# ===== 安全配置 =====
# 管理面板令牌(强烈建议设置)
ADMIN_TOKEN=YourRandomLongTokenHere
# 邀请令牌(防止陌生人注册)
INVITATIONS_ALLOWED=false
# 注册开放(生产环境务必关闭!)
SIGNUPS_ALLOWED=false
# 邮箱验证
SIGNUPS_VERIFY=true

# ===== 安全强化 =====
# 登录尝试限制
LOGIN_RATELIMIT_MAX_BURST=3
LOGIN_RATELIMIT_SECONDS=60

# ===== SMTP 邮件配置 =====
SMTP_HOST=smtp.gmail.com
SMTP_FROM=vault@example.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=you@gmail.com
SMTP_PASSWORD=your-app-password

# ===== 其他配置 =====
# WebSocket 通知(用于实时同步)
WEBSOCKET_ENABLED=true
# 日志级别
LOG_LEVEL=info
# 图标下载服务
ICON_SERVICE=internal

注意:

1
ADMIN_TOKEN

请务必使用一个足够长且随机的字符串,这相当于你密码管理器的后门钥匙。可以用以下命令生成:


1
openssl rand -base64 48

编写 Docker Compose 文件

创建

1
docker-compose.yml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# /opt/vaultwarden/docker-compose.yml
version: "3.8"

services:
  vaultwarden:
    image: vaultwarden/server:latest
    container_name: vaultwarden
    restart: always
    ports:
      - "127.0.0.1:8080:80"    # HTTP 端口,仅监听本地
      - "127.0.0.1:3012:3012"  # WebSocket 端口,仅监听本地
    volumes:
      - ./data:/data
    env_file:
      - .env
    environment:
      - WEBSOCKET_ENABLED=true
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/alive"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

一个关键细节:端口映射使用了

1
127.0.0.1

前缀,确保 Vaultwarden 只监听本地回环地址,不直接暴露到公网。所有外部流量必须通过 Nginx 反代,这是第一层安全屏障。

启动服务:


1
2
3
4
5
6
cd /opt/vaultwarden
docker compose up -d

# 检查状态
docker compose ps
docker compose logs --tail=20

看到

1
vaultwarden

容器状态为

1
Up

且健康检查通过,说明服务已正常启动。

Nginx 反向代理与 HTTPS 证书配置

密码管理器绝对不能在 HTTP 明文下运行,HTTPS 是硬性要求。这里我们用 Nginx 做反向代理,配合 Let’s Encrypt 自动签发证书。

安装 Nginx 和 Certbot


1
apt update && apt install -y nginx certbot python3-certbot-nginx

创建 Nginx 配置

创建

1
/etc/nginx/sites-available/vaultwarden.conf


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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# /etc/nginx/sites-available/vaultwarden.conf
server {
    listen 80;
    server_name vault.example.com;

    # Certbot 验证路径
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name vault.example.com;

    # SSL 证书路径
    ssl_certificate     /etc/letsencrypt/live/vault.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/vault.example.com/privkey.pem;

    # SSL 安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # HSTS(强制 HTTPS)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # 安全头部
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy no-referrer;

    # 日志
    access_log /var/log/nginx/vaultwarden.access.log;
    error_log /var/log/nginx/vaultwarden.error.log;

    # 客户端最大上传(附件)
    client_max_body_size 525M;

    # Vaultwarden Web 界面和 API
    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }

    # WebSocket 实时通知
    location /notifications/hub {
        proxy_pass http://127.0.0.1:3012;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header 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;
    }

    # 管理面板(建议限制访问 IP)
    location /admin {
        # allow 你的IP地址;
        # deny all;
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

启用配置并获取证书:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建软链接启用站点
ln -s /etc/nginx/sites-available/vaultwarden.conf /etc/nginx/sites-enabled/

# 测试 Nginx 配置
nginx -t

# 先用 HTTP 配置启动 Nginx
systemctl reload nginx

# 申请 Let's Encrypt 证书
certbot --nginx -d vault.example.com --non-interactive --agree-tos -m your@email.com

# 重新加载 Nginx
systemctl reload nginx

现在打开浏览器访问

1
https://vault.example.com

,你应该能看到 Bitwarden 的登录页面了。

首次配置与账号创建

服务跑起来后,第一件事是创建你的管理员账号。由于我们在

1
.env

中设置了

1
SIGNUPS_ALLOWED=false

,外部用户无法自行注册。你需要通过管理面板来创建账号:

  1. 访问
    1
    https://vault.example.com/admin
  2. 输入你在
    1
    ADMIN_TOKEN

    中设置的令牌

  3. 在管理面板中找到「Users」区域,点击「Invite User」
  4. 输入你的邮箱地址,发送邀请
  5. 查看邮箱,点击邀请链接设置主密码

创建完成后,建议在管理面板中将

1
SIGNUPS_ALLOWED

确认为

1
false

,并将自己的账号设为管理员。这样即使有人知道了你的域名,也无法注册。

关于主密码的选择——这是你所有密码的总钥匙,务必做到:

  • 长度至少 16 个字符
  • 包含大小写字母、数字和特殊符号
  • 不要使用字典中的单词或个人信息
  • 建议使用 DiceWare 方式生成的密码短语

生产环境安全加固

密码管理器是安全敏感型应用,部署完只是第一步,加固才是关键。以下是我建议的安全措施,按优先级排列:

1. 防火墙配置

只开放必要的端口,其余全部关闭:


1
2
3
4
5
6
7
8
# 使用 ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp      # SSH
ufw allow 80/tcp      # HTTP(证书续期)
ufw allow 443/tcp     # HTTPS
ufw enable
ufw status

确保 Docker 的 8080 和 3012 端口没有暴露到公网(我们已经在 docker-compose.yml 中绑定了 127.0.0.1)。

2. Fail2ban 防暴力破解


1
apt install -y fail2ban

创建

1
/etc/fail2ban/filter.d/vaultwarden.conf


1
2
3
[Definition]
failregex = ^.*Username or password is incorrect\. Try again\. IP: <HOST>\. Username:.*$
ignoreregex =

创建

1
/etc/fail2ban/jail.d/vaultwarden.local


1
2
3
4
5
6
7
8
9
[vaultwarden]
enabled = true
port = 80,443
filter = vaultwarden
action = iptables-allports[name=vaultwarden]
logpath = /var/log/nginx/vaultwarden.access.log
maxretry = 3
bantime = 3600
findtime = 600

启动 Fail2ban:


1
2
3
systemctl enable fail2ban
systemctl restart fail2ban
fail2ban-client status vaultwarden

3. 管理面板 IP 白名单

在 Nginx 配置中,取消

1
/admin

location 块里的 IP 限制注释,只允许你自己的 IP 访问:


1
2
3
4
5
location /admin {
    allow 你的公网IP;
    deny all;
    # ... 其他 proxy 配置
}

如果你是动态 IP,可以考虑只在使用时临时开放,或者通过 VPN 连接后再访问。

4. 启用两步验证(2FA)

登录 Vaultwarden 网页端后,进入「设置」→「两步登录」,建议至少启用以下之一:

  • TOTP 验证器(推荐):使用 Authy、Google Authenticator 等应用扫码绑定
  • WebAuthn / FIDO2(最安全):使用 YubiKey 等硬件安全密钥
  • Duo:通过 Duo Security 推送通知验证

5. 安全头部与 CSP 强化

在 Nginx 配置中添加 Content-Security-Policy 头,限制资源加载来源:


1
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com; connect-src 'self' https://api.pwnedpasswords.com https://2fa.directory; frame-ancestors 'none';" always;

这个 CSP 策略允许 Vaultwarden 正常工作(包括密码泄露检查功能),同时阻止外部脚本的加载。

数据备份与灾难恢复

密码管理器的数据比 VPS 本身更重要——VPS 挂了可以重装,密码丢了就真的丢了。必须建立可靠的备份机制。

本地自动备份脚本

创建

1
/opt/vaultwarden/backup.sh


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
#!/bin/bash
# Vaultwarden 自动备份脚本

BACKUP_DIR="/opt/vaultwarden/backups"
DATA_DIR="/opt/vaultwarden/data"
DATE=$(date +%Y%m%d_%H%M%S)
RETAIN_DAYS=30

mkdir -p $BACKUP_DIR

# SQLite 数据库安全备份
if command -v sqlite3 > /dev/null; then
    sqlite3 "$DATA_DIR/db.sqlite3" ".backup '$BACKUP_DIR/db_$DATE.sqlite3'"
else
    echo "WARN: sqlite3 not found, stopping container for backup..."
    cd /opt/vaultwarden && docker compose stop
    cp "$DATA_DIR/db.sqlite3" "$BACKUP_DIR/db_$DATE.sqlite3"
    cd /opt/vaultwarden && docker compose start
fi

# 备份附件目录
tar czf "$BACKUP_DIR/attachments_$DATE.tar.gz" -C "$DATA_DIR" attachments/ 2>/dev/null || true

# 备份 RSA 密钥(用于两步验证)
tar czf "$BACKUP_DIR/rsa_keys_$DATE.tar.gz" -C "$DATA_DIR" rsa_key* 2>/dev/null || true

# 备份配置文件
cp /opt/vaultwarden/.env "$BACKUP_DIR/env_$DATE.bak"
cp /opt/vaultwarden/docker-compose.yml "$BACKUP_DIR/docker-compose_$DATE.bak"

# 合并为一个完整备份包
tar czf "$BACKUP_DIR/vaultwarden_full_$DATE.tar.gz"     -C "$BACKUP_DIR"     "db_$DATE.sqlite3"     "attachments_$DATE.tar.gz"     "rsa_keys_$DATE.tar.gz"     "env_$DATE.bak"     "docker-compose_$DATE.bak"

# 清理临时文件
rm -f "$BACKUP_DIR/db_$DATE.sqlite3"       "$BACKUP_DIR/attachments_$DATE.tar.gz"       "$BACKUP_DIR/rsa_keys_$DATE.tar.gz"       "$BACKUP_DIR/env_$DATE.bak"       "$BACKUP_DIR/docker-compose_$DATE.bak"

# 删除超过保留天数的旧备份
find $BACKUP_DIR -name "vaultwarden_full_*.tar.gz" -mtime +$RETAIN_DAYS -delete

echo "[$DATE] Backup completed: vaultwarden_full_$DATE.tar.gz"

1
chmod +x /opt/vaultwarden/backup.sh

定时任务与异地备份

设置 cron 每天凌晨 3 点自动备份:


1
2
3
4
5
# 编辑 crontab
crontab -e

# 添加以下行
0 3 * * * /opt/vaultwarden/backup.sh >> /opt/vaultwarden/backups/backup.log 2>&1

本地备份只是第一步,更重要的是异地备份。你可以使用 rclone 将备份同步到云存储:


1
2
3
4
5
6
7
8
# 安装 rclone
curl https://rclone.org/install.sh | sudo bash

# 配置远程存储
rclone config

# 在 backup.sh 末尾添加异地同步
rclone copy /opt/vaultwarden/backups/ remote:vaultwarden-backup/ --max-age 30d

灾难恢复流程

当需要恢复时,按以下步骤操作:

  1. 在新 VPS 上安装 Docker 和 Docker Compose
  2. 创建
    1
    /opt/vaultwarden

    目录

  3. 从备份中恢复
    1
    .env

    1
    docker-compose.yml
  4. 解压数据库和附件到
    1
    data/

    目录

  5. 1
    docker compose up -d

    启动服务

  6. 配置 Nginx 和 HTTPS

整个恢复过程可以在 15 分钟内完成,前提是备份文件齐全。

客户端配置与日常使用

Vaultwarden 最大的优势是完全兼容 Bitwarden 官方客户端。你不需要安装任何第三方应用,直接使用 Bitwarden 官方客户端即可。

浏览器扩展

Chrome、Firefox、Edge、Safari 都有官方 Bitwarden 扩展。安装后,点击「设置」→「自托管」,填入你的服务器地址

1
https://vault.example.com

,然后正常登录即可。

手机客户端

iOS 和 Android 都有官方 Bitwarden App。同样在设置中将服务器改为自托管地址。注意:某些旧版本的 Android 客户端可能需要在「高级设置」中单独填写服务器 URL。

桌面客户端

Windows、macOS、Linux 均有官方桌面客户端。配置方式与浏览器扩展相同。

CLI 命令行工具

对于喜欢命令行的用户,Bitwarden 还提供了 CLI 工具:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装
npm install -g @bitwarden/cli

# 登录(指定自托管服务器)
bw config server https://vault.example.com
bw login you@example.com

# 解锁保险库
export BW_SESSION=$(bw unlock --raw)

# 常用操作
bw list items
bw get item "GitHub"
bw sync

CLI 工具在自动化场景中特别有用——比如从 CI/CD 流水线中读取部署密码,或者在服务器间同步配置。

高级功能与技巧

组织功能(团队共享)

Vaultwarden 支持组织(Organization)功能,可以和家人或小团队成员共享密码。创建组织后,可以建立不同权限的集合(Collection),实现只读共享、按组分配等精细化权限管理。这对于小团队管理共享账号(如社交媒体、云服务控制台等)非常实用。

密码泄露检测

Vaultwarden 集成了 Have I Been Pwned 的密码泄露检测功能。当你保存新密码或在安全检查时,它会将密码的 SHA-1 哈希前 5 位发送到 HIBP API(k-匿名模型,不会泄露完整密码),检查该密码是否出现在已知的泄露数据库中。如果匹配到,客户端会发出警告。

紧急访问

这是一个被低估但非常重要的功能:你可以指定信任的紧急联系人,在你无法访问密码库时(比如失联、意外),他们可以在等待期过后获得访问权限。设置方式是进入「设置」→「紧急访问」,添加联系人并设置等待天数(建议 7-14 天)。

API 集成与自动化

Vaultwarden 完全兼容 Bitwarden 的 REST API,你可以编写脚本自动化密码管理。比如定期检查并轮换服务器密码、从 CI/CD 流水线读取部署密钥、在服务器初始化时自动注入凭证等。配合 Bitwarden CLI 工具,这些操作都可以脚本化完成。

常见问题与故障排除

WebSocket 连接失败

症状:客户端无法实时同步,需要手动刷新。检查 Nginx 配置中

1
/notifications/hub

的 WebSocket 代理是否正确,确保包含了

1
Upgrade

1
Connection

头。同时确认

1
.env

1
WEBSOCKET_ENABLED=true

附件上传失败

检查 Nginx 配置中的

1
client_max_body_size

,默认值很小,建议设为

1
525M

。同时检查 VPS 磁盘空间是否充足。

邮件发送失败

检查 SMTP 配置是否正确,尤其是 Gmail 用户需要使用「应用专用密码」而非账户密码。查看日志:

1
docker compose logs | grep smtp

证书续期失败

Certbot 续期时需要通过 80 端口验证域名。确保防火墙放行了 80 端口,且 Nginx 正在运行。手动续期测试:

1
certbot renew --dry-run

容器更新


1
2
3
4
5
6
cd /opt/vaultwarden
docker compose pull
docker compose up -d

# 更新后检查
docker compose logs --tail=20

Vaultwarden 更新非常频繁,建议每月检查一次。更新不会影响数据,但重大版本升级前建议手动执行一次备份。

性能优化与监控

对于大多数个人用户来说,Vaultwarden 的默认配置已经足够。但如果你有更高的要求,这里有几个优化方向:

数据库优化

如果使用 SQLite,可以定期执行 VACUUM 来优化数据库文件大小:


1
2
# 在备份脚本中添加
sqlite3 /opt/vaultwarden/data/db.sqlite3 "VACUUM;"

对于用户量较大的场景,建议切换到 MariaDB/PostgreSQL。修改

1
.env

中的

1
DATABASE_URL

并启动对应的数据库容器即可。

图标缓存

Vaultwarden 默认会为每个密码条目下载网站图标(favicon),这会产生大量外部请求。如果你不介意图标缺失,可以设置

1
ICON_SERVICE=internal

来跳过外部图标下载,减少网络开销。

健康检查与监控

Vaultwarden 提供了

1
/alive

端点用于健康检查。你可以用简单的脚本监控服务状态:


1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
# 简单的 Vaultwarden 健康监控

RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" https://vault.example.com/alive)

if [ "$RESPONSE" != "200" ]; then
    echo "Vaultwarden is DOWN! HTTP: $RESPONSE"
    # 发送通知(Telegram/邮件等)
    # 重启服务
    cd /opt/vaultwarden && docker compose restart
fi

结合 Uptime Kuma 或 Prometheus + Grafana 监控体系,可以做到服务异常时自动告警。

总结

自建密码管理器并不复杂,一台 512MB 的小 VPS 就能跑起来,但安全责任完全在你自己身上。回顾一下关键要点:

  • 必须启用 HTTPS——没有 HTTPS 的密码管理器等于裸奔
  • 关闭公开注册——只允许通过管理员邀请创建账号
  • 设置强管理令牌——ADMIN_TOKEN 越长越好,定期更换
  • 启用两步验证——这是防止主密码泄露后的最后一道防线
  • 做好异地备份——本地备份+云存储双保险,定期验证恢复流程
  • 限制管理面板访问——Nginx 层面 IP 白名单
  • 保持更新——Vaultwarden 更新频繁,及时跟进安全补丁

把密码管理权掌握在自己手里,而不是交给第三方——这就是自托管的魅力,也是 VPS 玩家应该具备的基本功。如果你还没有开始使用密码管理器,现在就是最好的时机。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » VPS 自建密码管理器完全实战:用 Vaultwarden 部署私有 Bitwarden,从安装到生产加固一步到位
分享到: 更多 (0)