chore(release): 发布 v1.9.2
CI / verify (push) Canceled after 0s
Docker Release / build-and-push (amd64, linux/amd64) (push) Canceled after 0s
Docker Release / build-and-push (arm64, linux/arm64) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Docker Release / create-manifest (push) Canceled after 0s

- 「公网服务端」新增 Nginx 启停控制(Agent 0.15.2,停止带二次确认)
- frps 启动失败不再误报成功,并增强启动诊断
- frps vhost 端口禁止 80/443,避免与 VPS 上 Nginx 冲突
- 旧服务端配置的 tcp_mux / login_fail_exit 默认值补齐
- 新增安全审查、页面布局方案与场景操作文档
This commit is contained in:
2026-10-07 19:26:02 +08:00
parent a7d71752e3
commit 2a0740a60f
55 changed files with 5065 additions and 467 deletions
+24
View File
@@ -219,9 +219,15 @@ const agentMinVersionInsights = "0.11.0"
// agentMinVersionRouteVersions 是域名 vhost 版本列表 / 对比 / 回滚端点要求的最低 agent 版本
const agentMinVersionRouteVersions = "0.12.2"
// agentMinVersionNginxAction 是 Nginx 启停(start / stop / restart)端点要求的最低 agent 版本
const agentMinVersionNginxAction = "0.15.2"
// ErrAgentEndpointMissing 表示 VPS 上的 agent 版本过旧、没有该端点(HTTP 404/405)
var ErrAgentEndpointMissing = errors.New("VPS 上的 agent 版本过低,不支持该接口")
// ErrAgentTokenMismatch 表示 Havline 保存的 Token 与 VPS 上 Agent 配置不一致。
var ErrAgentTokenMismatch = errors.New("Agent Token 不匹配,请点击「升级 Agent」重新同步")
// statusError 保留 HTTP 状态码,便于上层区分「端点不存在」与真实错误
type statusError struct {
code int
@@ -232,6 +238,14 @@ func (e *statusError) Error() string {
return fmt.Sprintf("agent 返回 HTTP %d: %s", e.code, e.body)
}
func wrapAgentAuth(err error) error {
var statusErr *statusError
if errors.As(err, &statusErr) && statusErr.code == http.StatusUnauthorized {
return fmt.Errorf("%w: %s", ErrAgentTokenMismatch, statusErr.body)
}
return err
}
// wrapEndpointMissing 把「端点不存在」统一成带升级提示的错误(按端点给出最低版本),其它错误原样返回
func wrapEndpointMissing(err error, minVersion string) error {
var statusErr *statusError
@@ -280,6 +294,16 @@ func (c *AgentClient) NginxReload(ctx context.Context) (map[string]any, error) {
return result, nil
}
// NginxAction 启动 / 停止 / 重启 VPS 上的 Nginx(需 agent ≥ 0.15.2)
func (c *AgentClient) NginxAction(ctx context.Context, action string) (map[string]any, error) {
var result map[string]any
payload := map[string]string{"action": action}
if err := c.request(ctx, http.MethodPost, "/api/v1/nginx/action", payload, &result); err != nil {
return nil, wrapEndpointMissing(err, agentMinVersionNginxAction)
}
return result, nil
}
// FRPSConfig 回读 VPS 上的 frps.toml(用于与下发内容比对)
func (c *AgentClient) FRPSConfig(ctx context.Context) (map[string]any, error) {
var result map[string]any