Skip to content
twinkling.top服务VaultwardenEN
板型any Pi 4 or 5; a Pi Zero 2 W will serve two users comfortably
内核6.6.51+rpt-rpi-v8
空闲温度48 °C
内核架构arm64
参考机:Pi 4B 8GB / Bookworm 64-bit

部署配方 · 密钥与身份

Vaultwarden:放在家里的密码库

这是机架上唯一一个「消失就是真损失」的服务,也是唯一一个备份比在线率更重要的服务。Vaultwarden 是用 Rust 重写的、兼容 Bitwarden 服务端的实现:协议一致,所以官方浏览器扩展和手机 App 都能直连,而它占 90MB 内存,而不是官方服务端的好几个 GB。

vaultwarden/server:1.33.2 · 2026-09-20

Vaultwarden rack plate: board stack and host ports
服务参数
容器镜像vaultwarden/server:1.33.2
宿主端口:8083/tcp
数据目录/srv/homelab/vaultwarden/data
内存预留90 MB
CPU 上限0.20 vCPU (cpus: "0.20") — Argon2 KDF runs only at login
更新节奏quarterly, or immediately for a security release. Vaultwarden tracks the Bitwarden clients, which change their API expectations a few times a year
ARM 兼容arm64 native image; Argon2id login on a Pi 4 takes about 0.6 seconds at the default KDF settings
端口映射与暴露面
宿主容器proto暴露用途
:808380tcp仅局域网web vault, the browser extension API and the mobile apps

部署步骤

  1. 建数据目录并生成管理令牌

    下面把管理页面整个关掉了,但 CLI 做用户管理时仍然要用到这个令牌。生成一次,写进 env 文件。

    run
    sudo mkdir -p /srv/homelab/vaultwarden/data
    sudo chown -R 1000:1000 /srv/homelab/vaultwarden
    echo "VW_ADMIN_TOKEN=$(openssl rand -base64 48)" >> /srv/homelab/.env
  2. 先开放注册建号,再关掉

    上面的配置里注册是关闭的,因为那是长期该有的状态。初次搭建时先用 SIGNUPS_ALLOWED=true 启动一次,注册完两个账号再改回去重建。

    run
    docker compose up -d vaultwarden
    docker exec vaultwarden /vaultwarden --version
    # 在 https://vault.lan 注册,然后:
    docker compose up -d --force-recreate
  3. 开启双因素,把恢复码离线存好

    恢复码是手机丢失后唯一的回路。打印出来,或者手写在纸上。把它存在它自己保护的那个密码库里,是经典错误。

    run
    # 账号设置 -> 安全 -> 两步登录 -> 验证器应用
    # 然后查看恢复码并抄下来
  4. 把客户端指过来,确认双向同步

    服务器地址要在浏览器扩展和手机 App 里都设,不能只在网页端设。真正重要的是客户端——三种界面里,网页端是最少用的那个。

    run
    # 扩展 -> 设置 -> 自建环境 -> https://vault.lan
    # 然后在手机上新增一条测试记录,确认扩展里能看到
  5. 装好每晚的导出,并手动恢复一次

    导出就是数据目录的一个 tar 包。先手动跑一次、手动恢复一次,然后才放进 cron。

    run
    docker exec vaultwarden sqlite3 /data/db.sqlite3 ".backup '/data/db-backup.sqlite3'"
    tar czf /srv/homelab/backup/vaultwarden-$(date +%F).tgz -C /srv/homelab/vaultwarden data

为什么不用托管免费版

托管的免费版确实很好用,用它一点也不丢人。要自建这个服务的理由在于:密码库是其它一切所依赖的东西——路由器密码、恢复码、SSH 密钥都在里面——而放在你家某台机器上的密码库,是一个当手机、邮箱和托管账号同时被锁在外面时,你依然打得开的密码库。

相应的代价是义务:密码库的备份是这台机架上最重要的文件。它每晚备份、拷到 NAS,恢复材料还有一份打印件放在抽屉里。

只走局域网和 WireGuard,不上公网

vault.lan 在局域网内解析,在外面通过 WireGuard 隧道同一个主机名也能解析。路由器上不做任何转发,所以密码库不存在公开登录页——这是「每天被扫描的服务」和「根本不会被扫到的服务」之间的区别。

客户端对此适应良好:浏览器扩展会缓存密码库,隧道一通就同步,手机 App 同理。需要知道的局限是:在飞机上新增的密码要等三天后才同步——这是真实存在的限制,也是离线导出功能存在的理由。

Argon2 参数与树莓派的登录开销

Vaultwarden 在登录时用 Argon2id 派生密码库密钥。Pi 4 在默认参数下大约六百毫秒——正是这个开销让被偷走的数据库难以破解,也正是它让两个用户登录时 CPU 的尖峰在 Grafana 上看得见。

