Skip to content

Last updated: 2026-02-11

Grafana TLS/SSL Configuration Guide

This guide provides recommended TLS/SSL settings for Grafana, an open-source platform for monitoring and observability dashboards. Securing Grafana with TLS protects login credentials, dashboard data, and API tokens in transit.

Prerequisites

Certificate Setup

Set permissions on certificate files:

chmod 640 /etc/grafana/ssl/privkey.pem
chown root:grafana /etc/grafana/ssl/privkey.pem
chmod 644 /etc/grafana/ssl/fullchain.pem

Server Configuration

Configure TLS in Grafana's configuration file (/etc/grafana/grafana.ini) under the [server] section.

Enable HTTPS

[server]
protocol = https
cert_file = /etc/grafana/ssl/fullchain.pem
cert_key = /etc/grafana/ssl/privkey.pem

HTTP Port

By default, Grafana listens on port 3000. You can change this to the standard HTTPS port:

[server]
http_port = 443

Running on port 443 requires Grafana to run as root or use setcap:

setcap 'cap_net_bind_service=+ep' /usr/share/grafana/bin/grafana

Minimum TLS Version

[server]
min_tls_version = TLS1.2

Available values: TLS1.0, TLS1.1, TLS1.2, TLS1.3.

Enforce HTTPS

Redirect HTTP requests to HTTPS and set security headers:

[server]
enforce_domain = true

[security]
cookie_secure = true
strict_transport_security = true
strict_transport_security_max_age_seconds = 63072000
strict_transport_security_preload = true
strict_transport_security_subdomains = true
content_security_policy = true

Client Certificate Authentication

For mutual TLS (mTLS), the recommended approach is to terminate TLS at a reverse proxy (Nginx, Apache, HAProxy) that validates client certificates and passes the authenticated identity to Grafana via the X-WEBAUTH-USER header using Grafana's Auth Proxy feature:

[auth.proxy]
enabled = true
header_name = X-WEBAUTH-USER
header_property = username
auto_sign_up = true

Configure your reverse proxy to verify client certificates and set the X-WEBAUTH-USER header to the certificate's Common Name (CN).

Data Source TLS

When Grafana connects to data sources (Prometheus, Elasticsearch, InfluxDB, etc.), configure TLS for those connections as well.

In the UI

When adding a data source in Grafana's web interface, expand the TLS/SSL Auth Details section:

In Provisioning Files

For automated deployments using YAML provisioning (/etc/grafana/provisioning/datasources/):

apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    url: https://prometheus.example.com:9090
    jsonData:
      tlsAuth: false
      tlsAuthWithCACert: true
    secureJsonData:
      tlsCACert: |
        -----BEGIN CERTIFICATE-----
        ... your CA certificate ...
        -----END CERTIFICATE-----

For data sources requiring client certificates:

    jsonData:
      tlsAuth: true
      tlsAuthWithCACert: true
    secureJsonData:
      tlsCACert: |
        -----BEGIN CERTIFICATE-----
        ... CA cert ...
        -----END CERTIFICATE-----
      tlsClientCert: |
        -----BEGIN CERTIFICATE-----
        ... client cert ...
        -----END CERTIFICATE-----
      tlsClientKey: |
        -----BEGIN RSA PRIVATE KEY-----
        ... client key ...
        -----END RSA PRIVATE KEY-----

Database TLS

If Grafana uses MySQL or PostgreSQL as its backend database, configure TLS for that connection too:

MySQL

[database]
type = mysql
host = db.example.com:3306
name = grafana
user = grafana
password = secret
ssl_mode = true
ca_cert_path = /etc/grafana/ssl/db-ca.pem
client_cert_path = /etc/grafana/ssl/db-client-cert.pem
client_key_path = /etc/grafana/ssl/db-client-key.pem

PostgreSQL

[database]
type = postgres
host = db.example.com:5432
name = grafana
user = grafana
password = secret
ssl_mode = verify-full
ca_cert_path = /etc/grafana/ssl/db-ca.pem
client_cert_path = /etc/grafana/ssl/db-client-cert.pem
client_key_path = /etc/grafana/ssl/db-client-key.pem

Complete Configuration

[server]
protocol = https
http_port = 3000
cert_file = /etc/grafana/ssl/fullchain.pem
cert_key = /etc/grafana/ssl/privkey.pem
min_tls_version = TLS1.2
enforce_domain = true

[security]
cookie_secure = true
cookie_samesite = strict
strict_transport_security = true
strict_transport_security_max_age_seconds = 63072000
strict_transport_security_preload = true
strict_transport_security_subdomains = true
content_security_policy = true
x_content_type_options = true
x_xss_protection = true

Behind a Reverse Proxy

If Grafana runs behind a TLS-terminating reverse proxy (Nginx, HAProxy, etc.), you may not need Grafana's built-in TLS. Instead, configure the proxy to handle TLS and communicate with Grafana over HTTP on localhost:

[server]
protocol = http
http_port = 3000
domain = grafana.example.com
root_url = https://grafana.example.com/

[security]
cookie_secure = true
strict_transport_security = true
strict_transport_security_max_age_seconds = 63072000

Ensure the proxy sets the X-Forwarded-Proto: https header so Grafana knows the client connection is encrypted.

Verification

Restart Grafana:

systemctl restart grafana-server

Check the Grafana log for TLS initialization:

journalctl -u grafana-server | grep -i tls

Test the HTTPS connection:

curl -I https://grafana.example.com:3000

Test with OpenSSL:

openssl s_client -connect grafana.example.com:3000

Verify HSTS and security headers:

curl -sI https://grafana.example.com:3000 | grep -i strict