diff --git a/modules/nixos/services/grafana/dashboards/caddy.json b/modules/nixos/services/grafana/dashboards/caddy.json new file mode 100644 index 0000000..ce75f00 --- /dev/null +++ b/modules/nixos/services/grafana/dashboards/caddy.json @@ -0,0 +1,296 @@ +{ + "title": "Caddy", + "uid": "jallen-caddy", + "schemaVersion": 38, + "version": 1, + "refresh": "30s", + "time": { "from": "now-1h", "to": "now" }, + "templating": { + "list": [ + { + "name": "datasource", + "type": "datasource", + "query": "prometheus", + "current": {}, + "hide": 0, + "label": "Datasource" + }, + { + "name": "handler", + "type": "query", + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "query": "label_values(caddy_http_requests_total, handler)", + "refresh": 2, + "includeAll": true, + "allValue": ".*", + "label": "Handler" + } + ] + }, + "panels": [ + { + "id": 1, + "type": "stat", + "title": "Request Rate (5m)", + "gridPos": { "x": 0, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_requests_total[5m]))", + "legendFormat": "req/s", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 2, + "type": "stat", + "title": "Error Rate (5m)", + "gridPos": { "x": 4, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 0.01 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_requests_total{code=~\"5..\"}[5m]))", + "legendFormat": "5xx/s", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 3, + "type": "stat", + "title": "Active Requests", + "gridPos": { "x": 8, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(caddy_http_active_requests)", + "legendFormat": "active", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 4, + "type": "stat", + "title": "P99 Latency (5m)", + "gridPos": { "x": 12, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "s", + "decimals": 3, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 0.5 }, + { "color": "red", "value": 2 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(caddy_http_request_duration_seconds_bucket[5m])) by (le))", + "legendFormat": "P99", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 5, + "type": "stat", + "title": "Total Bytes Received", + "gridPos": { "x": 16, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(caddy_http_request_size_bytes_sum)", + "legendFormat": "bytes in", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 6, + "type": "stat", + "title": "Total Bytes Sent", + "gridPos": { "x": 20, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(caddy_http_response_size_bytes_sum)", + "legendFormat": "bytes out", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 7, + "type": "timeseries", + "title": "Request Rate by Status Code", + "gridPos": { "x": 0, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "5xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "4xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "orange", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "2xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "3xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } }] } + ] + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_requests_total{code=~\"2..\"}[5m]))", + "legendFormat": "2xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(caddy_http_requests_total{code=~\"3..\"}[5m]))", + "legendFormat": "3xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(caddy_http_requests_total{code=~\"4..\"}[5m]))", + "legendFormat": "4xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(caddy_http_requests_total{code=~\"5..\"}[5m]))", + "legendFormat": "5xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 8, + "type": "timeseries", + "title": "Request Latency Percentiles", + "gridPos": { "x": 12, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "s", + "decimals": 3, + "custom": { "lineWidth": 2 } + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(caddy_http_request_duration_seconds_bucket[5m])) by (le))", + "legendFormat": "P50", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "histogram_quantile(0.90, sum(rate(caddy_http_request_duration_seconds_bucket[5m])) by (le))", + "legendFormat": "P90", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "histogram_quantile(0.99, sum(rate(caddy_http_request_duration_seconds_bucket[5m])) by (le))", + "legendFormat": "P99", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 9, + "type": "timeseries", + "title": "Request Rate by Handler", + "gridPos": { "x": 0, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + } + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_requests_total{handler=~\"$handler\"}[5m])) by (handler)", + "legendFormat": "{{handler}}", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 10, + "type": "timeseries", + "title": "Bandwidth", + "gridPos": { "x": 12, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { "lineWidth": 2, "fillOpacity": 10 } + } + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_request_size_bytes_sum[5m]))", + "legendFormat": "Inbound", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(caddy_http_response_size_bytes_sum[5m]))", + "legendFormat": "Outbound", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + } + ] +} diff --git a/modules/nixos/services/grafana/dashboards/gitea.json b/modules/nixos/services/grafana/dashboards/gitea.json new file mode 100644 index 0000000..c24a958 --- /dev/null +++ b/modules/nixos/services/grafana/dashboards/gitea.json @@ -0,0 +1,246 @@ +{ + "title": "Gitea", + "uid": "jallen-gitea", + "schemaVersion": 38, + "version": 1, + "refresh": "1m", + "time": { "from": "now-6h", "to": "now" }, + "templating": { + "list": [ + { + "name": "datasource", + "type": "datasource", + "query": "prometheus", + "current": {}, + "hide": 0, + "label": "Datasource" + } + ] + }, + "panels": [ + { + "id": 1, + "type": "stat", + "title": "Repositories", + "gridPos": { "x": 0, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_repositories", + "legendFormat": "repos", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 2, + "type": "stat", + "title": "Users", + "gridPos": { "x": 4, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_users", + "legendFormat": "users", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 3, + "type": "stat", + "title": "Open Issues", + "gridPos": { "x": 8, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_issues_open", + "legendFormat": "open issues", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 4, + "type": "stat", + "title": "Open PRs", + "gridPos": { "x": 12, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "purple", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_issues_open{type=\"pull_request\"}", + "legendFormat": "open PRs", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 5, + "type": "stat", + "title": "Orgs", + "gridPos": { "x": 16, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_organizations", + "legendFormat": "orgs", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 6, + "type": "stat", + "title": "Mirrors", + "gridPos": { "x": 20, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_repositories_mirrors", + "legendFormat": "mirrors", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 7, + "type": "timeseries", + "title": "HTTP Request Rate by Method", + "gridPos": { "x": 0, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + } + }, + "targets": [ + { + "expr": "sum(rate(gitea_access_total[5m])) by (method)", + "legendFormat": "{{method}}", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 8, + "type": "timeseries", + "title": "HTTP Response Codes", + "gridPos": { "x": 12, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "5xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "4xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "orange", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "2xx" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] } + ] + }, + "targets": [ + { + "expr": "sum(rate(gitea_access_total{code=~\"2..\"}[5m]))", + "legendFormat": "2xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(gitea_access_total{code=~\"4..\"}[5m]))", + "legendFormat": "4xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(gitea_access_total{code=~\"5..\"}[5m]))", + "legendFormat": "5xx", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 9, + "type": "timeseries", + "title": "Repository & User Growth", + "gridPos": { "x": 0, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "custom": { "lineWidth": 2 } + } + }, + "targets": [ + { + "expr": "gitea_repositories", + "legendFormat": "Repositories", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "gitea_users", + "legendFormat": "Users", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "gitea_organizations", + "legendFormat": "Organizations", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 10, + "type": "timeseries", + "title": "Issues & PRs Over Time", + "gridPos": { "x": 12, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "custom": { "lineWidth": 2 } + } + }, + "targets": [ + { + "expr": "gitea_issues_open", + "legendFormat": "Open Issues", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "gitea_issues_closed", + "legendFormat": "Closed Issues", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + } + ] +} diff --git a/modules/nixos/services/grafana/dashboards/nas-overview.json b/modules/nixos/services/grafana/dashboards/nas-overview.json new file mode 100644 index 0000000..56b0111 --- /dev/null +++ b/modules/nixos/services/grafana/dashboards/nas-overview.json @@ -0,0 +1,582 @@ +{ + "title": "NAS Overview", + "uid": "jallen-nas-overview", + "schemaVersion": 38, + "version": 1, + "refresh": "30s", + "time": { "from": "now-1h", "to": "now" }, + "tags": ["nas", "overview"], + "templating": { + "list": [ + { + "name": "datasource", + "type": "datasource", + "query": "prometheus", + "current": {}, + "hide": 0, + "label": "Datasource" + } + ] + }, + "panels": [ + { + "id": 100, + "type": "row", + "title": "System", + "gridPos": { "x": 0, "y": 0, "w": 24, "h": 1 }, + "collapsed": false + }, + { + "id": 1, + "type": "stat", + "title": "CPU Usage", + "gridPos": { "x": 0, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 70 }, + { "color": "red", "value": 90 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "100 - (avg(rate(node_cpu_seconds_total{mode=\"idle\"}[2m])) * 100)", + "legendFormat": "CPU %", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 2, + "type": "stat", + "title": "RAM Used", + "gridPos": { "x": 4, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 75 }, + { "color": "red", "value": 90 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100", + "legendFormat": "RAM %", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 3, + "type": "stat", + "title": "RAM Available", + "gridPos": { "x": 8, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "yellow", "value": 2147483648 }, + { "color": "green", "value": 8589934592 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "node_memory_MemAvailable_bytes", + "legendFormat": "Available", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 4, + "type": "stat", + "title": "System Load (15m)", + "gridPos": { "x": 12, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "decimals": 2, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 4 }, + { "color": "red", "value": 8 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "node_load15", + "legendFormat": "load15", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 5, + "type": "stat", + "title": "Uptime", + "gridPos": { "x": 16, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "s", + "thresholds": { + "mode": "absolute", + "steps": [{ "color": "blue", "value": null }] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "time() - node_boot_time_seconds", + "legendFormat": "uptime", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 6, + "type": "stat", + "title": "Open File Descriptors", + "gridPos": { "x": 20, "y": 1, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 50000 }, + { "color": "red", "value": 90000 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "node_filefd_allocated", + "legendFormat": "open FDs", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 101, + "type": "row", + "title": "Storage", + "gridPos": { "x": 0, "y": 5, "w": 24, "h": 1 }, + "collapsed": false + }, + { + "id": 7, + "type": "bargauge", + "title": "Disk Usage by Mount", + "gridPos": { "x": 0, "y": 6, "w": 12, "h": 8 }, + "options": { + "reduceOptions": { "calcs": ["lastNotNull"] }, + "orientation": "horizontal", + "displayMode": "gradient" + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 75 }, + { "color": "red", "value": 90 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "100 - (node_filesystem_avail_bytes{fstype!~\"tmpfs|fuse.lxcfs|squashfs|vfat\"} / node_filesystem_size_bytes{fstype!~\"tmpfs|fuse.lxcfs|squashfs|vfat\"} * 100)", + "legendFormat": "{{mountpoint}}", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 8, + "type": "timeseries", + "title": "Disk I/O", + "gridPos": { "x": 12, "y": 6, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + } + }, + "targets": [ + { + "expr": "sum(rate(node_disk_read_bytes_total[5m]))", + "legendFormat": "Read", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(node_disk_written_bytes_total[5m]))", + "legendFormat": "Write", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 102, + "type": "row", + "title": "Network", + "gridPos": { "x": 0, "y": 14, "w": 24, "h": 1 }, + "collapsed": false + }, + { + "id": 9, + "type": "timeseries", + "title": "Network Throughput", + "gridPos": { "x": 0, "y": 15, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "Bps", + "custom": { "lineWidth": 2, "fillOpacity": 5 } + } + }, + "targets": [ + { + "expr": "sum(rate(node_network_receive_bytes_total{device!~\"lo|tailscale.*\"}[5m]))", + "legendFormat": "Received", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(node_network_transmit_bytes_total{device!~\"lo|tailscale.*\"}[5m]))", + "legendFormat": "Transmitted", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 10, + "type": "timeseries", + "title": "Network Errors & Drops", + "gridPos": { "x": 12, "y": 15, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "pps", + "custom": { "lineWidth": 2 } + } + }, + "targets": [ + { + "expr": "sum(rate(node_network_receive_errs_total[5m]))", + "legendFormat": "RX Errors", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(node_network_receive_drop_total[5m]))", + "legendFormat": "RX Drops", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "sum(rate(node_network_transmit_errs_total[5m]))", + "legendFormat": "TX Errors", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 103, + "type": "row", + "title": "UPS", + "gridPos": { "x": 0, "y": 23, "w": 24, "h": 1 }, + "collapsed": false + }, + { + "id": 11, + "type": "stat", + "title": "UPS Status", + "gridPos": { "x": 0, "y": 24, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "mappings": [ + { "type": "value", "options": { "1": { "text": "Online", "color": "green" } } }, + { "type": "value", "options": { "0": { "text": "On Battery", "color": "red" } } } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 1 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "network_ups_tools_ups_status", + "legendFormat": "Status", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 12, + "type": "gauge", + "title": "Battery Charge", + "gridPos": { "x": 4, "y": 24, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "orange", "value": 20 }, + { "color": "green", "value": 80 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_charge", + "legendFormat": "Charge", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 13, + "type": "gauge", + "title": "UPS Load", + "gridPos": { "x": 8, "y": 24, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 60 }, + { "color": "red", "value": 85 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_ups_load", + "legendFormat": "Load", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 14, + "type": "stat", + "title": "Runtime Remaining", + "gridPos": { "x": 12, "y": 24, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "s", + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "orange", "value": 300 }, + { "color": "green", "value": 600 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_runtime", + "legendFormat": "Runtime", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 104, + "type": "row", + "title": "Services", + "gridPos": { "x": 0, "y": 28, "w": 24, "h": 1 }, + "collapsed": false + }, + { + "id": 15, + "type": "stat", + "title": "Caddy Request Rate (5m)", + "gridPos": { "x": 0, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "reqps", + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(rate(caddy_http_requests_total[5m]))", + "legendFormat": "req/s", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 16, + "type": "stat", + "title": "PostgreSQL Active Connections", + "gridPos": { "x": 4, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 50 }, + { "color": "red", "value": 80 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "sum(pg_stat_activity_count{state=\"active\"})", + "legendFormat": "active conns", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 17, + "type": "stat", + "title": "Nextcloud Users (24h)", + "gridPos": { "x": 8, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "nextcloud_active_users_daily", + "legendFormat": "active users", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 18, + "type": "stat", + "title": "Gitea Repositories", + "gridPos": { "x": 12, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "gitea_repositories", + "legendFormat": "repos", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 19, + "type": "stat", + "title": "restic Backup Size", + "gridPos": { "x": 16, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "bytes", + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "restic_rest_server_bytes_total", + "legendFormat": "backup bytes", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 20, + "type": "stat", + "title": "MariaDB Queries/s", + "gridPos": { "x": 20, "y": 29, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "qps", + "thresholds": { "mode": "absolute", "steps": [{ "color": "blue", "value": null }] }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "rate(mysql_global_status_queries[5m])", + "legendFormat": "queries/s", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + } + ] +} diff --git a/modules/nixos/services/grafana/dashboards/nut.json b/modules/nixos/services/grafana/dashboards/nut.json new file mode 100644 index 0000000..199fee1 --- /dev/null +++ b/modules/nixos/services/grafana/dashboards/nut.json @@ -0,0 +1,301 @@ +{ + "title": "UPS (NUT)", + "uid": "jallen-nut", + "schemaVersion": 38, + "version": 1, + "refresh": "30s", + "time": { "from": "now-3h", "to": "now" }, + "templating": { + "list": [ + { + "name": "datasource", + "type": "datasource", + "query": "prometheus", + "current": {}, + "hide": 0, + "includeAll": false, + "label": "Datasource" + }, + { + "name": "ups", + "type": "query", + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "query": "label_values(network_ups_tools_ups_status, ups)", + "refresh": 2, + "includeAll": false, + "label": "UPS" + } + ] + }, + "panels": [ + { + "id": 1, + "type": "stat", + "title": "Status", + "gridPos": { "x": 0, "y": 0, "w": 4, "h": 4 }, + "options": { + "reduceOptions": { "calcs": ["lastNotNull"] }, + "colorMode": "background", + "textMode": "value" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { "type": "value", "options": { "1": { "text": "OL", "color": "green" } } }, + { "type": "value", "options": { "0": { "text": "OB", "color": "red" } } } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 1 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_ups_status{ups=\"$ups\"}", + "legendFormat": "Status", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 2, + "type": "gauge", + "title": "Battery Charge", + "gridPos": { "x": 4, "y": 0, "w": 4, "h": 4 }, + "options": { + "reduceOptions": { "calcs": ["lastNotNull"] }, + "minVizWidth": 75 + }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "orange", "value": 20 }, + { "color": "yellow", "value": 50 }, + { "color": "green", "value": 80 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_charge{ups=\"$ups\"}", + "legendFormat": "Charge", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 3, + "type": "gauge", + "title": "Load", + "gridPos": { "x": 8, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 60 }, + { "color": "red", "value": 85 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_ups_load{ups=\"$ups\"}", + "legendFormat": "Load", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 4, + "type": "stat", + "title": "Runtime Remaining", + "gridPos": { "x": 12, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "s", + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "orange", "value": 300 }, + { "color": "green", "value": 600 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_runtime{ups=\"$ups\"}", + "legendFormat": "Runtime", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 5, + "type": "stat", + "title": "Input Voltage", + "gridPos": { "x": 16, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "volt", + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 100 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_input_voltage{ups=\"$ups\"}", + "legendFormat": "Input V", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 6, + "type": "stat", + "title": "Battery Voltage", + "gridPos": { "x": 20, "y": 0, "w": 4, "h": 4 }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] } }, + "fieldConfig": { + "defaults": { + "unit": "volt", + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 10 } + ] + } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_voltage{ups=\"$ups\"}", + "legendFormat": "Battery V", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 7, + "type": "timeseries", + "title": "Battery Charge Over Time", + "gridPos": { "x": 0, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "max": 100, + "custom": { "lineWidth": 2, "fillOpacity": 10 }, + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "green", "value": 50 } + ] + }, + "color": { "mode": "thresholds" } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_charge{ups=\"$ups\"}", + "legendFormat": "Charge %", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 8, + "type": "timeseries", + "title": "Load Over Time", + "gridPos": { "x": 12, "y": 4, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "percent", + "min": 0, + "custom": { "lineWidth": 2, "fillOpacity": 10 } + } + }, + "targets": [ + { + "expr": "network_ups_tools_ups_load{ups=\"$ups\"}", + "legendFormat": "Load %", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 9, + "type": "timeseries", + "title": "Input Voltage Over Time", + "gridPos": { "x": 0, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "volt", + "decimals": 1, + "custom": { "lineWidth": 2, "fillOpacity": 5 } + } + }, + "targets": [ + { + "expr": "network_ups_tools_input_voltage{ups=\"$ups\"}", + "legendFormat": "Input Voltage", + "datasource": { "type": "prometheus", "uid": "$datasource" } + }, + { + "expr": "network_ups_tools_output_voltage{ups=\"$ups\"}", + "legendFormat": "Output Voltage", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + }, + { + "id": 10, + "type": "timeseries", + "title": "Runtime Remaining Over Time", + "gridPos": { "x": 12, "y": 12, "w": 12, "h": 8 }, + "fieldConfig": { + "defaults": { + "unit": "s", + "custom": { "lineWidth": 2, "fillOpacity": 10 } + } + }, + "targets": [ + { + "expr": "network_ups_tools_battery_runtime{ups=\"$ups\"}", + "legendFormat": "Runtime", + "datasource": { "type": "prometheus", "uid": "$datasource" } + } + ] + } + ] +} diff --git a/modules/nixos/services/grafana/default.nix b/modules/nixos/services/grafana/default.nix index 123afa4..46c16fe 100755 --- a/modules/nixos/services/grafana/default.nix +++ b/modules/nixos/services/grafana/default.nix @@ -1,6 +1,7 @@ { config, lib, + pkgs, namespace, ... }: @@ -9,6 +10,83 @@ let name = "grafana"; cfg = config.${namespace}.services.${name}; + # --------------------------------------------------------------------------- + # Community dashboards — fetched at build time, pinned by hash. + # --------------------------------------------------------------------------- + communityDashboards = pkgs.linkFarm "grafana-community-dashboards" [ + { + # Node Exporter Full — https://grafana.com/grafana/dashboards/1860 + name = "node-exporter-full.json"; + path = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/1860/revisions/latest/download"; + sha256 = "sha256-pNgn6xgZBEu6LW0lc0cXX2gRkQ8lg/rer34SPE3yEl4="; + }; + } + { + # PostgreSQL Database — https://grafana.com/grafana/dashboards/9628 + name = "postgresql.json"; + path = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/9628/revisions/latest/download"; + sha256 = "sha256-UhusNAZbyt7fJV/DhFUK4FKOmnTpG0R15YO2r+nDnMc="; + }; + } + { + # Redis Dashboard for prometheus-redis-exporter 1.x — https://grafana.com/grafana/dashboards/763 + name = "redis.json"; + path = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/763/revisions/latest/download"; + sha256 = "sha256-pThz+zHjcTT9vf8fpUuZK/ejNnH9GwEZVXOY27c9Aw8="; + }; + } + { + # MySQL Overview — https://grafana.com/grafana/dashboards/7362 + name = "mysql.json"; + path = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/7362/revisions/latest/download"; + sha256 = "sha256-WW7g60KY20XAdyUpumA0hBrjFC9MQGuGjiJKUhSVBXI="; + }; + } + { + # Nextcloud — https://grafana.com/grafana/dashboards/9632 + name = "nextcloud.json"; + path = pkgs.fetchurl { + url = "https://grafana.com/api/dashboards/9632/revisions/latest/download"; + sha256 = "sha256-Z28Q/sMg3jxglkszAs83IpL8f4p9loNnTQzjc3S/SAQ="; + }; + } + ]; + + # --------------------------------------------------------------------------- + # Custom dashboards — maintained in this repo under dashboards/ + # --------------------------------------------------------------------------- + customDashboards = pkgs.linkFarm "grafana-custom-dashboards" [ + { + name = "nut.json"; + path = ./dashboards/nut.json; + } + { + name = "caddy.json"; + path = ./dashboards/caddy.json; + } + { + name = "gitea.json"; + path = ./dashboards/gitea.json; + } + { + name = "nas-overview.json"; + path = ./dashboards/nas-overview.json; + } + ]; + + # Minimal .my.cnf for the mysqld exporter. No credentials are needed + # because runAsLocalSuperUser = true runs as the mysql OS user, which + # MariaDB authenticates via the unix_socket plugin automatically. + mysqldExporterCnf = pkgs.writeText "prometheus-mysqld-exporter.cnf" '' + [client] + user=root + socket=/run/mysqld/mysqld.sock + ''; + giteaPort = config.${namespace}.services.gitea.port; resticPort = config.${namespace}.services.restic.port; nextcloudPort = config.${namespace}.services.nextcloud.port; @@ -21,6 +99,10 @@ let services = { prometheus = { enable = true; + # bearer_token_file paths (e.g. Gitea metrics key) are SOPS secrets + # that only exist at runtime, not in the Nix build sandbox. + # "syntax-only" still catches config errors without stat-ing the files. + checkConfig = "syntax-only"; exporters = { node = { enable = true; @@ -64,11 +146,12 @@ let # No fixed --redis.addr: multi-target mode uses ?target= param. }; - # MariaDB — runs as the mysql OS user so it can connect via Unix - # socket without a password. + # MariaDB — runs as the mysql OS user so it can connect via the + # Unix socket without a password (unix_socket auth). mysqld = { enable = true; runAsLocalSuperUser = true; + configFile = mysqldExporterCnf; }; # Nextcloud — authenticates with the admin account. @@ -201,6 +284,12 @@ let http_port = cfg.port; http_addr = "0.0.0.0"; }; + security = { + # Read the secret key from a SOPS-managed file at runtime so it + # never appears in the Nix store. The "$__file{}" syntax is + # Grafana's built-in file provider. + secret_key = "$__file{${config.sops.secrets."jallen-nas/grafana/secret-key".path}}"; + }; }; dataDir = "${cfg.configDir}/grafana"; @@ -215,6 +304,26 @@ let url = "http://localhost:${toString config.services.prometheus.port}"; } ]; + dashboards.settings.providers = [ + { + name = "community"; + orgId = 1; + type = "file"; + disableDeletion = true; + updateIntervalSeconds = 60; + allowUiUpdates = false; + options.path = communityDashboards; + } + { + name = "custom"; + orgId = 1; + type = "file"; + disableDeletion = true; + updateIntervalSeconds = 60; + allowUiUpdates = false; + options.path = customDashboards; + } + ]; }; }; }; diff --git a/secrets/nas-secrets.yaml b/secrets/nas-secrets.yaml index 1f92277..d3136e7 100644 --- a/secrets/nas-secrets.yaml +++ b/secrets/nas-secrets.yaml @@ -92,6 +92,8 @@ jallen-nas: db-password: ENC[AES256_GCM,data:0F1vpsQf339rxzroPw==,iv:4RXvLwfA2kIZSDdpeHMht3PHqTM6i14mske9WeaBnvc=,tag:BLaGRlQVZKPyD8x+lCT1bg==,type:str] api-encryption-key: ENC[AES256_GCM,data:X1wbJu6uTyvwBOKblS87j5Ql++ILdTMMIz+jSTkTadgx/Z0GmK3YGOwS1xUTDDR/NTIcvvXSD/x03bgK7l00Zg==,iv:BBc9M+/NlUhLMgNUArBaKZJLKzAHmukyeVmSTQQtvLA=,tag:BeosEj+uESwGRGAWSDxsWg==,type:str] auth-secret: ENC[AES256_GCM,data:aJIjDzyJy3nWUNpKHEGyYdTfO93pfNcLKTTz6lKl8IO49JHuzFefaCNCzbwSKVMda8snohE2DE9Ul94paIcSwQ==,iv:rMZVu1SACErvtrhlLecP1bQ/2wnvZ1UnlYHMqFbB8I4=,tag:IxEw+MvDqAmK492uiIIRaw==,type:str] + grafana: + secret-key: ENC[AES256_GCM,data:dPHXEAKGrbbM36uH3W4yzm3GmJI=,iv:yHMAMJ8w+uoH/IvLSbxyQm6dEml0MWvwfRIIVHmc6LE=,tag:AyDLS20gUH4gupRGrtGReQ==,type:str] sops: shamir_threshold: 1 age: @@ -239,8 +241,8 @@ sops: L0gwQm5takNjMkVGNzVlSStJYlUwWDAKP8QA3rRUHYbyyhPC/k0Eq2EIKfjyc7Co 7BkHH3msC6h9g42BB5iIYe6KQ+UGxMQBFvp+qSB27jaIfajN5MP0BA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-03-20T22:28:39Z" - mac: ENC[AES256_GCM,data:sGShkufxLGHjk6nGkvnsAxmNv9/N7lxFnW7E4Wwf6LetpXeVM9yWwuchZPWQYt2tmAMLAebvB3HLYREMD+av/b6yfogH/IZePC6ryQiCLG3357dxlEkS7UjTOUv2bMM0kpWjmIL2/AvoxtQai3hpVvRb+M7OA4lw6FrSd5s+al0=,iv:zit7Omsdii3v7pL2jBuVHFl8XztwNVk7RxFXigbRS7U=,tag:UhFsV+nyHgWoc6Hcpbxm3A==,type:str] + lastmodified: "2026-03-24T14:56:54Z" + mac: ENC[AES256_GCM,data:vT6sECqPM0XBCfsuGqeUe4szq6dqT8Hp/yDxWBKyLca7/rROc8qTdEll/aq060TJb98HrPcteKBIy3UxAUiRJOEfpn8XyUkiEGZuLzbesrq7qOkGOCVHKQk0Us8PM3kL9s5VIj9BWaCHS8GfdyboIP+1+Wn6ZxO+nDyzWXnSRKE=,iv:r+wQTeYtIydw3T0QDhcen7hQF0g93eBjfPY7DZuHU3o=,tag:xpM6YZxDoH8ZLYBesH4m1w==,type:str] pgp: - created_at: "2026-02-06T15:34:30Z" enc: |- diff --git a/systems/x86_64-linux/jallen-nas/apps.nix b/systems/x86_64-linux/jallen-nas/apps.nix index 4033531..dff63ef 100755 --- a/systems/x86_64-linux/jallen-nas/apps.nix +++ b/systems/x86_64-linux/jallen-nas/apps.nix @@ -53,7 +53,7 @@ in caddy = enabled; cockpit = { enable = true; - port = 9090; + port = 9091; }; calibre = { enable = false; diff --git a/systems/x86_64-linux/jallen-nas/default.nix b/systems/x86_64-linux/jallen-nas/default.nix index 5bca535..c201e6a 100755 --- a/systems/x86_64-linux/jallen-nas/default.nix +++ b/systems/x86_64-linux/jallen-nas/default.nix @@ -233,7 +233,7 @@ in services = { grafana = { - enable = false; + enable = true; port = 9999; }; }; diff --git a/systems/x86_64-linux/jallen-nas/sops.nix b/systems/x86_64-linux/jallen-nas/sops.nix index 8ebb2b7..08af039 100755 --- a/systems/x86_64-linux/jallen-nas/sops.nix +++ b/systems/x86_64-linux/jallen-nas/sops.nix @@ -140,7 +140,7 @@ in group = "keys"; restartUnits = [ "nextcloud.service" - "prometheus-nextcloud-exporter.service" + "prometheus-nextcloud-exporter.service" # actual systemd unit name ]; }; "jallen-nas/nextcloud/smtp_settings" = { @@ -285,6 +285,21 @@ in sopsFile = defaultSops; restartUnits = [ "podman-authenticRac.service" ]; }; + + # ------------------------------ + # Grafana + # ------------------------------ + # secret_key was previously the upstream default "SW2YcwTIb9zpOOhoPsMm". + # It is stored here so Grafana can read it via the file provider without + # embedding it in the world-readable Nix store. + # To rotate: use https://github.com/erooke/grafana-secretkey-rotation-tool + "jallen-nas/grafana/secret-key" = { + sopsFile = defaultSops; + owner = "grafana"; + group = "grafana"; + mode = "0400"; + restartUnits = [ "grafana.service" ]; + }; }; # ------------------------------ diff --git a/systems/x86_64-linux/jallen-nas/users.nix b/systems/x86_64-linux/jallen-nas/users.nix index 94bf25d..56e2e73 100755 --- a/systems/x86_64-linux/jallen-nas/users.nix +++ b/systems/x86_64-linux/jallen-nas/users.nix @@ -44,14 +44,16 @@ in }; root.shell = pkgs.zsh; - # Allow the Prometheus Nextcloud exporter to read its password secret. - prometheus-nextcloud-exporter = { + # The NixOS nextcloud exporter runs as 'nextcloud-exporter' (the default + # generated by the exporter base module). Add it to 'keys' so it can + # read the SOPS-managed adminpassword secret. + nextcloud-exporter = { isSystemUser = true; - group = "prometheus-nextcloud-exporter"; + group = "nextcloud-exporter"; extraGroups = [ "keys" ]; }; }; - groups.prometheus-nextcloud-exporter = { }; + groups.nextcloud-exporter = { }; }; }