# Grafana Server # # Scope: Beautiful plots of time series data retrieved from Prometheus # See https://christine.website/blog/prometheus-grafana-loki-nixos-2020-11-20 { config, lib, ... }: let cfg = config.services.private-storage.monitoring.grafana; grafanaAuth = if (cfg.googleOAuthClientID == "") then { anonymous.enable = true; } else { google.enable = true; google.clientSecretFile = cfg.googleOAuthClientSecretFile; google.clientId = cfg.googleOAuthClientID; }; in { options.services.private-storage.monitoring.grafana = { domain = lib.mkOption { type = lib.types.str; example = lib.literalExample "grafana.grid.private.storage"; description = "The FQDN of the Grafana host"; }; prometheusUrl = lib.mkOption { type = lib.types.str; example = lib.literalExample "http://prometheus:9090/"; default = "http://localhost:9090/"; description = "The URL of the Prometheus host to access"; }; lokiUrl = lib.mkOption { type = lib.types.str; example = lib.literalExample "http://loki:3100/"; default = "http://localhost:3100/"; description = "The URL of the Loki host to access"; }; letsEncryptAdminEmail = lib.mkOption { type = lib.types.str; description = '' An email address to give to Let's Encrypt as an operational contact for the service's TLS certificate. ''; }; googleOAuthClientID = lib.mkOption { type = lib.types.str; example = lib.literalExample "grafana-staging-345678"; default = "replace-by-your-client-id-or-set-empty-string-for-anonymous-access"; description = "The GSuite OAuth2 SSO Client ID. Empty string turns SSO auth off and anonymous (free for all) access on."; }; googleOAuthClientSecretFile = lib.mkOption { type = lib.types.path; example = lib.literalExample "/var/secret/monitoring-gsuite-client-secret"; default = /run/keys/grafana-google-sso.secret; description = "The path to the GSuite SSO secret file."; }; }; config = { # Port 80 for ACME ssl retrieval only. 443 for nginx -> grafana. networking.firewall.allowedTCPPorts = [ 80 443 ]; services.grafana = { enable = true; domain = cfg.domain; port = 2342; addr = "127.0.0.1"; # No phoning home analytics.reporting.enable = false; }; services.grafana.auth = { anonymous.org_role = "Admin"; anonymous.org_name = "Main Org."; } // grafanaAuth; services.grafana.provision = { enable = true; # See https://grafana.com/docs/grafana/latest/administration/provisioning/#datasources datasources = [{ name = "Prometheus"; type = "prometheus"; access = "proxy"; url = cfg.prometheusUrl; isDefault = true; } { name = "Loki"; type = "loki"; access = "proxy"; url = cfg.lokiUrl; }]; # See https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards dashboards = [{ name = "provisioned"; options.path = ./grafana-config; }]; }; # nginx reverse proxy security.acme.email = cfg.letsEncryptAdminEmail; security.acme.acceptTerms = true; services.nginx = { enable = true; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; # Only allow PFS-enabled ciphers with AES256: sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; virtualHosts.${config.services.grafana.domain} = { enableACME = true; onlySSL = true; locations."/" = { proxyPass = "http://127.0.0.1:${toString config.services.grafana.port}"; proxyWebsockets = true; }; }; }; }; }