SafeLine Web Server(mgt-api)开发与构建指南:从 Proto 生成、FVM 依赖初始化到编译运行
【免费下载链接】SafeLineSafeLine is a self-hosted WAF(Web Application Firewall) / reverse proxy to protect your web apps from attacks and exploits.项目地址: https://gitcode.com/GitHub_Trending/sa/SafeLine
本指南以 management/webserver/README.md 为核心脉络,系统讲解 SafeLine 社区版管理平面核心组件 —— mgt-api Web Server 的完整开发环境搭建、protobuf 代码生成、FVM 依赖库初始化、容器化构建以及运行时配置与启动参数。读完本文,你将掌握如何从零搭建该模块的开发环境、生成 gRPC 绑定代码、准备底层检测依赖,并理解其 HTTP API 路由与 gRPC 订阅机制背后的源码实现。
模块定位:mgt-api 的 Web Server
在 SafeLine 的整体架构中,management/webserver是管理平面(Management Micro Service)中的 Web 服务进程,对外提供基于 Gin 的 REST API,对内通过 gRPC 双向流与tcontrollerd通信,并依赖 FVM(Fast Virtual Machine)字节码支撑检测能力。其入口为 management/webserver/main.go,构建产物为build/webserver(见 management/Makefile 中的build-webserver目标)。
从 main.go 可以看到,该进程支持多个命令行参数,是理解其运行方式的入口:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
-v | bool | false | 打印版本号、Git hash、构建时间与 Go 版本 |
-c | string | 常量ConfigFilePath | 指定配置文件路径 |
-gen_certs | bool | false | 仅生成 TLS 证书后退出 |
-show_fsl | bool | false | 打印完整 FSL(Full Selectors)后退出 |
-push_fsl | bool | false | 编译并推送 FSL 到数据库后退出 |
-fake_logs | bool | false | 生成测试用假日志后退出 |
-reset_user | string | 空 | 重置指定用户名密码后退出 |
环境要求
- Go 1.18+:仓库内
management/webserver/go.mod与management/tcontrollerd/go.mod均基于此版本开发; - protoc 及 Go 插件:用于生成 protobuf/gRPC 绑定代码;
- FVM / libct / fusion 相关二进制库:构建时需链接
libfvm.so; - Docker:官方推荐的构建方式是使用
chaitin.cn/ci/golang:1.18镜像。
第一步:初始化 protobuf(生成 gRPC 绑定代码)
安装工具链
webserver与tcontrollerd之间通过 gRPC 通信,接口定义位于 management/webserver/proto/website/website.proto。生成 Go 代码前需先安装编译器与插件:
# 1. 安装 protoc(编译器本体) # 参考官方 protoc 安装文档完成安装 # 2. 安装 Go 插件 go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.30.0 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0 # 3. 将 GOPATH/bin 加入 PATH,使 protoc 能找到插件 export PATH="$PATH:$(go env GOPATH)/bin"执行生成脚本
# 在仓库根目录(management 同级)执行 ./scripts/genproto.sh该脚本位于 management/scripts/genproto.sh,其工作方式为:遍历webserver/proto与tcontrollerd/proto两个目录下所有子目录,对每个包含.proto文件的目录执行:
protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ "${FS}"其中paths=source_relative表示生成的.pb.go文件与.proto源文件保持相同相对路径;生成后还会用goimports -local chaitin.cn -w ./*.pb.go整理导入并保持chaitin.cn本地包分组。
以 website.proto 为例,它定义了一个名为Website的 gRPC 服务,提供唯一的双向流方法Subscribe(stream Response) returns (stream Event):客户端(tcd)连接后,服务端会持续推送website事件,客户端则以pong应答维持心跳。生成后可在management/webserver/proto/website/下看到对应的website.pb.go与website_grpc.pb.go。
提示:
genproto.sh开头会校验脚本必须从仓库根目录运行(scripts/genproto.sh路径匹配),否则以状态码 255 退出,因此在子目录直接执行会报错。
第二步:初始化 FVM 依赖库
FVM(Fast Virtual Machine)是 SafeLine 检测能力的核心执行引擎,其头文件与动态库并非随源码仓库发布,需要从私有制品源手动下载放置到submodule目录。README 中给出的完整初始化步骤如下:
# 由于需要 fvm 的 C 头文件,先创建目录 mkdir -p management/webserver/submodule/fvm/ mkdir -p management/webserver/submodule/libct/ cd management/webserver/submodule/fvm/ # 下载 https://chaitin.cn/patronus/fvm/-/tags 1.8.21 release 的 artifacts unzip artifacts.zip rm artifacts.zip cd management/webserver/submodule/libct/ # 下载 https://chaitin.cn/patronus/libct/-/tags 1.1.1.0 release 的 artifacts # 按 README 说明重命名相关文件 rm artifacts.zip cd management/webserver/submodule/ # 下载 https://chaitin.cn/patronus/fusion-2/-/tags 5.3.9-r1 build:release 的 artifacts unzip artifacts.zip mv artifacts/lib/libfusion.so libfvm.so rm artifacts.zip rm -r artifacts/其中最后一步将 fusion 产物重命名为libfvm.so,正是后续容器化构建时需要复制到系统库目录(/usr/lib/)的动态库。产物最终期望的目录结构为:
management/webserver/submodule/fvm/—— FVM 1.8.21 头文件;management/webserver/submodule/libct/—— libct 1.1.1.0 头文件;management/webserver/submodule/libfvm.so—— fusion 5.3.9-r1 编译出的动态链接库。
这些依赖在运行时也承担实际任务:main.go启动时调用fvm.InitFVMBytecode()初始化 FVM 字节码(字节码目录由配置detector.fsl_bytecode指定),而cmd/push_fsl.go、cmd/show_fsl.go分别通过 fvm.PushFSL 与 fvm.GenerateFullFSL 将策略选择器编译为 FSL 并写入数据库 / 打印到日志。
第三步:容器化构建
依赖就绪后,按 README 使用官方 Go 1.18 镜像构建:
cd management/ docker run -it --rm -w="/mnt" --mount type=bind,source="$(pwd)",target=/mnt chaitin.cn/ci/golang:1.18 bash cp webserver/submodule/libfvm.so /usr/lib/ make build-webserver在容器内先复制libfvm.so到/usr/lib/使链接器可找到动态库,再执行make build-webserver。查看 management/Makefile 可了解构建细节:
GOBUILD = $(GO) build -mod=readonly BUILDFLAGS := -ldflags "-X main.buildstamp=$(STAMP) -X main.githash=$(GITHASH) -X main.version=$(GITTAG)" .PHONY: build-webserver build-webserver: cd webserver && $(GOBUILD) $(BUILDFLAGS) -o ../build/webserver main.go .PHONY: build-tcd build-tcd: cd tcontrollerd && CGO_ENABLED=0 $(GOBUILD) $(BUILDFLAGS) -o ../build/tcontrollerd main.go要点说明:
- 使用
-mod=readonly防止构建过程静默改写go.mod; - 通过
-ldflags注入构建时间戳、Git 短哈希与版本号,供main.go的-v参数打印; build-webserver保留 CGO 以链接 FVM 动态库;而build-tcd显式设置CGO_ENABLED=0产出纯静态二进制;make build-all依次执行proto(调用scripts/genproto.sh)、build-webserver、build-tcd,一条命令完成代码生成与双进程构建。
运行时配置详解
开发环境使用的配置文件为 management/webserver/config.yml(文件头注明仅供开发使用,生产环境以package/build/mgt-api/webserver/config.yml为准),各配置段说明如下:
log: output: stdout # 日志输出目标:"stdout"、"stderr" 或文件路径 level: debug # 日志级别:"debug"、"info"、"warn"、"error" server: listen_addr: :9001 # HTTP API 监听地址(Gin 服务) dev_mode: true # 开发模式开关 db: url: postgres://safeline-ce:safeline-ce@127.0.0.1/safeline-ce # PostgreSQL 连接串 log_sql: false # 是否打印 SQL 日志 detector: addr: "" # 检测器(detector)地址 fsl_bytecode: fvm/bytecode # FVM 字节码目录,启动时由 InitFVMBytecode 加载 grpc_server: listen_addr: :9002 # gRPC 服务监听地址配置加载由 pkg/config/config.go 的InitConfigs完成:依次解析 DB、Log、Server、Detector、Telemetry、gRPC 等配置段,并支持通过环境变量覆盖两个资源目录 ——MANAGEMENT_RESOURCES_DIR与NGINX_RESOURCES_DIR。启动时还会从数据库读取SecretKey作为会话 cookie 的加密密钥(见 main.go)。
HTTP API 路由一览
main.go 中按是否需要认证将路由分为两组:/api公开路由与受middleware.AuthRequired保护的受限路由。端点常量定义在 api/endpoints.go,包括:
- 认证与会话:
POST /api/Login、POST /api/Logout、GET /api/OTPUrl、GET /api/User - 站点管理:
GET/POST/PUT/DELETE /api/Website - 检测日志:
GET /api/DetectLogList、GET /api/DetectLogDetail - 策略管理:
GET/POST/PUT/DELETE /api/PolicyRule、PUT /api/SwitchPolicyRule、GET/PUT /api/PolicyGroupGlobal - 仪表盘:
GET /api/dashboard/counts|sites|qps|requests|intercepts - 证书:
POST /api/UploadSSLCert、POST /api/SSLCert - 其他:
GET /api/Version、GET /api/UpgradeTips、POST /api/Behaviour、POST /api/FalsePositives、GET/PUT /api/SrcIPConfig
调试与运维时可通过环境变量切换认证行为(见 main.go):
NO_AUTH:设置后跳过登录认证(打印 "No auth" 警告);READ_ONLY:设置后叠加middleware.ReadOnly只读中间件;- 另内置
GET /api/Ping健康检查接口,返回{"message": "pong"}。
gRPC 订阅机制:站点配置下发通道
webserver与tcontrollerd通过 rpc/website.go 实现的双向流Subscribe协作。其工作机制为:
- 客户端(tcd)建立流后,服务端立即调用
publishFullWebsite(),从数据库读出全部站点并 JSON 序列化,以EventTypeFullWebsite事件推送给客户端; pingLoop按KeepaliveTime周期发送type=ping的心跳事件,客户端需回pong;recvLoop接收客户端应答,非pong消息视为站点更新结果(成功或err标记失败);- 通过
Subscriber全局单例保证同一时刻只有一个订阅者,新订阅会顶替旧连接; - 站点增删改时,API 层调用
Publish(msg, eventType)将变更同步推送,并等待客户端确认;超过WaitRspTimeout未收到结果则返回超时错误("Wait timeout for updating result")。
这套“服务端主动推送 + 客户端确认”的协议,正是 SafeLine 管理面与检测面保持站点配置一致性的关键通道。
运维辅助命令
webserver二进制还提供几个独立运维命令,均需在数据库初始化(database.InitDB)完成后执行:
-gen_certs:调用 cmd/gen_certs.go 生成服务器证书(server.crt/server.key)与客户端 CA 证书(client_ca.crt/client_ca.key),证书有效期 3650 天、RSA 4096 位,若文件已存在则跳过(WriteCertIfNotExist);-show_fsl:打印数据库中所有策略编译出的完整 FSL(以;换行美化输出),便于排查策略编译结果;-push_fsl:将最新策略编译并推送回数据库;-fake_logs:向数据库写入模拟检测日志,供前端开发与联调;-reset_user <username>:重置指定用户的密码。
小结
从 README 出发可以看到,SafeLine 的management/webserver模块虽然文档简洁,但其背后是一条完整的工程链路:protobuf 生成脚本(genproto.sh)保证 gRPC 契约代码与.proto同步、submodule 方式引入 FVM 检测依赖、Makefile 统一串联“生成 → 构建 → 测试 → 静态检查”流程,而 main.go 则把配置加载、数据库初始化、会话认证、REST API 与 gRPC 订阅通道有机组合起来。对于想二次开发或自建构建环境的开发者,按“装工具 → 生成 proto → 放依赖 → Docker 构建 → 配置运行”五步即可复现整个开发闭环。
【免费下载链接】SafeLineSafeLine is a self-hosted WAF(Web Application Firewall) / reverse proxy to protect your web apps from attacks and exploits.项目地址: https://gitcode.com/GitHub_Trending/sa/SafeLine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考