From 91ea1cdcd1a1bab0b74972cf8a5b8ff6c9f49e18 Mon Sep 17 00:00:00 2001 From: Moraxyc Date: Wed, 11 Dec 2024 15:45:03 +0800 Subject: [PATCH 1/4] nezha: 0.20.3 -> 1.9.5 Diff: https://github.com/nezhahq/nezha/compare/refs/tags/v0.20.3...v1.9.5 BREAKING CHANGE: Incompatible Configuration Changes - The upgrade includes significant architectural changes, resulting in a complete incompatibility with previous configurations. - Users will need to reconfigure their setups as the old configuration is no longer supported. - Please review the updated documentation for the new configuration format and features. Docs: https://nezha.wiki --- pkgs/by-name/ne/nezha/package.nix | 103 ++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 18 deletions(-) diff --git a/pkgs/by-name/ne/nezha/package.nix b/pkgs/by-name/ne/nezha/package.nix index bd3ccd452275..920e2107c4d4 100644 --- a/pkgs/by-name/ne/nezha/package.nix +++ b/pkgs/by-name/ne/nezha/package.nix @@ -1,26 +1,83 @@ { lib, - buildGoModule, + buildGo124Module, fetchFromGitHub, + go-swag, versionCheckHook, dbip-country-lite, + formats, nix-update-script, + nezha-theme-admin, + nezha-theme-user, + withThemes ? [ ], }: -buildGoModule rec { +let pname = "nezha"; - version = "0.20.13"; + version = "1.9.5"; + + frontendName = lib.removePrefix "nezha-theme-"; + + frontend-templates = + let + mkTemplate = theme: { + path = "${frontendName theme.pname}-dist"; + name = frontendName theme.pname; + repository = theme.meta.homepage; + author = theme.src.owner; + version = theme.version; + isofficial = false; + isadmin = false; + }; + in + (formats.yaml { }).generate "frontend-templates.yaml" ( + [ + ( + mkTemplate nezha-theme-admin + // { + name = "OfficialAdmin"; + isadmin = true; + isofficial = true; + } + ) + ( + mkTemplate nezha-theme-user + // { + name = "Official"; + isofficial = true; + } + ) + ] + ++ map mkTemplate withThemes + ); +in +buildGo124Module { + inherit pname version; src = fetchFromGitHub { - owner = "naiba"; + owner = "nezhahq"; repo = "nezha"; tag = "v${version}"; - hash = "sha256-fJvL2cESQoiW93aj2RHPyZXvP8246Mf8hIRiP/DSRRY="; + hash = "sha256-06x/M3Np8223ovMVj1K6e7WyoI5+QZohEIHNs/9+bJ0="; }; - postPatch = '' - cp ${dbip-country-lite.mmdb} pkg/geoip/geoip.db - ''; + proxyVendor = true; + + prePatch = + '' + rm -rf cmd/dashboard/*-dist + + cp ${frontend-templates} service/singleton/frontend-templates.yaml + '' + + lib.concatStringsSep "\n" ( + map (theme: "cp -r ${theme} cmd/dashboard/${frontendName theme.pname}-dist") ( + [ + nezha-theme-admin + nezha-theme-user + ] + ++ withThemes + ) + ); patches = [ # Nezha originally used ipinfo.mmdb to provide geoip query feature. @@ -29,12 +86,22 @@ buildGoModule rec { ./dbip.patch ]; - vendorHash = "sha256-SYefkgc0CsAEdkL7rxu9fpz7dpBnx1LwabIadUeOKco="; + postPatch = '' + cp ${dbip-country-lite.mmdb} pkg/geoip/geoip.db + ''; + + nativeBuildInputs = [ go-swag ]; + + # Generate code for Swagger documentation endpoints (see cmd/dashboard/docs). + preBuild = '' + GOROOT=''${GOROOT-$(go env GOROOT)} swag init --pd -d . -g ./cmd/dashboard/main.go -o ./cmd/dashboard/docs --parseGoList=false + ''; + + vendorHash = "sha256-q9/P6xSoGtMExhdwl5UuyvXTAaI+mD7MfIAidRz0rxw="; ldflags = [ "-s" - "-w" - "-X github.com/naiba/nezha/service/singleton.Version=${version}" + "-X github.com/nezhahq/nezha/service/singleton.Version=${version}" ]; checkFlags = "-skip=^TestSplitDomainSOA$"; @@ -43,18 +110,18 @@ buildGoModule rec { mv $out/bin/dashboard $out/bin/nezha ''; - nativeInstallCheckInputs = [ - versionCheckHook - ]; - versionCheckProgramArg = [ "--version" ]; + nativeInstallCheckInputs = [ versionCheckHook ]; + versionCheckProgramArg = [ "-v" ]; doInstallCheck = true; - passthru.updateScript = nix-update-script { }; + passthru = { + updateScript = nix-update-script { }; + }; meta = { description = "Self-hosted, lightweight server and website monitoring and O&M tool"; - homepage = "https://github.com/naiba/nezha"; - changelog = "https://github.com/naiba/nezha/releases/tag/v${version}"; + homepage = "https://github.com/nezhahq/nezha"; + changelog = "https://github.com/nezhahq/nezha/releases/tag/v${version}"; license = lib.licenses.asl20; maintainers = with lib.maintainers; [ moraxyc ]; mainProgram = "nezha"; From 6b79819539eb3e5e7f48641df76a014720161274 Mon Sep 17 00:00:00 2001 From: Moraxyc Date: Wed, 11 Dec 2024 15:45:57 +0800 Subject: [PATCH 2/4] nezha-agent: 0.20.5 -> 1.9.2 Diff: https://github.com/nezhahq/agent/compare/refs/tags/v0.20.5...v1.9.2 BREAKING CHANGE: Incompatible Configuration Changes - The upgrade includes significant architectural changes, resulting in a complete incompatibility with previous configurations. - Users will need to reconfigure their setups as the old configuration is no longer supported. - Please review the updated documentation for the new configuration format and features. Docs: https://nezha.wiki --- pkgs/by-name/ne/nezha-agent/package.nix | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/ne/nezha-agent/package.nix b/pkgs/by-name/ne/nezha-agent/package.nix index b6ed4e9f3850..70d9187a50f5 100644 --- a/pkgs/by-name/ne/nezha-agent/package.nix +++ b/pkgs/by-name/ne/nezha-agent/package.nix @@ -8,24 +8,27 @@ }: buildGoModule rec { pname = "nezha-agent"; - version = "0.20.5"; + version = "1.9.2"; src = fetchFromGitHub { owner = "nezhahq"; repo = "agent"; tag = "v${version}"; - hash = "sha256-CVE1c0LLheGlH8oMWQWs6fox7mlHc5Y2O9XQ6kqXAwI="; + hash = "sha256-bXzTZ8GCD3gNQsJzvXGlcufKxbX2aTq51toy5P02BxY="; }; - vendorHash = "sha256-ytFsTHl6kVwmqCabaMDxxijszY3jzWWUIZKBCebPMkI="; + vendorHash = "sha256-klwWNTKR7Vdqg3BDDMTyfnVfC+XZ+sFV/17pq7YdJTs="; ldflags = [ "-s" - "-w" - "-X main.version=${version}" + "-X github.com/nezhahq/agent/pkg/monitor.Version=${version}" "-X main.arch=${stdenv.hostPlatform.system}" ]; + preBuild = '' + go generate ./... + ''; + checkFlags = let # Skip tests that require network access From 1235bed1b5018082f11f7d68eb5a0f50438de212 Mon Sep 17 00:00:00 2001 From: Moraxyc Date: Wed, 11 Dec 2024 15:46:55 +0800 Subject: [PATCH 3/4] nixos/nezha-agent: refactor --- .../services/monitoring/nezha-agent.nix | 372 ++++++++++++------ 1 file changed, 258 insertions(+), 114 deletions(-) diff --git a/nixos/modules/services/monitoring/nezha-agent.nix b/nixos/modules/services/monitoring/nezha-agent.nix index 035485a939b8..87ecbfdde710 100644 --- a/nixos/modules/services/monitoring/nezha-agent.nix +++ b/nixos/modules/services/monitoring/nezha-agent.nix @@ -6,6 +6,11 @@ }: let cfg = config.services.nezha-agent; + + # nezha-agent uses yaml as the configuration file format. + # Since we need to use jq to update the content, so here we generate json + settingsFormat = pkgs.formats.json { }; + configFile = settingsFormat.generate "config.json" cfg.settings; in { meta = { @@ -16,141 +21,280 @@ in enable = lib.mkEnableOption "Agent of Nezha Monitoring"; package = lib.mkPackageOption pkgs "nezha-agent" { }; + debug = lib.mkEnableOption "verbose log"; - tls = lib.mkOption { + + settings = lib.mkOption { + description = '' + Generate to {file}`config.json` as a Nix attribute set. + Check the [guide](https://nezha.wiki/en_US/guide/agent.html) + for possible options. + ''; + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options = { + disable_command_execute = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Disable executing the command from dashboard. + ''; + }; + disable_nat = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Disable NAT penetration. + ''; + }; + disable_send_query = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Disable sending TCP/ICMP/HTTP requests. + ''; + }; + gpu = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable GPU monitoring. + ''; + }; + tls = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable SSL/TLS encryption. + ''; + }; + temperature = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Enable temperature monitoring. + ''; + }; + use_ipv6_country_code = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Use ipv6 countrycode to report location. + ''; + }; + skip_connection_count = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Do not monitor the number of connections. + ''; + }; + skip_procs_count = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Do not monitor the number of processes. + ''; + }; + report_delay = lib.mkOption { + type = lib.types.enum [ + 1 + 2 + 3 + 4 + ]; + default = 3; + description = '' + The interval between system status reportings. + The value must be an integer from 1 to 4. + ''; + }; + server = lib.mkOption { + type = lib.types.str; + example = "127.0.0.1:8008"; + description = '' + Address to the dashboard. + ''; + }; + uuid = lib.mkOption { + type = with lib.types; nullOr str; + # pre-defined uuid of Dns in RFC 4122 + example = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; + default = null; + description = '' + Must be set to a unique identifier, preferably a UUID according to + RFC 4122. UUIDs can be generated with `uuidgen` command, found in + the `util-linux` package. + + Set {option}`services.nezha-agent.genUuid` to true to generate uuid + from {option}`networking.fqdn` automatically. + ''; + }; + }; + }; + }; + + genUuid = lib.mkOption { type = lib.types.bool; default = false; description = '' - Enable SSL/TLS encryption. + Whether to generate uuid from fqdn automatically. + Please note that changes in hostname/domain will result in different uuid. ''; }; - gpu = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Enable GPU monitoring. - ''; - }; - temperature = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Enable temperature monitoring. - ''; - }; - useIPv6CountryCode = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Use ipv6 countrycode to report location. - ''; - }; - disableCommandExecute = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Disable executing the command from dashboard. - ''; - }; - disableNat = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Disable NAT penetration. - ''; - }; - disableSendQuery = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Disable sending TCP/ICMP/HTTP requests. - ''; - }; - skipConnection = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Do not monitor the number of connections. - ''; - }; - skipProcess = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Do not monitor the number of processes. - ''; - }; - reportDelay = lib.mkOption { - type = lib.types.enum [ - 1 - 2 - 3 - 4 - ]; - default = 1; - description = '' - The interval between system status reportings. - The value must be an integer from 1 to 4 - ''; - }; - passwordFile = lib.mkOption { - type = with lib.types; nullOr str; + + clientSecretFile = lib.mkOption { + type = with lib.types; nullOr path; default = null; description = '' - Path to the file contained the password from dashboard. - ''; - }; - server = lib.mkOption { - type = lib.types.str; - description = '' - Address to the dashboard - ''; - }; - extraFlags = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - example = [ "--gpu" ]; - description = '' - Extra command-line flags passed to nezha-agent. + Path to the file contained the client_secret of the dashboard. ''; }; }; }; + imports = with lib; [ + (mkRenamedOptionModule + [ "services" "nezha-agent" "disableCommandExecute" ] + [ "services" "nezha-agent" "settings" "disable_command_execute" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "disableNat" ] + [ "services" "nezha-agent" "settings" "disable_nat" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "disableSendQuery" ] + [ "services" "nezha-agent" "settings" "disable_send_query" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "gpu" ] + [ "services" "nezha-agent" "settings" "gpu" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "tls" ] + [ "services" "nezha-agent" "settings" "tls" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "temperature" ] + [ "services" "nezha-agent" "settings" "temperature" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "useIPv6CountryCode" ] + [ "services" "nezha-agent" "settings" "use_ipv6_country_code" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "skipConnection" ] + [ "services" "nezha-agent" "settings" "skip_connection_count" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "skipProcess" ] + [ "services" "nezha-agent" "settings" "skip_procs_count" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "reportDelay" ] + [ "services" "nezha-agent" "settings" "report_delay" ] + ) + (mkRenamedOptionModule + [ "services" "nezha-agent" "server" ] + [ "services" "nezha-agent" "settings" "server" ] + ) + (lib.mkRemovedOptionModule [ "services" "nezha-agent" "extraFlags" ] '' + Use `services.nezha-agent.settings` instead. + + Nezha-agent v1 is no longer configured via command line flags. + '') + (lib.mkRemovedOptionModule [ "services" "nezha-agent" "passwordFile" ] '' + Use `services.nezha-agent.clientSecretFile` instead. + + Nezha-agent v1 uses the client secret from the dashboard to connect. + '') + ]; + config = lib.mkIf cfg.enable { - systemd.packages = [ cfg.package ]; + assertions = [ + { + assertion = cfg.settings.uuid == null -> cfg.genUuid; + message = "Please set `service.nezha-agent.settings.uuid` while `genUuid` is false."; + } + { + assertion = cfg.settings.uuid != null -> !cfg.genUuid; + message = "When `service.nezha-agent.genUuid = true`, `settings.uuid` cannot be set."; + } + ]; + + services.nezha-agent.settings = { + debug = cfg.debug; + # Automatic updates should never be enabled in NixOS. + disable_auto_update = true; + disable_force_update = true; + }; systemd.services.nezha-agent = { serviceConfig = { - ProtectSystem = "full"; - PrivateDevices = "yes"; - PrivateTmp = "yes"; + Restart = "on-failure"; + StateDirectory = "nezha-agent"; + RuntimeDirectory = "nezha-agent"; + WorkingDirectory = "/var/lib/nezha-agent"; + ReadWritePaths = "/var/lib/nezha-agent"; + + LoadCredential = lib.optionalString ( + cfg.clientSecretFile != null + ) "client-secret:${cfg.clientSecretFile}"; + + # Hardening + ProcSubset = "all"; # Needed to get host information + DynamicUser = true; + RemoveIPC = true; + LockPersonality = true; + ProtectClock = true; + MemoryDenyWriteExecute = true; + PrivateUsers = true; + ProtectHostname = true; + RestrictSUIDSGID = true; + AmbientCapabilities = [ ]; + CapabilityBoundingSet = ""; NoNewPrivileges = true; + PrivateTmp = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + UMask = "0066"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + PrivateDevices = "yes"; }; - path = [ cfg.package ]; + environment.HOME = "/var/lib/nezha-agent"; + enableStrictShellChecks = true; startLimitIntervalSec = 10; startLimitBurst = 3; - script = lib.concatStringsSep " " ( - [ - "${lib.getExe cfg.package}" - "--disable-auto-update" - "--disable-force-update" - "--password $(cat ${cfg.passwordFile})" - ] - ++ lib.optional cfg.debug "--debug" - ++ lib.optional cfg.disableCommandExecute "--disable-command-execute" - ++ lib.optional cfg.disableNat "--disable-nat" - ++ lib.optional cfg.disableSendQuery "--disable-send-query" - ++ lib.optional (cfg.reportDelay != null) "--report-delay ${toString cfg.reportDelay}" - ++ lib.optional (cfg.server != null) "--server ${cfg.server}" - ++ lib.optional cfg.skipConnection "--skip-conn" - ++ lib.optional cfg.skipProcess "--skip-procs" - ++ lib.optional cfg.tls "--tls" - ++ lib.optional cfg.gpu "--gpu" - ++ lib.optional cfg.temperature "--temperature" - ++ lib.optional cfg.useIPv6CountryCode "--use-ipv6-countrycode" - ++ cfg.extraFlags - ); + script = '' + cp "${configFile}" "''${RUNTIME_DIRECTORY}"/config.json + ${lib.optionalString (cfg.clientSecretFile != null) '' + ${lib.getExe pkgs.jq} --arg client_secret "$(<"''${CREDENTIALS_DIRECTORY}"/client-secret)" \ + '. + { client_secret: $client_secret }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp + mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json + ''} + ${lib.optionalString cfg.genUuid '' + ${lib.getExe pkgs.jq} --arg uuid "$(${lib.getExe' pkgs.util-linux "uuidgen"} --md5 -n @dns -N "${config.networking.fqdn}")" \ + '. + { uuid: $uuid }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp + mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json + ''} + ${lib.getExe cfg.package} --config "''${RUNTIME_DIRECTORY}"/config.json + ''; wantedBy = [ "multi-user.target" ]; }; }; From 1df119a49c62e5d8412b635f17e0f94662db85bd Mon Sep 17 00:00:00 2001 From: Moraxyc Date: Fri, 20 Dec 2024 13:01:54 +0800 Subject: [PATCH 4/4] nixos/doc/rl-2505: mention Nezha update --- nixos/doc/manual/release-notes/rl-2505.section.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index f6578de089f2..dce0bf143bf2 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -221,6 +221,8 @@ - `strawberry` has been updated to 1.2, which drops support for the VLC backend and Qt 5. The `strawberry-qt5` package and `withGstreamer`/`withVlc` override options have been removed due to this. +- `nezha` and its agent `nezha-agent` have been updated to v1, which contains breaking changes. See the [official wiki](https://nezha.wiki/en_US/) for more details. + - `ps3-disc-dumper` was updated to 4.2.5, which removed the CLI project and now exclusively offers the GUI - [](#opt-services.nextcloud.config.dbtype) is unset by default, the previous default was `sqlite`.