WebSocket 把 proxy_http_version 1.1 + Upgrade/Connection 移进 location / 内部
CI / verify (push) Canceled after 0s

This commit is contained in:
2026-10-17 11:58:43 +08:00
parent c1bcdd0b86
commit 6b8ff0e5a3
6 changed files with 35 additions and 12 deletions
+10
View File
@@ -81,6 +81,16 @@ func TestNginxRouteSharedTemplateSemantics(t *testing.T) {
}
}
denyIdx := strings.Index(out, "deny 8.8.8.8;")
// WebSocket 头必须落在 location 内部:location 自定义 proxy_set_header 后,
// server 级的那组不会被继承,写在 server 块里等于没生效(升级请求会一直挂起)
locationIdx := strings.Index(out, "location / {")
upgradeIdx := strings.Index(out, "proxy_set_header Upgrade $http_upgrade;")
if locationIdx < 0 || upgradeIdx < 0 || upgradeIdx < locationIdx {
t.Fatalf("Upgrade 头必须写在 location 内:\n%s", out)
}
if !strings.Contains(out, "proxy_read_timeout 3600s;") {
t.Fatalf("WebSocket 未配读超时时应给长连接默认超时:\n%s", out)
}
allowIdx := strings.Index(out, "allow 192.168.1.0/24;")
denyAllIdx := strings.Index(out, "deny all;")
if denyIdx < 0 || allowIdx < 0 || denyAllIdx < 0 || !(denyIdx < allowIdx && allowIdx < denyAllIdx) {
+12 -6
View File
@@ -31,7 +31,7 @@ import (
"github.com/havline/havline/internal/sysinfo"
)
const AgentVersion = "0.15.3"
const AgentVersion = "0.15.4"
// Config 是 havline-agent 的运行配置。agent 只在 VPS 本地管理自己的 Nginx 片段、证书和 frps 配置。
type Config struct {
@@ -1656,10 +1656,6 @@ func nginxRoute(req routeRequest, certDir string) string {
if req.ConnLimitMax > 0 {
b.WriteString(" limit_conn_status 503;\n")
}
if req.WebSocket {
b.WriteString(" proxy_http_version 1.1;\n")
b.WriteString(nginxtmpl.UpgradeHeaders(" ", "\"upgrade\""))
}
// IP 访问控制:白名单(allow + deny all)与黑名单(deny)可同时生效;
// 顺序由共享模板统一:deny → 仅大陆规则 → allow → deny all。
chinaDeny := ""
@@ -1690,7 +1686,17 @@ func nginxRoute(req routeRequest, certDir string) string {
Burst: req.RateLimitBurst,
Conn: req.ConnLimitMax,
}, " ")
fmt.Fprintf(&b, " location / {\n%s%s%s proxy_pass http://%s;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_http_version 1.1;\n }\n}\n", aclText, authLine, limitText, req.Upstream)
// WebSocket 必须写在 location 里:location 一旦自定义了 proxy_set_header,
// server 级的那组不会被继承——写在 server 块等于没写,表现就是升级请求一直挂起。
wsText := ""
if req.WebSocket {
wsText = nginxtmpl.UpgradeHeaders(" ", "\"upgrade\"")
// 规则没显式配 proxy_read_timeout 时给长连接留足空闲时间,避免 60 秒被 Nginx 掐断
if strings.TrimSpace(req.ProxyReadTimeout) == "" {
wsText += " proxy_read_timeout 3600s;\n"
}
}
fmt.Fprintf(&b, " location / {\n%s%s%s proxy_pass http://%s;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_http_version 1.1;\n%s }\n}\n", aclText, authLine, limitText, req.Upstream, wsText)
return b.String()
}