1. 为什么我把密码库从 1Password 搬回了自家 NAS
密码这件事,越用越觉得别扭。1Password 体验确实好,但每年续费的时候总会想:这些数据真的只能放在别人服务器上吗?LastPass 那几次事故之后,我对「把全部身家密码托管给第三方」这件事越来越没安全感。后来我试过 Bitwarden 官方自托管,功能是全,但一台 2C2G 的小机器跑起来内存直接飙到 500MB 以上,对我这种把服务塞在 NAS 和迷你主机上的人来说有点重。
直到用上 Vaultwarden,情况才变得舒服。它是一个用 Rust 写的 Bitwarden 服务端替代实现,兼容官方 Bitwarden 全平台客户端,内存占用实测稳定在 50MB 上下,Docker 一条命令就能拉起来。你可以把它理解成「Bitwarden 的发动机换成了更省油的 Rust 版本,但方向盘、仪表盘还是原来那套」——桌面端、浏览器扩展、手机 App 全都照常连。
这篇要交付的东西很具体:一份可直接复制的 Docker Compose 配置、反向代理的 HTTPS 骨架、以及把 TaoToken 的统一 Key/API 通道接进 settings.json 的写法,最后是服务启动和客户端连接的验证动作。适合有 NAS 或一台常开小主机、想自己掌控密码数据、又不想折腾太重服务的人。整个过程不需要你懂 Rust,会复制粘贴、会改域名就行。
2. 前置准备:TaoToken 通道与目录规划
在动手之前,先把两件事理清楚:一是服务器和域名,二是 API 通道的接入方式。
服务器方面,Vaultwarden 对资源要求极低,1 核 512MB 的机器就能跑得很稳。我自己的环境是一台装了 Docker 的迷你主机,系统盘之外挂了一块数据盘专门放密码库。域名建议单独准备一个子域,比如vw.yourdomain.com,因为 Vaultwarden 的 Web Vault 和客户端同步都强依赖 HTTPS,用 IP 直连会在浏览器扩展登录时出各种奇怪问题。
API 通道这块,我用 TaoToken 做统一入口。它的作用是把你分散的模型调用、编码 Agent 请求收敛到一个 Key 和一套 API 地址上,省得每个工具单独配一遍。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。注意 API 地址不要带 UTM 参数,直接写干净路径就行。
你需要提前拿到的东西:
- 一个 TaoToken 的 API Key,在控制台里创建,地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- 一个解析到服务器的域名,以及对应的 TLS 证书(Let's Encrypt 或你自己的都行)
- 服务器上装好 Docker 和 Docker Compose 插件
目录我习惯这样规划:/opt/vaultwarden放 compose 文件,/opt/vaultwarden/vw-data挂载数据卷。数据卷是命根子,后面备份就靠它。另外单独建一个/opt/vaultwarden/taotoken目录放通道配置,跟密码库数据物理隔开,避免误删。
提示:Vaultwarden 的
DOMAIN环境变量必须填你最终对外访问的 HTTPS 地址,填错会导致客户端同步失败、附件上传 404。这个坑我踩过,排查了半天。
3. 可复制配置:Docker Compose 与 TaoToken 通道骨架
先上主菜,docker-compose.yml。这份配置我实测跑通,包含数据卷、环境变量、端口绑定和日志设置。
services: vaultwarden: image: vaultwarden/server:latest container_name: vaultwarden restart: unless-stopped environment: DOMAIN: "https://vw.yourdomain.com" SIGNUPS_ALLOWED: "true" INVITATIONS_ALLOWED: "false" WEB_VAULT_ENABLED: "true" ADMIN_TOKEN: "换成你自己的长随机串" LOG_FILE: "/data/vaultwarden.log" LOG_LEVEL: "info" EXTENDED_LOGGING: "true" volumes: - ./vw-data:/data ports: - "127.0.0.1:8080:80"几个参数说明一下。SIGNUPS_ALLOWED第一次启动时设成true,方便你注册主账号;注册完立刻改回false并重启,防止陌生人注册。ADMIN_TOKEN是管理面板的访问令牌,用openssl rand -base64 48生成一串,别用简单密码。端口只绑127.0.0.1,对外一律走反向代理,不要直接把 8080 暴露到公网。
启动命令:
cd /opt/vaultwarden docker compose up -d docker compose logs -f vaultwarden看到日志里出现Rocket has launched之类的字样,说明服务起来了。此时本机curl http://127.0.0.1:8080应该能返回 Web Vault 的 HTML。
接下来是 TaoToken 通道的settings.json骨架。这个文件用于把编码 Agent 或模型调用统一指向 TaoToken 的 API 通道,放在/opt/vaultwarden/taotoken/settings.json:
{ "api_base": "https://taotoken.net/api", "api_key": "sk-你的TaoToken密钥", "default_model": "claude-sonnet-4-5", "timeout_seconds": 60, "retry": { "max_attempts": 3, "backoff_seconds": 2 }, "headers": { "Content-Type": "application/json" } }api_base固定写https://taotoken.net/api,不要加任何查询参数。api_key从控制台复制,权限最小化,别用主账号全权限 Key。default_model按你实际订阅的模型填,长期跑编码任务的话建议配合 Coding Plan 使用,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,能省不少调用成本。
反向代理我用 Nginx,配置如下,重点是 WebSocket 升级头和client_max_body_size,附件上传大文件时后者不给够会直接 413:
server { listen 80; server_name vw.yourdomain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name vw.yourdomain.com; ssl_certificate /etc/letsencrypt/live/vw.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/vw.yourdomain.com/privkey.pem; client_max_body_size 128M; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; 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; proxy_set_header X-Forwarded-Host $host; } }改完nginx -t测试语法,再systemctl reload nginx。如果你用 Traefik,思路一样,给容器打上traefik.enable=true和路由规则标签即可,核心还是把 80 端口交给它、TLS 由它终结。
4. 验证请求:从服务启动到客户端连接
配置写完不算完,得一步步验证。我按顺序走一遍。
第一步,确认容器健康:
docker compose ps curl -I https://vw.yourdomain.com返回HTTP/2 200说明反代和证书都通了。如果返回 502,多半是 Nginx 到 8080 的链路断了,检查容器是否在跑、端口是否绑对。
第二步,验证 TaoToken 通道连通性。用 curl 直接打 API 基址,确认 Key 有效:
curl -s https://taotoken.net/api/v1/models \ -H "Authorization: Bearer sk-你的TaoToken密钥" \ -H "Content-Type: application/json" | head -c 500能返回模型列表 JSON 就说明通道正常。如果返回 401,检查 Key 有没有复制全、有没有多余空格;返回 404 则确认路径是不是/api/v1/...,别漏了/api前缀。
第三步,客户端连接。桌面端和浏览器扩展的配置路径一样:安装官方 Bitwarden 客户端,进入设置,找到「Self-hosted」或「自托管环境」,把服务器地址填成https://vw.yourdomain.com,保存后登录。手机端在登录页点齿轮图标,选「自托管」,同样填这个地址。
登录成功后,建一条测试登录项,然后在另一台设备上同步,看能不能秒级出现。这一步能验证 WebSocket 推送是否正常——如果同步要手动刷新才出来,说明反代的 Upgrade 头没配对。
第四步,验证 TOTP。随便找一条登录项,编辑时填入 Authenticator Key(那串otpauth://或纯 Base32),保存后条目上会显示 6 位动态码,跟手机上的验证器对一下,一致就说明内置 TOTP 工作正常。
第五步,跑一次备份,确认数据卷可读:
tar -czvf /opt/backup/vw-$(date +%Y%m%d).tar.gz -C /opt/vaultwarden vw-data备份文件能正常生成、大小不为 0,就说明数据落盘没问题。建议把这条命令丢进 crontab,每天凌晨跑一次。
5. 本篇常见错排查
报错一:客户端提示「无法连接到服务器」或「证书无效」。九成是DOMAIN环境变量和实际访问地址不一致,或者证书链不完整。检查 compose 里的DOMAIN是否带https://、域名是否和浏览器地址栏完全一致。证书用fullchain.pem而不是单独的cert.pem。
报错二:附件上传失败,返回 413。Nginx 的client_max_body_size默认只有 1M,改成 128M 或更大,reload 后重试。Traefik 用户检查是否有中间件限制请求体大小。
报错三:TaoToken 调用返回 401/403。先确认 Key 没写错、没过期,再确认请求头是Authorization: Bearer sk-xxx格式。如果 Key 权限被限制到特定模型,调用其他模型也会 403,去控制台核对权限范围。
报错四:容器启动后立刻退出。看docker compose logs vaultwarden,常见原因是数据目录权限不对。vw-data目录需要容器内用户可写,执行chown -R 1000:1000 /opt/vaultwarden/vw-data再重启。
报错五:WebSocket 连接失败,实时同步不工作。反代配置里proxy_set_header Upgrade $http_upgrade;和Connection "upgrade"两行必须都有,缺一个都会导致长连接建立不起来。
报错六:忘记管理员令牌进不去面板。直接改 compose 里的ADMIN_TOKEN,docker compose up -d重建容器即可,数据不受影响。
注意:生产环境务必把
SIGNUPS_ALLOWED设为false。开放注册的 Vaultwarden 实例会被扫描器盯上,虽然密码是加密的,但没必要给别人留门。
6. 后续怎么用:把通道和密码库串起来
密码库跑起来只是第一步。我现在的用法是:Vaultwarden 管所有账号密码和 TOTP,TaoToken 通道管编码 Agent 和模型调用的统一入口,两者各司其职。日常写代码时,Agent 通过settings.json里的api_base走 TaoToken,需要换模型或查用量就去模型对话页面对比效果,地址是 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。
如果你要接 Claude Code 这类工具,接入文档里有完整的端点说明,地址是 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,照着填ANTHROPIC_BASE_URL之类的环境变量就行。Key 的管理和轮换在 API Keys 页面,地址是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite ,建议给不同工具分配不同 Key,方便出问题时单独吊销。
最后说个我自己的习惯:Vaultwarden 的备份和 TaoToken 的 Key 轮换,我都放在每月一号做。备份验证过一次恢复流程,Key 轮换后同步更新settings.json并重启相关服务。密码管理这件事,配置一次能安稳用很久,但备份和轮换这两个动作别偷懒。