diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 9100f5b27a04..5cdcca29c89c 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -521,6 +521,7 @@ ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix + ./services/web-apps/frab.nix ./services/web-apps/mattermost.nix ./services/web-apps/nixbot.nix ./services/web-apps/pump.io.nix diff --git a/nixos/modules/services/web-apps/frab.nix b/nixos/modules/services/web-apps/frab.nix new file mode 100644 index 000000000000..d5329ef03c89 --- /dev/null +++ b/nixos/modules/services/web-apps/frab.nix @@ -0,0 +1,224 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.frab; + + package = pkgs.frab; + ruby = package.ruby; + + databaseConfig = builtins.toJSON { production = cfg.database; }; + + frabEnv = { + RAILS_ENV = "production"; + RACK_ENV = "production"; + SECRET_KEY_BASE = cfg.secretKeyBase; + FRAB_HOST = cfg.host; + FRAB_PROTOCOL = cfg.protocol; + FROM_EMAIL = cfg.fromEmail; + RAILS_SERVE_STATIC_FILES = "1"; + } // cfg.extraEnvironment; + + frab-rake = pkgs.stdenv.mkDerivation rec { + name = "frab-rake"; + buildInputs = [ package.env pkgs.makeWrapper ]; + phases = "installPhase fixupPhase"; + installPhase = '' + mkdir -p $out/bin + makeWrapper ${package.env}/bin/bundle $out/bin/frab-bundle \ + ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") frabEnv)} \ + --set PATH '${lib.makeBinPath (with pkgs; [ nodejs file imagemagick ])}:$PATH' \ + --set RAKEOPT '-f ${package}/share/frab/Rakefile' \ + --run 'cd ${package}/share/frab' + makeWrapper $out/bin/frab-bundle $out/bin/frab-rake \ + --add-flags "exec rake" + ''; + }; + +in + +{ + options = { + services.frab = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the frab service. + ''; + }; + + host = mkOption { + type = types.str; + example = "frab.example.com"; + description = '' + Hostname under which this frab instance can be reached. + ''; + }; + + protocol = mkOption { + type = types.str; + default = "https"; + example = "http"; + description = '' + Either http or https, depending on how your Frab instance + will be exposed to the public. + ''; + }; + + fromEmail = mkOption { + type = types.str; + default = "frab@localhost"; + description = '' + Email address used by frab. + ''; + }; + + listenAddress = mkOption { + type = types.str; + default = "localhost"; + description = '' + Address or hostname frab should listen on. + ''; + }; + + listenPort = mkOption { + type = types.int; + default = 3000; + description = '' + Port frab should listen on. + ''; + }; + + statePath = mkOption { + type = types.str; + default = "/var/lib/frab"; + description = '' + Directory where frab keeps its state. + ''; + }; + + user = mkOption { + type = types.str; + default = "frab"; + description = '' + User to run frab. + ''; + }; + + group = mkOption { + type = types.str; + default = "frab"; + description = '' + Group to run frab. + ''; + }; + + secretKeyBase = mkOption { + type = types.str; + description = '' + Your secret key is used for verifying the integrity of signed cookies. + If you change this key, all old signed cookies will become invalid! + + Make sure the secret is at least 30 characters and all random, + no regular words or you'll be exposed to dictionary attacks. + ''; + }; + + database = mkOption { + type = types.attrs; + default = { + adapter = "sqlite3"; + database = "/var/lib/frab/db.sqlite3"; + pool = 5; + timeout = 5000; + }; + example = { + adapter = "postgresql"; + database = "frab"; + host = "localhost"; + username = "frabuser"; + password = "supersecret"; + encoding = "utf8"; + pool = 5; + }; + description = '' + Rails database configuration for Frab as Nix attribute set. + ''; + }; + + extraEnvironment = mkOption { + type = types.attrs; + default = {}; + example = { + FRAB_CURRENCY_UNIT = "€"; + FRAB_CURRENCY_FORMAT = "%n%u"; + EXCEPTION_EMAIL = "frab-owner@example.com"; + SMTP_ADDRESS = "localhost"; + SMTP_PORT = "587"; + SMTP_DOMAIN = "localdomain"; + SMTP_USER_NAME = "root"; + SMTP_PASSWORD = "toor"; + SMTP_AUTHENTICATION = "1"; + SMTP_NOTLS = "1"; + }; + description = '' + Additional environment variables to set for frab for further + configuration. See the frab documentation for more information. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ frab-rake ]; + + users.extraUsers = [ + { name = cfg.user; + group = cfg.group; + home = "${cfg.statePath}"; + } + ]; + + users.extraGroups = [ { name = cfg.group; } ]; + + systemd.services.frab = { + after = [ "network.target" "gitlab.service" ]; + wantedBy = [ "multi-user.target" ]; + environment = frabEnv; + + preStart = '' + mkdir -p ${cfg.statePath}/system/attachments + chown ${cfg.user}:${cfg.group} -R ${cfg.statePath} + + mkdir /run/frab -p + ln -sf ${pkgs.writeText "frab-database.yml" databaseConfig} /run/frab/database.yml + ln -sf ${cfg.statePath}/system /run/frab/system + + if ! test -e "${cfg.statePath}/db-setup-done"; then + ${frab-rake}/bin/frab-rake db:setup + touch ${cfg.statePath}/db-setup-done + else + ${frab-rake}/bin/frab-rake db:migrate + fi + ''; + + serviceConfig = { + PermissionsStartOnly = true; + PrivateTmp = true; + PrivateDevices = true; + Type = "simple"; + User = cfg.user; + Group = cfg.group; + TimeoutSec = "300s"; + Restart = "on-failure"; + RestartSec = "10s"; + WorkingDirectory = "${package}/share/frab"; + ExecStart = "${frab-rake}/bin/frab-bundle exec rails server " + + "--binding=${cfg.listenAddress} --port=${toString cfg.listenPort}"; + }; + }; + + }; +}