at 25.11-pre 4.2 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9 10let 11 cfg = config.services.node-red; 12 defaultUser = "node-red"; 13in 14{ 15 options.services.node-red = { 16 enable = mkEnableOption "the Node-RED service"; 17 18 package = mkPackageOption pkgs [ "node-red" ] { }; 19 20 openFirewall = mkOption { 21 type = types.bool; 22 default = false; 23 description = '' 24 Open ports in the firewall for the server. 25 ''; 26 }; 27 28 withNpmAndGcc = mkOption { 29 type = types.bool; 30 default = false; 31 description = '' 32 Give Node-RED access to NPM and GCC at runtime, so 'Nodes' can be 33 downloaded and managed imperatively via the 'Palette Manager'. 34 ''; 35 }; 36 37 configFile = mkOption { 38 type = types.path; 39 default = "${cfg.package}/lib/node_modules/node-red/packages/node_modules/node-red/settings.js"; 40 defaultText = literalExpression ''"''${package}/lib/node_modules/node-red/packages/node_modules/node-red/settings.js"''; 41 description = '' 42 Path to the JavaScript configuration file. 43 See <https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js> 44 for a configuration example. 45 ''; 46 }; 47 48 port = mkOption { 49 type = types.port; 50 default = 1880; 51 description = "Listening port."; 52 }; 53 54 user = mkOption { 55 type = types.str; 56 default = defaultUser; 57 description = '' 58 User under which Node-RED runs.If left as the default value this user 59 will automatically be created on system activation, otherwise the 60 sysadmin is responsible for ensuring the user exists. 61 ''; 62 }; 63 64 group = mkOption { 65 type = types.str; 66 default = defaultUser; 67 description = '' 68 Group under which Node-RED runs.If left as the default value this group 69 will automatically be created on system activation, otherwise the 70 sysadmin is responsible for ensuring the group exists. 71 ''; 72 }; 73 74 userDir = mkOption { 75 type = types.path; 76 default = "/var/lib/node-red"; 77 description = '' 78 The directory to store all user data, such as flow and credential files and all library data. If left 79 as the default value this directory will automatically be created before the node-red service starts, 80 otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership 81 and permissions. 82 ''; 83 }; 84 85 safe = mkOption { 86 type = types.bool; 87 default = false; 88 description = "Whether to launch Node-RED in --safe mode."; 89 }; 90 91 define = mkOption { 92 type = types.attrs; 93 default = { }; 94 description = "List of settings.js overrides to pass via -D to Node-RED."; 95 example = literalExpression '' 96 { 97 "logging.console.level" = "trace"; 98 } 99 ''; 100 }; 101 }; 102 103 config = mkIf cfg.enable { 104 users.users = optionalAttrs (cfg.user == defaultUser) { 105 ${defaultUser} = { 106 isSystemUser = true; 107 group = defaultUser; 108 }; 109 }; 110 111 users.groups = optionalAttrs (cfg.group == defaultUser) { 112 ${defaultUser} = { }; 113 }; 114 115 networking.firewall = mkIf cfg.openFirewall { 116 allowedTCPPorts = [ cfg.port ]; 117 }; 118 119 systemd.services.node-red = { 120 description = "Node-RED Service"; 121 wantedBy = [ "multi-user.target" ]; 122 after = [ "networking.target" ]; 123 environment = { 124 HOME = cfg.userDir; 125 }; 126 path = lib.optionals cfg.withNpmAndGcc [ 127 pkgs.nodejs 128 pkgs.gcc 129 ]; 130 serviceConfig = mkMerge [ 131 { 132 User = cfg.user; 133 Group = cfg.group; 134 ExecStart = "${cfg.package}/bin/node-red ${pkgs.lib.optionalString cfg.safe "--safe"} --settings ${cfg.configFile} --port ${toString cfg.port} --userDir ${cfg.userDir} ${ 135 concatStringsSep " " (mapAttrsToList (name: value: "-D ${name}=${value}") cfg.define) 136 }"; 137 PrivateTmp = true; 138 Restart = "always"; 139 WorkingDirectory = cfg.userDir; 140 } 141 (mkIf (cfg.userDir == "/var/lib/node-red") { StateDirectory = "node-red"; }) 142 ]; 143 }; 144 }; 145}