2023-05-05 11:29:38 -05:00
|
|
|
|
# Edit this configuration file to define what should be installed on
|
2023-05-05 15:59:59 -05:00
|
|
|
|
# your system. Help is available in the configuration.nix(5) man page
|
2023-05-05 11:29:38 -05:00
|
|
|
|
# and in the NixOS manual (accessible by running ‘nixos-help’).
|
|
|
|
|
|
|
2025-11-20 23:08:52 -06:00
|
|
|
|
{
|
|
|
|
|
|
config,
|
2025-12-28 21:18:13 -06:00
|
|
|
|
metadata,
|
2025-11-20 23:08:52 -06:00
|
|
|
|
pkgs,
|
2026-05-12 21:25:24 -05:00
|
|
|
|
top,
|
2025-11-20 23:08:52 -06:00
|
|
|
|
...
|
|
|
|
|
|
}:
|
2023-05-05 15:59:59 -05:00
|
|
|
|
let
|
2024-10-03 11:26:39 -05:00
|
|
|
|
wanInterface = "enp2s0";
|
|
|
|
|
|
lanInterface = "enp1s0";
|
2025-12-28 21:18:13 -06:00
|
|
|
|
lanIpAddress = metadata.hosts.${config.networking.hostName}.ip;
|
2023-05-05 15:59:59 -05:00
|
|
|
|
in
|
2023-05-05 11:29:38 -05:00
|
|
|
|
|
|
|
|
|
|
{
|
2024-10-11 12:28:53 -05:00
|
|
|
|
imports = [
|
|
|
|
|
|
# Include the results of the hardware scan.
|
2026-02-23 17:14:08 -06:00
|
|
|
|
./arr.nix
|
2024-10-11 12:28:53 -05:00
|
|
|
|
./hardware-configuration.nix
|
2026-05-12 21:25:24 -05:00
|
|
|
|
top.niks3.nixosModules.niks3
|
2024-10-11 12:28:53 -05:00
|
|
|
|
];
|
2023-05-05 11:29:38 -05:00
|
|
|
|
|
2026-05-12 21:25:24 -05:00
|
|
|
|
age.secrets = {
|
|
|
|
|
|
cache-private-key = {
|
|
|
|
|
|
file = ../../../secrets/cache-private-key.age;
|
|
|
|
|
|
owner = "niks3";
|
|
|
|
|
|
};
|
|
|
|
|
|
grafana-secret-key = {
|
|
|
|
|
|
file = ../../../secrets/grafana-secret-key.age;
|
|
|
|
|
|
owner = "grafana";
|
|
|
|
|
|
};
|
|
|
|
|
|
niks3-access-key-id = {
|
|
|
|
|
|
file = ../../../secrets/niks3/access_key_id.age;
|
|
|
|
|
|
owner = "niks3";
|
|
|
|
|
|
};
|
|
|
|
|
|
niks3-api-token = {
|
|
|
|
|
|
file = ../../../secrets/niks3/api_token.age;
|
|
|
|
|
|
owner = "niks3";
|
|
|
|
|
|
};
|
|
|
|
|
|
niks3-secret-access-key = {
|
|
|
|
|
|
file = ../../../secrets/niks3/secret_access_key.age;
|
|
|
|
|
|
owner = "niks3";
|
|
|
|
|
|
};
|
2026-03-25 06:02:17 -05:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-10-03 11:26:39 -05:00
|
|
|
|
# Bootloader
|
|
|
|
|
|
boot = {
|
|
|
|
|
|
loader = {
|
|
|
|
|
|
systemd-boot.enable = true;
|
|
|
|
|
|
efi = {
|
|
|
|
|
|
canTouchEfiVariables = true;
|
|
|
|
|
|
efiSysMountPoint = "/boot/";
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
extraModprobeConfig = "vboxdrv";
|
|
|
|
|
|
};
|
2025-11-08 15:37:02 -06:00
|
|
|
|
|
|
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
|
|
|
|
clinfo
|
|
|
|
|
|
jellyfin-ffmpeg
|
|
|
|
|
|
libva-utils
|
2025-11-08 16:11:37 -06:00
|
|
|
|
mesa-demos
|
2025-11-08 15:37:02 -06:00
|
|
|
|
radeontop
|
|
|
|
|
|
vulkan-tools
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
greg = {
|
|
|
|
|
|
home = true;
|
2026-04-01 16:45:59 -05:00
|
|
|
|
nebula.enable = true;
|
2025-11-08 15:37:02 -06:00
|
|
|
|
proxies = {
|
|
|
|
|
|
"jellyfin.home".target = "http://localhost:8096/";
|
|
|
|
|
|
"jellyfin.thehellings.lan".target = "http://localhost:8096/";
|
2026-03-25 17:21:21 -05:00
|
|
|
|
"grafana.home".target = "http://localhost:3001/";
|
|
|
|
|
|
"grafana.thehellings.lan".target = "http://localhost:3001/";
|
2025-11-08 15:37:02 -06:00
|
|
|
|
};
|
2025-11-15 14:08:34 -06:00
|
|
|
|
tailscale = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
tags = [ "home" ];
|
|
|
|
|
|
};
|
2026-04-04 02:05:03 -05:00
|
|
|
|
backup.jobs.albyhub = {
|
|
|
|
|
|
src = "/chain/alby";
|
|
|
|
|
|
dest = "albyhub";
|
|
|
|
|
|
pre = "systemctl stop albyhub || true";
|
|
|
|
|
|
post = "systemctl start albyhub";
|
|
|
|
|
|
};
|
2025-11-08 15:37:02 -06:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
hardware = {
|
|
|
|
|
|
enableAllFirmware = true;
|
|
|
|
|
|
enableRedistributableFirmware = true;
|
|
|
|
|
|
graphics = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
extraPackages = with pkgs; [
|
|
|
|
|
|
intel-media-driver
|
2025-11-08 16:01:21 -06:00
|
|
|
|
intel-vaapi-driver
|
|
|
|
|
|
libva-vdpau-driver
|
2025-11-08 15:37:02 -06:00
|
|
|
|
#intel-media-sdk
|
|
|
|
|
|
intel-compute-runtime
|
|
|
|
|
|
];
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
2023-09-01 23:42:22 -05:00
|
|
|
|
|
2024-10-03 11:26:39 -05:00
|
|
|
|
networking = {
|
2025-12-28 21:18:13 -06:00
|
|
|
|
defaultGateway = metadata.infra.gw;
|
2026-03-25 11:40:00 -05:00
|
|
|
|
hostName = "hosea";
|
2024-10-03 11:26:39 -05:00
|
|
|
|
interfaces = {
|
|
|
|
|
|
"${wanInterface}".useDHCP = true;
|
|
|
|
|
|
"${lanInterface}" = {
|
|
|
|
|
|
useDHCP = false;
|
2024-10-11 12:28:53 -05:00
|
|
|
|
ipv4.addresses = [
|
|
|
|
|
|
{
|
|
|
|
|
|
address = lanIpAddress;
|
|
|
|
|
|
prefixLength = 16;
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
2024-10-03 11:26:39 -05:00
|
|
|
|
};
|
|
|
|
|
|
};
|
2026-05-12 21:25:24 -05:00
|
|
|
|
firewall.interfaces.nebula0.allowedTCPPorts = [ 5751 ];
|
2026-03-25 11:40:00 -05:00
|
|
|
|
nameservers = [ metadata.infra.dns ];
|
2024-10-03 11:26:39 -05:00
|
|
|
|
};
|
2023-05-05 11:29:38 -05:00
|
|
|
|
|
2024-10-03 11:26:39 -05:00
|
|
|
|
services = {
|
2025-12-23 18:13:25 -06:00
|
|
|
|
albyhub = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
openFirewall = true;
|
|
|
|
|
|
settings = {
|
|
|
|
|
|
workDir = "/chain/alby";
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
2025-11-08 15:37:02 -06:00
|
|
|
|
jellyfin = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
openFirewall = true;
|
|
|
|
|
|
};
|
2025-11-19 22:43:28 -06:00
|
|
|
|
grafana = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
provision = {
|
|
|
|
|
|
enable = true;
|
2025-11-20 23:08:52 -06:00
|
|
|
|
dashboards.settings.providers = [
|
|
|
|
|
|
{
|
|
|
|
|
|
name = "Dashboards";
|
|
|
|
|
|
disableDeletion = true;
|
|
|
|
|
|
options = {
|
|
|
|
|
|
path = "/etc/grafana-dashboards";
|
|
|
|
|
|
foldersFromFilesStructure = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
|
|
|
|
|
datasources.settings.datasources = [
|
|
|
|
|
|
{
|
|
|
|
|
|
name = "Prometheus";
|
|
|
|
|
|
type = "prometheus";
|
2026-03-25 12:37:29 -05:00
|
|
|
|
uid = "prometheus";
|
2025-11-22 21:57:05 -06:00
|
|
|
|
url = "https://prometheus.shire-zebra.ts.net";
|
2025-11-20 23:08:52 -06:00
|
|
|
|
isDefault = true;
|
|
|
|
|
|
editable = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
2025-11-19 22:43:28 -06:00
|
|
|
|
};
|
|
|
|
|
|
settings = {
|
2026-03-25 06:02:17 -05:00
|
|
|
|
security.secret_key = "$__file{${config.age.secrets.grafana-secret-key.path}}";
|
2025-11-19 22:43:28 -06:00
|
|
|
|
server = {
|
|
|
|
|
|
domain = "${config.networking.hostName}.shire-zebra.ts.net";
|
2026-03-25 17:40:38 -05:00
|
|
|
|
enforce_domain = false;
|
2025-11-19 22:43:28 -06:00
|
|
|
|
http_addr = "0.0.0.0";
|
|
|
|
|
|
enable_gzip = true;
|
|
|
|
|
|
http_port = 3001;
|
|
|
|
|
|
};
|
|
|
|
|
|
analytics.reporting_enabled = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
2026-05-12 21:25:24 -05:00
|
|
|
|
niks3 = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
|
|
|
|
|
|
apiTokenFile = config.age.secrets.niks3-api-token.path;
|
|
|
|
|
|
gc.enable = false;
|
|
|
|
|
|
httpAddr = "${metadata.hosts.hosea.nebulaIp}:5751";
|
|
|
|
|
|
nginx = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
domain = "hosea.nebula";
|
|
|
|
|
|
enableACME = false;
|
|
|
|
|
|
forceSSL = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
s3 = {
|
|
|
|
|
|
accessKeyFile = config.age.secrets.niks3-access-key-id.path;
|
|
|
|
|
|
bucket = "niks3";
|
|
|
|
|
|
endpoint = "nas1.shire-zebra.ts.net:9000";
|
|
|
|
|
|
secretKeyFile = config.age.secrets.niks3-secret-access-key.path;
|
|
|
|
|
|
useSSL = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
signKeyFiles = [ config.age.secrets.cache-private-key.path ];
|
|
|
|
|
|
};
|
2025-11-22 21:57:05 -06:00
|
|
|
|
prometheus.exporters.graphite.enable = true;
|
2024-10-03 11:26:39 -05:00
|
|
|
|
# Configure keymap
|
|
|
|
|
|
xserver.xkb = {
|
|
|
|
|
|
layout = "us";
|
|
|
|
|
|
variant = "";
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
2025-11-08 15:37:02 -06:00
|
|
|
|
|
2026-03-25 07:24:24 -05:00
|
|
|
|
# After first deploy: create a Grafana service account + API token for Klaatu
|
|
|
|
|
|
# via the Grafana UI, then encrypt it: agenix -e secrets/grafana-api-token.age
|
|
|
|
|
|
age.secrets.grafana-api-token = {
|
|
|
|
|
|
file = ../../../secrets/grafana-api-token.age;
|
|
|
|
|
|
owner = "grafana";
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
environment.etc = {
|
|
|
|
|
|
"grafana-dashboards/system-health.json".text = ''
|
|
|
|
|
|
{
|
|
|
|
|
|
"uid": "system-health",
|
|
|
|
|
|
"title": "System Health Overview",
|
|
|
|
|
|
"schemaVersion": 38,
|
|
|
|
|
|
"version": 1,
|
|
|
|
|
|
"refresh": "30s",
|
|
|
|
|
|
"time": {"from": "now-3h", "to": "now"},
|
|
|
|
|
|
"panels": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 1,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Hosts Up",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 0, "w": 6, "h": 4},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(up{job=\"node\"} == 1)", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 2,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Hosts Down",
|
|
|
|
|
|
"gridPos": {"x": 6, "y": 0, "w": 6, "h": 4},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(up{job=\"node\"} == 0) or vector(0)", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {
|
|
|
|
|
|
"defaults": {
|
|
|
|
|
|
"thresholds": {
|
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
|
"steps": [{"color": "green", "value": null}, {"color": "red", "value": 1}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 3,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "CPU Usage %",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 4, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)", "legendFormat": "{{instance}}", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 4,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Memory Usage %",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 4, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100", "legendFormat": "{{instance}}", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 5,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Disk Usage % (/)",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 12, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "100 - ((node_filesystem_avail_bytes{mountpoint=\"/\",fstype!~\"tmpfs|overlay\"} / node_filesystem_size_bytes{mountpoint=\"/\",fstype!~\"tmpfs|overlay\"}) * 100)", "legendFormat": "{{instance}}", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 6,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Network RX bytes/s",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 20, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "rate(node_network_receive_bytes_total{device!~\"lo|tailscale.*\"}[5m])", "legendFormat": "{{instance}} {{device}}", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 7,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Network TX bytes/s",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 20, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "rate(node_network_transmit_bytes_total{device!~\"lo|tailscale.*\"}[5m])", "legendFormat": "{{instance}} {{device}}", "refId": "A"}]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
|
|
"grafana-dashboards/backup-health.json".text = ''
|
|
|
|
|
|
{
|
|
|
|
|
|
"uid": "backup-health",
|
|
|
|
|
|
"title": "Backup Health",
|
|
|
|
|
|
"schemaVersion": 38,
|
|
|
|
|
|
"version": 1,
|
|
|
|
|
|
"refresh": "30s",
|
|
|
|
|
|
"time": {"from": "now-3h", "to": "now"},
|
|
|
|
|
|
"panels": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 1,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Backup Jobs Reporting",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 0, "w": 8, "h": 4},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(restic_last_success_timestamp_seconds) or vector(0)", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 2,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Stale Backups (>26h)",
|
|
|
|
|
|
"gridPos": {"x": 8, "y": 0, "w": 8, "h": 4},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(time() - restic_last_success_timestamp_seconds > 93600) or vector(0)", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {
|
|
|
|
|
|
"defaults": {
|
|
|
|
|
|
"thresholds": {
|
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
|
"steps": [{"color": "green", "value": null}, {"color": "red", "value": 1}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 3,
|
|
|
|
|
|
"type": "table",
|
|
|
|
|
|
"title": "Last Backup Times",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 4, "w": 24, "h": 10},
|
|
|
|
|
|
"options": {"instant": true},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "restic_last_success_timestamp_seconds", "instant": true, "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {"defaults": {"unit": "dateTimeAsLocal"}}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 4,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Backup Duration (seconds)",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 14, "w": 24, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "restic_last_run_duration_seconds", "refId": "A"}]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
|
|
"grafana-dashboards/kubernetes.json".text = ''
|
|
|
|
|
|
{
|
|
|
|
|
|
"uid": "kubernetes-overview",
|
|
|
|
|
|
"title": "Kubernetes Overview",
|
|
|
|
|
|
"schemaVersion": 38,
|
2026-03-27 09:06:19 -05:00
|
|
|
|
"version": 3,
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"refresh": "30s",
|
|
|
|
|
|
"time": {"from": "now-3h", "to": "now"},
|
|
|
|
|
|
"panels": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 1,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Running Pods",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 0, "w": 6, "h": 4},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(kube_pod_status_phase{phase=\"Running\"} == 1) or vector(0)", "refId": "A"}]
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 2,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Failed Pods",
|
|
|
|
|
|
"gridPos": {"x": 6, "y": 0, "w": 6, "h": 4},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(kube_pod_status_phase{phase=\"Failed\"} == 1) or vector(0)", "refId": "A"}],
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"fieldConfig": {
|
|
|
|
|
|
"defaults": {
|
|
|
|
|
|
"thresholds": {
|
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
|
"steps": [{"color": "green", "value": null}, {"color": "red", "value": 1}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 3,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Pending Pods",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 0, "w": 6, "h": 4},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(kube_pod_status_phase{phase=\"Pending\"} == 1) or vector(0)", "refId": "A"}],
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"fieldConfig": {
|
|
|
|
|
|
"defaults": {
|
|
|
|
|
|
"thresholds": {
|
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
|
"steps": [{"color": "green", "value": null}, {"color": "yellow", "value": 1}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
{
|
|
|
|
|
|
"id": 8,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Nodes Ready",
|
|
|
|
|
|
"gridPos": {"x": 18, "y": 0, "w": 6, "h": 4},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(kube_node_status_condition{condition=\"Ready\",status=\"true\"} == 1) or vector(0)", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {
|
|
|
|
|
|
"defaults": {
|
|
|
|
|
|
"thresholds": {
|
|
|
|
|
|
"mode": "absolute",
|
|
|
|
|
|
"steps": [{"color": "red", "value": null}, {"color": "green", "value": 1}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
{
|
|
|
|
|
|
"id": 4,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Pod Restart Rate",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 4, "w": 24, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "topk(10, rate(kube_pod_container_status_restarts_total[15m]) * 900)", "legendFormat": "{{namespace}}/{{pod}}", "refId": "A"}]
|
|
|
|
|
|
},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
{
|
|
|
|
|
|
"id": 9,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Container CPU Usage (cores)",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 12, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "topk(10, rate(container_cpu_usage_seconds_total{container!=\"\",container!=\"POD\"}[5m]))", "legendFormat": "{{namespace}}/{{pod}}/{{container}}", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 10,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Container Memory Usage",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 12, "w": 12, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "topk(10, container_memory_working_set_bytes{container!=\"\",container!=\"POD\"})", "legendFormat": "{{namespace}}/{{pod}}/{{container}}", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {"defaults": {"unit": "bytes"}}
|
|
|
|
|
|
},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
{
|
|
|
|
|
|
"id": 5,
|
|
|
|
|
|
"type": "table",
|
|
|
|
|
|
"title": "All Pods",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 0, "y": 20, "w": 24, "h": 10},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "kube_pod_status_phase == 1", "instant": true, "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 11,
|
|
|
|
|
|
"type": "table",
|
|
|
|
|
|
"title": "Deployments",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 30, "w": 24, "h": 8},
|
|
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "kube_deployment_status_replicas_available", "instant": true, "refId": "A"}]
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 6,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Node CPU Usage",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 0, "y": 38, "w": 12, "h": 8},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "100 - (avg by(node) (rate(node_cpu_seconds_total{mode=\"idle\",job=\"node\"}[5m])) * 100)", "refId": "A"}]
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 7,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Node Memory Usage %",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 12, "y": 38, "w": 12, "h": 8},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100", "refId": "A"}]
|
2026-03-27 09:06:19 -05:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 12,
|
|
|
|
|
|
"type": "bargauge",
|
|
|
|
|
|
"title": "Top 5 Fullest PersistentVolumes",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 46, "w": 24, "h": 8},
|
|
|
|
|
|
"targets": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"datasource": {"type": "prometheus", "uid": "prometheus"},
|
|
|
|
|
|
"expr": "topk(5, kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes * 100)",
|
|
|
|
|
|
"legendFormat": "{{namespace}}/{{persistentvolumeclaim}}",
|
|
|
|
|
|
"refId": "A",
|
|
|
|
|
|
"instant": true
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"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": 70},
|
|
|
|
|
|
{"color": "red", "value": 90}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-25 07:24:24 -05:00
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
|
|
"grafana-dashboards/network.json".text = ''
|
|
|
|
|
|
{
|
|
|
|
|
|
"uid": "network-overview",
|
|
|
|
|
|
"title": "Network & UniFi",
|
|
|
|
|
|
"schemaVersion": 38,
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"version": 3,
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"refresh": "30s",
|
|
|
|
|
|
"time": {"from": "now-3h", "to": "now"},
|
|
|
|
|
|
"panels": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 1,
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "DNS Queries",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 0, "y": 0, "w": 6, "h": 4},
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "rate(dnsmasq_servers_queries[5m]) or vector(0)", "refId": "A"}]
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 3,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "UniFi Devices",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 6, "y": 0, "w": 6, "h": 4},
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(unpoller_device_uptime_seconds) or vector(0)", "refId": "A"}]
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
{
|
|
|
|
|
|
"id": 7,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "WiFi Clients",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 0, "w": 6, "h": 4},
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(unpoller_client_uptime_seconds{wired=\"false\"}) or vector(0)", "refId": "A"}]
|
2026-03-27 13:08:50 +00:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 8,
|
|
|
|
|
|
"type": "stat",
|
|
|
|
|
|
"title": "Wired Clients",
|
|
|
|
|
|
"gridPos": {"x": 18, "y": 0, "w": 6, "h": 4},
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "count(unpoller_client_uptime_seconds{wired=\"true\"}) or vector(0)", "refId": "A"}]
|
2026-03-27 13:08:50 +00:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 9,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "WAN RX (bytes/s)",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 4, "w": 12, "h": 8},
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "unpoller_device_wan_receive_rate_bytes", "legendFormat": "{{name}}", "refId": "A"}],
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"fieldConfig": {"defaults": {"unit": "Bps"}}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 10,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "WAN TX (bytes/s)",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 4, "w": 12, "h": 8},
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "unpoller_device_wan_transmit_rate_bytes", "legendFormat": "{{name}}", "refId": "A"}],
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"fieldConfig": {"defaults": {"unit": "Bps"}}
|
|
|
|
|
|
},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
{
|
|
|
|
|
|
"id": 4,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "UniFi Port RX (bytes/s)",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 0, "y": 12, "w": 12, "h": 8},
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "rate(unpoller_device_port_receive_bytes_total[5m])", "legendFormat": "{{port_id}} {{name}}", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {"defaults": {"unit": "Bps"}}
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 5,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "UniFi Port TX (bytes/s)",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 12, "y": 12, "w": 12, "h": 8},
|
2026-03-27 09:03:07 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "rate(unpoller_device_port_transmit_bytes_total[5m])", "legendFormat": "{{port_id}} {{name}}", "refId": "A"}],
|
|
|
|
|
|
"fieldConfig": {"defaults": {"unit": "Bps"}}
|
2026-03-25 07:24:24 -05:00
|
|
|
|
},
|
2026-03-27 13:08:50 +00:00
|
|
|
|
{
|
|
|
|
|
|
"id": 11,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Top Client Throughput (bytes/s)",
|
|
|
|
|
|
"gridPos": {"x": 0, "y": 20, "w": 24, "h": 8},
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "topk(10, rate(unpoller_client_receive_bytes_total[5m]) + rate(unpoller_client_transmit_bytes_total[5m]))", "legendFormat": "{{name}} {{ip}}", "refId": "A"}],
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"fieldConfig": {"defaults": {"unit": "Bps"}}
|
|
|
|
|
|
},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
{
|
|
|
|
|
|
"id": 6,
|
|
|
|
|
|
"type": "timeseries",
|
|
|
|
|
|
"title": "Ping Latency (ms)",
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"gridPos": {"x": 0, "y": 28, "w": 12, "h": 8},
|
2026-03-25 07:24:24 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "probe_duration_seconds{job=\"ping\"} * 1000", "legendFormat": "{{instance}}", "refId": "A"}]
|
2026-03-27 13:08:50 +00:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": 12,
|
|
|
|
|
|
"type": "table",
|
|
|
|
|
|
"title": "Device Status",
|
|
|
|
|
|
"gridPos": {"x": 12, "y": 28, "w": 12, "h": 8},
|
2026-03-27 08:44:12 -05:00
|
|
|
|
"targets": [{"datasource": {"type": "prometheus", "uid": "prometheus"}, "expr": "unpoller_device_uptime_seconds", "instant": true, "refId": "A"}],
|
2026-03-27 13:08:50 +00:00
|
|
|
|
"fieldConfig": {"defaults": {"unit": "s"}}
|
2026-03-25 07:24:24 -05:00
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
'';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-08 15:37:02 -06:00
|
|
|
|
users.users = {
|
|
|
|
|
|
greg.extraGroups = [ "vboxusers" ];
|
|
|
|
|
|
|
|
|
|
|
|
jellyfin.extraGroups = [
|
|
|
|
|
|
"video"
|
|
|
|
|
|
"render"
|
|
|
|
|
|
];
|
|
|
|
|
|
};
|
2023-05-05 11:29:38 -05:00
|
|
|
|
}
|