系列文章:

  • 第一篇:系统基础与启动流程
  • 第二篇:存储架构深挖
  • 第三篇:系统目录结构与技术栈
  • 第四篇:文件服务与用户权限体系
  • 第五篇:Web 后端架构深度解析(本文)
  • 第六篇:系统识别方法论与二次开发指南

如果说前四篇我们在看 fnOS 的"身体",那这一篇我们要看它的"大脑"——Web 后端架构。

fnOS 的 Web 管理界面是用户和系统交互的唯一入口,所有操作(创建用户、管理存储、安装应用)都通过它完成。搞清楚 Web 后端的架构,就等于拿到了二次开发的钥匙——你会知道 API 请求怎么走、后端服务怎么通信、自己的程序怎么耦合进去。

这一篇的内容全部来自实际的 Nginx 配置文件和系统探查,没有任何猜测。


一、整体请求链路

先看一张完整的请求链路图:

浏览器(React SPA)
    ↓ HTTP/HTTPS (5666/5667)
Nginx(自编译 + 自研模块)
    ↓ 反向代理
┌─────────────────────────────────────────────┐
│  后端微服务集群(30+ 个,几乎全部 Unix Socket) │
│                                              │
│  核心:trim_http_cgi (/cgi, /app/)           │
│  账户:accountsrv (/v1/accountapi)           │
│  相册:trim_photos (/p)                      │
│  媒体:trim_media (/v)                       │
│  分享:trim_share (/s/)                      │
│  快照:trim_snapshots (/snapshot)            │
│  同步:trim_sync_server (/sync/)             │
│  搜索:trim_seek (/seek)                     │
│  应用:trim_app_center (/app-center)         │
│  Docker:dockermgr (/docker/*)               │
│  虚拟机:trim_vm (/vm)                       │
│  ...(共30+个后端服务)                       │
└─────────────────────────────────────────────┘
    ↓
PostgreSQL(127.0.0.1:5432,只监听本地)

整个架构是典型的前后端分离 + 微服务:

  • 前端是 React SPA,打包后的静态文件放在 /usr/trim/www/
  • Nginx 既提供静态文件,又做反向代理,把 API 请求转发到后端服务
  • 后端是 30+ 个微服务,每个负责一个功能模块
  • 几乎所有后端服务都通过 Unix Socket 和 Nginx 通信,不是 TCP 端口
  • 数据层是 PostgreSQL,只监听本地回环地址

二、Nginx:自编译 + 自研模块

fnOS 的 Nginx 不是系统自带的,而是自己编译的,安装在 /usr/trim/nginx/。主配置文件是 /usr/trim/nginx/conf/nginx.conf。

2.1 重大发现:飞牛自研了 Nginx 模块

load_module modules/ngx_http_trim_cert_module.so;

飞牛编译了自己的 Nginx 动态模块 ngx_http_trim_cert_module,用于证书管理和动态切换。相关配置:

trim_cert_cfg_path /usr/trim/etc/network_gateway_cert.conf;
trim_hook_cert_switch on;
ssl_certificate $ssl_server_name;
ssl_certificate_key $ssl_server_name;
配置说明
trim_cert_cfg_path证书配置文件路径
trim_hook_cert_switch on开启证书切换功能
ssl_certificate $ssl_server_name动态证书——根据 SNI(服务器名称指示)选择对应证书

这说明飞牛对 Nginx 的定制不止是编译参数,还写了自己的模块。这个模块负责管理多域名证书、自动切换证书,可能和飞牛互联的远程访问域名有关。

2.2 监听端口与重定向

listen 0.0.0.0:5666 default_server;
listen [::]:5666 ipv6only=on default_server;
listen 0.0.0.0:5667 ssl http2 default_server;
listen [::]:5667 ssl http2 ipv6only=on default_server;
listen 0.0.0.0:80 default_server;
listen [::]:80 ipv6only=on default_server;
listen 0.0.0.0:443 ssl http2 default_server;
listen [::]:443 ssl http2 ipv6only=on default_server;

if ($server_port = 80) {
    return 302 $scheme://$host:5666$request_uri;
}
if ($server_port = 443) {
    return 302 $scheme://$host:5667$request_uri;
}
端口协议作用
5666HTTPWeb 管理界面(主端口)
5667HTTPS/HTTP2Web 管理界面(加密)
80HTTP重定向到 5666
443HTTPS重定向到 5667

飞牛用 5666/5667 作为管理端口,80/443 只是重定向。这样做的好处是避免和其他 Web 服务冲突(比如用户自己装的 Nginx/Apache)。

2.3 性能与安全配置

user  www-data;
worker_processes  auto;
worker_connections  10240;
client_max_body_size 1000000g;
server_tokens off;
配置说明
worker_processes auto自动根据 CPU 核心数设置工作进程
worker_connections 10240每个工作进程 10240 个连接(很大,支持高并发)
client_max_body_size 1000000g上传文件大小限制 1000000G——几乎无限制,NAS 要传大文件
server_tokens off隐藏 Nginx 版本号,安全考虑

2.4 特殊 location

主配置里定义了几个特殊的 location:

# WebSocket
location /websocket {
    proxy_pass http://trim_cgi;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

# 大文件上传
location /upload {
    proxy_pass http://trim_upload;
    proxy_request_buffering off;
    client_body_buffer_size 512K;
    tcp_nopush on;
}

# 下载
location /download {
    alias /;
    download_auth on;
}

# 应用 UI
location /appui {
    alias /vol0/@appui;
}
location作用特点
/websocketWebSocket 连接支持 Upgrade 头,转发到 trim_cgi
/upload文件上传关闭请求缓冲(proxy_request_buffering off),支持大文件流式上传
/download文件下载alias / 映射到根目录,download_auth on 开启下载认证
/appui应用 UI静态文件,在 /vol0/@appui
include globals/trim-cookie-v2-to-v1-map.conf;
proxy_set_header Cookie $trim_cookie_v2_to_v1_cookie;

这是一个很有意思的细节:飞牛的认证系统有 v1 和 v2 两个版本的 Cookie,Nginx 层做了自动转换。说明认证系统在升级中,新旧版本兼容——老的后端服务只认 v1 Cookie,新的前端发 v2 Cookie,Nginx 在转发时自动转换。


三、30+ 后端服务的路由映射表

Nginx 主配置的最后一行是:

include conf.d/*.conf;

所有 API 的反向代理规则都在 /usr/trim/nginx/conf/conf.d/ 目录下。我们看一下有多少个配置文件:

$ ls /usr/trim/nginx/conf/conf.d/
accountsrv.conf         file_version.conf        trimcon.conf
auto_thumbnailer.conf   gzip.conf                trim_docs.conf
baidu_netdisk.conf      html_nocache.conf        trim_http_cgi.conf
cloud_storage_dav.conf  multiple_downloads.conf  trim_iscsi.conf
docker_web.conf         safe_code_access.conf    trim_license.conf
download_web.conf       trim_app_center.conf     trim_media.conf
dsmgr.conf              trim_chromium.conf       trim_music.conf
                        trim_open_gateway.conf   trim_photos.conf
                        trim_sac.conf            trim_seek.conf
                        trim_sharelink.conf      trim_snapshots.conf
                        trim_sync.conf           trim_text_editor.conf
                        trim_txt_mime.conf       trim_vm.conf

一共 30 个配置文件,每个对应一个后端服务或功能模块。下面是完整的路由映射表:

3.1 核心服务

服务API 路径通信方式说明
trim_http_cgi/cgi、/app/Unix Socket核心 CGI 服务,大部分业务逻辑
accountsrv/v1/accountapi、/oauthapiUnix Socket账户管理、OAuth 认证
uploadsrv/uploadUnix Socket文件上传(主配置里)

3.2 媒体与内容服务

服务API 路径通信方式说明
trim_photos/pUnix SocketAI 相册
trim_media/vUnix Socket媒体服务(视频转码等)
trim_music/musicUnix Socket音乐服务
auto_thumbnailer/thumbUnix Socket自动缩略图生成
trim_seek/seekUnix Socket搜索(文件内容搜索?)
trim_docs/docsTCP localhost:10500文档服务(OnlyOffice 文档服务)
onlyoffice/onlyoffice/TCP localhost:10501在线文档编辑

3.3 分享与同步服务

服务API 路径通信方式说明
trim_share/s/Unix Socket外部分享(分享链接)
trim_snapshots/snapshotUnix Socket快照管理
trim_sync_server/sync/Unix Socket文件同步(跨设备同步)
trim_sharelink(独立配置)Unix Socket收集链接

3.4 应用与虚拟化服务

服务API 路径通信方式说明
trim_app_center/app-centerUnix Socket应用中心
dockermgr/docker/*Unix SocketDocker 管理
trim_vm/vmUnix Socket虚拟机管理
trim_chromium/chromium/TCP 127.0.0.1:3000浏览器应用
trim_iscsi/iscsi静态文件iSCSI 管理
file_version/file-version静态文件文件版本管理
trim_text_editor/app/text-editor静态文件文本编辑器

3.5 系统与安全服务

服务API 路径通信方式说明
trim_license/license/Unix Socket许可证管理
trim_sac/sac/Unix Socket系统应用控制
trim_open_gateway/og.、/grpc.gRPC over Unix Socket开放网关(gRPC 协议)
os-access-code全局 auth_requestUnix Socket安全访问码
multiple-downloads/multiple-downloadUnix Socket多任务下载
baidu_netdisk/app-baidu-netdiskUnix Socket百度网盘
cloud_storage_dav/cloud-storageTCP 127.0.0.1:15244云存储

3.6 飞牛互联服务

服务API 路径通信方式说明
trim-connect/trimfnUnix Socket飞牛互联(远程访问)
trimcon/trimcon/*Nginx 直接处理飞牛互联的 CORS 和重定向

四、重大发现:几乎全部 Unix Socket 通信

把上面的表统计一下:

通信方式服务数量占比
Unix Socket25+~85%
TCP(127.0.0.1)4~13%
gRPC over Unix Socket1~3%

绝大多数后端服务都通过 Unix Socket 和 Nginx 通信,不是 TCP 端口。 比如:

  • 相册:unix:/var/run/trim_photos.sock
  • 媒体:unix:/var/run/trim_media.sock
  • 分享:unix:/var/run/trim_share.sock
  • 核心 CGI:unix:/var/run/trim_http_cgi.socket

只有 4 个服务用 TCP:

  • cloud_storage_dav → 127.0.0.1:15244
  • docs → localhost:10500
  • onlyoffice → localhost:10501
  • chromium → 127.0.0.1:3000

这 4 个都是第三方组件(OnlyOffice、Chromium 等),不方便改成 Unix Socket,所以用 TCP。

为什么用 Unix Socket 而不是 TCP?

  1. 更安全:Unix Socket 只能本机访问,不对外暴露端口,减少攻击面
  2. 性能更好:Unix Socket 不经过 TCP/IP 协议栈,没有握手、序列号、校验和等开销,延迟更低
  3. 更简单:不需要管理端口分配,不用担心端口冲突,用文件名标识就行

这是一个非常好的架构设计——内部服务用 Unix Socket,只有需要对外暴露的才用 TCP。


五、gRPC:trim_open_gateway

在一堆 HTTP 反向代理中,有一个与众不同:

location ~ ^/(og|grpc)\. {
    auth_request off;
    grpc_pass grpc://unix:/var/run/trim_open_gateway.socket;
    grpc_read_timeout 300s;
    grpc_send_timeout 300s;
}

trim_open_gateway 用的是 gRPC 协议,不是 HTTP。Nginx 用 grpc_pass 而不是 proxy_pass 来转发。

gRPC 是 Google 开源的高性能 RPC 框架,基于 HTTP/2,用 Protocol Buffers 序列化,性能比 RESTful JSON 好很多。这说明飞牛内部服务间通信可能用 gRPC,对外暴露时通过这个网关转换成 HTTP。

路径匹配 ^/(og|grpc)\.,说明 API 路径以 /og. 或 /grpc. 开头的都走 gRPC 网关。


六、全局安全访问码机制

在 safe_code_access.conf 里,有一个全局的认证机制:

auth_request /_access_code_check;
proxy_set_header X-Access-Code "";

auth_request 是 Nginx 的认证请求模块——每个请求到达后端之前,先转发到 /_access_code_check 做认证,认证通过才转发到实际后端。

认证流程:

用户请求
    ↓
Nginx 先调用 /_access_code_check
    ↓
转发到 unix:/run/os-access-code.sock:/check
    ↓
    ├─ 认证通过 → 继续转发到实际后端
    └─ 认证失败 → 重定向到 /_access_code_page(访问码输入页面)

相关的 location:

location作用
/_access_code_check内部认证端点,调用 os-access-code 服务的 /check
/access_code_verify验证访问码
/_access_code_page访问码输入页面(内部,返回 HTML)
/c/(code)URL 访问码——访问 /c/xxxxxx 时自动验证访问码

这个机制支持多种访问码:

  • 页面访问码:访问页面时弹出输入框
  • URL 访问码:URL 里带 /c/xxxxxx,自动验证
  • 设备访问码:通过 X-Device-ID 头识别设备

对于 WebSocket 和 APP/TV 客户端,不返回 HTML 页面,而是直接返回 401:

if ($http_upgrade != "") { return 401; }
if ($http_sec_websocket_key != "") { return 401; }
if ($http_x_access_source = app) { return 401; }
if ($http_x_access_source = tv) { return 401; }

这是飞牛的一个安全功能——可以给共享链接、特定页面设置访问密码,防止未授权访问。


七、WebSocket 与长连接

多个服务支持 WebSocket,用于实时推送:

服务WebSocket 路径用途
trim_http_cgi/websocket、/app/通用 WebSocket(系统通知等)
dockermgr/docker/terminal、/docker/logs容器终端、容器日志(实时输出)
trim_seek/seek/api/v1/ws搜索进度推送
trim_sync_server/sync/event/register同步事件推送
trim_vm/vm虚拟机控制台(VNC/SPICE over WebSocket)

Docker 终端和日志的超时设为 20 分钟:

proxy_send_timeout 20m;
proxy_read_timeout 20m;

同步服务的超时设为 7 天:

proxy_read_timeout 7d;
proxy_send_timeout 7d;
client_body_timeout 7d;

因为文件同步可能需要很长时间,连接要保持很久。


八、前端技术栈回顾

在第三篇里我们已经分析过前端技术栈,这里快速回顾:

技术证据
Reactlottie-react.js
TypeScripttslib.es6.js
Semi DesignCSS 变量 --semi-color-bg-0(字节跳动组件库)
Rolldownrolldown-runtime.js(新一代打包工具)
i18next国际化(多语言)
Lodash工具库
Lottie动画

前端文件在 /usr/trim/www/,是打包后的静态文件。Nginx 的 root /usr/trim/www,所有未匹配到 API 的路径都返回 index.html(SPA 的 history 模式):

root /usr/trim/www;
index index.html index.htm;
error_page 404 /index.html;

九、本地监听的内部服务

最后看一下只监听本地回环地址的内部服务:

$ ss -tlnp | grep 127.0.0.1
127.0.0.1:5432   ← PostgreSQL(只监听本地,安全)
127.0.0.1:7475   ← P2PClient(飞牛互联 P2P 客户端)
127.0.0.1:10000  ← baiduNas(百度网盘客户端)
127.0.0.1:10500  ← 文档服务
127.0.0.1:10501  ← OnlyOffice

PostgreSQL 只监听 127.0.0.1:5432,不对外暴露,这是安全的标准做法。


十、本章小结

这一篇我们深度解析了 fnOS 的 Web 后端架构,核心发现:

  1. Nginx 是自编译的,还加了自研模块 ngx_http_trim_cert_module,用于动态证书管理
  2. 30+ 微服务架构,每个服务负责一个功能模块,通过 Nginx 反向代理统一入口
  3. 几乎全部 Unix Socket 通信——更安全、性能更好,只有第三方组件用 TCP
  4. 支持 gRPC——trim_open_gateway 用 gRPC 协议,说明内部服务间通信可能用 gRPC
  5. 全局安全访问码机制——所有请求先经过 auth_request 认证,支持页面访问码、URL 访问码
  6. Cookie v2→v1 转换——认证系统在升级,Nginx 层做新旧兼容
  7. 前端是 React + TypeScript + Semi Design + Rolldown,打包后的静态文件

这套架构的设计水平相当高——微服务解耦、Unix Socket 安全高效、统一认证、前后端分离。对于二次开发来说,只要在 /usr/trim/nginx/conf/conf.d/ 下加一个配置文件,把自己的 API 路径代理到自己的 Unix Socket,就能无缝耦合进系统。

下一篇是本系列的收官之作——系统识别方法论与二次开发指南。我们会总结出一套"拿到一台设备,5分钟判断是不是飞牛系统"的多维度识别方法(即使对方把进程名、目录名都改了也能判断),并给出基于 fnOS 做二次开发的完整路径。敬请期待。