提高 KDF 迭代次数会让密码库更难破解,也会让所有人的登录变慢,包括每一台在 App 更新后需要重新派生密钥的设备。这个体量下默认值就是对的取舍;要改,值得把理由写下来。

shell
docker exec vaultwarden /vaultwarden hash --preset owasp
# 需要轮换时生成新的 ADMIN_TOKEN 哈希

真正的交付物是恢复演练

一个从没被恢复过的密码库备份是信念,不是备份。演练二十分钟,一年做两次:停容器、把数据目录挪开、恢复昨晚的副本、启动、从某台设备登录。

要在同一台派上做,把生产数据挪到一边,而不是找一台备用机器。目的是证明「光靠数据目录就够」——因为固态盘坏掉时,你手上正好就只有它。

shell
docker compose stop vaultwarden
sudo mv /srv/homelab/vaultwarden/data /srv/homelab/vaultwarden/data.old
sudo tar xzf /srv/homelab/backup/vaultwarden-$(date -d yesterday +%F).tgz -C /srv/homelab/vaultwarden
docker compose up -d vaultwarden && docker logs --tail 10 vaultwarden

compose 文件

整份文件放在 /srv/homelab/vaultwarden/compose.yaml。标签固定版本号,不用 latest——树莓派上回滚比升级麻烦得多。

compose.yaml
services:
  vaultwarden:
    image: vaultwarden/server:1.33.2
    container_name: vaultwarden
    restart: unless-stopped
    ports:
      - "8083:80/tcp"
    environment:
      TZ: Asia/Shanghai
      DOMAIN: https://vault.lan
      SIGNUPS_ALLOWED: "false"
      INVITATIONS_ALLOWED: "false"
      ADMIN_TOKEN: ${VW_ADMIN_TOKEN}
      SHOW_PASSWORD_HINT: "false"
      ROCKET_PORT: "80"
      SENDS_ALLOWED: "true"
      WEB_VAULT_ENABLED: "true"
    volumes:
      - /srv/homelab/vaultwarden/data:/data
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    networks: [rack]

networks:
  rack:
    external: true

加固清单

  • 关闭注册,别人发现了这个实例也建不了账号
  • 完全关闭管理面板;用户管理通过 CLI 加令牌完成,令牌放在 env 文件里
  • 密码库只在局域网和 WireGuard 内可达,从不做端口转发——公网上的密码管理器登录页就是一个靶子
  • 两个账号都强制开启双因素,恢复码打印出来离线保存
  • 除数据卷外,容器以只读方式运行

备份方案

SQLite 数据库连同附件和 send 目录每晚复制一次,另外还有一份拷进手机上的离线密码管理器。这第二份不是偏执:这个服务存在的全部意义,就是它装着你无法通过其它途径找回的那些凭据。

上线后验证

  • 手机在移动网络下经 WireGuard 能打开密码库,并看到在局域网内新增的条目
  • 在派上网页端登录大约一秒,这是 Argon2id 的开销而不是问题
  • 昨晚的归档能恢复进一个运行中的实例,且账号照常登录
  • 登录页上没有注册入口,管理页面返回 404

踩过的坑

  • SIGNUPS_ALLOWED 留在 true,就是自建密码库里出现陌生人的方式。镜像里它的默认值是 true,这也是这里显式设成 false 的原因。
  • 把双因素恢复码存进它保护的那个密码库里,意味着手机和密码库会同时丢失。写在纸上,放抽屉。
  • 数据目录必须对容器的 uid 可写。只读式的 rootless 配置如果漏了可写卷,会得到一个能启动、但每次写入都以数据库错误失败的容器。
  • 客户端都有本地缓存,服务器不可达时会照样显示一份过期的密码库。如果某处改动在第二台设备上没出现,先检查客户端的服务器地址,别急着认定服务端坏了。

硬件与选型问答

自建密码管理器安全吗?
它和那台机器、以及那份备份一样安全。它防的威胁——托管服务商被入侵——真实但罕见;它引入的威胁——没打补丁的派、被转发的端口、放在共享盘上的备份——反而更可能发生。放在局域网里、保持更新、备份离线保管,它就是净收益。
能让全家共用密码吗?
可以,通过组织和集合。建一个组织,把共用条目——wifi 密码、流媒体账号、门锁密码——放进两个账号都能看到的集合,私人条目留在各自的私人库里。无论怎样,双因素的恢复码都保持个人所有并离线保存。
派坏掉会怎样?
把数据目录恢复到新卡或新固态盘上,启动容器,每个客户端会同步回它们各自的位置。你甚至可以在没有服务器的情况下读出密码库内容,因为每个客户端都保留着一份加密的本地副本——手机 App 的导出就是那扇逃生门,值得在需要它之前先测一次。