飞牛 fnOS 深度解析（三）：系统目录结构与技术栈全览
本系列文章将对国产 NAS 系统飞牛 fnOS 进行全方位深度解析。本文是系列第三篇，聚焦系统目录结构与技术栈，详细解析 fnOS 的安装目录布局、100+ 自研程序分类、前端技术栈、配置文件体系，以及二次开发的目录布局参考。阅读本文前，建议先阅读前两篇：飞牛 fnOS 深度解析（一）：系统基础与启动流程全揭秘飞牛 fnOS 深度解析（二）：存储架构深挖——ZFS、LVM 与自研 trimafs 联合文件系统前言前两篇我们解析了 fnOS 的系统基础、启动流程和存储架构，对系统的整体面貌有了认知。但如果要基于 fnOS 做二次开发，或者要快速解构另一台 NAS 设备，还需要搞清楚一个关键问题：厂商的东西都放在哪？Linux 发行版有标准的目录规范（FHS），但 NAS 厂商通常会把自己的自研程序、配置、前端文件、内核模块等放在一个统一的目录下，和系统自带的东西隔离开。找到这个目录，就找到了厂商的全部家当。本文将带大家完整解析 fnOS 的安装目录 /usr/trim/，看看里面到底有什么、怎么组织的、用了哪些技术栈，以及对二次开发有什么参考价值。测试环境：fnOS 1.2.0505，x86_64 平台。一、fnOS 安装根目录总览从启动流程的分析中我们已经知道，fnOS 的核心程序在 /usr/trim/bin/ 下。我们来看看整个 /usr/trim/ 目录的结构：ls -la /usr/trim/输出：drwxr-xr-x 12 root root 4096 Sep 3 08:03 . drwxr-xr-x 14 root root 4096 Sep 3 08:00 .. drwxr-xr-x 5 root root 4096 Sep 3 08:03 bin drwxr-xr-x 2 root root 4096 Sep 3 07:59 config drwxr-xr-x 7 root root 4096 Sep 3 08:03 etc drwxr-xr-x 6 root root 4096 Sep 3 07:59 lib drwxr-xr-x 3 root root 4096 Sep 3 08:03 logs drwxr-xr-x 8 root root 4096 Sep 3 08:00 modules drwxr-xr-x 13 root root 4096 Sep 3 08:03 nginx drwxr-xr-x 6 root root 4096 Sep 3 07:59 share drwxr-xr-x 11 root root 4096 Sep 3 07:59 var drwxr-xr-x 9 root root 4096 Sep 3 08:03 www/usr/trim/ 下有 11 个子目录，整体布局参考了 Linux 的 FHS 标准，但做了简化和定制：目录作用类比系统目录bin/所有自研程序和脚本（100+个）/usr/bin/etc/服务级配置文件（40+个）/etc/lib/库文件/usr/lib/logs/日志/var/log/modules/内核模块（多个版本）/lib/modules/nginx/自编译 Nginx（独立目录）—share/共享文件/usr/share/var/各服务运行时数据/var/lib/www/Web 前端文件—config/运行时配置—logs/日志—设计思路很清晰：把所有 fnOS 自研的东西统一放在 /usr/trim/ 下，和 Debian 系统自带的东西完全隔离。这样做的好处：升级方便：系统升级时，直接替换 /usr/trim/ 目录就行，不会影响系统自带的文件卸载干净：如果要移除 fnOS，删掉 /usr/trim/ 目录和相关的 systemd 服务就行结构清晰：开发者一眼就能找到自研程序、配置、前端文件的位置权限可控：可以对整个 /usr/trim/ 目录统一设置权限下面我们逐个目录详细解析。二、bin 目录：100+ 自研程序全览bin/ 是 fnOS 最核心的目录，所有自研程序和脚本都在这里。ls /usr/trim/bin/输出有 100+ 个文件，包括二进制程序和 shell 脚本。我们按功能分类整理：2.1 核心基础设施程序作用trim核心主进程（trim_main.service 执行的就是它）rpc_brokerRPC 消息代理（服务间通信的总线）triminit / triminitd系统初始化（一次性 + 常驻）trimacl飞牛自研 ACL 工具（跨文件系统统一权限）trimtools飞牛工具集handlers事件处理器2.2 Web 与 API程序作用trim_http_cgiHTTP CGI 接口trim_open_gateway开放网关uploadsrv / run_uploadserver.sh上传服务trim-connect飞牛互联远程访问trimdnsafeDNS 安全2.3 用户与权限程序作用accountsrv账户服务usersrv用户服务useradd / groupadd飞牛自己的用户/组管理工具（不是系统的）check_perm / check_token权限/令牌校验security_service安全服务trim_tfa双因素认证trim_license许可证管理值得注意的是：fnOS 有自己的 useradd 和 groupadd，不是调用系统的。这说明 fnOS 的用户管理是完全自研的，Web 界面创建用户时，调用的是 /usr/trim/bin/useradd，而不是系统的 /usr/sbin/useradd。这也解释了为什么 Web 用户和系统用户的关系需要专门研究（我们将在第四篇详细解析）。2.4 文件与存储程序作用filestor_service文件存储服务finder_service / filemanager文件查找/管理share_service / share-management共享管理trim_file_monitor文件监控trashbind回收站trim_sharelink分享链接trim_nfusr / trim_mount_nfsNFS 相关extdev_service外部设备管理（U盘、移动硬盘等）diskpowerd / diskcheck硬盘电源管理/检测2.5 文件协议程序作用smbftpd / smbftpd-user飞牛自己的 FTP 服务（不是 vsftpd/proftpd）webdavWebDAV 服务wsdd2WSD 发现（Windows 网络邻居）minidlnadDLNA 媒体服务器cloud_storage_dav / trim_curlftpfs云存储挂载又一个自研组件：fnOS 的 FTP 服务叫 smbftpd，不是常见的 vsftpd 或 proftpd。从名字看，它可能和 SMB 共享用户体系，或者是基于某个开源项目修改的。这个名字本身就值得研究。2.6 网络服务程序作用network_service / netdetect网络管理/检测upnp_service / avahi_serviceUPnP/零配置网络ipblockerIP 封禁trim_nic_name_consistency网卡名称一致性（保证重启后网卡名不变）nic_performance_mode.sh网卡性能模式切换2.7 AI 与媒体程序作用ai_managerAI 管理器（AI 相册的核心）imagesrv图像服务mediasrv媒体服务auto_thumbnailer自动缩略图生成2.8 Docker 与应用程序作用dockermgr / dsmgrDocker 管理/流服务trim_app_center应用中心trim_sac系统应用控制（System Apps Control）trim_registry镜像仓库docker-shutdown-containers.shDocker 关机时优雅停止容器的脚本2.9 备份与下载程序作用backup_service备份服务（总入口）backup_local / backup_remote / backup_cloud本地/远程/云备份rapidrecovery快速恢复dlcenter / multiple-downloads下载中心/多任务下载trim-aria2c / trim-qbittorrent-nox下载工具（飞牛封装版）备份服务拆成了 local/remote/cloud 三个独立程序，说明飞牛的备份方案支持多种备份目标，架构上做了拆分。2.10 系统管理程序作用updatemgr / liveupdate系统升级/在线更新sysdiag / sysinfo_service系统诊断/信息sysrestore_service系统还原system_startup.sh / system_shutdown.sh / system_umount.sh系统启停脚本system_setgpio.sh / system_setled.sh / system_setmac.sh硬件设置脚本（GPIO/LED/MAC）resmon_service / eventlogger_service / logchecker资源监控/日志show_startup_info.sh显示启动信息（可能是前面板屏幕）2.11 硬件与存储管理程序作用pwm-fancontrol.shPWM 风扇调速maligpu-fw-symlinkMali GPU 固件（通用镜像，x86 上可能没用）mdadm飞牛自己的 mdadm（可能打了补丁或加了快速同步功能）fast_resync_md_raid / check_raid456_resync_status / init_resync_waitRAID 同步管理（快速重建、状态检查、等待同步）resize-rootfs.sh首次开机自动扩容根分区scrub_watch.jsonZFS scrub 监控（在 etc 目录下）又一个自研组件：fnOS 有自己的 mdadm，而且配套了 fast_resync_md_raid（快速 RAID 同步）。标准 mdadm 的 RAID 重建速度是有限制的，飞牛可能做了优化，加快重建速度。这也是一个技术亮点。2.12 工具与其他程序作用7zz压缩工具（7-Zip 的 Linux 版）benchmark / coremark性能测试工具bpfBPF（Berkeley Packet Filter）工具dfree磁盘空间查询（Samba 用的）wait_trim_init.sh / run_trim.sh / trim_launch_tty.sh辅助脚本upssched_cmd.shUPS 电源调度2.13 bin 目录的重大发现总结自研程度非常高：从核心主进程、用户管理、FTP 服务，到 mdadm、useradd 这些基础工具，fnOS 都有自己的版本，不是简单套用开源软件微服务架构：100+ 个程序，每个负责一个小功能，通过 rpc_broker 通信，不是一个大而全的单体程序脚本与二进制混合：既有编译好的二进制程序（trim、rpc_broker 等），也有大量 shell 脚本（.sh 结尾），用于系统启停、硬件设置等硬件定制深入：GPIO、LED、风扇、MAC地址、UPS，都有专门的管理工具，说明飞牛对硬件层有较深的定制三、www 目录：Web 前端文件与技术栈www/ 是 Web 前端文件目录，也就是用户在浏览器里看到的管理界面的所有静态文件。3.1 目录结构ls /usr/trim/www/输出：access-code apps assets favicon.ico index.html locales lottie modules robots.txt static目录/文件作用index.html入口页面assets/打包后的 JS/CSS 文件locales/多语言文件modules/前端模块apps/应用页面（可能是各个功能模块的入口）access-code/访问码相关页面lottie/Lottie 动画文件static/静态资源（图片、字体等）favicon.ico网站图标robots.txt爬虫规则这是一个典型的单页应用（SPA）结构：一个 index.html 入口 + 一堆打包后的 JS/CSS 文件 + 多语言文件。3.2 前端技术栈分析我们来看 index.html 的内容：head -20 /usr/trim/www/index.html输出（关键部分）： 飞牛 fnOS 从 index.html 引用的 JS 文件名，我们可以分析出完整的前端技术栈：技术证据说明Reactlottie-react.jsLottie 的 React 绑定，说明用了 ReactTypeScripttslib.es6.jsTypeScript 运行时库，说明用了 TSSemi DesignCSS 变量 --semi-color-bg-0字节跳动开源的 React 组件库Rolldownrolldown-runtime.js新一代 JavaScript 打包工具（基于 Rust，类似 Vite 的底层）i18nexti18next.js国际化框架，支持多语言Lodashlodash.jsJavaScript 工具库Lottielottie-react.js + lottie/ 目录动画库，用于界面动画ES Modules 原生 ES 模块，现代前端标准结论：fnOS 的前端技术栈是 React + TypeScript + Semi Design（字节组件库），用 Rolldown 打包，i18next 做国际化。几个值得注意的点：用了字节的 Semi Design：Semi Design 是字节跳动开源的企业级 React 组件库，飞牛用它做 UI 组件，说明前端团队可能和字节有技术交流，或者就是偏好字节的技术栈用了 Rolldown 打包：Rolldown 是一个比较新的打包工具（基于 Rust，由 Vite 团队开发），说明飞牛的前端技术栈比较新，跟进前沿工具多语言支持：从 locales/ 目录和 i18next 来看，fnOS 支持多语言，至少有中文（zh_CN）和西班牙语（es）有 biz 主题：从 body--biz 相关的 CSS 来看，fnOS 可能有"商业版"或"企业版"的主题，和普通版区分开3.3 前端文件的权限与更新www/ 目录下的文件都是打包后的静态文件，不是源码。这意味着：不能直接修改源码：要改前端界面，需要有源码，用构建工具重新打包可以直接替换打包后的文件：如果只是小改动（比如改个标题、换个图标），可以直接替换 www/ 下的对应文件升级会被覆盖：系统升级时，www/ 目录会被整体替换，自定义修改会丢失对于二次开发来说，如果要加自己的前端页面，有两种思路：在 www/ 下加静态文件：简单直接，但升级会被覆盖，且无法融入原有的菜单和路由体系通过 Nginx 配置加独立路由：在 Nginx 配置里加一个 location，把某个路径指向自己的前端文件目录，这样和原系统隔离，升级不受影响四、etc 目录：配置文件宝库etc/ 是 fnOS 的服务级配置文件目录，有 40+ 个配置文件。ls /usr/trim/etc/输出（分类整理）：4.1 版本与设备信息文件作用versionfnOS 版本号machine_id设备唯一标识system_inited_timestamp系统初始化时间戳fw.conf固件配置gpu_device_info.jsonGPU 设备信息我们来看版本号：cat /usr/trim/etc/version输出：1.2.0505fnOS 的版本号是 1.2.0505。注意这个版本号不在 /etc/os-release 里（那里只有 Debian 12 的信息），而是在 fnOS 自己的 /usr/trim/etc/version 里。这也是找 NAS 系统版本号的一个通用方法：去厂商的安装目录下找 version 文件。4.2 安全密钥与证书文件作用rsa_private_key.pemRSA 私钥rsa_public_key.pemRSA 公钥ssl.crtSSL 证书ssl.keySSL 私钥ssl.csrSSL 证书签名请求trim.key.enc加密的密钥文件download.key下载相关密钥这些密钥和证书主要用于：飞牛互联远程访问的加密通信Web 界面的 HTTPS应用下载的签名验证trim.key.enc 是加密的密钥文件，说明飞牛对核心密钥做了加密保护，不是明文存储。4.3 网络配置文件作用network_ssh.confSSH 配置network_gateway_cert.conf网关证书配置network_gateway_setting.conf网关设置network_cert_all.conf网络证书（全部）network_nic_performance_mode.conf网卡性能模式4.4 服务配置文件作用rpc_broker.confRPC 消息代理配置dockermgr.confDocker 管理配置smbftp.confFTP 服务配置webdav.confWebDAV 配置mediasrv.conf媒体服务配置minidlna.confDLNA 配置resmon_service.conf资源监控配置event_logger.conf事件日志配置diskcheck.conf硬盘检测配置trim_file_monitor.conf文件监控配置trim_nic_name_consistency.conf网卡名称一致性配置4.5 安全白名单文件作用appcgi_notoken_whitelist不需要 Token 认证的 CGI 接口白名单safe_code_whitelist.conf安全代码白名单trim_nosig_whitelist不需要签名验证的白名单这三个白名单文件很有意思，说明 fnOS 的安全机制：API 接口默认需要 Token 认证，白名单里的接口不需要代码执行有安全校验，白名单里的代码可以直接运行应用/文件默认需要签名验证，白名单里的不需要这对二次开发很重要——如果要加自己的 API 接口或应用，可能需要加到对应的白名单里，否则会被安全机制拦截。4.6 存储相关文件作用storage/存储配置目录（当前为空，可能运行时生成）scrub_watch.jsonZFS scrub（数据校验）监控配置upgrade.conf系统升级配置4.7 其他文件作用cloud_storage_dav/云存储 DAV 配置network_cert_all.conf.old旧的网络证书配置（备份）五、nginx 目录：自编译 NginxfnOS 用的不是 Debian 自带的 Nginx，而是自己编译的，放在 /usr/trim/nginx/ 下。ls /usr/trim/nginx/输出：client_body_temp conf fastcgi_temp html logs modules proxy_temp sbin scgi_temp test_js uwsgi_temp目录作用sbin/Nginx 二进制程序（/usr/trim/nginx/sbin/nginx）conf/Nginx 配置文件html/默认静态文件（可能不是主前端，主前端在 www/）logs/Nginx 日志modules/Nginx 模块（自编译的模块）test_js/测试用的 JS 文件*_temp/各种临时文件目录（client_body、fastcgi、proxy、scgi、uwsgi）从启动配置我们知道：ExecStartPre=/usr/trim/nginx/sbin/nginx -t ExecStart=/usr/trim/nginx/sbin/nginxNginx 启动前会先执行 nginx -t 测试配置文件，有语法错误就不启动，避免 Web 界面挂掉。自编译 Nginx 的好处：可以加自定义模块：modules/ 目录说明飞牛可能编译了自己的 Nginx 模块版本可控：不受 Debian 包管理器的版本限制，可以用最新版或特定版本路径独立：和系统 Nginx 完全隔离，不会冲突六、modules 目录：内核模块与多版本保留modules/ 是内核模块目录，存放飞牛定制内核的模块文件。ls /usr/trim/modules/输出：6.18.18.c1032-trim 6.18.18.c788-trim 6.18.18.c877-trim 6.18.18.c938-trim 6.18.18.c952-trim 6.18.18-trim飞牛保留了 6 个内核版本的模块！版本说明6.18.18.c1032-trim当前运行的版本6.18.18.c952-trim上一个版本6.18.18.c938-trim更早的版本6.18.18.c877-trim更早的版本6.18.18.c788-trim更早的版本6.18.18-trim最早的版本（没有 c 后缀）这说明：内核迭代非常频繁：从 c788 到 c1032，至少迭代了 5 个版本，说明飞牛对内核的更新很积极支持升级回滚：保留旧版本的内核模块，系统升级后如果新内核有问题，可以回滚到旧版本定制模块放在这里：trimafs2、zfs（飞牛定制版）这些自研内核模块，就放在对应版本的目录下标准的 Linux 内核模块放在 /lib/modules/$(uname -r)/ 下，飞牛把自己的内核模块额外放在 /usr/trim/modules/ 下，可能是为了升级时方便整体替换，或者是因为他们的内核模块和标准内核模块有冲突，需要独立存放。七、var 目录：各服务运行时数据var/ 存放各服务的运行时数据，每个服务有独立的子目录。ls /usr/trim/var/输出：ai_manager backup_service downloadcenter minidlna trim_connect auto_thumbnailer dockermgr eventlogger_service share_service目录对应服务存放内容ai_manager/AI 管理器AI 模型缓存、推理临时数据auto_thumbnailer/自动缩略图缩略图缓存backup_service/备份服务备份任务状态、临时文件dockermgr/Docker 管理Docker 相关状态downloadcenter/下载中心下载任务状态、临时文件eventlogger_service/事件日志事件日志数据minidlna/DLNADLNA 媒体库索引share_service/共享服务共享配置状态trim_connect/飞牛互联远程连接状态、临时数据这种"每个服务一个 var 子目录"的设计，和微服务架构是匹配的——每个服务独立管理自己的运行时数据，互不干扰，也方便清理和备份。八、其他目录8.1 lib 目录lib/ 存放 fnOS 自研程序依赖的库文件。虽然我们没有详细列出内容，但从目录存在可以推断，飞牛的一些程序可能依赖了特定版本的库，为了不和系统库冲突，单独放在这里。8.2 share 目录share/ 存放共享文件，可能包括：程序的资源文件（图标、模板、默认配置）文档示例文件8.3 config 目录config/ 存放运行时配置，和 etc/ 的区别可能是：etc/ 是静态的、出厂默认的配置config/ 是运行时生成的、用户修改过的配置我们看到 config/ 下有：appcgi_notoken_whitelist gpu_device_info.json trim_nosig_whitelist这些和 etc/ 下的文件有重叠，可能是运行时从 etc 复制过来并修改的，或者是用户在 Web 界面修改后保存到这里。8.4 logs 目录logs/ 存放 fnOS 的日志。标准的系统日志在 /var/log/ 下，fnOS 把自己的日志单独放在 /usr/trim/logs/ 下，方便统一管理和清理。九、二次开发的目录布局参考基于以上分析，如果要基于 fnOS 做二次开发（比如加一个自己的存证功能），推荐的目录布局如下：/usr/trim/ ← fnOS 原厂目录（升级会被覆盖，不要改） ├── bin/ ← 原厂程序 ├── etc/ ← 原厂配置 ├── www/ ← 原厂前端 └── ... /opt/myapp/ ← 自己的程序放在这里（和原厂隔离，升级不影响） ├── bin/ ← 自己的程序二进制 ├── etc/ ← 自己的配置 ├── www/ ← 自己的前端页面 ├── var/ ← 自己的运行时数据 └── logs/ ← 自己的日志 /etc/systemd/system/myapp.service ← 自己的 systemd 服务文件关键原则：不要修改 /usr/trim/ 下的任何文件。 因为系统升级时这个目录会被整体替换，你的修改会丢失。自己的东西放在 /opt/ 或 /usr/local/ 下，通过 systemd 服务和 Nginx 配置和原系统集成。对于前端页面，可以通过修改 Nginx 配置（在 /usr/trim/nginx/conf/ 下加一个 conf 文件，或者在主配置里 include 自己的配置），把某个路径（比如 /myapp/）指向自己的前端目录，这样和原系统的前端完全隔离，升级不受影响。十、系统解构方法论：怎么快速找到厂商的安装目录分析完 fnOS 的目录结构，我们可以总结出一套通用的方法论——拿到任何一台新 NAS（或其他 Linux 设备），怎么快速找到厂商的安装目录和核心程序：方法 1：从 systemd 服务入手# 列出所有运行中的服务，找名字特殊的（不是 Debian 原生的） systemctl list-units --type=service --state=running # 看某个可疑服务的配置，找 ExecStart 路径 systemctl cat <服务名>服务的 ExecStart 指向的程序路径，通常就在厂商的安装目录下。比如 fnOS 的 trim_main.service 的 ExecStart=/usr/trim/bin/trim，一看就知道厂商目录是 /usr/trim/。方法 2：从进程入手# 看所有进程，找路径特殊的 ps aux | grep -v '/usr/bin\|/usr/sbin\|/bin\|/sbin' # 或者看监听端口的进程 ss -tlnpWeb 服务、后端服务这些进程的可执行文件路径，通常就在厂商目录下。方法 3：从常见位置找NAS 厂商通常把自己的东西放在这些位置：/usr/厂商名/（比如 fnOS 的 /usr/trim/）/opt/厂商名//usr/local/厂商名//厂商名/（根目录下）可以直接 ls /usr/、ls /opt/ 看看有没有可疑的目录。方法 4：找版本号文件# 在常见位置找 version 文件 find /usr /opt /etc -name "version" -o -name "VERSION" 2>/dev/null # 或者找 os-release 的补充文件 cat /etc/*release* 2>/dev/null版本号文件通常在厂商的 etc 目录下，找到它也就找到了厂商目录。方法 5：从前端文件入手# 找 Nginx 配置，看 root 指向哪 find /etc /usr -name "nginx.conf" 2>/dev/null # 或者直接看常见的前端位置 ls /var/www/ /usr/share/nginx/html/ 2>/dev/nullWeb 前端文件的位置，通常也在厂商目录下。十一、总结通过本文的解析，我们对 fnOS 的系统目录结构和技术栈有了完整的认知：统一安装目录：所有 fnOS 自研的东西都在 /usr/trim/ 下，和 Debian 系统完全隔离，11 个子目录布局清晰自研程度极高：100+ 自研程序，从核心主进程、用户管理（useradd）、FTP 服务（smbftpd），到 mdadm 这些基础工具都有自己的版本，不是简单套用开源软件微服务架构：每个功能一个独立程序，通过 rpc_broker 通信，职责清晰，易于维护和扩展前端技术栈现代：React + TypeScript + Semi Design（字节组件库）+ Rolldown 打包 + i18next 国际化，技术栈比较新自编译 Nginx：独立目录、独立模块、启动前配置测试，和系统 Nginx 完全隔离多版本内核保留：保留 6 个版本的内核模块，支持升级回滚，内核迭代频繁配置体系完善：40+ 配置文件，涵盖版本、密钥、网络、服务、安全白名单等，安全机制严密二次开发建议：不要修改 /usr/trim/ 下的文件，自己的东西放在 /opt/ 下，通过 systemd 和 Nginx 配置集成系列预告下一篇《飞牛 fnOS 深度解析（四）：文件服务与用户权限体系》，我们将详细解析：SMB/CIFS 服务的配置与认证机制（Samba 用什么认证后端？共享配置是动态生成的吗？）NFS、WebDAV、FTP 的实现方式（飞牛自己的 smbftpd 是什么？）四种文件协议的对比与统一认证Web 用户和 Linux 系统用户的关系（/usr/trim/bin/useradd 做了什么？）用户信息存在哪里（/etc/passwd？PostgreSQL？）权限是 POSIX ACL 还是自研的 trimacl？跨协议权限怎么保证一致？敬请期待。本文基于 fnOS 1.2.0505 版本实测，不同版本可能存在差异。二次开发有风险，请勿在生产环境随意修改系统文件。
飞牛 fnOS 深度解析（二）：存储架构深挖——ZFS、LVM 与自研 trimafs 联合文件系统
本系列文章将对国产 NAS 系统飞牛 fnOS 进行全方位深度解析。本文是系列第二篇，聚焦存储架构，从物理盘、RAID、LVM 到文件系统，一层一层剥开 fnOS 的存储底层，重点解析飞牛自研的 trimafs 联合文件系统和 trimacl 权限机制。阅读本文前，建议先阅读第一篇：飞牛 fnOS 深度解析（一）：系统基础与启动流程全揭秘前言存储是 NAS 系统的核心。一台 NAS 不管界面多漂亮、功能多丰富，底层的存储架构决定了它的数据安全性、扩展性和性能上限。群晖有 SHR，威联通有 Qtier，飞牛 fnOS 的存储方案是什么？官方宣传里提到的"存储池"、"智能合并"背后是什么技术？是用的开源 ZFS？还是 mdadm + LVM 的传统方案？还是自研了什么东西？本文将通过 SSH 登录系统，用最原始的命令行方式，从物理盘到文件系统，一层一层解析 fnOS 的存储架构。测试环境：fnOS 1.2.0505，x86_64 平台，4 块硬盘（1×NVMe SSD 119G + 1×SATA 931G + 2×SATA 465G），8G 内存。一、存储架构总览先看最终的挂载情况：df -h关键输出：Filesystem Size Used Avail Use% Mounted on /dev/nvme0n1p2 63G 14G 46G 24% / /dev/nvme0n1p1 93M 8.1M 85M 9% /boot/efi trim_6c71e3b3-... 900G 99M 900G 1% /vol2 /dev/mapper/trim_d1c5b5d5-... 932G 15G 915G 2% /vol3 /dev/mapper/trim_a7d015a3-... 56G 25G 29G 47% /vol1 trimafs 1.9T 40G 1.8T 3% /fs可以看到，fnOS 有 4 个数据挂载点：/vol1、/vol2、/vol3、/fs，加上系统盘 /。再看块设备层级：lsblk输出：NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 931.5G 0 disk └─sda1 8:1 0 931.5G 0 part sdb 8:16 0 465.8G 0 disk └─sdb1 8:17 0 465.8G 0 part └─md1 9:1 0 931.3G 0 raid0 └─trim_d1c5b5d5_... 253:1 0 931.3G 0 lvm /vol3 sdc 8:32 0 465.8G 0 disk └─sdc1 8:33 0 465.8G 0 part └─md1 9:1 0 931.3G 0 raid0 └─trim_d1c5b5d5_... 253:1 0 931.3G 0 lvm /vol3 nvme0n1 259:0 0 119.2G 0 disk ├─nvme0n1p1 259:1 0 94M 0 part /boot/efi ├─nvme0n1p2 259:2 0 63.9G 0 part / └─nvme0n1p3 259:3 0 55.2G 0 part └─md0 9:0 0 55.2G 0 raid1 └─trim_a7d015a3_... 253:0 0 55.2G 0 lvm /vol1综合这两条命令，fnOS 的存储架构是一个四层混合架构：┌─────────────────────────────────────────────────────────────┐ │ 挂载点（用户可访问） │ │ / /vol1 /vol2 /vol3 /fs │ └──┬────────┬──────────┬───────────┬────────────┬──────────────┘ │ │ │ │ │ ┌──▼────────▼──────────▼───────────▼────────────▼──────────────┐ │ 文件系统层 │ │ ext4 ext4 ZFS ext4 trimafs(联合层) │ └──┬────────┬──────────┬───────────┬────────────┬──────────────┘ │ │ │ │ │ ┌──▼────────▼──────────▼───────────▼────────────▼──────────────┐ │ 逻辑卷层 │ │ 无 LVM 无(ZFS自带) LVM 无 │ └──┬────────┬──────────┬───────────┬────────────┬──────────────┘ │ │ │ │ │ ┌──▼────────▼──────────▼───────────▼────────────▼──────────────┐ │ RAID 层 │ │ 无 mdadm RAID1 无(单盘) mdadm RAID0 无 │ └──┬────────┬──────────┬───────────┬────────────┬──────────────┘ │ │ │ │ │ ┌──▼────────▼──────────▼───────────▼────────────▼──────────────┐ │ 物理硬盘 │ │ nvme0n1p2 nvme0n1p3 sda sdb + sdc (跨vol2+vol3) │ │ (63G系统) (55G) (931G) (465G×2) │ └─────────────────────────────────────────────────────────────────┘一句话总结：系统盘用 NVMe SSD，数据盘同时使用了 mdadm 软 RAID + LVM 和 ZFS 两种方案，最上面还有一层自研的 trimafs 联合文件系统把多个卷合并成统一入口。下面我们一层一层详细解析。二、物理盘层：4 块硬盘的分工这台机器有 4 块硬盘，分工明确：设备类型大小用途nvme0n1NVMe SSD119.2G系统盘 + vol1（高速存储）sdaSATA 硬盘931.5GZFS 存储池（vol2）sdbSATA 硬盘465.8GRAID0 成员（vol3）sdcSATA 硬盘465.8GRAID0 成员（vol3）NVMe SSD 被分成了 3 个分区：分区大小挂载点用途nvme0n1p194M/boot/efiEFI 引导分区nvme0n1p263.9G/系统根分区nvme0n1p355.2G→ md0 → LVM → /vol1高速数据卷设计思路很清晰：系统和引导放在 NVMe SSD 上，保证开机速度和系统响应划出一部分 NVMe 空间作为高速数据卷（vol1），适合存 Docker 配置、数据库等需要高速 IO 的数据大容量 SATA 硬盘作为数据存储，分别走 ZFS 和 RAID0 两种方案三、RAID 层：mdadm 软 RAID 的巧妙设计fnOS 使用 Linux 原生的 mdadm（multiple devices admin）做软 RAID。cat /proc/mdstat输出：Personalities : [raid0] [raid1] [raid4] [raid5] [raid6] [raid10] [linear] md1 : active raid0 sdc1[1] sdb1[0] 976506880 blocks super 1.2 512k chunks md0 : active raid1 nvme0n1p3[0] 57891840 blocks super 1.2 [1/1] [U] unused devices: <none>有两个 md 设备：md0 和 md1。3.1 md1（vol3 的底层）：标准双盘 RAID0md1 : active raid0 sdc1[1] sdb1[0] 976506880 blocks super 1.2 512k chunks成员：sdb1 + sdc1，两块 465G 硬盘级别：RAID0（条带化）总容量：976506880 blocks ≈ 931G（465×2）条带大小：512k chunks状态：active（正常）RAID0 的原理是把数据切成小块，轮流存在两块盘上，读写时两块盘同时工作，性能翻倍，容量也是两块盘之和。但代价是没有冗余——任何一块盘坏了，所有数据都没了。vol3 用 RAID0，适合存电影、下载等可以重新获取的数据，追求大容量和高性能，不追求安全性。3.2 md0（vol1 的底层）：单盘 RAID1 的巧妙设计md0 : active raid1 nvme0n1p3[0] 57891840 blocks super 1.2 [1/1] [U]这是最有意思的地方：成员：只有 nvme0n1p3 一块盘级别：RAID1（镜像）容量：57891840 blocks ≈ 55.2G状态：[1/1] [U] —— 期望1盘/实际1盘/状态正常正常来说，RAID1 至少需要两块盘，把同一份数据写两份，一块盘坏了另一块还有。但这里只有一块盘也做成了 RAID1。这不是降级状态（降级会显示 [2/1] [_U]），而是飞牛故意设计的单盘 RAID1。为什么要这么设计？好处很明显：方便后期扩容。如果用户一开始只有一块盘，直接用裸盘或 LVM，后期想加第二块盘做镜像保护，操作非常麻烦——需要备份数据、重新建 RAID、恢复数据。但如果一开始就把单盘封装成 RAID1（虽然只有一个成员），后期加第二块盘时，只需要一条命令把新盘加进这个 RAID1，系统就会自动开始同步数据，同步完成后就变成了真正的双盘镜像。全程不需要重新格式化，不需要迁移数据，业务不中断。这是一个非常巧妙的设计，用很小的开销（RAID1 层的一点点性能损耗）换取了后期扩容的极大便利性。3.3 内核支持完整的 RAID 级别从 Personalities 一行可以看到：[raid0] [raid1] [raid4] [raid5] [raid6] [raid10] [linear]fnOS 的内核支持所有主流 RAID 级别，包括 RAID5/6 这些需要校验的级别。说明飞牛的存储方案不只是支持简单的 RAID0/1，多盘场景下应该也支持 RAID5/6。四、LVM 层：逻辑卷管理与工具移除在 RAID 层之上，vol1 和 vol3 都套了一层 LVM（Logical Volume Manager，逻辑卷管理器）。从 lsblk 可以看到：md0 (raid1) → trim_a7d015a3_... (lvm) → /vol1 md1 (raid0) → trim_d1c5b5d5_... (lvm) → /vol3LVM 的逻辑卷设备路径是 /dev/mapper/trim_xxx，这是标准的 LVM 设备映射路径。4.1 LVM 的作用LVM 是 Linux 下的逻辑卷管理工具，它在物理盘和文件系统之间加了一层抽象，主要好处是：灵活调整分区大小：传统分区大小定死了就不好改，LVM 可以在线扩大逻辑卷多盘合并：可以把多块盘的空间合并成一个大卷快照：LVM 支持快照功能但在 fnOS 这里，LVM 的使用方式比较简单——每个 RAID 阵列对应一个逻辑卷，1:1 映射，没有做复杂的空间池化。也就是说，LVM 在这里主要是为了获得"在线扩容"的能力，而不是为了多盘合并。4.2 管理工具被移除一个值得注意的现象是：fnOS 系统里没有安装 LVM 的管理命令。pvs # -bash: pvs: command not found vgs # -bash: vgs: command not found lvs # -bash: lvs: command not found dmsetup ls # -bash: dmsetup: command not foundpvs（看物理卷）、vgs（看卷组）、lvs（看逻辑卷）、dmsetup（设备映射管理）这些 LVM 的标准管理工具全部不存在。但 /etc/lvm/ 目录是存在的：ls /etc/lvm/ archive backup lvm.conf lvmlocal.conf profile说明 LVM 的配置和备份机制还在，只是管理命令被移除了。这是飞牛的设计理念：底层用了高级技术，但把管理命令都藏起来，所有存储操作只能通过 Web 界面进行。 这样做的好处是防止用户在命令行下误操作搞坏存储，坏处是高级用户失去了命令行管理的灵活性。同样的情况也出现在 ZFS 上（下一节会讲到）。五、文件系统层：ZFS + ext4 + trimafs文件系统是存储架构的最上层，直接决定了数据怎么存、怎么管理、有哪些高级功能。fnOS 同时使用了三种文件系统：ext4、ZFS、trimafs（自研）。5.1 ext4：经典可靠vol1 和 vol3（LVM 逻辑卷之上）使用的是 ext4 文件系统。ext4 是 Linux 最经典、最稳定的文件系统，几乎所有 Linux 发行版的默认文件系统都是它。它的特点是稳定、成熟、性能好，但没有快照、数据校验等高级功能。fnOS 把 ext4 用在 LVM 卷上，是一个稳妥的选择——对于不需要高级功能的存储卷，ext4 是最可靠的选择。5.2 ZFS：高级功能与飞牛定制vol2 使用的是 ZFS 文件系统。ZFS 的确认证据虽然 zfs 和 zpool 命令被移除了（和 LVM 工具一样），但我们可以通过其他方式确认 ZFS 的存在：1. 内核模块已加载：lsmod | grep zfs输出：zfs 5849088 28 spl 131072 1 zfszfs 模块（约 5.6MB）和它的依赖 spl（Solaris Porting Layer）都已加载。2. 挂载参数显示 ZFS：mount | grep vol2输出：trim_6c71e3b3-8964-4324-9c51-5adc8ca42fb5 on /vol2 type zfs (rw,noatime,xattr,trimacl,casesensitive)文件系统类型明确是 zfs。3. ZFS 快照目录存在：ls -la /vol2/.zfs/输出：drwxr-xr-x 3 root root 2 Sep 3 15:32 shares drwxr-xr-x 3 root root 2 Jul 20 09:39 snapshot.zfs 是 ZFS 的特殊隐藏目录，里面有 snapshot（快照）和 shares（共享）子目录。这是 ZFS 的标志性特征，其他文件系统没有这个目录。4. 快照已挂载：trim_6c71e3b3-...@UTC_08-2026.07.20-09.39.25 on /vol2/.zfs/snapshot/UTC_08-2026.07.20-09.39.25 type zfs (ro,relatime,xattr,trimacl,casesensitive)有一个 2026年7月20日的自动快照，以只读方式挂载在 .zfs/snapshot/ 下。用户可以通过这个目录访问文件的历史版本。ZFS 数据集命名ZFS 的数据集名是 trim_6c71e3b3-8964-4324-9c51-5adc8ca42fb5，这是一个 UUID 格式的名字，不是人类可读的名字（比如 tank/vol2）。说明飞牛在创建 ZFS 池时，用 UUID 作为数据集名，可能是为了避免命名冲突或统一管理。挂载参数分析rw,noatime,xattr,trimacl,casesensitive参数说明rw读写模式noatime不更新文件访问时间，提升性能xattr支持扩展属性trimacl⚠️ 飞牛自定义的 ACL 挂载选项casesensitive大小写敏感重大发现：trimacl —— 飞牛给 ZFS 打的内核补丁这里最值得关注的是 trimacl 这个挂载参数。标准 ZFS 没有 trimacl 这个挂载选项。 ZFS 的 ACL 相关参数是 acltype（posixacl/nfsv4acl）、aclmode 等，从来没有 trimacl。这说明：飞牛对 ZFS 内核模块打了补丁，增加了自己的 ACL 实现，命名为 trimacl。为什么要这么做？推测原因：跨文件系统统一权限：fnOS 同时使用 ZFS 和 ext4，两种文件系统的 ACL 机制不同（ZFS 用 NFSv4 ACL，ext4 用 POSIX ACL）。飞牛需要一个统一的权限层，让用户在 Web 界面设置的权限，不管底层是 ZFS 还是 ext4，行为都一致。和 SMB/NFS 权限对齐：NAS 的文件共享主要走 SMB 和 NFS，这两种协议的权限模型和 Linux 本地权限不完全一样。飞牛可能需要一个自定义的 ACL 层来更好地对齐 SMB/NFS 的权限语义。和 trimafs 配合：后面会讲到，飞牛还有一层 trimafs 联合文件系统，它也需要统一的权限管理。trimacl 可能是贯穿 ZFS/ext4/trimafs 的统一权限机制。不管具体实现是什么，trimacl 的存在说明：飞牛不是简单套用开源 ZFS，而是对 ZFS 做了内核级的定制开发。 这是有相当技术含量的工作。ZFS 在 fnOS 中的定位vol2 是单盘 ZFS（只有 sda 一块盘），所以没有 RAID 冗余（一块盘坏了数据还是没了），但享受了 ZFS 的高级功能：快照：自动创建快照，用户可以恢复误删/误改的文件数据校验：每个块都有校验和，读取时自动检测数据损坏Copy-on-Write：写时复制，不会因为中途断电导致文件损坏压缩：ZFS 支持透明压缩（虽然这里没看到压缩参数，但可能默认开了）Docker 的数据目录也设在了 vol2 上（/vol2/docker/），利用 ZFS 的快照和数据校验保护容器数据和镜像。5.3 trimafs：飞牛自研联合文件系统（重点）最后来说最神秘的 /fs，它使用的文件系统叫 trimafs。trimafs 的确认cat /proc/filesystems | grep trim输出：nodev trimafsnodev 表示这个文件系统不需要对应块设备——它不是直接管理物理硬盘的文件系统，而是在其他文件系统之上做一层抽象。lsmod | grep trim输出：trimafs2 77824 1内核模块名叫 trimafs2（注意是 2，第二版），大小只有 77824 字节（约 76KB），被 1 处引用。mount | grep ' /fs '输出：trimafs on /fs type trimafs (rw,relatime,trimacl)挂载参数里也有 trimacl——和 ZFS 用的是同一个自定义 ACL 机制。ps aux | grep trimafs没有 trimafs 的用户态进程（只有 grep 自己）。说明 trimafs 不是 FUSE 用户态文件系统，而是纯内核模块实现。trimafs 是什么？综合以上证据：纯内核模块实现（不是 FUSE）nodev，不直接管理块设备模块名 trimafs2，已经迭代到第二版仅 76KB，轻量级挂载参数支持 trimacl，和 ZFS 统一权限总容量 1.9T ≈ vol2(900G) + vol3(932G)结论：trimafs 是飞牛自研的内核级联合文件系统（Union Filesystem），它的作用是把多个底层存储卷（vol2、vol3）合并成一个统一的命名空间 /fs，让用户感觉像是在一个大文件夹里操作，实际上文件可能分布在不同的物理卷上。类似的开源方案有 mergerfs、unionfs、aufs，但飞牛选择了自己实现一个内核模块，而不是用开源方案。trimafs 的工作原理验证我们来验证一下 trimafs 是不是真的把 vol2 和 vol3 联合起来了。看 /fs 下的目录：ls -la /fs/输出：drwxrwxrwx 5 root root 0 Sep 3 08:03 . drwxr-xr-x 25 root root 4096 Sep 3 08:03 .. drwxr-xr-x 3 root root 0 Sep 3 08:03 1000 drwxr-xr-x 3 root root 0 Sep 3 08:03 1001 drwxr-xr-x 3 root root 0 Sep 3 08:03 1002/fs 下只有三个目录：1000、1001、1002——这是三个用户的 UID（用户 ID），对应用户的个人存储空间。再看 /vol2 下的目录：ls -la /vol2/输出：d--------- 2 dio root 2 Jul 14 12:40 1000 d--------- 2 D root 2 Jul 18 09:08 1001 d--------- 2 D1 root 2 Jul 18 09:09 1002 drwxr-x--- 2 root root 2 Aug 4 08:58 appcenter-downloads drwxr-xr-x 3 root root 3 Jul 20 09:38 @appmeta drwx--x--- 12 root root 13 Sep 3 08:03 docker d------r-x 3 root root 3 Jul 20 08:58 @team d--------- 9 root root 9 Jul 20 09:38 thumb/vol2 下也有 1000、1001、1002 三个用户目录，属主分别是 dio（UID 1000）、D（UID 1001）、D1（UID 1002）。再看 /vol3 下的目录：ls -la /vol3/输出：d--------- 1 dio root 80 Aug 6 00:11 1000 d--------- 1 D root 0 Jul 20 18:28 1001 d--------- 1 D1 root 0 Jul 20 18:28 1002 drwxr-x--- 1 root root 0 Aug 5 15:04 appcenter-downloads drwxr-xr-x 1 root root 26 Jul 20 19:03 @appmeta d--------- 1 root root 62 Jul 20 19:03 thumb/vol3 下同样有 1000、1001、1002 三个用户目录。真相大白：每个用户在 vol2 和 vol3 上都有自己的目录，trimafs 把这两个位置的同名目录联合成 /fs/1000/ 一个入口。 用户通过 /fs/1000/ 访问自己的文件时，trimafs 自动把文件分布到 vol2 和 vol3 上，用户不需要关心文件实际存在哪块盘。空间使用情况也验证了这一点：挂载点总容量已用/fs（trimafs）1.9T40G/vol2（ZFS）900G99M/vol3（ext4）932G15G/fs 的 1.9T 正好约等于 vol2(900G) + vol3(932G)。trimafs 的设计意义trimafs 是飞牛存储架构的核心创新，它解决了几个问题：统一入口：用户不需要关心自己的文件存在哪个卷、哪块盘，只需要知道 /fs/我的目录/ 就行跨文件系统透明：不管底层是 ZFS 还是 ext4，用户看到的都是统一的目录结构和权限行为（通过 trimacl 统一）自动负载均衡：trimafs 可以根据各卷的空间使用情况，自动决定新文件存在哪个卷上在线扩容：加一块新盘、建一个新卷，trimafs 可以把它加入联合，用户无感知这就是飞牛官方宣传的"存储池"、"智能合并"背后的技术实现——不是什么黑科技，而是一个自研的内核级联合文件系统，但做得很轻量（76KB）、很底层（内核模块）、和权限系统深度整合（trimacl）。六、数据目录结构了解了存储架构之后，我们来看看数据在各卷上是怎么组织的。6.1 用户数据每个用户（按 UID）在每个数据卷上都有自己的目录：/vol2/1000/ → 用户 dio 在 ZFS 卷上的个人空间 /vol3/1000/ → 用户 dio 在 ext4 卷上的个人空间 /fs/1000/ → trimafs 联合后的统一入口（用户实际访问的位置）目录权限是 d---------（700），只有属主本人能访问，安全性不错。6.2 系统数据除了用户目录，每个卷上还有一些系统目录：目录存在位置用途@appmetavol2、vol3应用元数据appcenter-downloadsvol2、vol3应用中心下载缓存thumbvol2、vol3缩略图缓存docker仅 vol2Docker 数据（镜像、容器、卷）@team仅 vol2团队空间？可以看到，@appmeta、appcenter-downloads、thumb 这些目录在每个卷上都有——说明每个存储卷有自己独立的应用元数据和缓存。而 Docker 数据只在 vol2（ZFS）上，因为飞牛把 Docker 默认数据目录设在了 ZFS 卷上，利用 ZFS 的快照和校验保护容器数据。带 @ 前缀的目录（@appmeta、@team）是飞牛的命名约定，用来标识系统目录，和用户目录区分开。七、存储解构方法论：5 条命令摸清新 NAS 的存储分析完 fnOS 的存储架构，我们可以总结出一套通用的方法论——拿到任何一台新 NAS（包括其他品牌的设备），用以下 5 条命令，5 分钟内就能摸清它的存储架构：命令 1：看挂载和文件系统df -h看有哪些挂载点、各自多大、用了多少看文件系统类型（ext4？xfs？zfs？btrfs？还是自研的？）重点关注非标准的文件系统类型（比如 fnOS 的 trimafs）命令 2：看块设备层级lsblk看有几块物理盘、每块盘怎么分区看有没有 RAID 设备（md0、md1）看有没有 LVM 逻辑卷（dm-0、dm-1，或 /dev/mapper/ 路径）看挂载点和物理盘的对应关系这是最核心的一条命令，一张图就能看清整个存储栈命令 3：看软 RAIDcat /proc/mdstat看有几个 md 设备、各自是 RAID 几看成员盘有哪些、状态是否正常看条带大小等参数命令 4：看内核模块（找自研文件系统）lsmod | grep -E 'zfs|trim|fuse|union|btrfs'看加载了哪些文件系统相关的内核模块重点找非标准的模块名（比如 fnOS 的 trimafs2）这些自研模块往往是厂商的核心技术命令 5：看注册的文件系统类型cat /proc/filesystems看内核注册了哪些文件系统类型nodev 的是不直接管理块设备的虚拟文件系统（比如联合文件系统、网络文件系统）找非标准的文件系统名（比如 fnOS 的 trimafs）bonus：看厂商安装目录ls /usr/trim/ # fnOS 的安装目录 # 其他品牌可能在 /usr/local/、/opt/、或自己的命名目录找厂商的自研程序、配置、脚本看版本号文件（通常在 etc/version 或类似位置）看有没有自研的存储管理工具八、总结通过本文的深度解析，我们对 fnOS 的存储架构有了完整的认知：四层混合架构：物理盘 → mdadm RAID → LVM/ZFS → 文件系统（ext4/ZFS/trimafs），同时使用多种存储技术，不是一刀切的方案巧妙的 RAID 设计：单盘也封装成 RAID1，方便后期加盘做镜像，不需要重新格式化和迁移数据ZFS 内核级定制：不是简单套用开源 ZFS，而是打了 trimacl 内核补丁，实现跨文件系统的统一权限管理trimafs 自研联合文件系统：76KB 的轻量内核模块，把多个存储卷合并成统一入口，是飞牛"存储池"概念的底层实现，已经迭代到第二版管理工具移除策略：LVM 和 ZFS 的命令行管理工具全部被移除，所有存储操作只能通过 Web 界面，防止用户误操作数据分层存储：Docker 数据放 ZFS 卷（利用快照和校验），用户数据通过 trimafs 自动分布，系统缓存每个卷独立管理fnOS 的存储架构不是简单的"拿来主义"，而是在开源技术的基础上做了不少自研和定制，尤其是 trimafs 和 trimacl 这两个内核级组件，体现了相当的技术功底。系列预告下一篇《飞牛 fnOS 深度解析（三）：文件服务与用户权限体系》，我们将详细解析：SMB/CIFS 服务的配置与认证机制NFS、WebDAV、FTP 的实现方式四种文件协议的对比与统一认证Web 用户和 Linux 系统用户的关系用户信息存在哪里（/etc/passwd？数据库？）权限是 POSIX ACL 还是自研的 trimacl？跨协议权限怎么保证一致敬请期待。本文基于 fnOS 1.2.0505 版本实测，不同版本可能存在差异。存储操作有风险，请勿在生产环境随意执行本文中的命令。
飞牛 fnOS 深度解析（一）：系统基础与启动流程全揭秘
本系列文章将对国产 NAS 系统飞牛 fnOS 进行全方位深度解析，从系统底层、存储架构、文件服务、用户权限，到 Web 前后端架构、应用生态、镜像定制，力争讲清楚每一个模块"是什么、怎么实现、配置文件在哪、关键命令是什么"。本文是系列第一篇，聚焦系统基础信息摸底与启动流程追踪。前言飞牛 fnOS 是近年来国产 NAS 系统中关注度较高的一款，以易用的 Web 管理界面和丰富的应用生态著称。但作为一个基于 Linux 的 NAS 系统，它的底层到底做了哪些定制？启动流程是怎样的？Web 界面背后跑着哪些服务？本系列将通过 SSH 登录系统，用最原始的命令行方式，一层一层剥开 fnOS 的外壳，看看里面到底是什么。测试环境：fnOS 1.2.0505，x86_64 平台，4 块硬盘（1×NVMe SSD + 3×SATA HDD），8G 内存。一、系统基础信息摸底1.1 系统版本与内核首先看系统版本：cat /etc/os-release输出：PRETTY_NAME="Debian GNU/Linux 12 (bookworm)" NAME="Debian GNU/Linux" VERSION_ID="12" VERSION="12 (bookworm)" VERSION_CODENAME=bookworm ID=debianfnOS 基于 Debian 12 (bookworm)，但有意思的是，/etc/os-release 里完全没有 fnOS 自己的版本标识，是纯 Debian 的内容。fnOS 的版本号存在别的地方（后面会提到）。再看内核：uname -a输出：Linux DIO 6.18.18.c1032-trim #1032 SMP PREEMPT_DYNAMIC Fri Aug 21 01:49:29 UTC 2026 x86_64 GNU/Linux这里有几个关键点：内核版本 6.18.18，非常新，远高于 Debian 12 自带的 6.1 内核c1032-trim 后缀，这是飞牛自己的编译标记，说明内核是飞牛定制编译的PREEMPT_DYNAMIC，动态抢占内核，偏向桌面/响应式优化，不是服务器吞吐量优先编译时间 2026-08-21，非常新结论：fnOS 没有用 Debian 自带内核，而是自己编译了一个很新的 6.18 内核，并打上了自己的标记。1.2 硬件与分区概览lsblk输出：NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 931.5G 0 disk └─sda1 8:1 0 931.5G 0 part sdb 8:16 0 465.8G 0 disk └─sdb1 8:17 0 465.8G 0 part └─md1 9:1 0 931.3G 0 raid0 └─trim_d1c5b5d5_... 253:1 0 931.3G 0 lvm /vol3 sdc 8:32 0 465.8G 0 disk └─sdc1 8:33 0 465.8G 0 part └─md1 9:1 0 931.3G 0 raid0 └─trim_d1c5b5d5_... 253:1 0 931.3G 0 lvm /vol3 nvme0n1 259:0 0 119.2G 0 disk ├─nvme0n1p1 259:1 0 94M 0 part /boot/efi ├─nvme0n1p2 259:2 0 63.9G 0 part / └─nvme0n1p3 259:3 0 55.2G 0 part └─md0 9:0 0 55.2G 0 raid1 └─trim_a7d015a3_... 253:0 0 55.2G 0 lvm /vol1这台机器有 4 块硬盘：设备类型大小用途nvme0n1NVMe SSD119.2G系统盘 + vol1sdaSATA 硬盘931.5GZFS 存储池（vol2）sdbSATA 硬盘465.8GRAID0 成员（vol3）sdcSATA 硬盘465.8GRAID0 成员（vol3）存储架构是混合的：系统盘用 NVMe SSD，数据盘同时使用了 mdadm 软 RAID + LVM 和 ZFS 两种方案。这部分我们将在系列第二篇《存储架构深挖》中详细展开。1.3 运行服务统计systemctl list-units --type=service --state=running一共 81 个服务在运行。这个数字相当可观，说明 fnOS 的功能模块拆得很细。快速浏览服务列表，会发现一个明显的规律：fnOS 自研的服务大多以 trim_ 开头，这和内核版本里的 c1032-trim 标记对应上了——"trim" 应该是飞牛的内部代号。二、服务清单深度分析2.1 fnOS 自研服务识别在 81 个运行服务中，以 trim_ 开头的有 21 个：服务名作用trim_main.service核心主服务trim_nginx.serviceWeb 服务（自编译 Nginx）trim_init.service系统初始化trim_connect.service飞牛互联远程访问trim_open_gateway.service开放网关trim_app_center.service应用中心trim_license.service许可证管理trim_upload.service上传服务trim_sharelink.service分享链接trim_file_monitor.service文件监控trim_http_cgi.serviceHTTP CGI 接口trim_sac.service系统应用控制trim_tfa.service双因素认证trim_trashbind.service回收站trim_diskpowerd.service硬盘电源管理trim_raid_check.serviceRAID 检查trim_nic_name_consistency.service网卡名称一致性trim_clean_up.service清理服务trim-docs-docservice.service文档服务trim-docs-fileconverter.service文件转换服务除了 trim_ 前缀的，还有大量不带前缀但同样是 fnOS 自研的服务，比如 accountsrv（账户服务）、usersrv（用户服务）、filestor_service（文件存储服务）、rpc_broker（RPC 消息代理）、dockermgr（Docker 管理）、ai_manager（AI 管理）等，加起来 fnOS 自研服务大约有 40+ 个。2.2 服务分类总览把 81 个服务按功能分类：分类代表服务数量核心基础设施trim_main、rpc_broker、trim_init、system_startup~5Web 服务trim_nginx、trim_http_cgi、trim_open_gateway~3用户与权限accountsrv、usersrv、security_service、trim_tfa~4文件存储filestor_service、finder_service、share_service、trim_file_monitor~5文件协议smbd、nmbd、winbind、nfs-*、webdav、smbftpd、wsdd2~10网络network_service、avahi、upnp、ipblocker、trim_connect、ovs-*~8Docker/应用docker、dockermgr、dsmgr、trim_app_center、trim_sac~5AI/媒体ai_manager、imagesrv、mediasrv、auto_thumbnailer、minidlna~5备份/下载backup_service、dlcenter、multiple-downloads~3系统管理updatemgr、sysdiag、sysinfo、sysrestore、resmon、eventlogger~6硬件定制led-set、pwm-fancontrol、set_gpio-init、system_setmac、resize-rootfs~6Debian 原生ssh、cron、dbus、NetworkManager、postgresql、rsyslog 等~15值得注意的是，fnOS 甚至用了 Open vSwitch（ovs-vswitchd、ovsdb-server），这是一个虚拟交换机，通常用于虚拟化和容器网络，说明飞牛的网络架构不是简单的物理网卡配置。2.3 被飞牛覆盖的 Debian 原生服务在 /etc/systemd/system/ 目录下，我们发现了几个熟悉的名字：docker.service、smbd.service、nmbd.service、sshd.service、avahi.service。这些本来是 Debian 包自带的服务，但飞牛在 /etc/systemd/system/ 里放了自己的版本，覆盖了原生配置。这意味着飞牛修改了这些服务的启动参数、依赖关系，甚至替换了二进制程序。一个典型的例子是 nmbd.service（Samba 的 NetBIOS 名称服务），它的启动时间异常地长（后面会详细分析），很可能就是飞牛修改配置导致的。三、启动流程全链路追踪搞清楚有哪些服务之后，接下来的问题是：这些服务是按什么顺序启动的？从按电源到 Web 管理界面能打开，中间经历了什么？3.1 启动耗时分析systemd-analyze blame这条命令按启动耗时从长到短排序，前几名如下：排名服务耗时1nmbd.service1分30秒2system_startup.service12.3秒3NetworkManager-wait-online.service7.8秒4dockermgr.service5.0秒5accountsrv.service5.0秒6auto_thumbnailer.service5.0秒7trim_connect.service5.0秒8trim_open_gateway.service5.0秒9trim_nginx.service4.1秒10postgresql@15-main.service2.8秒几个值得注意的点：nmbd 花了 1分30秒，这是最大的异常，后面单独分析system_startup 花了 12.3秒，这是 fnOS 自己的初始化脚本多个 fnOS 服务（dockermgr、accountsrv、trim_connect 等）都正好 5 秒左右，这不是巧合，很可能是这些服务都有一个 5 秒的初始化等待，或者都依赖同一个 5 秒才就绪的东西PostgreSQL 数据库启动只要 2.8 秒，不算瓶颈trim_nginx（Web 服务）4.1 秒，也不算慢3.2 关键路径分析systemd-analyze critical-chain输出：graphical.target @1min 41.828s └─multi-user.target @1min 41.828s └─winbind.service @1min 41.744s +84ms └─network.target @4.292s └─networking.service @4.168s +122ms └─ovs-vswitchd.service @3.834s +296ms └─ovsdb-server.service @3.565s +267ms └─network-pre.target @3.563s └─system_setmac.service @3.535s +26ms └─basic.target @3.502s └─resize-rootfs.service @3.218s +283ms └─sysinit.target @3.213s这棵树展示了决定整体启动时间的最长依赖链。有一个非常反直觉的发现：网络在开机后 4.3 秒就就绪了！但 graphical.target（系统完全启动的标志）要等到 1分41秒。中间这 97 秒在等什么？答案是 winbind.service——它在 1分41.7秒才开始启动，只花了 84ms。winbind 为什么等这么久？因为它在等 nmbd（就是那个花了 1分30秒的 NetBIOS 服务）。所以实际的瓶颈链是：nmbd.service（1分30秒）→ winbind.service（84ms）→ graphical.target3.3 从开机到 Web 可用的完整时序综合 blame 和 critical-chain 的数据，我们可以画出完整的启动时序：0s 开机 → BIOS/UEFI → 加载内核(6.18.18.c1032-trim) → systemd 启动 ↓ 0.3s systemd-journald（日志）、加载内核模块 ↓ 3.2s sysinit.target（系统初始化完成） ↓ 3.5s 硬件定制：system_setmac（设MAC）、set_gpio-init、led-set、pwm-fancontrol ↓ 3.8s 网络启动：ovsdb-server → ovs-vswitchd（Open vSwitch）→ networking ↓ 4.3s network.target（网络就绪！） ↓ ~5s trim_init.service（fnOS 初始化） ↓ ~5.5s rc-local.service（Debian 本地脚本） ↓ ~6s trim_main.service（核心主进程启动，常驻） ↓ ~6s rpc_broker.service（RPC 消息总线启动，常驻） ↓ ~6s system_startup.service（初始化脚本开始执行，花12.3秒） ↓ ~18s system_startup 完成 → trim_nginx.service（Web 服务启动，4.1秒） ↓ ~22s ✅ Web 管理界面可以访问了！ ↓ ~25s 其他服务陆续启动：accountsrv、filestor、dockermgr、trim_connect... ↓ ~90s nmbd.service（NetBIOS 名称服务）终于启动完成 ↓ ~90s winbind.service（84ms） ↓ 101s graphical.target（systemd 认为系统完全启动）3.4 实际体验时间 vs systemd 完成时间这里有一个很重要的认知：graphical.target 的时间（1分41秒）不代表用户体验时间。用户实际能访问 Web 管理界面，只需要等 20 秒左右。剩下的 80 秒都在等 nmbd（Windows 网上邻居发现），这对通过 Web 界面管理 NAS 的用户来说完全无感。这也解释了为什么很多人觉得 NAS "开机慢"——其实系统早就可用了，只是 systemd 的"完全启动"标志被某个慢服务拖住了。四、核心服务拆解启动流程中，有几个服务是 fnOS 的核心命脉，我们逐个看它们的配置文件。4.1 trim_main.service —— 核心主进程[Unit] Description=trim main service After=rc-local.service After=trim_init.service [Service] Type=simple ExecStart=/usr/trim/bin/trim Restart=always RestartSec=5 [Install] WantedBy=multi-user.target关键点：执行的是 /usr/trim/bin/trim 这个二进制程序，不是脚本Type=simple，常驻后台运行Restart=always，崩溃后 5 秒自动重启——这是系统的核心命脉，不能挂在 trim_init 和 rc-local 之后启动trim_main 是 fnOS 最核心的服务，其他很多服务都依赖它或在它之后启动。4.2 rpc_broker.service —— RPC 消息总线[Unit] Description=trim rpc broker service After=rc-local.service After=trim_main.service [Service] Type=simple ExecStart=/usr/trim/bin/rpc_broker Restart=always RestartSec=5 [Install] WantedBy=multi-user.target关键点：执行 /usr/trim/bin/rpc_broker，也是二进制程序在 trim_main 之后启动同样崩溃自动重启很多 fnOS 服务的描述里都写了 "(RPC API)"，比如 filestor_service、usersrv、sysinfo_service。这些服务之间不是直接调用，而是通过 rpc_broker 转发消息。整体架构是微服务 + RPC 消息总线：Web 前端 → trim_nginx → trim_main（核心） → rpc_broker（消息总线） ↓ 各个子服务（filestor、usersrv、accountsrv...）4.3 trim_nginx.service —— 自编译 Web 服务[Unit] Description=trim nginx service After=rc-local.service After=trim_init.service After=system_startup.service [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/trim/nginx/sbin/nginx -t ExecStart=/usr/trim/nginx/sbin/nginx ExecReload=/usr/trim/nginx/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true Restart=always RestartSec=5 [Install] WantedBy=multi-user.target关键点：Nginx 二进制在 /usr/trim/nginx/sbin/nginx，不是 Debian 包的 /usr/sbin/nginx，是飞牛自己编译的ExecStartPre=/usr/trim/nginx/sbin/nginx -t，启动前先测试配置文件，有语法错误就不启动在 system_startup 之后启动——这就是为什么 Web 界面要等 20 秒左右Type=forking，Nginx 标准的主进程 + 工作进程模式飞牛用自编译 Nginx，可能是打了补丁或者加了自定义模块。4.4 system_startup.service —— 初始化脚本[Unit] Description=Run custom script After trim_main After=trim_main.service [Service] Type=oneshot ExecStart=/usr/trim/bin/system_startup.sh TimeoutStopSec=3 RemainAfterExit=yes [Install] WantedBy=multi-user.target关键点：描述直接写了 "Run custom script After trim_main"，非常直白Type=oneshot，一次性服务，执行完就退出执行的是 /usr/trim/bin/system_startup.sh 这个 shell 脚本RemainAfterExit=yes，执行完后仍然标记为 active，这样依赖它的服务不会认为它失败了花了 12.3 秒，是启动流程中除了 nmbd 之外最慢的环节五、启动瓶颈分析：nmbd 为什么要 1分30秒？最后来说说这个最大的异常——nmbd.service 花了 1分30秒。nmbd 是 Samba 套件里的 NetBIOS 名称服务，负责让 Windows 网上邻居能发现这台 NAS。正常情况下，nmbd 启动应该在几秒内完成。1分30秒这个数字很微妙——它正好是很多网络操作的默认超时时间。可能的原因包括：配置了 WINS 服务器但连不上：nmbd 在等待 WINS 服务器响应，超时后才继续DNS 解析超时：nmbd 启动时尝试解析某些主机名，DNS 不通导致等待网络接口未完全就绪：虽然 network.target 在 4.3 秒就完成了，但某些虚拟接口（比如 Open vSwitch 的网桥）可能还没完全就绪飞牛修改了 nmbd 配置：前面提到飞牛覆盖了 nmbd.service，可能加了一些自定义的启动前脚本或依赖不管具体原因是什么，这个 1分30秒的延迟只影响 Windows 网上邻居发现，不影响 Web 界面访问，也不影响通过 IP 地址直接访问 SMB 共享。对大多数用户来说，这个瓶颈是无感的。但如果要优化启动速度，nmbd 是第一个该动刀的地方。六、总结通过本文的分析，我们对 fnOS 的系统基础和启动流程有了完整的认知：系统层面：基于 Debian 12，但使用自己编译的 6.18 新内核，版本号 1.2.0505服务架构：微服务架构，81 个运行服务，其中 40+ 是 fnOS 自研，服务间通过 RPC 消息总线通信启动流程：从开机到 Web 可用约 20 秒，systemd 完全启动要 1分41秒（被 nmbd 拖住）核心服务：trim_main（核心主进程）、rpc_broker（RPC 总线）、trim_nginx（自编译 Web 服务）设计特点：大量使用自研组件（自编译内核、自编译 Nginx、自研 useradd/mdadm/smbftpd 等），覆盖 Debian 原生服务系列预告下一篇《飞牛 fnOS 深度解析（二）：存储架构深挖》，我们将详细解析 fnOS 的四层存储架构，包括：mdadm 软 RAID 的巧妙设计（单盘也封装 RAID1）LVM 的使用方式（以及为什么管理工具被移除了）ZFS 的定制（trimacl 内核补丁是什么）trimafs2 自研联合文件系统——飞牛存储池的底层实现拿到一台新 NAS，如何用 5 条命令快速摸清存储架构敬请期待。本文基于 fnOS 1.2.0505 版本实测，不同版本可能存在差异。