Server: Support HTTPS and HTTP/2 over Unix domain sockets (#118155)

This commit introduces a new protocol scheme 'sockettls' (internal constant
SocketHTTP2Scheme) that enables serving TLS-encrypted traffic over Unix
domain sockets.

Previously, Grafana supported plain HTTP over Unix sockets via the 'socket'
protocol, but there was no way to enable TLS or HTTP/2 when using sockets.
This is useful when Grafana is behind a reverse proxy that communicates
via sockets and requires end-to-end encryption or HTTP/2 features.

Key changes:
- pkg/setting: Added SocketHTTP2Scheme and updated readServerSettings to
  parse the 'sockettls' protocol. This includes support for socket paths,
  GID/mode permissions, and TLS certificate/key configuration.
- pkg/api: Modified HTTPServer to support listening on Unix sockets when
  TLS is enabled. Updated Run, getListener, and configureTLS to
  correctly handle the new scheme.
- pkg/services/rendering: Updated getGrafanaCallbackURL to use 'https'
  scheme for the new socket-based scheme, ensuring correct callback URLs.
- pkg/services/frontend: Enabled the Http2Enabled flag for the new scheme
  to inform the frontend about HTTP/2 availability.
- conf: Updated defaults.ini and sample.ini to include 'sockettls' in
  the documented protocol options.
- docs: Updated configuration documentation to reflect the new protocol.
This commit is contained in:
Ingmar Stein
2026-02-20 18:24:51 +01:00
committed by GitHub
parent 487af99929
commit 549ecb060e
8 changed files with 29 additions and 20 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ permitted_provisioning_paths = devenv/dev-dashboards|conf/provisioning
#################################### Server ##############################
[server]
# Protocol (http, https, h2, socket)
# Protocol (http, https, h2, socket, socket_h2)
protocol = http
# Minimum TLS version allowed. By default, this value is empty. Accepted values are: TLS1.2, TLS1.3. If nothing is set TLS1.2 would be taken
+1 -1
View File
@@ -35,7 +35,7 @@
#################################### Server ####################################
[server]
# Protocol (http, https, h2, socket)
# Protocol (http, https, h2, socket, socket_h2)
;protocol = http
# Minimum TLS version allowed. By default, this value is empty. Accepted values are: TLS1.2, TLS1.3. If nothing is set TLS1.2 would be taken
@@ -222,7 +222,7 @@ Dashboards are reloaded when the JSON files change.
#### `protocol`
`http`,`https`,`h2` or `socket`
`http`,`https`,`h2`,`socket` or `socket_h2`
#### `min_tls_version`
+1 -1
View File
@@ -307,7 +307,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
RendererDefaultImageWidth: hs.Cfg.RendererDefaultImageWidth,
RendererDefaultImageHeight: hs.Cfg.RendererDefaultImageHeight,
RendererDefaultImageScale: hs.Cfg.RendererDefaultImageScale,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme,
Http2Enabled: hs.Cfg.Protocol == setting.HTTP2Scheme || hs.Cfg.Protocol == setting.SocketHTTP2Scheme,
GrafanaJavascriptAgent: hs.Cfg.GrafanaJavascriptAgent,
PluginCatalogURL: hs.Cfg.PluginCatalogURL,
PluginAdminEnabled: hs.Cfg.PluginAdminEnabled,
+5 -5
View File
@@ -453,7 +453,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
hs.httpSrv.ErrorLog = stdlog.New(customErrorLogger, "", 0)
switch hs.Cfg.Protocol {
case setting.HTTP2Scheme, setting.HTTPSScheme:
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
if err := hs.configureTLS(); err != nil {
return err
}
@@ -499,7 +499,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
}
return err
}
case setting.HTTP2Scheme, setting.HTTPSScheme:
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
if err := hs.httpSrv.ServeTLS(listener, "", ""); err != nil {
if errors.Is(err, http.ErrServerClosed) {
hs.log.Debug("server was shutdown gracefully")
@@ -528,7 +528,7 @@ func (hs *HTTPServer) getListener() (net.Listener, error) {
return nil, fmt.Errorf("failed to open listener on address %s: %w", hs.httpSrv.Addr, err)
}
return listener, nil
case setting.SocketScheme:
case setting.SocketScheme, setting.SocketHTTP2Scheme:
listener, err := net.ListenUnix("unix", &net.UnixAddr{Name: hs.Cfg.SocketPath, Net: "unix"})
if err != nil {
return nil, fmt.Errorf("failed to open listener for socket %s: %w", hs.Cfg.SocketPath, err)
@@ -840,7 +840,7 @@ func (hs *HTTPServer) getDefaultCiphers(tlsVersion uint16, protocol string) []ui
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
}
}
if protocol == "h2" {
if protocol == "h2" || protocol == "socket_h2" {
return []uint16{
tls.TLS_CHACHA20_POLY1305_SHA256,
tls.TLS_AES_128_GCM_SHA256,
@@ -965,7 +965,7 @@ func (hs *HTTPServer) configureTLS() error {
hs.httpSrv.TLSConfig = tlsCfg
if hs.Cfg.Protocol == setting.HTTP2Scheme {
if hs.Cfg.Protocol == setting.HTTP2Scheme || hs.Cfg.Protocol == setting.SocketHTTP2Scheme {
hs.httpSrv.TLSConfig.NextProtos = []string{"h2", "http/1.1"}
}
+1 -1
View File
@@ -42,7 +42,7 @@ func NewFSRequestConfig(cfg *setting.Cfg, license licensing.Licensing) FSRequest
GoogleAnalytics4SendManualPageViews: cfg.GoogleAnalytics4SendManualPageViews,
GoogleAnalyticsId: cfg.GoogleAnalyticsID,
GrafanaJavascriptAgent: cfg.GrafanaJavascriptAgent,
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme,
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme || cfg.Protocol == setting.SocketHTTP2Scheme,
JwtHeaderName: cfg.JWTAuth.HeaderName,
JwtUrlLogin: cfg.JWTAuth.URLLogin,
LdapEnabled: cfg.LDAPAuthEnabled,
+1 -1
View File
@@ -413,7 +413,7 @@ func (rs *RenderingService) getGrafanaCallbackURL(path string) string {
switch protocol {
case setting.HTTPScheme:
protocol = "http"
case setting.HTTP2Scheme, setting.HTTPSScheme:
case setting.HTTP2Scheme, setting.HTTPSScheme, setting.SocketHTTP2Scheme:
protocol = "https"
default:
// TODO: Handle other schemes?
+18 -9
View File
@@ -37,10 +37,11 @@ import (
type Scheme string
const (
HTTPScheme Scheme = "http"
HTTPSScheme Scheme = "https"
HTTP2Scheme Scheme = "h2"
SocketScheme Scheme = "socket"
HTTPScheme Scheme = "http"
HTTPSScheme Scheme = "https"
HTTP2Scheme Scheme = "h2"
SocketScheme Scheme = "socket"
SocketHTTP2Scheme Scheme = "socket_h2"
)
const (
@@ -1983,23 +1984,31 @@ func (cfg *Cfg) readServerSettings(iniFile *ini.File) error {
protocolStr := valueAsString(server, "protocol", "http")
if protocolStr == "https" {
switch protocolStr {
case "https":
cfg.Protocol = HTTPSScheme
cfg.CertFile = server.Key("cert_file").String()
cfg.KeyFile = server.Key("cert_key").String()
cfg.CertPassword = server.Key("cert_pass").String()
}
if protocolStr == "h2" {
case "h2":
cfg.Protocol = HTTP2Scheme
cfg.CertFile = server.Key("cert_file").String()
cfg.KeyFile = server.Key("cert_key").String()
cfg.CertPassword = server.Key("cert_pass").String()
}
if protocolStr == "socket" {
case "socket":
cfg.Protocol = SocketScheme
cfg.SocketGid = server.Key("socket_gid").MustInt(-1)
cfg.SocketMode = server.Key("socket_mode").MustInt(0660)
cfg.SocketPath = server.Key("socket").String()
case "socket_h2":
cfg.Protocol = SocketHTTP2Scheme
cfg.SocketGid = server.Key("socket_gid").MustInt(-1)
cfg.SocketMode = server.Key("socket_mode").MustInt(0660)
cfg.SocketPath = server.Key("socket").String()
cfg.CertFile = server.Key("cert_file").String()
cfg.KeyFile = server.Key("cert_key").String()
cfg.CertPassword = server.Key("cert_pass").String()
default:
}
cfg.MinTLSVersion = valueAsString(server, "min_tls_version", "TLS1.2")