diff options
Diffstat (limited to 'nixos/modules/services/web-apps')
-rw-r--r-- | nixos/modules/services/web-apps/node-red.nix | 148 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/tt-rss.nix | 127 |
2 files changed, 216 insertions, 59 deletions
diff --git a/nixos/modules/services/web-apps/node-red.nix b/nixos/modules/services/web-apps/node-red.nix new file mode 100644 index 00000000000..16cfb29cf57 --- /dev/null +++ b/nixos/modules/services/web-apps/node-red.nix @@ -0,0 +1,148 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.node-red; + defaultUser = "node-red"; + finalPackage = if cfg.withNpmAndGcc then node-red_withNpmAndGcc else cfg.package; + node-red_withNpmAndGcc = pkgs.runCommandNoCC "node-red" { + nativeBuildInputs = [ pkgs.makeWrapper ]; + } + '' + mkdir -p $out/bin + makeWrapper ${pkgs.nodePackages.node-red}/bin/node-red $out/bin/node-red \ + --set PATH '${lib.makeBinPath [ pkgs.nodePackages.npm pkgs.gcc ]}:$PATH' \ + ''; +in +{ + options.services.node-red = { + enable = mkEnableOption "the Node-RED service"; + + package = mkOption { + default = pkgs.nodePackages.node-red; + defaultText = "pkgs.nodePackages.node-red"; + type = types.package; + description = "Node-RED package to use."; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Open ports in the firewall for the server. + ''; + }; + + withNpmAndGcc = mkOption { + type = types.bool; + default = false; + description = '' + Give Node-RED access to NPM and GCC at runtime, so 'Nodes' can be + downloaded and managed imperatively via the 'Palette Manager'. + ''; + }; + + configFile = mkOption { + type = types.path; + default = "${cfg.package}/lib/node_modules/node-red/settings.js"; + defaultText = "\${cfg.package}/lib/node_modules/node-red/settings.js"; + description = '' + Path to the JavaScript configuration file. + See <link + xlink:href="https://github.com/node-red/node-red/blob/master/packages/node_modules/node-red/settings.js"/> + for a configuration example. + ''; + }; + + port = mkOption { + type = types.port; + default = 1880; + description = "Listening port."; + }; + + user = mkOption { + type = types.str; + default = defaultUser; + description = '' + User under which Node-RED runs.If left as the default value this user + will automatically be created on system activation, otherwise the + sysadmin is responsible for ensuring the user exists. + ''; + }; + + group = mkOption { + type = types.str; + default = defaultUser; + description = '' + Group under which Node-RED runs.If left as the default value this group + will automatically be created on system activation, otherwise the + sysadmin is responsible for ensuring the group exists. + ''; + }; + + userDir = mkOption { + type = types.path; + default = "/var/lib/node-red"; + description = '' + The directory to store all user data, such as flow and credential files and all library data. If left + as the default value this directory will automatically be created before the node-red service starts, + otherwise the sysadmin is responsible for ensuring the directory exists with appropriate ownership + and permissions. + ''; + }; + + safe = mkOption { + type = types.bool; + default = false; + description = "Whether to launch Node-RED in --safe mode."; + }; + + define = mkOption { + type = types.attrs; + default = {}; + description = "List of settings.js overrides to pass via -D to Node-RED."; + example = literalExample '' + { + "logging.console.level" = "trace"; + } + ''; + }; + }; + + config = mkIf cfg.enable { + users.users = optionalAttrs (cfg.user == defaultUser) { + ${defaultUser} = { + isSystemUser = true; + }; + }; + + users.groups = optionalAttrs (cfg.group == defaultUser) { + ${defaultUser} = { }; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.port ]; + }; + + systemd.services.node-red = { + description = "Node-RED Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "networking.target" ]; + environment = { + HOME = cfg.userDir; + }; + serviceConfig = mkMerge [ + { + User = cfg.user; + Group = cfg.group; + ExecStart = "${finalPackage}/bin/node-red ${pkgs.lib.optionalString cfg.safe "--safe"} --settings ${cfg.configFile} --port ${toString cfg.port} --userDir ${cfg.userDir} ${concatStringsSep " " (mapAttrsToList (name: value: "-D ${name}=${value}") cfg.define)}"; + PrivateTmp = true; + Restart = "always"; + WorkingDirectory = cfg.userDir; + } + (mkIf (cfg.userDir == "/var/lib/node-red") { StateDirectory = "node-red"; }) + ]; + }; + }; +} diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix index b78487cc928..ed13845915c 100644 --- a/nixos/modules/services/web-apps/tt-rss.nix +++ b/nixos/modules/services/web-apps/tt-rss.nix @@ -19,82 +19,84 @@ let mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql"; pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql"; - tt-rss-config = pkgs.writeText "config.php" '' + tt-rss-config = let + password = + if (cfg.database.password != null) then + "${(escape ["'" "\\"] cfg.database.password)}" + else if (cfg.database.passwordFile != null) then + "file_get_contents('${cfg.database.passwordFile}'" + else + "" + ; + in pkgs.writeText "config.php" '' <?php + putenv('TTRSS_PHP_EXECUTABLE=${pkgs.php}/bin/php'); - define('PHP_EXECUTABLE', '${pkgs.php}/bin/php'); + putenv('TTRSS_LOCK_DIRECTORY=${lockDir}'); + putenv('TTRSS_CACHE_DIR=${cacheDir}'); + putenv('TTRSS_ICONS_DIR=${feedIconsDir}'); + putenv('TTRSS_ICONS_URL=${feedIconsDir}'); + putenv('TTRSS_SELF_URL_PATH=${cfg.selfUrlPath}'); - define('LOCK_DIRECTORY', '${lockDir}'); - define('CACHE_DIR', '${cacheDir}'); - define('ICONS_DIR', '${feedIconsDir}'); - define('ICONS_URL', '${feedIconsDir}'); - define('SELF_URL_PATH', '${cfg.selfUrlPath}'); + putenv('TTRSS_MYSQL_CHARSET=UTF8'); - define('MYSQL_CHARSET', 'UTF8'); + putenv('TTRSS_DB_TYPE=${cfg.database.type}'); + putenv('TTRSS_DB_HOST=${optionalString (cfg.database.host != null) cfg.database.host}'); + putenv('TTRSS_DB_USER=${cfg.database.user}'); + putenv('TTRSS_DB_NAME=${cfg.database.name}'); + putenv('TTRSS_DB_PASS=${password}'); + putenv('TTRSS_DB_PORT=${toString dbPort}'); - define('DB_TYPE', '${cfg.database.type}'); - define('DB_HOST', '${optionalString (cfg.database.host != null) cfg.database.host}'); - define('DB_USER', '${cfg.database.user}'); - define('DB_NAME', '${cfg.database.name}'); - define('DB_PASS', ${ - if (cfg.database.password != null) then - "'${(escape ["'" "\\"] cfg.database.password)}'" - else if (cfg.database.passwordFile != null) then - "file_get_contents('${cfg.database.passwordFile}')" - else - "''" - }); - define('DB_PORT', '${toString dbPort}'); + putenv('TTRSS_AUTH_AUTO_CREATE=${boolToString cfg.auth.autoCreate}'); + putenv('TTRSS_AUTH_AUTO_LOGIN=${boolToString cfg.auth.autoLogin}'); - define('AUTH_AUTO_CREATE', ${boolToString cfg.auth.autoCreate}); - define('AUTH_AUTO_LOGIN', ${boolToString cfg.auth.autoLogin}); + putenv('TTRSS_FEED_CRYPT_KEY=${escape ["'" "\\"] cfg.feedCryptKey}'); - define('FEED_CRYPT_KEY', '${escape ["'" "\\"] cfg.feedCryptKey}'); + putenv('TTRSS_SINGLE_USER_MODE=${boolToString cfg.singleUserMode}'); - define('SINGLE_USER_MODE', ${boolToString cfg.singleUserMode}); + putenv('TTRSS_SIMPLE_UPDATE_MODE=${boolToString cfg.simpleUpdateMode}'); - define('SIMPLE_UPDATE_MODE', ${boolToString cfg.simpleUpdateMode}); + # Never check for updates - the running version of the code should + # be controlled entirely by the version of TT-RSS active in the + # current Nix profile. If TT-RSS updates itself to a version + # requiring a database schema upgrade, and then the SystemD + # tt-rss.service is restarted, the old code copied from the Nix + # store will overwrite the updated version, causing the code to + # detect the need for a schema "upgrade" (since the schema version + # in the database is different than in the code), but the update + # schema operation in TT-RSS will do nothing because the schema + # version in the database is newer than that in the code. + putenv('TTRSS_CHECK_FOR_UPDATES=false'); - // Never check for updates - the running version of the code should be - // controlled entirely by the version of TT-RSS active in the current Nix - // profile. If TT-RSS updates itself to a version requiring a database - // schema upgrade, and then the SystemD tt-rss.service is restarted, the - // old code copied from the Nix store will overwrite the updated version, - // causing the code to detect the need for a schema "upgrade" (since the - // schema version in the database is different than in the code), but the - // update schema operation in TT-RSS will do nothing because the schema - // version in the database is newer than that in the code. - define('CHECK_FOR_UPDATES', false); + putenv('TTRSS_FORCE_ARTICLE_PURGE=${toString cfg.forceArticlePurge}'); + putenv('TTRSS_SESSION_COOKIE_LIFETIME=${toString cfg.sessionCookieLifetime}'); + putenv('TTRSS_ENABLE_GZIP_OUTPUT=${boolToString cfg.enableGZipOutput}'); - define('FORCE_ARTICLE_PURGE', ${toString cfg.forceArticlePurge}); - define('SESSION_COOKIE_LIFETIME', ${toString cfg.sessionCookieLifetime}); - define('ENABLE_GZIP_OUTPUT', ${boolToString cfg.enableGZipOutput}); + putenv('TTRSS_PLUGINS=${builtins.concatStringsSep "," cfg.plugins}'); - define('PLUGINS', '${builtins.concatStringsSep "," cfg.plugins}'); + putenv('TTRSS_LOG_DESTINATION=${cfg.logDestination}'); + putenv('TTRSS_CONFIG_VERSION=${toString configVersion}'); - define('LOG_DESTINATION', '${cfg.logDestination}'); - define('CONFIG_VERSION', ${toString configVersion}); + putenv('TTRSS_PUBSUBHUBBUB_ENABLED=${boolToString cfg.pubSubHubbub.enable}'); + putenv('TTRSS_PUBSUBHUBBUB_HUB=${cfg.pubSubHubbub.hub}'); - define('PUBSUBHUBBUB_ENABLED', ${boolToString cfg.pubSubHubbub.enable}); - define('PUBSUBHUBBUB_HUB', '${cfg.pubSubHubbub.hub}'); + putenv('TTRSS_SPHINX_SERVER=${cfg.sphinx.server}'); + putenv('TTRSS_SPHINX_INDEX=${builtins.concatStringsSep "," cfg.sphinx.index}'); - define('SPHINX_SERVER', '${cfg.sphinx.server}'); - define('SPHINX_INDEX', '${builtins.concatStringsSep "," cfg.sphinx.index}'); + putenv('TTRSS_ENABLE_REGISTRATION=${boolToString cfg.registration.enable}'); + putenv('TTRSS_REG_NOTIFY_ADDRESS=${cfg.registration.notifyAddress}'); + putenv('TTRSS_REG_MAX_USERS=${toString cfg.registration.maxUsers}'); - define('ENABLE_REGISTRATION', ${boolToString cfg.registration.enable}); - define('REG_NOTIFY_ADDRESS', '${cfg.registration.notifyAddress}'); - define('REG_MAX_USERS', ${toString cfg.registration.maxUsers}); + putenv('TTRSS_SMTP_SERVER=${cfg.email.server}'); + putenv('TTRSS_SMTP_LOGIN=${cfg.email.login}'); + putenv('TTRSS_SMTP_PASSWORD=${escape ["'" "\\"] cfg.email.password}'); + putenv('TTRSS_SMTP_SECURE=${cfg.email.security}'); - define('SMTP_SERVER', '${cfg.email.server}'); - define('SMTP_LOGIN', '${cfg.email.login}'); - define('SMTP_PASSWORD', '${escape ["'" "\\"] cfg.email.password}'); - define('SMTP_SECURE', '${cfg.email.security}'); - - define('SMTP_FROM_NAME', '${escape ["'" "\\"] cfg.email.fromName}'); - define('SMTP_FROM_ADDRESS', '${escape ["'" "\\"] cfg.email.fromAddress}'); - define('DIGEST_SUBJECT', '${escape ["'" "\\"] cfg.email.digestSubject}'); + putenv('TTRSS_SMTP_FROM_NAME=${escape ["'" "\\"] cfg.email.fromName}'); + putenv('TTRSS_SMTP_FROM_ADDRESS=${escape ["'" "\\"] cfg.email.fromAddress}'); + putenv('TTRSS_DIGEST_SUBJECT=${escape ["'" "\\"] cfg.email.digestSubject}'); ${cfg.extraConfig} ''; @@ -564,9 +566,12 @@ let "Z '${cfg.root}' 0755 ${cfg.user} tt_rss - -" ]; - systemd.services.tt-rss = - { + systemd.services = { + phpfpm-tt-rss = mkIf (cfg.pool == "${poolName}") { + restartTriggers = [ tt-rss-config pkgs.tt-rss ]; + }; + tt-rss = { description = "Tiny Tiny RSS feeds update daemon"; preStart = let @@ -604,6 +609,9 @@ let ''} ln -sf "${tt-rss-config}" "${cfg.root}/config.php" chmod -R 755 "${cfg.root}" + chmod -R ug+rwX "${cfg.root}/${lockDir}" + chmod -R ug+rwX "${cfg.root}/${cacheDir}" + chmod -R ug+rwX "${cfg.root}/${feedIconsDir}" '' + (optionalString (cfg.database.type == "pgsql") '' @@ -640,6 +648,7 @@ let wantedBy = [ "multi-user.target" ]; requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; after = [ "network.target" ] ++ optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service"; + }; }; services.mysql = mkIf mysqlLocal { |