From d7483490cd044aff33358f02d7ab28546f0706d0 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 15 Sep 2025 18:13:23 +0200 Subject: [PATCH] Add prometheus for home network --- hosts/iron/ports.nix | 1 + hosts/iron/secrets.yaml | 8 +- hosts/iron/services/default.nix | 5 +- hosts/iron/services/prometheus.nix | 207 ++++++++++++++++++ hosts/iron/services/unifi-controller.nix | 17 -- .../services/unifi-controller/default.nix | 35 +++ .../services/unifi-controller/unpoller.nix | 22 ++ pkgs/default.nix | 3 + pkgs/vodafone-station-exporter/default.nix | 12 + pkgs/vodafone-station-exporter/gomod2nix.toml | 42 ++++ 10 files changed, 331 insertions(+), 21 deletions(-) create mode 100644 hosts/iron/services/prometheus.nix delete mode 100644 hosts/iron/services/unifi-controller.nix create mode 100644 hosts/iron/services/unifi-controller/default.nix create mode 100644 hosts/iron/services/unifi-controller/unpoller.nix create mode 100644 pkgs/vodafone-station-exporter/default.nix create mode 100644 pkgs/vodafone-station-exporter/gomod2nix.toml diff --git a/hosts/iron/ports.nix b/hosts/iron/ports.nix index 106b26f..317909d 100644 --- a/hosts/iron/ports.nix +++ b/hosts/iron/ports.nix @@ -28,5 +28,6 @@ unifi-https.tcp = 8443; wireguard-public-ip-tunnel.udp = 51000; wireguard-esphome.udp = 51001; + prometheus-vodafone-station-exporter.tcp = 9420; }; } diff --git a/hosts/iron/secrets.yaml b/hosts/iron/secrets.yaml index 54e1ca4..a866030 100644 --- a/hosts/iron/secrets.yaml +++ b/hosts/iron/secrets.yaml @@ -18,6 +18,10 @@ mqtt-users: valetudo: ENC[AES256_GCM,data:+HRz6X+A5dhmx43G99ka0u9VozuzOFWR,iv:SPw5yoiBqN7sBH5EofevacTtu45jmuTPqToKrar0aJ0=,tag:lf+usB/eNNP1yuWW/QyTqQ==,type:str] photoprism: oidc-secret: ENC[AES256_GCM,data:XTAiUiGZJfSZHNbz6fePl3iMDdbxFSE7+SQH2ECRFqlo7w8TAhLyNXBxlEfGvu+8vttbKdkEm0r7132Q4ftOtA==,iv:WGsQXolbtRWIq4EDgODWNmkXdOZCsA9A3Fqoo4lJyec=,tag:5zJftwB5If/RZB3hI0Ly8A==,type:str] +prometheus: + exporters: + vodafone-station: ENC[AES256_GCM,data:eaFqYEuK3UU=,iv:BauymCkvj33TmZLyii367uVEc4Iq4GGcik4nbyT9Fpk=,tag:poB+qh5tAdv/dEt3WN6yVw==,type:str] + unpoller: ENC[AES256_GCM,data:WI1oUKHW4ef4pBk+mGM=,iv:C1LykPf1/ypUmy3ZCQzjfSjkpxhUukDNnfJnZLp2CJg=,tag:mSnZJKl9IHcx7I7GpFherw==,type:str] sops: age: - recipient: age1hx7fdu4mcha7kkxe7yevtvs6xgzgaafgenm3drhvr609wlj94sgqm497je @@ -29,8 +33,8 @@ sops: SU1USkxFUUY2NVhmUHBhZkdrNDR1Q0kKiXIicInELRjDR3tuyA+lnXeCcd9lYvbV GnBRGPM7BNO/6AA7HhAei48Kt+XE6+jQX66yTXyviKhK7Lpjrlb2YQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-06-11T22:17:21Z" - mac: ENC[AES256_GCM,data:l785PSSvzb/C3n6QnUHc+YTKSRLP/FjGzi0EOersLEFd/XGDy0vzPv5RJzE6475zUt9hHko9324z2woficG84CenjB3+IF0GtTtM8654KlLN5C91n06OrInG2hvOp68j6mAg1x9+XS1OBuNLGXEr7Bt0lkqD31JH6NyWqirQ1/4=,iv:Nuurf42iuTmH4bJ790HbGgB3tThA2/EZQ9JOcns5QeA=,tag:Qh9tsPWiYJAIO3cP430ccg==,type:str] + lastmodified: "2025-09-15T15:29:31Z" + mac: ENC[AES256_GCM,data:7clDIKf/lRxXaYpiJS8+j8MzUvPTZmf20M4xM2sto+DSh2h/rJTvQanbg4/2yNVmLCX6FZ6USJb7bqg7aBw7Yv7RMoEio/HO6BtKNcHiLLiCW0dXkIROO4s5rc1S/nwtSFpifhgN2KrjXyBq+PVFk61on7K861zimsHev/KmDKk=,iv:9S1KONQWBMJBQElvAQ+NAOn15BrN0IkIyjedwSUm7oY=,tag:Kc8N8F5rz0EVIHseT1x0Kw==,type:str] pgp: - created_at: "2024-01-31T01:20:30Z" enc: |- diff --git a/hosts/iron/services/default.nix b/hosts/iron/services/default.nix index f19a759..4a10130 100644 --- a/hosts/iron/services/default.nix +++ b/hosts/iron/services/default.nix @@ -7,20 +7,21 @@ ./esphome ./home-assistant.nix ./jellyfin.nix - ./wireguard-esphome.nix ./mail.nix ./matrix.nix ./navidrome.nix ./nginx.nix ./ntp.nix ./photoprism.nix + ./prometheus.nix ./public-ip-tunnel.nix ./radicale.nix ./remarkable.nix ./snapcast ./sturzbach.nix ./tts.nix - ./unifi-controller.nix + ./unifi-controller ./whatsapp.nix + ./wireguard-esphome.nix ]; } diff --git a/hosts/iron/services/prometheus.nix b/hosts/iron/services/prometheus.nix new file mode 100644 index 0000000..5d571bc --- /dev/null +++ b/hosts/iron/services/prometheus.nix @@ -0,0 +1,207 @@ +{ config +, lib +, pkgs +, ... +}: +let + #domain = ""; + cfg = config.services.prometheus; + mkStaticTargets = targets: lib.singleton { inherit targets; }; + inherit (config.networking) ports; + blackboxRelabelConfig = [ + { + source_labels = [ "__address__" ]; + target_label = "__param_target"; + } + { + source_labels = [ "__param_target" ]; + target_label = "instance"; + } + { + target_label = "__address__"; + replacement = with config.services.prometheus.exporters.blackbox; "${listenAddress}:${toString port}"; + } + ]; +in +{ + #sops.secrets.prometheus-htpasswd = { + # owner = "nginx"; + # sopsFile = ../secrets.yaml; + #}; + + services.prometheus = { + enable = true; + listenAddress = "127.0.0.1"; + #webExternalUrl = "https://${domain}"; + globalConfig = { + scrape_interval = "15s"; + evaluation_interval = "15s"; + }; + extraFlags = [ + "--storage.tsdb.retention.time=90d" + "--web.enable-admin-api" + ]; + scrapeConfigs = [ + { + job_name = "node"; + static_configs = [ + { + targets = with config.services.prometheus.exporters.node; [ + "${listenAddress}:${toString port}" + ]; + } + ]; + relabel_configs = [ + { + source_labels = [ "__address__" ]; + target_label = "instance"; + replacement = config.networking.hostName; + } + ]; + } + { + job_name = "vodafone_station"; + static_configs = mkStaticTargets [ + "127.0.0.1:${toString ports.prometheus-vodafone-station-exporter.tcp}" + ]; + } + { + job_name = "unifi"; + static_configs = mkStaticTargets [ + "${cfg.exporters.unpoller.listenAddress}:${toString cfg.exporters.unpoller.port}" + ]; + } + { + job_name = "blackbox"; + metrics_path = "/probe"; + params.module = [ "http_2xx" ]; + static_configs = [ + { + targets = [ + "https://c58r0l3wtmqltl4y.myfritz.net:44919/" + ]; + } + ]; + relabel_configs = blackboxRelabelConfig; + } + { + job_name = "internet_ip4"; + static_configs = mkStaticTargets [ "1.1.1.1" "8.8.8.8" ]; + metrics_path = "/probe"; + params.module = [ "icmp_ip4" ]; + relabel_configs = blackboxRelabelConfig; + } + { + job_name = "internet_ip6"; + static_configs = mkStaticTargets [ "2606:4700:4700::1111" "2001:4860:4860::8888" ]; + metrics_path = "/probe"; + params.module = [ "icmp_ip6" ]; + relabel_configs = blackboxRelabelConfig; + } + ]; + + exporters = { + node.enable = true; + + blackbox = { + enable = true; + listenAddress = "127.0.0.1"; + + # https://github.com/prometheus/blackbox_exporter/blob/master/CONFIGURATION.md + configFile = pkgs.writeText "prometheus-blackbox-config" (builtins.toJSON { + modules = { + icmp_ip4 = { + prober = "icmp"; + timeout = "5s"; + icmp = { + ip_protocol_fallback = false; + preferred_ip_protocol = "ip4"; + }; + }; + icmp_ip6 = { + prober = "icmp"; + timeout = "5s"; + icmp = { + ip_protocol_fallback = false; + preferred_ip_protocol = "ip6"; + }; + }; + http_2xx = { + prober = "http"; + timeout = "5s"; + http = { + valid_http_versions = [ "HTTP/1.1" "HTTP/2.0" ]; + valid_status_codes = [ ]; # Defaults to 2xx + method = "GET"; + follow_redirects = true; + fail_if_ssl = false; + fail_if_not_ssl = true; + tls_config = { + insecure_skip_verify = false; + }; + preferred_ip_protocol = "ip4"; # defaults to "ip6" + ip_protocol_fallback = false; # no fallback to "ip6" + }; + }; + }; + }); + }; + }; + }; + + /* + */ + # + + systemd.services.prometheus-vodafone-station-exporter = + let + unitName = "prometheus-vodafone-station-exporter"; + in + { + enable = true; + description = "Prometheus Vodafone Station exporter"; + wants = [ "network.target" ]; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + BindReadOnlyPaths = [ + "/nix/store" + "/etc/resolv.conf" + ]; + DynamicUser = "yes"; + ExecStart = lib.strings.concatStringsSep " " [ + "${pkgs.vodafone-station-exporter}/bin/vodafone-station-exporter" + "-web.listen-address" + "127.0.0.1:${toString ports.prometheus-vodafone-station-exporter.tcp}" + "-vodafone.station-url" + "http://192.168.100.1" + "-vodafone.station-password-file" + "\${CREDENTIALS_DIRECTORY}/password" + ]; + LoadCredential = "password:${config.sops.secrets."prometheus/exporters/vodafone-station".path}"; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; + RestrictNamespaces = true; + RootDirectory = "%t/${unitName}"; + RuntimeDirectory = [ unitName ]; + }; + }; + + /* + services.nginx.virtualHosts."${domain}" = { + enableACME = true; + forceSSL = true; + + #basicAuthFile = config.sops.secrets.prometheus-htpasswd.path; + + locations = { + "/".proxyPass = "http://${cfg.listenAddress}:${toString cfg.port}"; + }; + }; + */ +} diff --git a/hosts/iron/services/unifi-controller.nix b/hosts/iron/services/unifi-controller.nix deleted file mode 100644 index f351e4b..0000000 --- a/hosts/iron/services/unifi-controller.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ config, pkgs, ... }: - -let - inherit (config.networking) ports; - interfaces = import ../interfaces.nix; -in -{ - services.unifi = { - enable = true; - unifiPackage = pkgs.unifi; - mongodbPackage = pkgs.mongodb-7_0; - }; - networking.firewall.interfaces."${interfaces.lan}".allowedTCPPorts = [ - ports.unifi-http.tcp - ports.unifi-https.tcp - ]; -} diff --git a/hosts/iron/services/unifi-controller/default.nix b/hosts/iron/services/unifi-controller/default.nix new file mode 100644 index 0000000..c9e7a2c --- /dev/null +++ b/hosts/iron/services/unifi-controller/default.nix @@ -0,0 +1,35 @@ +{ config, ... }: + +let + inherit (config.networking) ports; + interfaces = import ../../interfaces.nix; + #domain = "unifi.weinturm.de"; +in +{ + imports = [ + ./unpoller.nix + ]; + + services.unifi.enable = true; + + networking.firewall.interfaces."${interfaces.lan}".allowedTCPPorts = [ + ports.unifi-http.tcp + ports.unifi-https.tcp + ]; + + /* + services.nginx.virtualHosts = { + "${domain}" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "https://127.0.0.1:8443"; + recommendedProxySettings = true; + extraConfig = '' + proxy_ssl_verify off; + ''; + }; + }; + }; + */ +} diff --git a/hosts/iron/services/unifi-controller/unpoller.nix b/hosts/iron/services/unifi-controller/unpoller.nix new file mode 100644 index 0000000..9305ca5 --- /dev/null +++ b/hosts/iron/services/unifi-controller/unpoller.nix @@ -0,0 +1,22 @@ +{ config, ... }: + +{ + sops.secrets."prometheus/exporters/unpoller" = { + owner = config.services.prometheus.exporters.unpoller.user; + sopsFile = ../../secrets.yaml; + }; + + services.prometheus.exporters.unpoller = { + enable = true; + controllers = [ + { + user = "unpoller"; + url = "https://127.0.0.1:8443"; + pass = config.sops.secrets."prometheus/exporters/unpoller".path; + verify_ssl = false; + hash_pii = true; + } + ]; + log.prometheusErrors = true; + }; +} diff --git a/pkgs/default.nix b/pkgs/default.nix index de3d6d4..898812b 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -34,4 +34,7 @@ in vim-fluid = callPackage ./vim-fluid { inherit (prev.vimUtils) buildVimPlugin; }; vim-typoscript = callPackage ./vim-typoscript { inherit (prev.vimUtils) buildVimPlugin; }; }; + vodafone-station-exporter = callPackage ./vodafone-station-exporter { + inherit (inputs.gomod2nix.legacyPackages.${system}) buildGoApplication; + }; } diff --git a/pkgs/vodafone-station-exporter/default.nix b/pkgs/vodafone-station-exporter/default.nix new file mode 100644 index 0000000..9a80e97 --- /dev/null +++ b/pkgs/vodafone-station-exporter/default.nix @@ -0,0 +1,12 @@ +{ buildGoApplication, fetchgit }: + +buildGoApplication { + pname = "vodafone-station-exporter"; + version = "0.0.1"; + src = fetchgit { + url = "https://git.jalr.de/jalr/vodafone-station-exporter"; + rev = "808564b940c3570e3b32ce60657bf83fda75ec3c"; + hash = "sha256-A3Behy8Q7bhYXoGUsZXzIAQd/dTXH4d4wd+FDYuD7tE="; + }; + modules = ./gomod2nix.toml; +} diff --git a/pkgs/vodafone-station-exporter/gomod2nix.toml b/pkgs/vodafone-station-exporter/gomod2nix.toml new file mode 100644 index 0000000..293cd7e --- /dev/null +++ b/pkgs/vodafone-station-exporter/gomod2nix.toml @@ -0,0 +1,42 @@ +schema = 3 + +[mod] + [mod."github.com/beorn7/perks"] + version = "v1.0.1" + hash = "sha256-h75GUqfwJKngCJQVE5Ao5wnO3cfKD9lSIteoLp/3xJ4=" + [mod."github.com/cespare/xxhash/v2"] + version = "v2.3.0" + hash = "sha256-7hRlwSR+fos1kx4VZmJ/7snR7zHh8ZFKX+qqqqGcQpY=" + [mod."github.com/kr/text"] + version = "v0.2.0" + hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE=" + [mod."github.com/munnerz/goautoneg"] + version = "v0.0.0-20191010083416-a7dc8b61c822" + hash = "sha256-79URDDFenmGc9JZu+5AXHToMrtTREHb3BC84b/gym9Q=" + [mod."github.com/prometheus/client_golang"] + version = "v1.23.2" + hash = "sha256-3GD4fBFa1tJu8MS4TNP6r2re2eViUE+kWUaieIOQXCg=" + [mod."github.com/prometheus/client_model"] + version = "v0.6.2" + hash = "sha256-q6Fh6v8iNJN9ypD47LjWmx66YITa3FyRjZMRsuRTFeQ=" + [mod."github.com/prometheus/common"] + version = "v0.66.1" + hash = "sha256-bqHPaV9IV70itx63wqwgy2PtxMN0sn5ThVxDmiD7+Tk=" + [mod."github.com/prometheus/procfs"] + version = "v0.16.1" + hash = "sha256-OBCvKlLW2obct35p0L9Q+1ZrxZjpTmbgHMP2rng9hpo=" + [mod."go.yaml.in/yaml/v2"] + version = "v2.4.2" + hash = "sha256-oC8RWdf1zbMYCtmR0ATy/kCkhIwPR9UqFZSMOKLVF/A=" + [mod."golang.org/x/crypto"] + version = "v0.42.0" + hash = "sha256-qa6cGxZUhVnbkpVzfvLGQQsl/NCqNceJp9SIx5vkyiI=" + [mod."golang.org/x/exp"] + version = "v0.0.0-20250911091902-df9299821621" + hash = "sha256-cSDirFex900mrckzB3fe18hW2Vk4/y4xKvlUWq3yoDA=" + [mod."golang.org/x/sys"] + version = "v0.36.0" + hash = "sha256-9h4SHGnlJzmTENUp6226hC8fQ73QrQC3D85NNMxLuXg=" + [mod."google.golang.org/protobuf"] + version = "v1.36.8" + hash = "sha256-yZN8ZON0b5HjUNUSubHst7zbvnMsOzd81tDPYQRtPgM="