at 25.11-pre 10 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.nezha-agent; 9 10 # nezha-agent uses yaml as the configuration file format. 11 # Since we need to use jq to update the content, so here we generate json 12 settingsFormat = pkgs.formats.json { }; 13 configFile = settingsFormat.generate "config.json" cfg.settings; 14in 15{ 16 meta = { 17 maintainers = with lib.maintainers; [ moraxyc ]; 18 }; 19 options = { 20 services.nezha-agent = { 21 enable = lib.mkEnableOption "Agent of Nezha Monitoring"; 22 23 package = lib.mkPackageOption pkgs "nezha-agent" { }; 24 25 debug = lib.mkEnableOption "verbose log"; 26 27 settings = lib.mkOption { 28 description = '' 29 Generate to {file}`config.json` as a Nix attribute set. 30 Check the [guide](https://nezha.wiki/en_US/guide/agent.html) 31 for possible options. 32 ''; 33 type = lib.types.submodule { 34 freeformType = settingsFormat.type; 35 36 options = { 37 disable_command_execute = lib.mkOption { 38 type = lib.types.bool; 39 default = true; 40 description = '' 41 Disable executing the command from dashboard. 42 ''; 43 }; 44 disable_nat = lib.mkOption { 45 type = lib.types.bool; 46 default = false; 47 description = '' 48 Disable NAT penetration. 49 ''; 50 }; 51 disable_send_query = lib.mkOption { 52 type = lib.types.bool; 53 default = false; 54 description = '' 55 Disable sending TCP/ICMP/HTTP requests. 56 ''; 57 }; 58 gpu = lib.mkOption { 59 type = lib.types.bool; 60 default = false; 61 description = '' 62 Enable GPU monitoring. 63 ''; 64 }; 65 tls = lib.mkOption { 66 type = lib.types.bool; 67 default = false; 68 description = '' 69 Enable SSL/TLS encryption. 70 ''; 71 }; 72 temperature = lib.mkOption { 73 type = lib.types.bool; 74 default = true; 75 description = '' 76 Enable temperature monitoring. 77 ''; 78 }; 79 use_ipv6_country_code = lib.mkOption { 80 type = lib.types.bool; 81 default = true; 82 description = '' 83 Use ipv6 countrycode to report location. 84 ''; 85 }; 86 skip_connection_count = lib.mkOption { 87 type = lib.types.bool; 88 default = false; 89 description = '' 90 Do not monitor the number of connections. 91 ''; 92 }; 93 skip_procs_count = lib.mkOption { 94 type = lib.types.bool; 95 default = false; 96 description = '' 97 Do not monitor the number of processes. 98 ''; 99 }; 100 report_delay = lib.mkOption { 101 type = lib.types.enum [ 102 1 103 2 104 3 105 4 106 ]; 107 default = 3; 108 description = '' 109 The interval between system status reportings. 110 The value must be an integer from 1 to 4. 111 ''; 112 }; 113 server = lib.mkOption { 114 type = lib.types.str; 115 example = "127.0.0.1:8008"; 116 description = '' 117 Address to the dashboard. 118 ''; 119 }; 120 uuid = lib.mkOption { 121 type = with lib.types; nullOr str; 122 # pre-defined uuid of Dns in RFC 4122 123 example = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; 124 default = null; 125 description = '' 126 Must be set to a unique identifier, preferably a UUID according to 127 RFC 4122. UUIDs can be generated with `uuidgen` command, found in 128 the `util-linux` package. 129 130 Set {option}`services.nezha-agent.genUuid` to true to generate uuid 131 from {option}`networking.fqdn` automatically. 132 ''; 133 }; 134 }; 135 }; 136 }; 137 138 genUuid = lib.mkOption { 139 type = lib.types.bool; 140 default = false; 141 description = '' 142 Whether to generate uuid from fqdn automatically. 143 Please note that changes in hostname/domain will result in different uuid. 144 ''; 145 }; 146 147 clientSecretFile = lib.mkOption { 148 type = with lib.types; nullOr path; 149 default = null; 150 description = '' 151 Path to the file contained the client_secret of the dashboard. 152 ''; 153 }; 154 }; 155 }; 156 157 imports = with lib; [ 158 (mkRenamedOptionModule 159 [ "services" "nezha-agent" "disableCommandExecute" ] 160 [ "services" "nezha-agent" "settings" "disable_command_execute" ] 161 ) 162 (mkRenamedOptionModule 163 [ "services" "nezha-agent" "disableNat" ] 164 [ "services" "nezha-agent" "settings" "disable_nat" ] 165 ) 166 (mkRenamedOptionModule 167 [ "services" "nezha-agent" "disableSendQuery" ] 168 [ "services" "nezha-agent" "settings" "disable_send_query" ] 169 ) 170 (mkRenamedOptionModule 171 [ "services" "nezha-agent" "gpu" ] 172 [ "services" "nezha-agent" "settings" "gpu" ] 173 ) 174 (mkRenamedOptionModule 175 [ "services" "nezha-agent" "tls" ] 176 [ "services" "nezha-agent" "settings" "tls" ] 177 ) 178 (mkRenamedOptionModule 179 [ "services" "nezha-agent" "temperature" ] 180 [ "services" "nezha-agent" "settings" "temperature" ] 181 ) 182 (mkRenamedOptionModule 183 [ "services" "nezha-agent" "useIPv6CountryCode" ] 184 [ "services" "nezha-agent" "settings" "use_ipv6_country_code" ] 185 ) 186 (mkRenamedOptionModule 187 [ "services" "nezha-agent" "skipConnection" ] 188 [ "services" "nezha-agent" "settings" "skip_connection_count" ] 189 ) 190 (mkRenamedOptionModule 191 [ "services" "nezha-agent" "skipProcess" ] 192 [ "services" "nezha-agent" "settings" "skip_procs_count" ] 193 ) 194 (mkRenamedOptionModule 195 [ "services" "nezha-agent" "reportDelay" ] 196 [ "services" "nezha-agent" "settings" "report_delay" ] 197 ) 198 (mkRenamedOptionModule 199 [ "services" "nezha-agent" "server" ] 200 [ "services" "nezha-agent" "settings" "server" ] 201 ) 202 (lib.mkRemovedOptionModule [ "services" "nezha-agent" "extraFlags" ] '' 203 Use `services.nezha-agent.settings` instead. 204 205 Nezha-agent v1 is no longer configured via command line flags. 206 '') 207 (lib.mkRemovedOptionModule [ "services" "nezha-agent" "passwordFile" ] '' 208 Use `services.nezha-agent.clientSecretFile` instead. 209 210 Nezha-agent v1 uses the client secret from the dashboard to connect. 211 '') 212 ]; 213 214 config = lib.mkIf cfg.enable { 215 assertions = [ 216 { 217 assertion = cfg.settings.uuid == null -> cfg.genUuid; 218 message = "Please set `service.nezha-agent.settings.uuid` while `genUuid` is false."; 219 } 220 { 221 assertion = cfg.settings.uuid != null -> !cfg.genUuid; 222 message = "When `service.nezha-agent.genUuid = true`, `settings.uuid` cannot be set."; 223 } 224 ]; 225 226 services.nezha-agent.settings = { 227 debug = cfg.debug; 228 # Automatic updates should never be enabled in NixOS. 229 disable_auto_update = true; 230 disable_force_update = true; 231 }; 232 233 systemd.services.nezha-agent = { 234 serviceConfig = { 235 Restart = "on-failure"; 236 StateDirectory = "nezha-agent"; 237 RuntimeDirectory = "nezha-agent"; 238 WorkingDirectory = "/var/lib/nezha-agent"; 239 ReadWritePaths = "/var/lib/nezha-agent"; 240 241 LoadCredential = lib.optionalString ( 242 cfg.clientSecretFile != null 243 ) "client-secret:${cfg.clientSecretFile}"; 244 245 # Hardening 246 ProcSubset = "all"; # Needed to get host information 247 DynamicUser = true; 248 RemoveIPC = true; 249 LockPersonality = true; 250 ProtectClock = true; 251 MemoryDenyWriteExecute = true; 252 PrivateUsers = true; 253 ProtectHostname = true; 254 RestrictSUIDSGID = true; 255 AmbientCapabilities = [ ]; 256 CapabilityBoundingSet = ""; 257 NoNewPrivileges = true; 258 PrivateTmp = true; 259 ProtectControlGroups = true; 260 ProtectHome = true; 261 ProtectKernelLogs = true; 262 ProtectKernelModules = true; 263 ProtectKernelTunables = true; 264 ProtectProc = "invisible"; 265 ProtectSystem = "strict"; 266 RestrictNamespaces = true; 267 RestrictRealtime = true; 268 SystemCallArchitectures = "native"; 269 UMask = "0066"; 270 SystemCallFilter = [ 271 "@system-service" 272 "~@privileged" 273 ]; 274 RestrictAddressFamilies = [ 275 "AF_INET" 276 "AF_INET6" 277 ]; 278 PrivateDevices = "yes"; 279 }; 280 environment.HOME = "/var/lib/nezha-agent"; 281 enableStrictShellChecks = true; 282 startLimitIntervalSec = 10; 283 startLimitBurst = 3; 284 script = '' 285 cp "${configFile}" "''${RUNTIME_DIRECTORY}"/config.json 286 ${lib.optionalString (cfg.clientSecretFile != null) '' 287 ${lib.getExe pkgs.jq} --arg client_secret "$(<"''${CREDENTIALS_DIRECTORY}"/client-secret)" \ 288 '. + { client_secret: $client_secret }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp 289 mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json 290 ''} 291 ${lib.optionalString cfg.genUuid '' 292 ${lib.getExe pkgs.jq} --arg uuid "$(${lib.getExe' pkgs.util-linux "uuidgen"} --md5 -n @dns -N "${config.networking.fqdn}")" \ 293 '. + { uuid: $uuid }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp 294 mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json 295 ''} 296 ${lib.getExe cfg.package} --config "''${RUNTIME_DIRECTORY}"/config.json 297 ''; 298 wantedBy = [ "multi-user.target" ]; 299 }; 300 }; 301}