737 lines
15 KiB
Markdown
737 lines
15 KiB
Markdown
# Havline 飞牛 Native 应用改造方案
|
||||
|
|
|
|||
|
|
> 日期:2026-10-02
|
|||
|
|
> 依据:飞牛应用开放平台 Native 应用案例、统一网关、应用权限、环境变量、应用资源
|
|||
|
|
> 目标:把 Havline 做成完全不依赖 Docker 的飞牛原生应用
|
|||
|
|
|
|||
|
|
## 一、结论
|
|||
|
|
|
|||
|
|
技术上可行,但不建议直接把当前离线 Docker 包替换掉。
|
|||
|
|
|
|||
|
|
推荐路线:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Go 主程序原生运行
|
|||
|
|
+ 统一网关 Unix Socket
|
|||
|
|
+ 打包 Nginx 双架构二进制
|
|||
|
|
+ frpc / cloudflared 按需打包或运行时下载
|
|||
|
|
+ cmd/main 管理进程生命周期
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
最终形态:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
不依赖 Docker Engine
|
|||
|
|
不依赖 Docker Compose
|
|||
|
|
不依赖外部镜像仓库
|
|||
|
|
管理界面通过 /app/havline 统一网关访问
|
|||
|
|
公网反代功能通过高位端口运行
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
主要风险:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Nginx 双架构打包与动态库依赖
|
|||
|
|
非 root 用户无法绑定 80/443
|
|||
|
|
进程启动、停止、状态和崩溃恢复
|
|||
|
|
frpc / cloudflared 架构与版本管理
|
|||
|
|
真机升级和回滚验证
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 二、官方 Native 应用模型
|
|||
|
|
|
|||
|
|
官方 Native 应用案例说明:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Native 应用是在飞牛 fnOS 上运行的进程
|
|||
|
|
可以提供 Web UI、后台服务、CLI 工具
|
|||
|
|
推荐使用统一网关 /app/{appname}
|
|||
|
|
服务监听 ${TRIM_APPDEST}/app.sock
|
|||
|
|
cmd/main 负责 start、stop、status
|
|||
|
|
应用文件放在 ${TRIM_APPDEST}
|
|||
|
|
数据放在 ${TRIM_PKGVAR}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
官方 Notepad 示例的关键结构:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
notepad/
|
|||
|
|
├── app/
|
|||
|
|
│ ├── server/
|
|||
|
|
│ └── ui/config
|
|||
|
|
├── cmd/
|
|||
|
|
│ └── main
|
|||
|
|
├── config/
|
|||
|
|
│ ├── privilege
|
|||
|
|
│ └── resource
|
|||
|
|
├── manifest
|
|||
|
|
├── ICON.PNG
|
|||
|
|
└── ICON_256.PNG
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
启动脚本核心逻辑:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
APP_DIR="${TRIM_APPDEST}/server"
|
|||
|
|
SOCKET_PATH="${TRIM_APPDEST}/app.sock"
|
|||
|
|
|
|||
|
|
start)
|
|||
|
|
cd "$APP_DIR"
|
|||
|
|
SOCKET_PATH="$SOCKET_PATH" ./havline &
|
|||
|
|
echo "$!" > "$PID_FILE"
|
|||
|
|
;;
|
|||
|
|
|
|||
|
|
stop)
|
|||
|
|
kill -TERM "$(cat "$PID_FILE")"
|
|||
|
|
rm -f "$SOCKET_PATH" "$PID_FILE"
|
|||
|
|
;;
|
|||
|
|
|
|||
|
|
status)
|
|||
|
|
kill -0 "$(cat "$PID_FILE")"
|
|||
|
|
;;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 三、Havline 依赖清单
|
|||
|
|
|
|||
|
|
### 3.1 Go 主程序
|
|||
|
|
|
|||
|
|
可以直接编译为 Linux 静态二进制:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
|
|||
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
SQLite 使用 modernc.org/sqlite,纯 Go,不依赖 CGO
|
|||
|
|
前端已经通过 go:embed 内嵌
|
|||
|
|
ACME、DDNS、通知、备份均为 Go 实现
|
|||
|
|
不需要 Node.js、Python 或 Java 运行时
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 必需外部依赖
|
|||
|
|
|
|||
|
|
| 依赖 | 用途 | 原生方案 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| Nginx | 反向代理、HTTPS、证书加载 | 必须打包双架构二进制 |
|
|||
|
|
| mime.types | Nginx MIME 配置 | 随包分发 |
|
|||
|
|
| ca-certificates | HTTPS 客户端信任 | 使用系统证书或随包分发 |
|
|||
|
|
| tzdata | 时区 | 使用系统时区或随包分发 |
|
|||
|
|
|
|||
|
|
### 3.3 可选外部依赖
|
|||
|
|
|
|||
|
|
| 依赖 | 用途 | 原生方案 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| frpc | FRP 内网穿透 | 打包双架构或运行时下载 |
|
|||
|
|
| cloudflared | Cloudflare Tunnel | 打包双架构或运行时下载 |
|
|||
|
|
| ssh | Agent 远程安装 | 使用系统 SSH |
|
|||
|
|
| systemctl | 公网 Agent 管理 frps | 仅 Agent 场景需要 |
|
|||
|
|
| ss | 端口诊断 | 使用系统工具 |
|
|||
|
|
|
|||
|
|
### 3.4 可以移除的依赖
|
|||
|
|
|
|||
|
|
原生应用不需要:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Docker Engine
|
|||
|
|
Docker Compose
|
|||
|
|
Docker Socket
|
|||
|
|
havline-updater sidecar
|
|||
|
|
宿主机 Compose 文件
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 四、目标包结构
|
|||
|
|
|
|||
|
|
建议新增独立工程:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
fnos-native/
|
|||
|
|
└── havline/
|
|||
|
|
├── manifest
|
|||
|
|
├── ICON.PNG
|
|||
|
|
├── ICON_256.PNG
|
|||
|
|
├── app/
|
|||
|
|
│ ├── server/
|
|||
|
|
│ │ ├── amd64/
|
|||
|
|
│ │ │ ├── havline
|
|||
|
|
│ │ │ └── nginx
|
|||
|
|
│ │ ├── arm64/
|
|||
|
|
│ │ │ ├── havline
|
|||
|
|
│ │ │ └── nginx
|
|||
|
|
│ │ ├── mime.types
|
|||
|
|
│ │ └── VERSION
|
|||
|
|
│ └── ui/
|
|||
|
|
│ ├── config
|
|||
|
|
│ └── images/
|
|||
|
|
├── cmd/
|
|||
|
|
│ ├── main
|
|||
|
|
│ ├── install_callback
|
|||
|
|
│ ├── upgrade_callback
|
|||
|
|
│ ├── config_callback
|
|||
|
|
│ └── uninstall_callback
|
|||
|
|
├── config/
|
|||
|
|
│ ├── privilege
|
|||
|
|
│ └── resource
|
|||
|
|
└── wizard/
|
|||
|
|
├── install
|
|||
|
|
├── config
|
|||
|
|
└── uninstall
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
安装后:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
/var/apps/havline/
|
|||
|
|
├── target/
|
|||
|
|
│ ├── server/
|
|||
|
|
│ │ ├── amd64/
|
|||
|
|
│ │ ├── arm64/
|
|||
|
|
│ │ └── mime.types
|
|||
|
|
│ └── app.sock
|
|||
|
|
├── var/
|
|||
|
|
│ ├── havline.db
|
|||
|
|
│ ├── session_secret
|
|||
|
|
│ ├── nginx/
|
|||
|
|
│ ├── certs/
|
|||
|
|
│ ├── frp/
|
|||
|
|
│ └── cloudflared/
|
|||
|
|
└── cmd/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 五、运行架构
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
cmd/main start
|
|||
|
|
-> 选择当前架构目录
|
|||
|
|
-> 设置 HAVLINE_DATA_DIR=${TRIM_PKGVAR}
|
|||
|
|
-> 设置 HAVLINE_NGINX_BIN=${TRIM_APPDEST}/server/<arch>/nginx
|
|||
|
|
-> 设置 HAVLINE_NGINX_MIME_TYPES=${TRIM_APPDEST}/server/mime.types
|
|||
|
|
-> 设置 HAVLINE_GATEWAY_SOCKET=${TRIM_APPDEST}/app.sock
|
|||
|
|
-> 启动 havline 主程序
|
|||
|
|
-> 写入 PID 文件
|
|||
|
|
|
|||
|
|
havline 主程序
|
|||
|
|
-> 监听 Unix Socket 供统一网关访问
|
|||
|
|
-> 启动 Nginx 子进程
|
|||
|
|
-> 按需启动 frpc / cloudflared
|
|||
|
|
-> 管理数据库、证书、DDNS、反代规则
|
|||
|
|
|
|||
|
|
cmd/main stop
|
|||
|
|
-> 发送 SIGTERM
|
|||
|
|
-> 等待主程序退出
|
|||
|
|
-> 主程序负责停止 Nginx 和可选子进程
|
|||
|
|
-> 清理 app.sock 和 PID 文件
|
|||
|
|
|
|||
|
|
cmd/main status
|
|||
|
|
-> 检查 PID 是否存活
|
|||
|
|
-> 存活返回 0,否则返回 3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 六、统一网关接入
|
|||
|
|
|
|||
|
|
`app/ui/config`:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
".url": {
|
|||
|
|
"havline.main": {
|
|||
|
|
"title": "Havline",
|
|||
|
|
"icon": "images/icon_{0}.png",
|
|||
|
|
"type": "iframe",
|
|||
|
|
"protocol": "",
|
|||
|
|
"gatewayPrefix": "/app/havline",
|
|||
|
|
"gatewaySocket": "app.sock",
|
|||
|
|
"url": "/app/havline",
|
|||
|
|
"allUsers": false,
|
|||
|
|
"control": {
|
|||
|
|
"accessPerm": "readonly"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
主程序需要新增:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
HAVLINE_GATEWAY_SOCKET=${TRIM_APPDEST}/app.sock
|
|||
|
|
HAVLINE_GATEWAY_PREFIX=/app/havline
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
监听方式:
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
listener, err := net.Listen("unix", cfg.GatewaySocket)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
os.Chmod(cfg.GatewaySocket, 0o660)
|
|||
|
|
server.Serve(listener)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
前端需要支持:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Vite base = /app/havline/
|
|||
|
|
Vue Router base = /app/havline/
|
|||
|
|
API base = /app/havline/api
|
|||
|
|
SSE base = /app/havline/api/...
|
|||
|
|
WebSocket base = /app/havline/ws
|
|||
|
|
Cookie Path = /app/havline 或 /
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 七、Nginx 原生打包
|
|||
|
|
|
|||
|
|
这是整个改造最大的技术点。
|
|||
|
|
|
|||
|
|
### 7.1 可选方案
|
|||
|
|
|
|||
|
|
| 方案 | 优点 | 缺点 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| 打包静态 Nginx | 不依赖系统 Nginx | 需要自行构建双架构 |
|
|||
|
|
| 打包动态 Nginx + 依赖库 | 接近发行版行为 | 需要处理 .so 和 LD_LIBRARY_PATH |
|
|||
|
|
| 使用飞牛系统 Nginx | 包体小 | 版本、路径、配置目录不可控 |
|
|||
|
|
| 改用 Go 内置反向代理 | 完全纯 Go | Havline 现有 Nginx 功能需要重写 |
|
|||
|
|
|
|||
|
|
推荐:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
打包静态 Nginx 或半静态 Nginx
|
|||
|
|
amd64 与 arm64 各一份
|
|||
|
|
随包提供 mime.types
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.2 Nginx 配置调整
|
|||
|
|
|
|||
|
|
原生应用以 package 用户运行,不能直接绑定 80/443。
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
管理界面:统一网关 Unix Socket
|
|||
|
|
Nginx HTTP:18080
|
|||
|
|
Nginx HTTPS:9443
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果确实需要 80/443:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
使用 root 生命周期脚本启动 Nginx master
|
|||
|
|
Nginx worker 降权到 package 用户
|
|||
|
|
或者给二进制授予 CAP_NET_BIND_SERVICE
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
不推荐让整个 Havline 长期以 root 运行。
|
|||
|
|
|
|||
|
|
### 7.3 Nginx 目录
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
${TRIM_APPDEST}/server/<arch>/nginx
|
|||
|
|
${TRIM_APPDEST}/server/mime.types
|
|||
|
|
${TRIM_PKGVAR}/nginx/
|
|||
|
|
${TRIM_PKGVAR}/certs/
|
|||
|
|
${TRIM_PKGVAR}/logs/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
环境变量:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
HAVLINE_NGINX_BIN=${TRIM_APPDEST}/server/<arch>/nginx
|
|||
|
|
HAVLINE_NGINX_MIME_TYPES=${TRIM_APPDEST}/server/mime.types
|
|||
|
|
HAVLINE_NGINX_PID=${TRIM_PKGVAR}/nginx/nginx.pid
|
|||
|
|
HAVLINE_NGINX_HTTP_PORT=18080
|
|||
|
|
HAVLINE_NGINX_HTTPS_PORT=9443
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 八、frpc 与 cloudflared
|
|||
|
|
|
|||
|
|
这两个是可选功能依赖。
|
|||
|
|
|
|||
|
|
### 方案 A:随包分发
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
app/server/amd64/frpc
|
|||
|
|
app/server/arm64/frpc
|
|||
|
|
app/server/amd64/cloudflared
|
|||
|
|
app/server/arm64/cloudflared
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
完全离线
|
|||
|
|
版本可控
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
包体变大
|
|||
|
|
每次升级 Havline 都要同步升级二进制
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 方案 B:运行时按需下载
|
|||
|
|
|
|||
|
|
保持 Havline 现有下载逻辑,但把下载目录指向:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
${TRIM_PKGVAR}/frp/
|
|||
|
|
${TRIM_PKGVAR}/cloudflared/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
FPK 更小
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
缺点:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
首次使用需要网络
|
|||
|
|
下载源可能被墙
|
|||
|
|
需要校验 SHA256
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
推荐首版:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
frpc:随包分发
|
|||
|
|
cloudflared:随包分发或首次使用时下载
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 九、数据目录与迁移
|
|||
|
|
|
|||
|
|
原生应用数据目录:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
${TRIM_PKGVAR}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
需要保留:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
havline.db
|
|||
|
|
session_secret
|
|||
|
|
nginx/
|
|||
|
|
certs/
|
|||
|
|
frp/
|
|||
|
|
cloudflared/
|
|||
|
|
logs/
|
|||
|
|
ssh_known_hosts
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
从当前离线 Docker 包迁移:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Docker 包数据目录:${TRIM_PKGVAR}
|
|||
|
|
原生包数据目录:${TRIM_PKGVAR}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果两个应用使用同一个 appname,路径可能相同。
|
|||
|
|
|
|||
|
|
迁移步骤:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
1. 停止 Docker 版 Havline
|
|||
|
|
2. 备份数据目录
|
|||
|
|
3. 安装原生版
|
|||
|
|
4. 确认 session_secret 不变
|
|||
|
|
5. 启动原生版
|
|||
|
|
6. 验证数据库、证书、规则、隧道
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十、生命周期脚本
|
|||
|
|
|
|||
|
|
### 10.1 cmd/main
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
start:选择架构、设置环境变量、启动 havline、写 PID
|
|||
|
|
stop:发送 SIGTERM、等待退出、清理 PID 和 Socket
|
|||
|
|
status:检查 PID 是否存活
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
关键环境变量:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
APP_DIR="${TRIM_APPDEST}/server"
|
|||
|
|
ARCH="$(uname -m)"
|
|||
|
|
case "$ARCH" in
|
|||
|
|
x86_64|amd64) ARCH_DIR="amd64" ;;
|
|||
|
|
aarch64|arm64) ARCH_DIR="arm64" ;;
|
|||
|
|
*) exit 1 ;;
|
|||
|
|
esac
|
|||
|
|
|
|||
|
|
export HAVLINE_DATA_DIR="$TRIM_PKGVAR"
|
|||
|
|
export HAVLINE_NGINX_BIN="$APP_DIR/$ARCH_DIR/nginx"
|
|||
|
|
export HAVLINE_NGINX_MIME_TYPES="$APP_DIR/mime.types"
|
|||
|
|
export HAVLINE_NGINX_HTTP_PORT=18080
|
|||
|
|
export HAVLINE_NGINX_HTTPS_PORT=9443
|
|||
|
|
export HAVLINE_GATEWAY_SOCKET="$TRIM_APPDEST/app.sock"
|
|||
|
|
export HAVLINE_GATEWAY_PREFIX="/app/havline"
|
|||
|
|
export HAVLINE_UPDATER_SOCKET=""
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.2 install_callback
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
创建 TRIM_PKGVAR
|
|||
|
|
设置目录权限
|
|||
|
|
复制默认配置
|
|||
|
|
检查二进制架构
|
|||
|
|
检查 Nginx 可执行
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.3 upgrade_callback
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
检查数据库和 session_secret
|
|||
|
|
保留数据目录
|
|||
|
|
检查新二进制架构
|
|||
|
|
必要时迁移 Nginx 配置
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.4 uninstall_callback
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
默认保留 TRIM_PKGVAR
|
|||
|
|
用户选择 purge 时删除数据
|
|||
|
|
清理 app.sock 和 PID 文件
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十一、多架构构建
|
|||
|
|
|
|||
|
|
构建脚本需要输出:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
amd64/havline
|
|||
|
|
arm64/havline
|
|||
|
|
amd64/nginx
|
|||
|
|
arm64/nginx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Go 二进制:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -o amd64/havline ./cmd/havline
|
|||
|
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -o arm64/havline ./cmd/havline
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Nginx:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
从静态构建产物复制
|
|||
|
|
或从容器镜像中提取
|
|||
|
|
并检查动态库依赖
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
检查:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
file amd64/havline
|
|||
|
|
file arm64/havline
|
|||
|
|
ldd amd64/nginx
|
|||
|
|
ldd arm64/nginx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十二、分阶段实施
|
|||
|
|
|
|||
|
|
### 阶段 1:Native PoC
|
|||
|
|
|
|||
|
|
目标:不打包 Nginx,先验证 Go 主程序原生运行。
|
|||
|
|
|
|||
|
|
内容:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
编译 amd64/arm64 Go 二进制
|
|||
|
|
统一网关 Unix Socket
|
|||
|
|
cmd/main start/stop/status
|
|||
|
|
TRIM_PKGVAR 数据目录
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[ ] 应用可安装
|
|||
|
|
[ ] /app/havline 可打开
|
|||
|
|
[ ] 进程可启停
|
|||
|
|
[ ] 数据可持久化
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段 2:Nginx 打包
|
|||
|
|
|
|||
|
|
目标:让反向代理功能原生可用。
|
|||
|
|
|
|||
|
|
内容:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
静态 Nginx 双架构
|
|||
|
|
mime.types
|
|||
|
|
18080/9443 端口
|
|||
|
|
证书目录
|
|||
|
|
nginx -t 校验
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
验收:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[ ] Nginx 可启动
|
|||
|
|
[ ] 配置可校验
|
|||
|
|
[ ] HTTPS 可加载
|
|||
|
|
[ ] 反向代理规则生效
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段 3:frpc / cloudflared
|
|||
|
|
|
|||
|
|
目标:恢复 FRP 和 Cloudflare Tunnel 功能。
|
|||
|
|
|
|||
|
|
内容:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
双架构二进制
|
|||
|
|
或按需下载
|
|||
|
|
SHA256 校验
|
|||
|
|
进程管理
|
|||
|
|
日志
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段 4:升级与迁移
|
|||
|
|
|
|||
|
|
目标:从 Docker 包迁移到原生包。
|
|||
|
|
|
|||
|
|
内容:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
数据迁移
|
|||
|
|
session_secret 保留
|
|||
|
|
版本兼容
|
|||
|
|
回滚方案
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段 5:真机验证
|
|||
|
|
|
|||
|
|
目标:x86_64 与 ARM 设备安装验证。
|
|||
|
|
|
|||
|
|
内容:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
安装、启动、停止
|
|||
|
|
统一网关入口
|
|||
|
|
反向代理
|
|||
|
|
证书
|
|||
|
|
FRP
|
|||
|
|
Cloudflare
|
|||
|
|
升级
|
|||
|
|
卸载
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十三、验收清单
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[ ] 不依赖 Docker Engine
|
|||
|
|
[ ] 不依赖 Docker Compose
|
|||
|
|
[ ] 不依赖外部镜像仓库
|
|||
|
|
[ ] Go 二进制支持 amd64 与 arm64
|
|||
|
|
[ ] Nginx 支持 amd64 与 arm64
|
|||
|
|
[ ] 管理界面通过 /app/havline 打开
|
|||
|
|
[ ] Unix Socket 权限正确
|
|||
|
|
[ ] 主程序可启动、停止、检查状态
|
|||
|
|
[ ] 数据写入 TRIM_PKGVAR
|
|||
|
|
[ ] session_secret 升级后不变
|
|||
|
|
[ ] Nginx 反向代理正常
|
|||
|
|
[ ] HTTPS 证书正常
|
|||
|
|
[ ] FRP 功能正常
|
|||
|
|
[ ] Cloudflare Tunnel 功能正常
|
|||
|
|
[ ] 升级不丢数据
|
|||
|
|
[ ] 卸载默认保留数据
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十四、风险与工作量
|
|||
|
|
|
|||
|
|
| 风险 | 影响 | 处理 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| Nginx 双架构打包 | 原生版无法启动 | 阶段 2 专项验证 |
|
|||
|
|
| Nginx 动态库依赖 | 目标设备缺库 | 静态编译或随包分发 .so |
|
|||
|
|
| 非 root 绑定 80/443 | 端口权限失败 | 使用 18080/9443 |
|
|||
|
|
| 进程崩溃 | 服务中断 | PID 检查、重启策略、日志 |
|
|||
|
|
| Socket 权限 | 网关无法访问 | 启动时 chmod |
|
|||
|
|
| 前端绝对路径 | 网关下 404 | 统一 base path |
|
|||
|
|
| frpc/cloudflared 版本 | 功能不可用 | 随包分发并校验 SHA256 |
|
|||
|
|
| 数据迁移 | 凭据无法解密 | 保留 session_secret |
|
|||
|
|
| 升级替换二进制 | 运行中进程被覆盖 | stop 后再替换 |
|
|||
|
|
| ARM 真机差异 | 测试不充分 | 真机验证 |
|
|||
|
|
|
|||
|
|
工作量估算:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
阶段 1:2 到 3 天
|
|||
|
|
阶段 2:3 到 5 天
|
|||
|
|
阶段 3:2 到 4 天
|
|||
|
|
阶段 4:2 到 3 天
|
|||
|
|
阶段 5:3 到 5 天
|
|||
|
|
合计:2 到 4 周
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十五、与离线 Docker 包对比
|
|||
|
|
|
|||
|
|
| 项目 | 离线 Docker 包 | 原生应用 |
|
|||
|
|
| --- | --- | --- |
|
|||
|
|
| 依赖 Docker | 是 | 否 |
|
|||
|
|
| 依赖仓库 | 否 | 否 |
|
|||
|
|
| 包体 | 约 150 MB | 预计 40 到 80 MB |
|
|||
|
|
| 改造量 | 已完成 | 2 到 4 周 |
|
|||
|
|
| Nginx | 容器内已有 | 需要自行打包 |
|
|||
|
|
| 升级 | Docker load | 替换二进制 |
|
|||
|
|
| 进程管理 | Docker Compose | cmd/main |
|
|||
|
|
| 风险 | 低 | 高 |
|
|||
|
|
| 推荐度 | 当前优先 | 长期演进 |
|
|||
|
|
|
|||
|
|
## 十六、建议
|
|||
|
|
|
|||
|
|
当前阶段建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
先发布并验证离线 Docker 包
|
|||
|
|
保留统一网关改造方案
|
|||
|
|
原生应用作为独立分支推进
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原生应用的推荐顺序:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
1. 先做 Go 主程序 + 统一网关 PoC
|
|||
|
|
2. 再做 Nginx 双架构打包
|
|||
|
|
3. 再恢复 FRP 和 Cloudflare
|
|||
|
|
4. 最后做数据迁移和真机升级
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
只有在以下条件满足时,才建议把原生应用作为正式发布形态:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Nginx 双架构在真实设备稳定运行
|
|||
|
|
统一网关 Socket 权限稳定
|
|||
|
|
升级和回滚验证通过
|
|||
|
|
frpc / cloudflared 架构验证通过
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 十七、官方参考
|
|||
|
|
|
|||
|
|
- Native 应用案例:<https://developer.fnnas.com/docs/examples/native/>
|
|||
|
|
- 统一网关:<https://developer.fnnas.com/docs/core-concepts/gateway-registration/>
|
|||
|
|
- 应用权限:<https://developer.fnnas.com/docs/core-concepts/privilege/>
|
|||
|
|
- 环境变量:<https://developer.fnnas.com/docs/core-concepts/environment-variables/>
|
|||
|
|
- 应用资源:<https://developer.fnnas.com/docs/core-concepts/resource/>
|
|||
|
|
- 应用入口:<https://developer.fnnas.com/docs/core-concepts/app-entry/>
|