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
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:
@@ -3,6 +3,7 @@ package agent
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -309,6 +310,83 @@ func (s *Server) nginxReload(w http.ResponseWriter, _ *http.Request) {
|
||||
writeJSON(w, http.StatusOK, payload)
|
||||
}
|
||||
|
||||
// nginxAction 启动 / 停止 / 重启 VPS 上的 Nginx。
|
||||
//
|
||||
// 不走 systemctl:宝塔、源码编译等安装方式没有 systemd unit,
|
||||
// 统一用 nginx 自身信号控制,与 reloadNginx 走同一条路径,行为一致可预期。
|
||||
func (s *Server) nginxAction(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<10)).Decode(&req); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
|
||||
return
|
||||
}
|
||||
if req.Action != "start" && req.Action != "stop" && req.Action != "restart" {
|
||||
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "action 需为 start/stop/restart"})
|
||||
return
|
||||
}
|
||||
nginx := s.nginxPath()
|
||||
if nginx == "" {
|
||||
writeJSON(w, http.StatusBadGateway, map[string]string{"error": "未找到 nginx 可执行文件:请先安装 Nginx,或用 HAVLINE_AGENT_NGINX_BIN 指定路径"})
|
||||
return
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if err := runNginxAction(nginx, req.Action); err != nil {
|
||||
writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// 启停异步生效,留出短暂窗口再重新探测,避免页面读到旧状态
|
||||
time.Sleep(600 * time.Millisecond)
|
||||
s.invalidateNginxProbe()
|
||||
probe := s.probeNginx()
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"ok": true,
|
||||
"action": req.Action,
|
||||
"nginx_running": probe.Running,
|
||||
"nginx_ok": probe.OK,
|
||||
"nginx_error": probe.Error,
|
||||
})
|
||||
}
|
||||
|
||||
// runNginxAction 执行一次启停;已经是目标状态时按幂等处理,不报错。
|
||||
func runNginxAction(nginx, action string) error {
|
||||
running := nginxRunning()
|
||||
switch action {
|
||||
case "start":
|
||||
if running {
|
||||
return nil
|
||||
}
|
||||
return startNginx(nginx)
|
||||
case "stop":
|
||||
if !running {
|
||||
return nil
|
||||
}
|
||||
return stopNginx(nginx)
|
||||
default: // restart
|
||||
if running {
|
||||
_ = stopNginx(nginx)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
return startNginx(nginx)
|
||||
}
|
||||
}
|
||||
|
||||
func startNginx(nginx string) error {
|
||||
if out, err := exec.Command(nginx).CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("启动 Nginx 失败:%s", strings.TrimSpace(string(out)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopNginx(nginx string) error {
|
||||
if out, err := exec.Command(nginx, "-s", "stop").CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("停止 Nginx 失败:%s", strings.TrimSpace(string(out)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// frpsConfig 回读 VPS 上的 frps.toml,供应用侧与「即将下发的内容」比对,检出被手工修改的情况
|
||||
func (s *Server) frpsConfig(w http.ResponseWriter, _ *http.Request) {
|
||||
path := strings.TrimSpace(s.cfg.FrpsConfigPath)
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/havline/havline/internal/sysinfo"
|
||||
)
|
||||
|
||||
const AgentVersion = "0.15.1"
|
||||
const AgentVersion = "0.15.2"
|
||||
|
||||
// Config 是 havline-agent 的运行配置。agent 只在 VPS 本地管理自己的 Nginx 片段、证书和 frps 配置。
|
||||
type Config struct {
|
||||
@@ -224,6 +224,7 @@ func agentRoutes(s *Server) []agentRoute {
|
||||
{http.MethodGet, "/api/v1/frps/config", s.frpsConfig},
|
||||
{http.MethodGet, "/api/v1/certs", s.certs},
|
||||
{http.MethodPost, "/api/v1/nginx/reload", s.nginxReload},
|
||||
{http.MethodPost, "/api/v1/nginx/action", s.nginxAction},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user