diff --git a/api.go b/api.go index 1cde3ab..68a3c33 100644 --- a/api.go +++ b/api.go @@ -347,6 +347,25 @@ type stringWriter interface { WriteString(s string) (int, error) } +// getProxyNextUpstream формирует строку proxy_next_upstream из кодов в settings. +// Дефолт: error timeout invalid_header http_500 http_502 http_503 http_504 +func getProxyNextUpstream(settings AppsSettings) string { + codes := "500,502,503,504" + if settings.ProxyNextUpstreamCodes.Valid && strings.TrimSpace(settings.ProxyNextUpstreamCodes.String) != "" { + codes = strings.TrimSpace(settings.ProxyNextUpstreamCodes.String) + } + + base := "error timeout invalid_header" + parts := strings.Split(codes, ",") + for _, part := range parts { + code := strings.TrimSpace(part) + if code != "" { + base += " http_" + code + } + } + return base +} + // getMaxFails возвращает max_fails из AppsSettings или дефолтное значение 5 func getMaxFails(settings AppsSettings) int { if settings.MaxFails.Valid && settings.MaxFails.Int64 >= 0 { diff --git a/db.go b/db.go index 63d7ef2..c5e60a1 100644 --- a/db.go +++ b/db.go @@ -160,6 +160,7 @@ func getAppsSettingsByClientTitle(db *sql.DB, clientTitle string) ([]AppsSetting max_fails, fail_timeout, balancing_method, + proxy_next_upstream_codes, custom_sw_nginx_ssl FROM apps_settings WHERE client_title = $1 @@ -194,6 +195,7 @@ func getAppsSettingsByClientTitle(db *sql.DB, clientTitle string) ([]AppsSetting &a.MaxFails, &a.FailTimeout, &a.BalancingMethod, + &a.ProxyNextUpstreamCodes, &a.CustomSWNginxSSL, ) if err != nil { diff --git a/nginx.go b/nginx.go index 5f41461..7d0aea6 100644 --- a/nginx.go +++ b/nginx.go @@ -272,7 +272,7 @@ func writeAngieResourceConfig(f *os.File, config Config, res ResourceData, conta f.WriteString(fmt.Sprintf(" error_log /var/log/angie/%d_%s_error.log error;\n\n", res.L7ResourceID, res.ServerName)) writeNetworkSettings(f, config) - writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug) + writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug, getProxyNextUpstream(res.AppsSettings)) if hasCustomLocation { log.Printf(" └─ Добавление location_angie_custom (отдельный блок) для l7ResourceID %d (HTTP, порт %d)", res.L7ResourceID, httpPort) @@ -325,7 +325,7 @@ func writeAngieResourceConfig(f *os.File, config Config, res ResourceData, conta } writeNetworkSettings(f, config) - writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug) + writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug, getProxyNextUpstream(res.AppsSettings)) if hasCustomLocation { log.Printf(" └─ Добавление location_angie_custom (отдельный блок) для l7ResourceID %d (HTTPS, порт %d)", res.L7ResourceID, httpsPort) @@ -399,26 +399,24 @@ func writeAngieSSLSettings(f *os.File, customSSL sql.NullString) { } // writeStandardServerSettings записывает стандартные настройки сервера (Angie) -func writeStandardServerSettings(f *os.File, customDirectives string, debug bool) { - settings := ` server_tokens off; - sendfile on; - gzip on; - client_max_body_size 0; - - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_http_version 1.1; - - js_set $safe_host main.sanitizeHost; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Connection $proxy_connection; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Host $safe_host; - proxy_set_header X-Original-Host $host; - proxy_pass_header Date; - proxy_pass_header Server; -` - f.WriteString(settings) +func writeStandardServerSettings(f *os.File, customDirectives string, debug bool, proxyNextUpstream string) { + f.WriteString(" server_tokens off;\n") + f.WriteString(" sendfile on;\n") + f.WriteString(" gzip on;\n") + f.WriteString(" client_max_body_size 0;\n") + f.WriteString("\n") + f.WriteString(fmt.Sprintf(" proxy_next_upstream %s;\n", proxyNextUpstream)) + f.WriteString(" proxy_http_version 1.1;\n") + f.WriteString("\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-Forwarded-For $proxy_add_x_forwarded_for;\n") + f.WriteString(" proxy_set_header Connection $proxy_connection;\n") + f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n") + f.WriteString(" proxy_set_header Host $safe_host;\n") + f.WriteString(" proxy_set_header X-Original-Host $host;\n") + f.WriteString(" proxy_pass_header Date;\n") + f.WriteString(" proxy_pass_header Server;\n") if debug { f.WriteString(" client_body_buffer_size 1m;\n") } @@ -426,24 +424,22 @@ func writeStandardServerSettings(f *os.File, customDirectives string, debug bool } // writeNginxStandardSettings записывает стандартные настройки сервера (Nginx) -func writeNginxStandardSettings(f *os.File, customDirectives string) { - settings := ` server_tokens off; - sendfile on; - gzip on; - client_max_body_size 0; - - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_http_version 1.1; - - #proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Connection $proxy_connection; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Host $backend_host; - proxy_pass_header Date; - proxy_pass_header Server; -` - f.WriteString(settings) +func writeNginxStandardSettings(f *os.File, customDirectives string, proxyNextUpstream string) { + f.WriteString(" server_tokens off;\n") + f.WriteString(" sendfile on;\n") + f.WriteString(" gzip on;\n") + f.WriteString(" client_max_body_size 0;\n") + f.WriteString("\n") + f.WriteString(fmt.Sprintf(" proxy_next_upstream %s;\n", proxyNextUpstream)) + f.WriteString(" proxy_http_version 1.1;\n") + f.WriteString("\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 Connection $proxy_connection;\n") + f.WriteString(" proxy_set_header Upgrade $http_upgrade;\n") + f.WriteString(" proxy_set_header Host $backend_host;\n") + f.WriteString(" proxy_pass_header Date;\n") + f.WriteString(" proxy_pass_header Server;\n") writeCustomOrDefaultDirectives(f, customDirectives) } @@ -514,7 +510,7 @@ func generateAngieCustomServerBlock(f *os.File, config Config, res ResourceData, res.L7ResourceID, sanitizeServerName(block.ServerName), block.Port)) writeNetworkSettings(f, config) - writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug) + writeStandardServerSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesAngieCustom), debug, getProxyNextUpstream(res.AppsSettings)) // Кастомные location блоки из location_angie_custom (перед location /) if customLocationStr != "" { @@ -703,7 +699,7 @@ func generateNginxResourceConfig(filepath string, config Config, res ResourceDat 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_recursive on;\n\n") - writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom)) + writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom), getProxyNextUpstream(res.AppsSettings)) if hasCustomNginxLocation && isFullNginxLocationBlock { log.Printf(" └─ Добавление location_nginx_custom (отдельный блок) для l7ResourceID %d (HTTP, порт %d)", res.L7ResourceID, httpPort) @@ -742,7 +738,7 @@ func generateNginxResourceConfig(filepath string, config Config, res ResourceDat 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_recursive on;\n\n") - writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom)) + writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom), getProxyNextUpstream(res.AppsSettings)) if hasCustomNginxLocation && isFullNginxLocationBlock { log.Printf(" └─ Добавление location_nginx_custom (отдельный блок) для l7ResourceID %d (HTTPS, порт %d)", res.L7ResourceID, httpsPort) @@ -836,7 +832,7 @@ func generateCustomServerBlock(f *os.File, res ResourceData, block CustomServerB f.WriteString(" real_ip_header X-Forwarded-For;\n") f.WriteString(" real_ip_recursive on;\n\n") - writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom)) + writeNginxStandardSettings(f, getCustomServerDirectives(res.AppsSettings.ServerDirectivesNginxCustom), getProxyNextUpstream(res.AppsSettings)) // Кастомные location блоки из location_nginx_custom (перед location /) if locationDirectives != "" && strings.Contains(locationDirectives, "location ") { diff --git a/sw_processor.go b/sw_processor.go index 40a5bcd..6000613 100644 --- a/sw_processor.go +++ b/sw_processor.go @@ -754,7 +754,7 @@ func writeSWStandardSettings(f *os.File, settings AppsSettings) { f.WriteString(" sendfile on;\n") f.WriteString(" gzip on;\n\n") - f.WriteString(" proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\n") + f.WriteString(" proxy_next_upstream " + getProxyNextUpstream(settings) + ";\n") f.WriteString(" proxy_http_version 1.1;\n\n") f.WriteString(" #proxy_set_header X-Real-IP $remote_addr;\n") @@ -783,7 +783,7 @@ func writeSWStandardSettings(f *os.File, settings AppsSettings) { f.WriteString(" client_max_body_size 1g;\n") f.WriteString(" large_client_header_buffers 4 128k;\n\n") - f.WriteString(" proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;\n") + f.WriteString(" proxy_next_upstream " + getProxyNextUpstream(settings) + ";\n") f.WriteString(" proxy_http_version 1.1;\n") f.WriteString(" proxy_connect_timeout 3s;\n") f.WriteString(" proxy_busy_buffers_size 32k;\n") diff --git a/types.go b/types.go index 9329ca3..20e7694 100644 --- a/types.go +++ b/types.go @@ -37,6 +37,7 @@ type AppsSettings struct { MaxFails sql.NullInt64 // Количество неудачных попыток к origin (дефолт 5) FailTimeout sql.NullInt64 // Время в секундах после которого origin снова доступен (дефолт 15) BalancingMethod sql.NullString // Метод балансировки: least_conn, ip_hash, random и т.д. + ProxyNextUpstreamCodes sql.NullString // HTTP-коды для proxy_next_upstream (дефолт: 500,502,503,504) CustomSWNginxSSL sql.NullString // Кастомные SSL директивы для SW nginx - полностью заменяют дефолтные если заполнено }