at master 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.ints.between 1 4; 102 default = 3; 103 description = '' 104 The interval between system status reportings. 105 The value must be an integer from 1 to 4. 106 ''; 107 }; 108 server = lib.mkOption { 109 type = lib.types.str; 110 example = "127.0.0.1:8008"; 111 description = '' 112 Address to the dashboard. 113 ''; 114 }; 115 uuid = lib.mkOption { 116 type = with lib.types; nullOr str; 117 # pre-defined uuid of Dns in RFC 4122 118 example = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; 119 default = null; 120 description = '' 121 Must be set to a unique identifier, preferably a UUID according to 122 RFC 4122. UUIDs can be generated with `uuidgen` command, found in 123 the `util-linux` package. 124 125 Set {option}`services.nezha-agent.genUuid` to true to generate uuid 126 from {option}`networking.fqdn` automatically. 127 ''; 128 }; 129 }; 130 }; 131 }; 132 133 genUuid = lib.mkOption { 134 type = lib.types.bool; 135 default = false; 136 description = '' 137 Whether to generate uuid from fqdn automatically. 138 Please note that changes in hostname/domain will result in different uuid. 139 ''; 140 }; 141 142 clientSecretFile = lib.mkOption { 143 type = with lib.types; nullOr path; 144 default = null; 145 description = '' 146 Path to the file contained the client_secret of the dashboard. 147 ''; 148 }; 149 }; 150 }; 151 152 imports = with lib; [ 153 (mkRenamedOptionModule 154 [ "services" "nezha-agent" "disableCommandExecute" ] 155 [ "services" "nezha-agent" "settings" "disable_command_execute" ] 156 ) 157 (mkRenamedOptionModule 158 [ "services" "nezha-agent" "disableNat" ] 159 [ "services" "nezha-agent" "settings" "disable_nat" ] 160 ) 161 (mkRenamedOptionModule 162 [ "services" "nezha-agent" "disableSendQuery" ] 163 [ "services" "nezha-agent" "settings" "disable_send_query" ] 164 ) 165 (mkRenamedOptionModule 166 [ "services" "nezha-agent" "gpu" ] 167 [ "services" "nezha-agent" "settings" "gpu" ] 168 ) 169 (mkRenamedOptionModule 170 [ "services" "nezha-agent" "tls" ] 171 [ "services" "nezha-agent" "settings" "tls" ] 172 ) 173 (mkRenamedOptionModule 174 [ "services" "nezha-agent" "temperature" ] 175 [ "services" "nezha-agent" "settings" "temperature" ] 176 ) 177 (mkRenamedOptionModule 178 [ "services" "nezha-agent" "useIPv6CountryCode" ] 179 [ "services" "nezha-agent" "settings" "use_ipv6_country_code" ] 180 ) 181 (mkRenamedOptionModule 182 [ "services" "nezha-agent" "skipConnection" ] 183 [ "services" "nezha-agent" "settings" "skip_connection_count" ] 184 ) 185 (mkRenamedOptionModule 186 [ "services" "nezha-agent" "skipProcess" ] 187 [ "services" "nezha-agent" "settings" "skip_procs_count" ] 188 ) 189 (mkRenamedOptionModule 190 [ "services" "nezha-agent" "reportDelay" ] 191 [ "services" "nezha-agent" "settings" "report_delay" ] 192 ) 193 (mkRenamedOptionModule 194 [ "services" "nezha-agent" "server" ] 195 [ "services" "nezha-agent" "settings" "server" ] 196 ) 197 (lib.mkRemovedOptionModule [ "services" "nezha-agent" "extraFlags" ] '' 198 Use `services.nezha-agent.settings` instead. 199 200 Nezha-agent v1 is no longer configured via command line flags. 201 '') 202 (lib.mkRemovedOptionModule [ "services" "nezha-agent" "passwordFile" ] '' 203 Use `services.nezha-agent.clientSecretFile` instead. 204 205 Nezha-agent v1 uses the client secret from the dashboard to connect. 206 '') 207 ]; 208 209 config = lib.mkIf cfg.enable { 210 assertions = [ 211 { 212 assertion = cfg.settings.uuid == null -> cfg.genUuid; 213 message = "Please set `service.nezha-agent.settings.uuid` while `genUuid` is false."; 214 } 215 { 216 assertion = cfg.settings.uuid != null -> !cfg.genUuid; 217 message = "When `service.nezha-agent.genUuid = true`, `settings.uuid` cannot be set."; 218 } 219 ]; 220 221 services.nezha-agent.settings = { 222 debug = cfg.debug; 223 # Automatic updates should never be enabled in NixOS. 224 disable_auto_update = true; 225 disable_force_update = true; 226 }; 227 228 systemd.services.nezha-agent = { 229 serviceConfig = { 230 Restart = "on-failure"; 231 StateDirectory = "nezha-agent"; 232 RuntimeDirectory = "nezha-agent"; 233 WorkingDirectory = "/var/lib/nezha-agent"; 234 ReadWritePaths = "/var/lib/nezha-agent"; 235 236 LoadCredential = lib.optionalString ( 237 cfg.clientSecretFile != null 238 ) "client-secret:${cfg.clientSecretFile}"; 239 240 # Hardening 241 ProcSubset = "all"; # Needed to get host information 242 DynamicUser = true; 243 RemoveIPC = true; 244 LockPersonality = true; 245 ProtectClock = true; 246 MemoryDenyWriteExecute = true; 247 PrivateUsers = true; 248 ProtectHostname = true; 249 RestrictSUIDSGID = true; 250 AmbientCapabilities = [ ]; 251 CapabilityBoundingSet = ""; 252 NoNewPrivileges = true; 253 PrivateTmp = true; 254 ProtectControlGroups = true; 255 ProtectHome = true; 256 ProtectKernelLogs = true; 257 ProtectKernelModules = true; 258 ProtectKernelTunables = true; 259 ProtectProc = "invisible"; 260 ProtectSystem = "strict"; 261 RestrictNamespaces = true; 262 RestrictRealtime = true; 263 SystemCallArchitectures = "native"; 264 UMask = "0066"; 265 SystemCallFilter = [ 266 "@system-service" 267 "~@privileged" 268 ]; 269 RestrictAddressFamilies = [ 270 "AF_INET" 271 "AF_INET6" 272 ]; 273 PrivateDevices = "yes"; 274 }; 275 environment.HOME = "/var/lib/nezha-agent"; 276 enableStrictShellChecks = true; 277 startLimitIntervalSec = 10; 278 startLimitBurst = 3; 279 script = '' 280 cp "${configFile}" "''${RUNTIME_DIRECTORY}"/config.json 281 ${lib.optionalString (cfg.clientSecretFile != null) '' 282 ${lib.getExe pkgs.jq} --arg client_secret "$(<"''${CREDENTIALS_DIRECTORY}"/client-secret)" \ 283 '. + { client_secret: $client_secret }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp 284 mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json 285 ''} 286 ${lib.optionalString cfg.genUuid '' 287 ${lib.getExe pkgs.jq} --arg uuid "$(${lib.getExe' pkgs.util-linux "uuidgen"} --md5 -n @dns -N "${config.networking.fqdn}")" \ 288 '. + { uuid: $uuid }' < "''${RUNTIME_DIRECTORY}"/config.json > "''${RUNTIME_DIRECTORY}"/config.json.tmp 289 mv "''${RUNTIME_DIRECTORY}"/config.json.tmp "''${RUNTIME_DIRECTORY}"/config.json 290 ''} 291 ${lib.getExe cfg.package} --config "''${RUNTIME_DIRECTORY}"/config.json 292 ''; 293 wantedBy = [ "multi-user.target" ]; 294 }; 295 }; 296}