refactor: extract startProxyServers helper from runServers
- commit
- 5c7260102f36221567b6feb07d15d24232618ae3
- author
- brice · · 2026-03-22 18:53 UTC
- parent
- e4d9ea0
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +49 -43
M internal/app/run.go +49 -43
| @@ -1796,49 +1796,9 @@ func runServers(ctx context.Context, v *viper.Viper, cfg Config, registryHandler | |||
| 1796 | 1796 | ||
| 1797 | 1797 | registrySrv, registryReady := startServer(fmt.Sprintf(":%d", cfg.Server.RegistryPort), registryHandler, "registry", nil, errChan, log) | |
| 1798 | 1798 | ||
| 1799 | - | var proxySrv *http.Server | |
| 1800 | - | var proxyReady <-chan struct{} | |
| 1801 | - | var tlsSrv *http.Server | |
| 1802 | - | var tlsReady <-chan struct{} | |
| 1803 | - | if cfg.Server.TLSEnabled { | |
| 1804 | - | if cfg.Server.TLSCertFile == "" || cfg.Server.TLSKeyFile == "" { | |
| 1805 | - | return fmt.Errorf("server.tls_enabled=true requires both server.tls_cert_file and server.tls_key_file") | |
| 1806 | - | } | |
| 1807 | - | // When TLS is enabled, HTTP port becomes redirect-only. | |
| 1808 | - | tlsPort := cfg.Server.TLSPort | |
| 1809 | - | redirectHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 1810 | - | host := r.Host | |
| 1811 | - | if h, _, err := net.SplitHostPort(host); err == nil { | |
| 1812 | - | host = h | |
| 1813 | - | } else if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { | |
| 1814 | - | host = strings.TrimSuffix(strings.TrimPrefix(host, "["), "]") | |
| 1815 | - | } | |
| 1816 | - | if tlsPort != 443 { | |
| 1817 | - | host = net.JoinHostPort(host, strconv.Itoa(tlsPort)) | |
| 1818 | - | } else if strings.Contains(host, ":") { | |
| 1819 | - | // Re-bracket bare IPv6 literal for the URL. | |
| 1820 | - | host = "[" + host + "]" | |
| 1821 | - | } | |
| 1822 | - | target := "https://" + host + r.RequestURI | |
| 1823 | - | http.Redirect(w, r, target, http.StatusPermanentRedirect) | |
| 1824 | - | }) | |
| 1825 | - | proxySrv, proxyReady = startServer(fmt.Sprintf(":%d", cfg.Server.Port), redirectHandler, "proxy-redirect", nil, errChan, log) | |
| 1826 | - | tlsSrv, tlsReady = startTLSServer( | |
| 1827 | - | fmt.Sprintf(":%d", cfg.Server.TLSPort), | |
| 1828 | - | proxyHandler, | |
| 1829 | - | "proxy-tls", | |
| 1830 | - | cfg.Server.TLSCertFile, | |
| 1831 | - | cfg.Server.TLSKeyFile, | |
| 1832 | - | errChan, | |
| 1833 | - | log, | |
| 1834 | - | ) | |
| 1835 | - | } else { | |
| 1836 | - | // Enable both HTTP/1.1 and cleartext HTTP/2 on the proxy server so Gordon can | |
| 1837 | - | // accept h2c traffic from clients and load balancers (e.g. Cloudflare). | |
| 1838 | - | var proxyProtos http.Protocols | |
| 1839 | - | proxyProtos.SetHTTP1(true) | |
| 1840 | - | proxyProtos.SetUnencryptedHTTP2(true) | |
| 1841 | - | proxySrv, proxyReady = startServer(fmt.Sprintf(":%d", cfg.Server.Port), proxyHandler, "proxy", &proxyProtos, errChan, log) | |
| 1799 | + | proxySrv, proxyReady, tlsSrv, tlsReady, err := startProxyServers(cfg, proxyHandler, errChan, log) | |
| 1800 | + | if err != nil { | |
| 1801 | + | return err | |
| 1842 | 1802 | } | |
| 1843 | 1803 | ||
| 1844 | 1804 | // Wait for all enabled servers to bind their ports before auto-starting containers. | |
| @@ -2119,6 +2079,52 @@ func gracefulShutdown(registrySrv, proxySrv, tlsSrv *http.Server, containerSvc * | |||
| 2119 | 2079 | log.Info().Msg("Gordon stopped") | |
| 2120 | 2080 | } | |
| 2121 | 2081 | ||
| 2082 | + | // startProxyServers sets up proxy server(s) depending on TLS configuration. | |
| 2083 | + | // With TLS enabled, the HTTP port becomes a redirect-only server and a separate TLS server handles traffic. | |
| 2084 | + | // Without TLS, a single server handles both HTTP/1.1 and cleartext HTTP/2. | |
| 2085 | + | func startProxyServers(cfg Config, proxyHandler http.Handler, errChan chan<- error, log zerowrap.Logger) (*http.Server, <-chan struct{}, *http.Server, <-chan struct{}, error) { | |
| 2086 | + | if !cfg.Server.TLSEnabled { | |
| 2087 | + | var proxyProtos http.Protocols | |
| 2088 | + | proxyProtos.SetHTTP1(true) | |
| 2089 | + | proxyProtos.SetUnencryptedHTTP2(true) | |
| 2090 | + | srv, ready := startServer(fmt.Sprintf(":%d", cfg.Server.Port), proxyHandler, "proxy", &proxyProtos, errChan, log) | |
| 2091 | + | return srv, ready, nil, nil, nil | |
| 2092 | + | } | |
| 2093 | + | ||
| 2094 | + | if cfg.Server.TLSCertFile == "" || cfg.Server.TLSKeyFile == "" { | |
| 2095 | + | return nil, nil, nil, nil, fmt.Errorf("server.tls_enabled=true requires both server.tls_cert_file and server.tls_key_file") | |
| 2096 | + | } | |
| 2097 | + | ||
| 2098 | + | tlsPort := cfg.Server.TLSPort | |
| 2099 | + | redirectHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 2100 | + | host := r.Host | |
| 2101 | + | if h, _, err := net.SplitHostPort(host); err == nil { | |
| 2102 | + | host = h | |
| 2103 | + | } else if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { | |
| 2104 | + | host = strings.TrimSuffix(strings.TrimPrefix(host, "["), "]") | |
| 2105 | + | } | |
| 2106 | + | if tlsPort != 443 { | |
| 2107 | + | host = net.JoinHostPort(host, strconv.Itoa(tlsPort)) | |
| 2108 | + | } else if strings.Contains(host, ":") { | |
| 2109 | + | host = "[" + host + "]" | |
| 2110 | + | } | |
| 2111 | + | target := "https://" + host + r.RequestURI | |
| 2112 | + | http.Redirect(w, r, target, http.StatusPermanentRedirect) | |
| 2113 | + | }) | |
| 2114 | + | ||
| 2115 | + | proxySrv, proxyReady := startServer(fmt.Sprintf(":%d", cfg.Server.Port), redirectHandler, "proxy-redirect", nil, errChan, log) | |
| 2116 | + | tlsSrv, tlsReady := startTLSServer( | |
| 2117 | + | fmt.Sprintf(":%d", cfg.Server.TLSPort), | |
| 2118 | + | proxyHandler, | |
| 2119 | + | "proxy-tls", | |
| 2120 | + | cfg.Server.TLSCertFile, | |
| 2121 | + | cfg.Server.TLSKeyFile, | |
| 2122 | + | errChan, | |
| 2123 | + | log, | |
| 2124 | + | ) | |
| 2125 | + | return proxySrv, proxyReady, tlsSrv, tlsReady, nil | |
| 2126 | + | } | |
| 2127 | + | ||
| 2122 | 2128 | // startServer starts an HTTP server, returning the server instance and a channel | |
| 2123 | 2129 | // that closes once the listening socket is bound. This lets callers wait for the | |
| 2124 | 2130 | // port to be ready before taking actions that depend on it (e.g. auto-start | |
| @@ -1796,49 +1796,9 @@ func runServers(ctx context.Context, v *viper.Viper, cfg Config, registryHandler | |||||
| 1796 | 1796 | ||||
| 1797 | registrySrv, registryReady := startServer(fmt.Sprintf(":%d", cfg.Server.RegistryPort), registryHandler, "registry", nil, errChan, log) | 1797 | registrySrv, registryReady := startServer(fmt.Sprintf(":%d", cfg.Server.RegistryPort), registryHandler, "registry", nil, errChan, log) | ||
| 1798 | 1798 | ||||
| 1799 | - | var proxySrv *http.Server | 1799 | + | proxySrv, proxyReady, tlsSrv, tlsReady, err := startProxyServers(cfg, proxyHandler, errChan, log) |
| 1800 | - | var proxyReady <-chan struct{} | 1800 | + | if err != nil { |
| 1801 | - | var tlsSrv *http.Server | 1801 | + | return err |
| 1802 | - | var tlsReady <-chan struct{} | |||
| 1803 | - | if cfg.Server.TLSEnabled { | |||
| 1804 | - | if cfg.Server.TLSCertFile == "" || cfg.Server.TLSKeyFile == "" { | |||
| 1805 | - | return fmt.Errorf("server.tls_enabled=true requires both server.tls_cert_file and server.tls_key_file") | |||
| 1806 | - | } | |||
| 1807 | - | // When TLS is enabled, HTTP port becomes redirect-only. | |||
| 1808 | - | tlsPort := cfg.Server.TLSPort | |||
| 1809 | - | redirectHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |||
| 1810 | - | host := r.Host | |||
| 1811 | - | if h, _, err := net.SplitHostPort(host); err == nil { | |||
| 1812 | - | host = h | |||
| 1813 | - | } else if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { | |||
| 1814 | - | host = strings.TrimSuffix(strings.TrimPrefix(host, "["), "]") | |||
| 1815 | - | } | |||
| 1816 | - | if tlsPort != 443 { | |||
| 1817 | - | host = net.JoinHostPort(host, strconv.Itoa(tlsPort)) | |||
| 1818 | - | } else if strings.Contains(host, ":") { | |||
| 1819 | - | // Re-bracket bare IPv6 literal for the URL. | |||
| 1820 | - | host = "[" + host + "]" | |||
| 1821 | - | } | |||
| 1822 | - | target := "https://" + host + r.RequestURI | |||
| 1823 | - | http.Redirect(w, r, target, http.StatusPermanentRedirect) | |||
| 1824 | - | }) | |||
| 1825 | - | proxySrv, proxyReady = startServer(fmt.Sprintf(":%d", cfg.Server.Port), redirectHandler, "proxy-redirect", nil, errChan, log) | |||
| 1826 | - | tlsSrv, tlsReady = startTLSServer( | |||
| 1827 | - | fmt.Sprintf(":%d", cfg.Server.TLSPort), | |||
| 1828 | - | proxyHandler, | |||
| 1829 | - | "proxy-tls", | |||
| 1830 | - | cfg.Server.TLSCertFile, | |||
| 1831 | - | cfg.Server.TLSKeyFile, | |||
| 1832 | - | errChan, | |||
| 1833 | - | log, | |||
| 1834 | - | ) | |||
| 1835 | - | } else { | |||
| 1836 | - | // Enable both HTTP/1.1 and cleartext HTTP/2 on the proxy server so Gordon can | |||
| 1837 | - | // accept h2c traffic from clients and load balancers (e.g. Cloudflare). | |||
| 1838 | - | var proxyProtos http.Protocols | |||
| 1839 | - | proxyProtos.SetHTTP1(true) | |||
| 1840 | - | proxyProtos.SetUnencryptedHTTP2(true) | |||
| 1841 | - | proxySrv, proxyReady = startServer(fmt.Sprintf(":%d", cfg.Server.Port), proxyHandler, "proxy", &proxyProtos, errChan, log) | |||
| 1842 | } | 1802 | } | ||
| 1843 | 1803 | ||||
| 1844 | // Wait for all enabled servers to bind their ports before auto-starting containers. | 1804 | // Wait for all enabled servers to bind their ports before auto-starting containers. | ||
| @@ -2119,6 +2079,52 @@ func gracefulShutdown(registrySrv, proxySrv, tlsSrv *http.Server, containerSvc * | |||||
| 2119 | log.Info().Msg("Gordon stopped") | 2079 | log.Info().Msg("Gordon stopped") | ||
| 2120 | } | 2080 | } | ||
| 2121 | 2081 | ||||
| 2082 | + | // startProxyServers sets up proxy server(s) depending on TLS configuration. | |||
| 2083 | + | // With TLS enabled, the HTTP port becomes a redirect-only server and a separate TLS server handles traffic. | |||
| 2084 | + | // Without TLS, a single server handles both HTTP/1.1 and cleartext HTTP/2. | |||
| 2085 | + | func startProxyServers(cfg Config, proxyHandler http.Handler, errChan chan<- error, log zerowrap.Logger) (*http.Server, <-chan struct{}, *http.Server, <-chan struct{}, error) { | |||
| 2086 | + | if !cfg.Server.TLSEnabled { | |||
| 2087 | + | var proxyProtos http.Protocols | |||
| 2088 | + | proxyProtos.SetHTTP1(true) | |||
| 2089 | + | proxyProtos.SetUnencryptedHTTP2(true) | |||
| 2090 | + | srv, ready := startServer(fmt.Sprintf(":%d", cfg.Server.Port), proxyHandler, "proxy", &proxyProtos, errChan, log) | |||
| 2091 | + | return srv, ready, nil, nil, nil | |||
| 2092 | + | } | |||
| 2093 | + | ||||
| 2094 | + | if cfg.Server.TLSCertFile == "" || cfg.Server.TLSKeyFile == "" { | |||
| 2095 | + | return nil, nil, nil, nil, fmt.Errorf("server.tls_enabled=true requires both server.tls_cert_file and server.tls_key_file") | |||
| 2096 | + | } | |||
| 2097 | + | ||||
| 2098 | + | tlsPort := cfg.Server.TLSPort | |||
| 2099 | + | redirectHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |||
| 2100 | + | host := r.Host | |||
| 2101 | + | if h, _, err := net.SplitHostPort(host); err == nil { | |||
| 2102 | + | host = h | |||
| 2103 | + | } else if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") { | |||
| 2104 | + | host = strings.TrimSuffix(strings.TrimPrefix(host, "["), "]") | |||
| 2105 | + | } | |||
| 2106 | + | if tlsPort != 443 { | |||
| 2107 | + | host = net.JoinHostPort(host, strconv.Itoa(tlsPort)) | |||
| 2108 | + | } else if strings.Contains(host, ":") { | |||
| 2109 | + | host = "[" + host + "]" | |||
| 2110 | + | } | |||
| 2111 | + | target := "https://" + host + r.RequestURI | |||
| 2112 | + | http.Redirect(w, r, target, http.StatusPermanentRedirect) | |||
| 2113 | + | }) | |||
| 2114 | + | ||||
| 2115 | + | proxySrv, proxyReady := startServer(fmt.Sprintf(":%d", cfg.Server.Port), redirectHandler, "proxy-redirect", nil, errChan, log) | |||
| 2116 | + | tlsSrv, tlsReady := startTLSServer( | |||
| 2117 | + | fmt.Sprintf(":%d", cfg.Server.TLSPort), | |||
| 2118 | + | proxyHandler, | |||
| 2119 | + | "proxy-tls", | |||
| 2120 | + | cfg.Server.TLSCertFile, | |||
| 2121 | + | cfg.Server.TLSKeyFile, | |||
| 2122 | + | errChan, | |||
| 2123 | + | log, | |||
| 2124 | + | ) | |||
| 2125 | + | return proxySrv, proxyReady, tlsSrv, tlsReady, nil | |||
| 2126 | + | } | |||
| 2127 | + | ||||
| 2122 | // startServer starts an HTTP server, returning the server instance and a channel | 2128 | // startServer starts an HTTP server, returning the server instance and a channel | ||
| 2123 | // that closes once the listening socket is bound. This lets callers wait for the | 2129 | // that closes once the listening socket is bound. This lets callers wait for the | ||
| 2124 | // port to be ready before taking actions that depend on it (e.g. auto-start | 2130 | // port to be ready before taking actions that depend on it (e.g. auto-start | ||