@@ -343,7 +343,12 @@ var runCmd = &cobra.Command{
343343 return
344344 }
345345
346- fqdn , err := url .Parse ("http://" + metricsConfig .Address )
346+ scheme := "http://"
347+ if metricsConfig .KeyFile != "" && metricsConfig .CertFile != "" {
348+ scheme = "https://"
349+ }
350+
351+ fqdn , err := url .Parse (scheme + metricsConfig .Address )
347352 if err != nil {
348353 logger .Error ().Err (err ).Msg ("Failed to parse metrics address" )
349354 span .RecordError (err )
@@ -386,15 +391,26 @@ var runCmd = &cobra.Command{
386391 )
387392 }()
388393
389- logger .Info ().Str ("address" , address ).Msg ("Metrics are exposed" )
394+ mux := http .NewServeMux ()
395+ mux .HandleFunc ("/" , func (responseWriter http.ResponseWriter , request * http.Request ) {
396+ // Serve a static page with a link to the metrics endpoint.
397+ if _ , err := responseWriter .Write ([]byte (fmt .Sprintf (
398+ `<html><head><title>GatewayD Prometheus Metrics Server</title></head><body><a href="%s">Metrics</a></body></html>` ,
399+ address ,
400+ ))); err != nil {
401+ logger .Error ().Err (err ).Msg ("Failed to write metrics" )
402+ span .RecordError (err )
403+ sentry .CaptureException (err )
404+ }
405+ })
390406
391407 if conf .Plugin .EnableMetricsMerger && metricsMerger != nil {
392408 handler = mergedMetricsHandler (handler )
393409 }
394410
395411 // Check if the metrics server is already running before registering the handler.
396412 if _ , err = http .Get (address ); err != nil { //nolint:gosec
397- http .Handle (metricsConfig .Path , gziphandler .GzipHandler (handler ))
413+ mux .Handle (metricsConfig .Path , gziphandler .GzipHandler (handler ))
398414 } else {
399415 logger .Warn ().Msg ("Metrics server is already running, consider changing the port" )
400416 span .RecordError (err )
@@ -403,14 +419,44 @@ var runCmd = &cobra.Command{
403419 // Create a new metrics server.
404420 metricsServer = & http.Server {
405421 Addr : metricsConfig .Address ,
406- Handler : handler ,
422+ Handler : mux ,
407423 ReadHeaderTimeout : metricsConfig .GetReadHeaderTimeout (),
408424 }
409425
410- // Start the metrics server.
411- if err = metricsServer .ListenAndServe (); ! errors .Is (err , http .ErrServerClosed ) {
412- logger .Error ().Err (err ).Msg ("Failed to start metrics server" )
413- span .RecordError (err )
426+ logger .Info ().Str ("address" , address ).Msg ("Metrics are exposed" )
427+
428+ if metricsConfig .CertFile != "" && metricsConfig .KeyFile != "" {
429+ // Set up TLS.
430+ metricsServer .TLSConfig = & tls.Config {
431+ MinVersion : tls .VersionTLS13 ,
432+ CurvePreferences : []tls.CurveID {
433+ tls .CurveP521 ,
434+ tls .CurveP384 ,
435+ tls .CurveP256 ,
436+ },
437+ PreferServerCipherSuites : true ,
438+ CipherSuites : []uint16 {
439+ tls .TLS_AES_128_GCM_SHA256 ,
440+ tls .TLS_AES_256_GCM_SHA384 ,
441+ tls .TLS_CHACHA20_POLY1305_SHA256 ,
442+ },
443+ }
444+ metricsServer .TLSNextProto = make (
445+ map [string ]func (* http.Server , * tls.Conn , http.Handler ), 0 )
446+ logger .Debug ().Msg ("Metrics server is running with TLS" )
447+
448+ // Start the metrics server with TLS.
449+ if err = metricsServer .ListenAndServeTLS (
450+ metricsConfig .CertFile , metricsConfig .KeyFile ); ! errors .Is (err , http .ErrServerClosed ) {
451+ logger .Error ().Err (err ).Msg ("Failed to start metrics server" )
452+ span .RecordError (err )
453+ }
454+ } else {
455+ // Start the metrics server without TLS.
456+ if err = metricsServer .ListenAndServe (); ! errors .Is (err , http .ErrServerClosed ) {
457+ logger .Error ().Err (err ).Msg ("Failed to start metrics server" )
458+ span .RecordError (err )
459+ }
414460 }
415461 }(conf .Global .Metrics [config .Default ], logger )
416462
0 commit comments