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
- Grafana 9.0 or later
- A valid SSL/TLS certificate
- Grafana is built with Go's
crypto/tls, which provides strong TLS defaults
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
- cookie_secure = true ensures session cookies are only sent over HTTPS.
- strict_transport_security = true enables the HSTS header.
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:
- TLS Client Authentication -- Upload client certificate and key if the data source requires mutual TLS
- Skip TLS Verification -- Leave unchecked (never skip in production)
- CA Certificate -- Upload the CA certificate if using a private CA
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