This commit is contained in:
Magnus Root 2026-06-09 17:34:53 +03:00
parent f01944f474
commit ee35b61ded
2 changed files with 105 additions and 20 deletions

100
nginx.go
View file

@ -54,6 +54,21 @@ func generateAngieConfigsWithoutReload(config Config, clientTitle string, client
} }
} }
// Если есть ресурсы с x_sid_check = true — генерируем map блоки
hasSidCheck := false
for _, res := range resources {
if res.AppsSettings.XSidCheck {
hasSidCheck = true
break
}
}
if hasSidCheck {
if err := writeAngieXSidMap(f, resources, resourcePortMap); err != nil {
os.Remove(tmpFile)
return false, fmt.Errorf("ошибка генерации x_sid map: %w", err)
}
}
f.Close() f.Close()
newHash, err := getFileHash(tmpFile) newHash, err := getFileHash(tmpFile)
@ -106,6 +121,57 @@ func generateAngieConfigs(config Config, clientTitle string, clientInfo ClientIn
return nil return nil
} }
// writeAngieXSidMap генерирует map блок для маршрутизации по $http_x_sid
// Используется когда x_sid_check = true в apps_settings хотя бы для одного ресурса
func writeAngieXSidMap(f *os.File, resources []ResourceData, resourcePortMap map[int][]PortMapping) error {
// Собираем уникальные порты только для ресурсов с x_sid_check = true
httpsPortSet := make(map[int]bool)
httpPortSet := make(map[int]bool)
for _, res := range resources {
if !res.AppsSettings.XSidCheck {
continue
}
for _, p := range getInputHTTPSPorts(res.AppsSettings) {
httpsPortSet[p] = true
}
for _, p := range getInputHTTPPorts(res.AppsSettings) {
httpPortSet[p] = true
}
}
// Map для HTTPS: $http_x_sid → имя upstream
for port := range httpsPortSet {
f.WriteString(fmt.Sprintf("\n# x_sid_check: маршрутизация по X-SID для HTTPS порта %d\n", port))
f.WriteString(fmt.Sprintf("map $http_x_sid $x_sid_upstream_https_%d {\n", port))
f.WriteString(" default \"\";\n")
for _, res := range resources {
if !res.AppsSettings.XSidCheck {
continue
}
upstreamName := fmt.Sprintf("secure%d_%d_%s", res.L7ResourceID, port, res.ServerName)
f.WriteString(fmt.Sprintf(" \"%d\" \"%s\";\n", res.L7ResourceID, upstreamName))
}
f.WriteString("}\n")
}
// Map для HTTP: $http_x_sid → имя upstream
for port := range httpPortSet {
f.WriteString(fmt.Sprintf("\n# x_sid_check: маршрутизация по X-SID для HTTP порта %d\n", port))
f.WriteString(fmt.Sprintf("map $http_x_sid $x_sid_upstream_http_%d {\n", port))
f.WriteString(" default \"\";\n")
for _, res := range resources {
if !res.AppsSettings.XSidCheck {
continue
}
upstreamName := fmt.Sprintf("unsecure%d_%d_%s", res.L7ResourceID, port, res.ServerName)
f.WriteString(fmt.Sprintf(" \"%d\" \"%s\";\n", res.L7ResourceID, upstreamName))
}
f.WriteString("}\n")
}
return nil
}
// writeAngieResourceConfig записывает конфигурацию для одного ресурса в Angie // writeAngieResourceConfig записывает конфигурацию для одного ресурса в Angie
func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo, res ResourceData, containerPorts []PortMapping, debug bool) error { func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo, res ResourceData, containerPorts []PortMapping, debug bool) error {
allDomains := []string{res.ServerName} allDomains := []string{res.ServerName}
@ -267,8 +333,12 @@ func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo,
f.WriteString("server {\n") f.WriteString("server {\n")
f.WriteString(fmt.Sprintf(" listen %d;\n", httpPort)) f.WriteString(fmt.Sprintf(" listen %d;\n", httpPort))
if res.AppsSettings.XSidCheck {
f.WriteString(" server_name _;\n\n")
} else {
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " "))) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " ")))
f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_access.log waf;\n", res.L7ResourceID, res.ServerName)) }
f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_access.log waf buffer=32m flush=5s;\n", res.L7ResourceID, res.ServerName))
f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName))
writeNetworkSettings(f, config, clientInfo) writeNetworkSettings(f, config, clientInfo)
@ -281,11 +351,16 @@ func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo,
} }
f.WriteString(" location / {\n") f.WriteString(" location / {\n")
if res.AppsSettings.XSidCheck {
f.WriteString(fmt.Sprintf(" if ($x_sid_upstream_http_%d = \"\") { return 444; }\n", httpPort))
f.WriteString(fmt.Sprintf(" proxy_pass http://$x_sid_upstream_http_%d;\n", httpPort))
} else {
if res.AppsSettings.ServerAngieCustom.Valid && serverDirectivesWithoutBlocks != "" { if res.AppsSettings.ServerAngieCustom.Valid && serverDirectivesWithoutBlocks != "" {
log.Printf(" └─ Добавление server_angie_custom для l7ResourceID %d (HTTP location /)", res.L7ResourceID) log.Printf(" └─ Добавление server_angie_custom для l7ResourceID %d (HTTP location /)", res.L7ResourceID)
writeIndentedLines(f, serverDirectivesWithoutBlocks) writeIndentedLines(f, serverDirectivesWithoutBlocks)
} }
f.WriteString(fmt.Sprintf(" proxy_pass http://%s;\n", upstreamName)) f.WriteString(fmt.Sprintf(" proxy_pass http://%s;\n", upstreamName))
}
f.WriteString(" }\n") f.WriteString(" }\n")
f.WriteString("}\n\n") f.WriteString("}\n\n")
} else { } else {
@ -316,8 +391,12 @@ func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo,
} else { } else {
f.WriteString(fmt.Sprintf(" listen %d;\n", httpsPort)) f.WriteString(fmt.Sprintf(" listen %d;\n", httpsPort))
} }
if res.AppsSettings.XSidCheck {
f.WriteString(" server_name _;\n\n")
} else {
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " "))) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " ")))
f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_access.log waf;\n", res.L7ResourceID, res.ServerName)) }
f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_access.log waf buffer=32m flush=5s;\n", res.L7ResourceID, res.ServerName))
f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName))
if sslEnabled { if sslEnabled {
@ -334,11 +413,16 @@ func writeAngieResourceConfig(f *os.File, config Config, clientInfo ClientInfo,
} }
f.WriteString(" location / {\n") f.WriteString(" location / {\n")
if res.AppsSettings.XSidCheck {
f.WriteString(fmt.Sprintf(" if ($x_sid_upstream_https_%d = \"\") { return 444; }\n", httpsPort))
f.WriteString(fmt.Sprintf(" proxy_pass http://$x_sid_upstream_https_%d;\n", httpsPort))
} else {
if res.AppsSettings.ServerAngieCustom.Valid && serverDirectivesWithoutBlocks != "" { if res.AppsSettings.ServerAngieCustom.Valid && serverDirectivesWithoutBlocks != "" {
log.Printf(" └─ Добавление server_angie_custom для l7ResourceID %d (HTTPS location /)", res.L7ResourceID) log.Printf(" └─ Добавление server_angie_custom для l7ResourceID %d (HTTPS location /)", res.L7ResourceID)
writeIndentedLines(f, serverDirectivesWithoutBlocks) writeIndentedLines(f, serverDirectivesWithoutBlocks)
} }
f.WriteString(fmt.Sprintf(" proxy_pass http://%s;\n", upstreamName)) f.WriteString(fmt.Sprintf(" proxy_pass http://%s;\n", upstreamName))
}
f.WriteString(" }\n") f.WriteString(" }\n")
f.WriteString("}\n\n") f.WriteString("}\n\n")
} else { } else {
@ -418,7 +502,7 @@ func writeStandardServerSettings(f *os.File, customDirectives string, debug bool
f.WriteString("\n") f.WriteString("\n")
f.WriteString(" js_set $safe_host main.sanitizeHost;\n") f.WriteString(" js_set $safe_host main.sanitizeHost;\n")
f.WriteString(" proxy_set_header X-Real-IP $remote_addr;\n") f.WriteString(" proxy_set_header X-Real-IP $remote_addr;\n")
f.WriteString(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n") f.WriteString(" proxy_set_header X-Forwarded-For $remote_addr;\n")
f.WriteString(" proxy_set_header Connection $proxy_connection;\n") f.WriteString(" proxy_set_header Connection $proxy_connection;\n")
f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n") f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n")
f.WriteString(" proxy_set_header Host $safe_host;\n") f.WriteString(" proxy_set_header Host $safe_host;\n")
@ -442,7 +526,7 @@ func writeNginxStandardSettings(f *os.File, customDirectives string, proxyNextUp
f.WriteString(" proxy_http_version 1.1;\n") f.WriteString(" proxy_http_version 1.1;\n")
f.WriteString("\n") f.WriteString("\n")
f.WriteString(" #proxy_set_header X-Real-IP $remote_addr;\n") f.WriteString(" #proxy_set_header X-Real-IP $remote_addr;\n")
f.WriteString(" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n") f.WriteString(" proxy_set_header X-Forwarded-For $remote_addr;\n")
f.WriteString(" proxy_set_header Connection $proxy_connection;\n") f.WriteString(" proxy_set_header Connection $proxy_connection;\n")
f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n") f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n")
f.WriteString(" proxy_set_header Host $backend_host;\n") f.WriteString(" proxy_set_header Host $backend_host;\n")
@ -541,7 +625,7 @@ func generateAngieCustomServerBlock(f *os.File, config Config, clientInfo Client
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", block.ServerName)) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", block.ServerName))
} }
f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_port%d_access.log waf;\n", f.WriteString(fmt.Sprintf(" access_log /var/log/angie/%d_%s_port%d_access.log waf buffer=32m flush=5s;\n",
res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port)) res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port))
f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_port%d_error.log error;\n\n", f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_port%d_error.log error;\n\n",
res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port)) res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port))
@ -734,7 +818,7 @@ func generateNginxResourceConfig(filepath string, config Config, res ResourceDat
f.WriteString("server {\n") f.WriteString("server {\n")
f.WriteString(fmt.Sprintf(" listen %d;\n", httpPort)) f.WriteString(fmt.Sprintf(" listen %d;\n", httpPort))
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " "))) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " ")))
f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_access.log waf;\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_access.log waf buffer=32m flush=5s;\n", res.L7ResourceID, res.ServerName))
f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName))
f.WriteString(" set_real_ip_from 172.16.0.0/12;\n") f.WriteString(" set_real_ip_from 172.16.0.0/12;\n")
f.WriteString(" real_ip_header X-Forwarded-For;\n") f.WriteString(" real_ip_header X-Forwarded-For;\n")
@ -771,7 +855,7 @@ func generateNginxResourceConfig(filepath string, config Config, res ResourceDat
f.WriteString("server {\n") f.WriteString("server {\n")
f.WriteString(fmt.Sprintf(" listen %d;\n", httpsPort)) f.WriteString(fmt.Sprintf(" listen %d;\n", httpsPort))
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " "))) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", strings.Join(defaultDomains, " ")))
f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_access.log waf;\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_access.log waf buffer=32m flush=5s;\n", res.L7ResourceID, res.ServerName))
f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName)) f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName))
f.WriteString(" proxy_ssl_server_name on;\n") f.WriteString(" proxy_ssl_server_name on;\n")
f.WriteString(" proxy_ssl_name $host;\n\n") f.WriteString(" proxy_ssl_name $host;\n\n")
@ -863,7 +947,7 @@ func generateCustomServerBlock(f *os.File, res ResourceData, block CustomServerB
f.WriteString(fmt.Sprintf(" server_name %s;\n\n", block.ServerName)) f.WriteString(fmt.Sprintf(" server_name %s;\n\n", block.ServerName))
} }
f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_port%d_access.log waf;\n", f.WriteString(fmt.Sprintf(" access_log /var/log/nginx/%d_%s_port%d_access.log waf buffer=32m flush=5s;\n",
res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port)) res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port))
f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_port%d_error.log error;\n\n", f.WriteString(fmt.Sprintf(" error_log /var/log/nginx/%d_%s_port%d_error.log error;\n\n",
res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port)) res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port))

View file

@ -38,6 +38,7 @@ type AppsSettings struct {
FailTimeout sql.NullInt64 // Время в секундах после которого origin снова доступен (дефолт 15) FailTimeout sql.NullInt64 // Время в секундах после которого origin снова доступен (дефолт 15)
BalancingMethod sql.NullString // Метод балансировки: least_conn, ip_hash, random и т.д. BalancingMethod sql.NullString // Метод балансировки: least_conn, ip_hash, random и т.д.
ProxyNextUpstreamCodes sql.NullString // HTTP-коды для proxy_next_upstream (дефолт: 500,502,503,504) ProxyNextUpstreamCodes sql.NullString // HTTP-коды для proxy_next_upstream (дефолт: 500,502,503,504)
XSidCheck bool // Маршрутизация в Angie по x-sid вместо server_name (дефолт: false)
CustomSWNginxSSL sql.NullString // Кастомные SSL директивы для SW nginx - полностью заменяют дефолтные если заполнено CustomSWNginxSSL sql.NullString // Кастомные SSL директивы для SW nginx - полностью заменяют дефолтные если заполнено
} }