前言:我遇到了什么问题
最近我的 Vaultwarden 突然出问题了:浏览器插件无法验证登录。

查了插件商店留言板才知道,插件升级到 2026.7 版本后,要求服务端不低于 1.37.0。

而我手里的 NAS 呢?群晖套件是 1.36.0,飞牛应用中心是 1.32.0,全都不达标。等官方更新遥遥无期,我决定自己动手——用 AI 辅助,把官方最新的 1.37.1 打包成飞牛可安装的 fpk 应用。


下面就是完整过程,全程可在飞牛 NAS 上复现。
准备工作
- 一台飞牛 fnOS 设备(x86 或 ARM 都可以,本文以 x86 为例)
- 设备上已安装
docker(用于从官方镜像提取二进制) - 设备上已安装打包工具
fnpack(在https://developer.fnnas.com/docs/cli/fnpack/下载,放到/usr/local/bin) - 一个能上网的终端(root 权限)
第一步:先读官方打包文档
飞牛的开发者文档讲得很清楚,直接让AI通读这几页:
- 快速开始:
developer.fnnas.com/docs/quick-started/prerequisites/ - 应用框架(目录结构、生命周期脚本):
/docs/core-concepts/framework/ - Manifest 规范:
/docs/core-concepts/manifest/ - fnpack 使用:
/docs/cli/fnpack/
重点记住几个关键点:
- fpk 本质是一个 gzip 压缩的 tar 包,里面有一个
app.tgz(你的应用文件)+manifest(元信息)+cmd/(生命周期脚本)+config/(权限和资源)+wizard/(安装向导)+ 图标; - 生命周期脚本里最核心的是
cmd/main,负责start/stop/status; - 安装时系统会提供
TRIM_APPDEST、TRIM_PKGVAR等环境变量告诉你文件装在哪、数据放哪,不要硬编码路径。
第二步:获取 1.37.1 二进制(这里有个大坑)
Vaultwarden 官方仓库(github.com/dani-garcia/vaultwarden)的 1.37.1 release 只发布容器镜像,没有直接的二进制下载。所以我的做法是:从官方 Docker 镜像里把二进制"抠"出来。
# 拉取官方镜像(先试默认版本)
docker pull vaultwarden/server:1.37.1
docker create --name vw vaultwarden/server:1.37.1
docker cp vw:/vaultwarden ./vaultwarden
docker rm vw
试运行一下:./vaultwarden --version——结果报错:
./vaultwarden: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found
这就是第一个坑:官方默认镜像编译的二进制要求 GLIBC 2.39,而飞牛系统基于 Debian 12,只有 GLIBC 2.36,跑不起来。
解决办法:改用官方 Alpine 变体镜像,它的二进制是静态编译(musl),不依赖系统库,任何 Linux 都能直接运行:
docker pull vaultwarden/server:1.37.1-alpine
docker create --name vw vaultwarden/server:1.37.1-alpine
docker cp vw:/vaultwarden ./vaultwarden
docker cp vw:/web-vault ./web-vault # 网页版前端资源,也要一起
docker rm vw
chmod +x ./vaultwarden
./vaultwarden --version # 输出:Vaultwarden 1.37.1 ✓
顺便提醒:如果以后要打 ARM 版,把第一步换成 docker pull --platform linux/arm64 vaultwarden/server:1.37.1-alpine 即可。
第三步:创建应用项目骨架
用 fnpack 生成标准项目结构:
fnpack create vaultwarden
会得到这样的目录:
vaultwarden/
├── app/ # 放你的二进制和 web 资源
├── cmd/ # 生命周期脚本
├── config/ # privilege / resource
├── wizard/ # 安装向导
├── manifest # 应用元信息
├── ICON.PNG
└── ICON_256.PNG
把上一步提取的二进制和前端资源放进去:
mv ./vaultwarden vaultwarden/app/vaultwarden
mv ./web-vault vaultwarden/app/web-vault
第四步:配置 manifest
编辑 manifest,关键字段如下:
appname = vaultwarden
version = 1.37.1
display_name = Vaultwarden
desc = 开源的 Bitwarden 兼容密码管理器服务器
maintainer = dani-garcia
distributor = 你自己的名字
distributor_url = https://你的主页
arch = x86_64 # ARM 设备写 arm
platform = x86 # 飞牛叫法:x86=amd64、arm=aarch64
source = thirdparty
desktop_uidir = ui
ctl_stop = true
service_port = 8080
checkport = true
注意:飞牛的架构叫法和平时不一样,x86 = amd64,arm = aarch64。
第五步:编写生命周期脚本
cmd/main 是整个应用的控制核心。我的写法是:从配置文件读端口(安装向导收集的),然后启动二进制:
#!/bin/bash
CONFIG_FILE="${TRIM_PKGETC}/config.conf"
PID_FILE="${TRIM_PKGVAR}/app.pid"
LOG_FILE="${TRIM_PKGVAR}/info.log"
BIN="${TRIM_APPDEST}/vaultwarden"
PORT=8080
[ -r "${CONFIG_FILE}" ] && . "${CONFIG_FILE}" && [ -n "${web_port}" ] && PORT="${web_port}"
start_process() {
CMD="cd '${TRIM_APPDEST}' && ROCKET_ADDRESS=0.0.0.0 ROCKET_PORT='${PORT}' \
DATA_FOLDER='${TRIM_PKGVAR}' WEB_VAULT_FOLDER='${TRIM_APPDEST}/web-vault' '${BIN}'"
bash -c "${CMD}" >> "${LOG_FILE}" 2>&1 &
echo $! > "${PID_FILE}"
}
case $1 in
start) start_process ;;
stop) [ -r "${PID_FILE}" ] && kill -TERM $(head -1 "${PID_FILE}"); rm -f "${PID_FILE}" ;;
status) pgrep -f "${BIN}" >/dev/null && exit 0 || exit 3 ;;
*) exit 1 ;;
esac
几个要点:
- 数据必须放
TRIM_PKGVAR(对应@appdata目录),这样重启、升级都不会丢; status返回 0 表示运行中,3 表示未运行(这是飞牛的约定,不能写错);- 安装向导收集的端口先由
install_callback写入$TRIM_PKGETC/config.conf,启动时再读出来,这样用户在向导里改的端口才有效。
第六步:安装向导 + 入口 + 图标
向导(wizard/install):让用户安装时能选端口:
[
{
"stepTitle": "服务配置",
"items": [
{
"type": "text",
"field": "wizard_port",
"label": "Web 服务端口",
"initValue": "8080",
"rules": [
{ "required": true, "message": "请输入端口号" },
{ "pattern": "^[0-9]+$", "message": "端口只能包含数字" }
]
}
]
}
]
桌面入口(app/ui/config):这里有个坑,我一开始写成 iframe 类型,结果打开被浏览器拒绝。原因有两个:一是桌面是 https,内嵌 http 的 iframe 会被混合内容拦截;二是 Vaultwarden 响应头里带了 frame-ancestors 'self',禁止跨源嵌入。端口服务类应用一律用 type: "url":
{
".url": {
"vaultwarden.Application": {
"title": "Vaultwarden",
"icon": "images/icon_{0}.png",
"type": "url",
"protocol": "http",
"port": "${wizard_port}",
"url": "/",
"allUsers": true
}
}
}
图标:用官方仓库 resources/ 里的 SVG,NAS 上没有 PS 也没有 ImageMagick?装个 librsvg 转一下就行:
apt-get install -y librsvg2-bin
rsvg-convert --background-color='#175DDC' -w 64 -h 64 -o ICON.PNG vaultwarden-icon-white.svg
rsvg-convert --background-color='#175DDC' -w 256 -h 256 -o ICON_256.PNG vaultwarden-icon-white.svg
第七步:打包
cd vaultwarden
fnpack build
生成 vaultwarden.fpk,搞定。
第八步:安装实测
把 fpk 传到飞牛上,用命令行安装(-v 是存储卷索引,从 1 开始;-e 是向导字段,可以预先提供端口):
echo "wizard_port=8080" > /tmp/install.env
appcenter-cli install-fpk vaultwarden.fpk -v 1 -e /tmp/install.env
appcenter-cli start vaultwarden
appcenter-cli status vaultwarden # 输出 running
验证几个点:
curl http://127.0.0.1:8080/ # 返回 Vaultwarden Web 页面
curl http://127.0.0.1:8080/alive # 健康检查 OK
再试试改端口:在应用中心设置里把端口改成 8081,确认服务自动重启并监听新端口。全通过,就可以放心用了。
总结:这次踩的坑
| 坑 | 表现 | 解法 |
|---|---|---|
| 默认镜像二进制要 GLIBC 2.39 | version 'GLIBC_2.39' not found | 改用 -alpine 变体(静态 musl) |
| 桌面入口被拒 | 打开报"拒绝访问" | type 用 url,别用 iframe |
| 安装后列表里看不到应用 | 应用中心找不到已启用的应用 | 别绕过应用中心手动启停,用 appcenter-cli stop/start 正规流程 |
| 改 manifest 展示信息不变 | 发布者/描述还是旧的 | 应用中心的展示信息在系统数据库里,不只是 manifest 文件 |
结尾

整个过程,从查文档、踩坑、打包到实测,我基本都是靠 AI完成的——把飞牛官方文档丢给它,让它按规范生成清单和脚本,遇到报错直接把错误贴给它分析。以前这种"差一点点就能用"的事情,可能要折腾一晚上,现在一个上午就能交付。
如果你也在飞牛/群晖上跑 Vaultwarden,遇到了插件无法验证的问题,直接照着这篇把服务端升到 1.37.x 就行。需要 ARM 版安装包、或者想让我把某个应用也打包成 fpk 的,评论区留言,我尽量帮大家安排。