diff options
Diffstat (limited to 'nixos/modules/services/web-apps')
-rw-r--r-- | nixos/modules/services/web-apps/akkoma.nix | 17 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/c2fmzq-server.md | 42 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/c2fmzq-server.nix | 125 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/cloudlog.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/dex.nix | 7 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/hedgedoc.nix | 1226 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/hledger-web.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/isso.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/jitsi-meet.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/lanraragi.nix | 100 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/meme-bingo-web.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/phylactery.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/plausible.nix | 6 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/shiori.nix | 9 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/snipe-it.nix | 18 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/zitadel.nix | 2 |
16 files changed, 550 insertions, 1020 deletions
diff --git a/nixos/modules/services/web-apps/akkoma.nix b/nixos/modules/services/web-apps/akkoma.nix index 8d1775258612..eaee70c712bb 100644 --- a/nixos/modules/services/web-apps/akkoma.nix +++ b/nixos/modules/services/web-apps/akkoma.nix @@ -282,11 +282,11 @@ let AKKOMA_CONFIG_PATH="$RUNTIME_DIRECTORY/config.exs" \ ERL_EPMD_ADDRESS="${cfg.dist.address}" \ ERL_EPMD_PORT="${toString cfg.dist.epmdPort}" \ - ERL_FLAGS="${concatStringsSep " " [ - "-kernel inet_dist_use_interface '${erlAddr cfg.dist.address}'" - "-kernel inet_dist_listen_min ${toString cfg.dist.portMin}" - "-kernel inet_dist_listen_max ${toString cfg.dist.portMax}" - ]}" \ + ERL_FLAGS=${lib.escapeShellArg (lib.escapeShellArgs ([ + "-kernel" "inet_dist_use_interface" (erlAddr cfg.dist.address) + "-kernel" "inet_dist_listen_min" (toString cfg.dist.portMin) + "-kernel" "inet_dist_listen_max" (toString cfg.dist.portMax) + ] ++ cfg.dist.extraFlags))} \ RELEASE_COOKIE="$(<"$RUNTIME_DIRECTORY/cookie")" \ RELEASE_NAME="akkoma" \ exec "${cfg.package}/bin/$(basename "$0")" "$@" @@ -553,6 +553,13 @@ in { description = mdDoc "TCP port to bind Erlang Port Mapper Daemon to."; }; + extraFlags = mkOption { + type = with types; listOf str; + default = [ ]; + description = mdDoc "Extra flags to pass to Erlang"; + example = [ "+sbwt" "none" "+sbwtdcpu" "none" "+sbwtdio" "none" ]; + }; + portMin = mkOption { type = types.port; default = 49152; diff --git a/nixos/modules/services/web-apps/c2fmzq-server.md b/nixos/modules/services/web-apps/c2fmzq-server.md new file mode 100644 index 000000000000..236953bd4ff7 --- /dev/null +++ b/nixos/modules/services/web-apps/c2fmzq-server.md @@ -0,0 +1,42 @@ +# c2FmZQ {#module-services-c2fmzq} + +c2FmZQ is an application that can securely encrypt, store, and share files, +including but not limited to pictures and videos. + +The service `c2fmzq-server` can be enabled by setting +``` +{ + services.c2fmzq-server.enable = true; +} +``` +This will spin up an instance of the server which is API-compatible with +[Stingle Photos](https://stingle.org) and an experimental Progressive Web App +(PWA) to interact with the storage via the browser. + +In principle the server can be exposed directly on a public interface and there +are command line options to manage HTTPS certificates directly, but the module +is designed to be served behind a reverse proxy or only accessed via localhost. + +``` +{ + services.c2fmzq-server = { + enable = true; + bindIP = "127.0.0.1"; # default + port = 8080; # default + }; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts."example.com" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8080"; + }; + }; + }; +} +``` + +For more information, see <https://github.com/c2FmZQ/c2FmZQ/>. diff --git a/nixos/modules/services/web-apps/c2fmzq-server.nix b/nixos/modules/services/web-apps/c2fmzq-server.nix new file mode 100644 index 000000000000..2749c2a5a87a --- /dev/null +++ b/nixos/modules/services/web-apps/c2fmzq-server.nix @@ -0,0 +1,125 @@ +{ lib, pkgs, config, ... }: + +let + inherit (lib) mkEnableOption mkPackageOption mkOption types; + + cfg = config.services.c2fmzq-server; + + argsFormat = { + type = with lib.types; nullOr (oneOf [ bool int str ]); + generate = lib.cli.toGNUCommandLineShell { }; + }; +in { + options.services.c2fmzq-server = { + enable = mkEnableOption "c2fmzq-server"; + + bindIP = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "The local address to use."; + }; + + port = mkOption { + type = types.port; + default = 8080; + description = "The local port to use."; + }; + + passphraseFile = mkOption { + type = types.str; + example = "/run/secrets/c2fmzq/pwfile"; + description = "Path to file containing the database passphrase"; + }; + + package = mkPackageOption pkgs "c2fmzq" { }; + + settings = mkOption { + type = types.submodule { + freeformType = argsFormat.type; + + options = { + address = mkOption { + internal = true; + type = types.str; + default = "${cfg.bindIP}:${toString cfg.port}"; + }; + + database = mkOption { + type = types.str; + default = "%S/c2fmzq-server/data"; + description = "Path of the database"; + }; + + verbose = mkOption { + type = types.ints.between 1 3; + default = 2; + description = "The level of logging verbosity: 1:Error 2:Info 3:Debug"; + }; + }; + }; + description = '' + Configuration for c2FmZQ-server passed as CLI arguments. + Run {command}`c2FmZQ-server help` for supported values. + ''; + example = { + verbose = 3; + allow-new-accounts = true; + auto-approve-new-accounts = true; + encrypt-metadata = true; + enable-webapp = true; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.c2fmzq-server = { + description = "c2FmZQ-server"; + documentation = [ "https://github.com/c2FmZQ/c2FmZQ/blob/main/README.md" ]; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "network-online.target" ]; + + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} ${argsFormat.generate cfg.settings}"; + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + DynamicUser = true; + Environment = "C2FMZQ_PASSPHRASE_FILE=%d/passphrase-file"; + IPAccounting = true; + IPAddressAllow = cfg.bindIP; + IPAddressDeny = "any"; + LoadCredential = "passphrase-file:${cfg.passphraseFile}"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateIPC = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SocketBindAllow = cfg.port; + SocketBindDeny = "any"; + StateDirectory = "c2fmzq-server"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged @obsolete" ]; + }; + }; + }; + + meta = { + doc = ./c2fmzq-server.md; + maintainers = with lib.maintainers; [ hmenke ]; + }; +} diff --git a/nixos/modules/services/web-apps/cloudlog.nix b/nixos/modules/services/web-apps/cloudlog.nix index da2cf93d7f1c..5519d6967a12 100644 --- a/nixos/modules/services/web-apps/cloudlog.nix +++ b/nixos/modules/services/web-apps/cloudlog.nix @@ -69,7 +69,7 @@ let in { options.services.cloudlog = with types; { - enable = mkEnableOption (mdDoc "Whether to enable Cloudlog"); + enable = mkEnableOption (mdDoc "Cloudlog"); dataDir = mkOption { type = str; default = "/var/lib/cloudlog"; diff --git a/nixos/modules/services/web-apps/dex.nix b/nixos/modules/services/web-apps/dex.nix index bd041db007a1..0c4a71c6dfe4 100644 --- a/nixos/modules/services/web-apps/dex.nix +++ b/nixos/modules/services/web-apps/dex.nix @@ -108,8 +108,7 @@ in ProtectClock = true; ProtectHome = true; ProtectHostname = true; - # Would re-mount paths ignored by temporary root - #ProtectSystem = "strict"; + ProtectSystem = "strict"; ProtectControlGroups = true; ProtectKernelLogs = true; ProtectKernelModules = true; @@ -121,9 +120,7 @@ in RestrictSUIDSGID = true; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" "~@privileged @setuid @keyring" ]; - TemporaryFileSystem = "/:ro"; - # Does not work well with the temporary root - #UMask = "0066"; + UMask = "0066"; } // optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = cfg.environmentFile; }; diff --git a/nixos/modules/services/web-apps/hedgedoc.nix b/nixos/modules/services/web-apps/hedgedoc.nix index bfa5fd5aff25..1a66f077b09d 100644 --- a/nixos/modules/services/web-apps/hedgedoc.nix +++ b/nixos/modules/services/web-apps/hedgedoc.nix @@ -1,7 +1,7 @@ { config, lib, pkgs, ... }: let - inherit (lib) literalExpression mdDoc mkEnableOption mkIf mkOption mkPackageOptionMD mkRenamedOptionModule types versionAtLeast; + inherit (lib) mkOption types mdDoc literalExpression; cfg = config.services.hedgedoc; @@ -9,990 +9,189 @@ let # versionAtLeast statement remains set to 21.03 for backwards compatibility. # See https://github.com/NixOS/nixpkgs/pull/108899 and # https://github.com/NixOS/rfcs/blob/master/rfcs/0080-nixos-release-schedule.md. - name = if versionAtLeast config.system.stateVersion "21.03" - then "hedgedoc" - else "codimd"; + name = if lib.versionAtLeast config.system.stateVersion "21.03" then + "hedgedoc" + else + "codimd"; - settingsFormat = pkgs.formats.json {}; - - prettyJSON = conf: - pkgs.runCommandLocal "hedgedoc-config.json" { - nativeBuildInputs = [ pkgs.jq ]; - } '' - jq '{production:del(.[]|nulls)|del(.[][]?|nulls)}' \ - < ${settingsFormat.generate "hedgedoc-ugly.json" cfg.settings} \ - > $out - ''; + settingsFormat = pkgs.formats.json { }; in { + meta.maintainers = with lib.maintainers; [ SuperSandro2000 h7x4 ]; + imports = [ - (mkRenamedOptionModule [ "services" "codimd" ] [ "services" "hedgedoc" ]) - (mkRenamedOptionModule - [ "services" "hedgedoc" "configuration" ] [ "services" "hedgedoc" "settings" ]) + (lib.mkRenamedOptionModule [ "services" "codimd" ] [ "services" "hedgedoc" ]) + (lib.mkRenamedOptionModule [ "services" "hedgedoc" "configuration" ] [ "services" "hedgedoc" "settings" ]) + (lib.mkRenamedOptionModule [ "services" "hedgedoc" "groups" ] [ "users" "users" "hedgedoc" "extraGroups" ]) + (lib.mkRemovedOptionModule [ "services" "hedgedoc" "workDir" ] '' + This option has been removed in favor of systemd managing the state directory. + + If you have set this option without specifying `services.settings.uploadsDir`, + please move these files to `/var/lib/hedgedoc/uploads`, or set the option to point + at the correct location. + '') ]; options.services.hedgedoc = { - package = mkPackageOptionMD pkgs "hedgedoc" { }; - enable = mkEnableOption (lib.mdDoc "the HedgeDoc Markdown Editor"); + package = lib.mkPackageOptionMD pkgs "hedgedoc" { }; + enable = lib.mkEnableOption (mdDoc "the HedgeDoc Markdown Editor"); - groups = mkOption { - type = types.listOf types.str; - default = []; - description = lib.mdDoc '' - Groups to which the service user should be added. - ''; - }; - - workDir = mkOption { - type = types.path; - default = "/var/lib/${name}"; - description = lib.mdDoc '' - Working directory for the HedgeDoc service. - ''; - }; + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; + options = { + domain = mkOption { + type = with types; nullOr str; + default = null; + example = "hedgedoc.org"; + description = mdDoc '' + Domain to use for website. - settings = let options = { - debug = mkEnableOption (lib.mdDoc "debug mode"); - domain = mkOption { - type = types.nullOr types.str; - default = null; - example = "hedgedoc.org"; - description = lib.mdDoc '' - Domain name for the HedgeDoc instance. - ''; - }; - urlPath = mkOption { - type = types.nullOr types.str; - default = null; - example = "/url/path/to/hedgedoc"; - description = lib.mdDoc '' - Path under which HedgeDoc is accessible. - ''; - }; - host = mkOption { - type = types.str; - default = "localhost"; - description = lib.mdDoc '' - Address to listen on. - ''; - }; - port = mkOption { - type = types.port; - default = 3000; - example = 80; - description = lib.mdDoc '' - Port to listen on. - ''; - }; - path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/run/hedgedoc.sock"; - description = lib.mdDoc '' - Specify where a UNIX domain socket should be placed. - ''; - }; - allowOrigin = mkOption { - type = types.listOf types.str; - default = []; - example = [ "localhost" "hedgedoc.org" ]; - description = lib.mdDoc '' - List of domains to whitelist. - ''; - }; - useSSL = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enable to use SSL server. This will also enable - {option}`protocolUseSSL`. - ''; - }; - enableStatsApi = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enables or disables the /status and /metrics endpoint. - ''; - }; - hsts = { - enable = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to enable HSTS if HTTPS is also enabled. - ''; - }; - maxAgeSeconds = mkOption { - type = types.int; - default = 31536000; - description = lib.mdDoc '' - Max duration for clients to keep the HSTS status. - ''; - }; - includeSubdomains = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to include subdomains in HSTS. - ''; - }; - preload = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to allow preloading of the site's HSTS status. - ''; - }; - }; - csp = mkOption { - type = types.nullOr types.attrs; - default = null; - example = literalExpression '' - { - enable = true; - directives = { - scriptSrc = "trustworthy.scripts.example.com"; - }; - upgradeInsecureRequest = "auto"; - addDefaults = true; - } - ''; - description = lib.mdDoc '' - Specify the Content Security Policy which is passed to Helmet. - For configuration details see <https://helmetjs.github.io/docs/csp/>. - ''; - }; - protocolUseSSL = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enable to use TLS for resource paths. - This only applies when {option}`domain` is set. - ''; - }; - urlAddPort = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Enable to add the port to callback URLs. - This only applies when {option}`domain` is set - and only for ports other than 80 and 443. - ''; - }; - useCDN = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Whether to use CDN resources or not. - ''; - }; - allowAnonymous = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to allow anonymous usage. - ''; - }; - allowAnonymousEdits = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Whether to allow guests to edit existing notes with the `freely` permission, - when {option}`allowAnonymous` is enabled. - ''; - }; - allowFreeURL = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Whether to allow note creation by accessing a nonexistent note URL. - ''; - }; - requireFreeURLAuthentication = mkOption { - type = types.bool; - default = false; - description = lib.mdDoc '' - Whether to require authentication for FreeURL mode style note creation. - ''; - }; - defaultPermission = mkOption { - type = types.enum [ "freely" "editable" "limited" "locked" "private" ]; - default = "editable"; - description = lib.mdDoc '' - Default permissions for notes. - This only applies for signed-in users. - ''; - }; - dbURL = mkOption { - type = types.nullOr types.str; - default = null; - example = '' - postgres://user:pass@host:5432/dbname - ''; - description = lib.mdDoc '' - Specify which database to use. - HedgeDoc supports mysql, postgres, sqlite and mssql. - See [ - https://sequelize.readthedocs.io/en/v3/](https://sequelize.readthedocs.io/en/v3/) for more information. - Note: This option overrides {option}`db`. - ''; - }; - db = mkOption { - type = types.attrs; - default = {}; - example = literalExpression '' - { - dialect = "sqlite"; - storage = "/var/lib/${name}/db.${name}.sqlite"; - } - ''; - description = lib.mdDoc '' - Specify the configuration for sequelize. - HedgeDoc supports mysql, postgres, sqlite and mssql. - See [ - https://sequelize.readthedocs.io/en/v3/](https://sequelize.readthedocs.io/en/v3/) for more information. - Note: This option overrides {option}`db`. - ''; - }; - sslKeyPath= mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/hedgedoc/hedgedoc.key"; - description = lib.mdDoc '' - Path to the SSL key. Needed when {option}`useSSL` is enabled. - ''; - }; - sslCertPath = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/hedgedoc/hedgedoc.crt"; - description = lib.mdDoc '' - Path to the SSL cert. Needed when {option}`useSSL` is enabled. - ''; - }; - sslCAPath = mkOption { - type = types.listOf types.str; - default = []; - example = [ "/var/lib/hedgedoc/ca.crt" ]; - description = lib.mdDoc '' - SSL ca chain. Needed when {option}`useSSL` is enabled. - ''; - }; - dhParamPath = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/hedgedoc/dhparam.pem"; - description = lib.mdDoc '' - Path to the SSL dh params. Needed when {option}`useSSL` is enabled. - ''; - }; - tmpPath = mkOption { - type = types.str; - default = "/tmp"; - description = lib.mdDoc '' - Path to the temp directory HedgeDoc should use. - Note that {option}`serviceConfig.PrivateTmp` is enabled for - the HedgeDoc systemd service by default. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - defaultNotePath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/default.md"; - defaultText = literalExpression "\"\${cfg.package}/public/default.md\""; - description = lib.mdDoc '' - Path to the default Note file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - docsPath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/docs"; - defaultText = literalExpression "\"\${cfg.package}/public/docs\""; - description = lib.mdDoc '' - Path to the docs directory. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - indexPath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/views/index.ejs"; - defaultText = literalExpression "\"\${cfg.package}/public/views/index.ejs\""; - description = lib.mdDoc '' - Path to the index template file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - hackmdPath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/views/hackmd.ejs"; - defaultText = literalExpression "\"\${cfg.package}/public/views/hackmd.ejs\""; - description = lib.mdDoc '' - Path to the hackmd template file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - errorPath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/views/error.ejs"; - defaultText = literalExpression "\"\${cfg.package}/public/views/error.ejs\""; - description = lib.mdDoc '' - Path to the error template file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - prettyPath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/views/pretty.ejs"; - defaultText = literalExpression "\"\${cfg.package}/public/views/pretty.ejs\""; - description = lib.mdDoc '' - Path to the pretty template file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - slidePath = mkOption { - type = types.nullOr types.str; - default = "${cfg.package}/public/views/slide.hbs"; - defaultText = literalExpression "\"\${cfg.package}/public/views/slide.hbs\""; - description = lib.mdDoc '' - Path to the slide template file. - (Non-canonical paths are relative to HedgeDoc's base directory) - ''; - }; - uploadsPath = mkOption { - type = types.str; - default = "${cfg.workDir}/uploads"; - defaultText = literalExpression "\"\${cfg.workDir}/uploads\""; - description = lib.mdDoc '' - Path under which uploaded files are saved. - ''; - }; - sessionName = mkOption { - type = types.str; - default = "connect.sid"; - description = lib.mdDoc '' - Specify the name of the session cookie. - ''; - }; - sessionSecret = mkOption { - type = types.nullOr types.str; - default = null; - description = lib.mdDoc '' - Specify the secret used to sign the session cookie. - If unset, one will be generated on startup. - ''; - }; - sessionLife = mkOption { - type = types.int; - default = 1209600000; - description = lib.mdDoc '' - Session life time in milliseconds. - ''; - }; - heartbeatInterval = mkOption { - type = types.int; - default = 5000; - description = lib.mdDoc '' - Specify the socket.io heartbeat interval. - ''; - }; - heartbeatTimeout = mkOption { - type = types.int; - default = 10000; - description = lib.mdDoc '' - Specify the socket.io heartbeat timeout. - ''; - }; - documentMaxLength = mkOption { - type = types.int; - default = 100000; - description = lib.mdDoc '' - Specify the maximum document length. - ''; - }; - email = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to enable email sign-in. - ''; - }; - allowEmailRegister = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to enable email registration. - ''; - }; - allowGravatar = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to use gravatar as profile picture source. - ''; - }; - imageUploadType = mkOption { - type = types.enum [ "imgur" "s3" "minio" "filesystem" ]; - default = "filesystem"; - description = lib.mdDoc '' - Specify where to upload images. - ''; - }; - minio = mkOption { - type = types.nullOr (types.submodule { - options = { - accessKey = mkOption { - type = types.str; - description = lib.mdDoc '' - Minio access key. - ''; - }; - secretKey = mkOption { - type = types.str; - description = lib.mdDoc '' - Minio secret key. - ''; - }; - endPoint = mkOption { - type = types.str; - description = lib.mdDoc '' - Minio endpoint. - ''; - }; - port = mkOption { - type = types.port; - default = 9000; - description = lib.mdDoc '' - Minio listen port. - ''; - }; - secure = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to use HTTPS for Minio. - ''; - }; + This is useful if you are trying to run hedgedoc behind + a reverse proxy. + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the minio third-party integration."; - }; - s3 = mkOption { - type = types.nullOr (types.submodule { - options = { - accessKeyId = mkOption { - type = types.str; - description = lib.mdDoc '' - AWS access key id. - ''; - }; - secretAccessKey = mkOption { - type = types.str; - description = lib.mdDoc '' - AWS access key. - ''; - }; - region = mkOption { - type = types.str; - description = lib.mdDoc '' - AWS S3 region. - ''; - }; - }; - }); - default = null; - description = lib.mdDoc "Configure the s3 third-party integration."; - }; - s3bucket = mkOption { - type = types.nullOr types.str; - default = null; - description = lib.mdDoc '' - Specify the bucket name for upload types `s3` and `minio`. - ''; - }; - allowPDFExport = mkOption { - type = types.bool; - default = true; - description = lib.mdDoc '' - Whether to enable PDF exports. - ''; - }; - imgur.clientId = mkOption { - type = types.nullOr types.str; - default = null; - description = lib.mdDoc '' - Imgur API client ID. - ''; - }; - azure = mkOption { - type = types.nullOr (types.submodule { - options = { - connectionString = mkOption { - type = types.str; - description = lib.mdDoc '' - Azure Blob Storage connection string. - ''; - }; - container = mkOption { - type = types.str; - description = lib.mdDoc '' - Azure Blob Storage container name. - It will be created if non-existent. - ''; - }; - }; - }); - default = null; - description = lib.mdDoc "Configure the azure third-party integration."; - }; - oauth2 = mkOption { - type = types.nullOr (types.submodule { - options = { - authorizationURL = mkOption { - type = types.str; - description = lib.mdDoc '' - Specify the OAuth authorization URL. - ''; - }; - tokenURL = mkOption { - type = types.str; - description = lib.mdDoc '' - Specify the OAuth token URL. - ''; - }; - baseURL = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the OAuth base URL. - ''; - }; - userProfileURL = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the OAuth userprofile URL. - ''; - }; - userProfileUsernameAttr = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the name of the attribute for the username from the claim. - ''; - }; - userProfileDisplayNameAttr = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the name of the attribute for the display name from the claim. - ''; - }; - userProfileEmailAttr = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the name of the attribute for the email from the claim. - ''; - }; - scope = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the OAuth scope. - ''; - }; - providerName = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the name to be displayed for this strategy. - ''; - }; - rolesClaim = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the role claim name. - ''; - }; - accessRole = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify role which should be included in the ID token roles claim to grant access - ''; - }; - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - Specify the OAuth client ID. - ''; - }; - clientSecret = mkOption { - type = with types; nullOr str; - default = null; - description = lib.mdDoc '' - Specify the OAuth client secret. - ''; - }; + urlPath = mkOption { + type = with types; nullOr str; + default = null; + example = "hedgedoc"; + description = mdDoc '' + URL path for the website. + + This is useful if you are hosting hedgedoc on a path like + `www.example.com/hedgedoc` + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the OAuth integration."; - }; - facebook = mkOption { - type = types.nullOr (types.submodule { - options = { - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - Facebook API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Facebook API client secret. - ''; - }; + host = mkOption { + type = with types; nullOr str; + default = "localhost"; + description = mdDoc '' + Address to listen on. + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the facebook third-party integration"; - }; - twitter = mkOption { - type = types.nullOr (types.submodule { - options = { - consumerKey = mkOption { - type = types.str; - description = lib.mdDoc '' - Twitter API consumer key. - ''; - }; - consumerSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Twitter API consumer secret. - ''; - }; + port = mkOption { + type = types.port; + default = 3000; + example = 80; + description = mdDoc '' + Port to listen on. + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the Twitter third-party integration."; - }; - github = mkOption { - type = types.nullOr (types.submodule { - options = { - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - GitHub API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Github API client secret. - ''; - }; + path = mkOption { + type = with types; nullOr path; + default = null; + example = "/run/hedgedoc/hedgedoc.sock"; + description = mdDoc '' + Path to UNIX domain socket to listen on + + ::: {.note} + If specified, {option}`host` and {option}`port` will be ignored. + ::: + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the GitHub third-party integration."; - }; - gitlab = mkOption { - type = types.nullOr (types.submodule { - options = { - baseURL = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - GitLab API authentication endpoint. - Only needed for other endpoints than gitlab.com. - ''; - }; - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - GitLab API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - GitLab API client secret. - ''; - }; - scope = mkOption { - type = types.enum [ "api" "read_user" ]; - default = "api"; - description = lib.mdDoc '' - GitLab API requested scope. - GitLab snippet import/export requires api scope. - ''; - }; + protocolUseSSL = mkOption { + type = types.bool; + default = false; + example = true; + description = mdDoc '' + Use `https://` for all links. + + This is useful if you are trying to run hedgedoc behind + a reverse proxy. + + ::: {.note} + Only applied if {option}`domain` is set. + ::: + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the GitLab third-party integration."; - }; - mattermost = mkOption { - type = types.nullOr (types.submodule { - options = { - baseURL = mkOption { - type = types.str; - description = lib.mdDoc '' - Mattermost authentication endpoint. - ''; - }; - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - Mattermost API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Mattermost API client secret. - ''; - }; + allowOrigin = mkOption { + type = with types; listOf str; + default = with cfg.settings; [ host ] ++ lib.optionals (domain != null) [ domain ]; + defaultText = literalExpression '' + with config.services.hedgedoc.settings; [ host ] ++ lib.optionals (domain != null) [ domain ] + ''; + example = [ "localhost" "hedgedoc.org" ]; + description = mdDoc '' + List of domains to whitelist. + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the Mattermost third-party integration."; - }; - dropbox = mkOption { - type = types.nullOr (types.submodule { - options = { - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - Dropbox API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Dropbox API client secret. - ''; - }; - appKey = mkOption { - type = types.str; - description = lib.mdDoc '' - Dropbox app key. - ''; - }; + db = mkOption { + type = types.attrs; + default = { + dialect = "sqlite"; + storage = "/var/lib/${name}/db.sqlite"; + }; + defaultText = literalExpression '' + { + dialect = "sqlite"; + storage = "/var/lib/hedgedoc/db.sqlite"; + } + ''; + example = literalExpression '' + db = { + username = "hedgedoc"; + database = "hedgedoc"; + host = "localhost:5432"; + # or via socket + # host = "/run/postgresql"; + dialect = "postgresql"; + }; + ''; + description = mdDoc '' + Specify the configuration for sequelize. + HedgeDoc supports `mysql`, `postgres`, `sqlite` and `mssql`. + See <https://sequelize.readthedocs.io/en/v3/> + for more information. + + ::: {.note} + The relevant parts will be overriden if you set {option}`dbURL`. + ::: + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the Dropbox third-party integration."; - }; - google = mkOption { - type = types.nullOr (types.submodule { - options = { - clientID = mkOption { - type = types.str; - description = lib.mdDoc '' - Google API client ID. - ''; - }; - clientSecret = mkOption { - type = types.str; - description = lib.mdDoc '' - Google API client secret. - ''; - }; + useSSL = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable to use SSL server. + + ::: {.note} + This will also enable {option}`protocolUseSSL`. + + It will also require you to set the following: + + - {option}`sslKeyPath` + - {option}`sslCertPath` + - {option}`sslCAPath` + - {option}`dhParamPath` + ::: + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the Google third-party integration."; - }; - ldap = mkOption { - type = types.nullOr (types.submodule { - options = { - providerName = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - Optional name to be displayed at login form, indicating the LDAP provider. - ''; - }; - url = mkOption { - type = types.str; - example = "ldap://localhost"; - description = lib.mdDoc '' - URL of LDAP server. - ''; - }; - bindDn = mkOption { - type = types.str; - description = lib.mdDoc '' - Bind DN for LDAP access. - ''; - }; - bindCredentials = mkOption { - type = types.str; - description = lib.mdDoc '' - Bind credentials for LDAP access. - ''; - }; - searchBase = mkOption { - type = types.str; - example = "o=users,dc=example,dc=com"; - description = lib.mdDoc '' - LDAP directory to begin search from. - ''; - }; - searchFilter = mkOption { - type = types.str; - example = "(uid={{username}})"; - description = lib.mdDoc '' - LDAP filter to search with. - ''; - }; - searchAttributes = mkOption { - type = types.nullOr (types.listOf types.str); - default = null; - example = [ "displayName" "mail" ]; - description = lib.mdDoc '' - LDAP attributes to search with. - ''; - }; - userNameField = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - LDAP field which is used as the username on HedgeDoc. - By default {option}`useridField` is used. - ''; - }; - useridField = mkOption { - type = types.str; - example = "uid"; - description = lib.mdDoc '' - LDAP field which is a unique identifier for users on HedgeDoc. - ''; - }; - tlsca = mkOption { - type = types.str; - default = "/etc/ssl/certs/ca-certificates.crt"; - example = "server-cert.pem,root.pem"; - description = lib.mdDoc '' - Root CA for LDAP TLS in PEM format. - ''; - }; + uploadsPath = mkOption { + type = types.path; + default = "/var/lib/${name}/uploads"; + defaultText = "/var/lib/hedgedoc/uploads"; + description = mdDoc '' + Directory for storing uploaded images. + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the LDAP integration."; - }; - saml = mkOption { - type = types.nullOr (types.submodule { - options = { - idpSsoUrl = mkOption { - type = types.str; - example = "https://idp.example.com/sso"; - description = lib.mdDoc '' - IdP authentication endpoint. - ''; - }; - idpCert = mkOption { - type = types.path; - example = "/path/to/cert.pem"; - description = lib.mdDoc '' - Path to IdP certificate file in PEM format. - ''; - }; - issuer = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - Optional identity of the service provider. - This defaults to the server URL. - ''; - }; - identifierFormat = mkOption { - type = types.str; - default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"; - description = lib.mdDoc '' - Optional name identifier format. - ''; - }; - groupAttribute = mkOption { - type = types.str; - default = ""; - example = "memberOf"; - description = lib.mdDoc '' - Optional attribute name for group list. - ''; - }; - externalGroups = mkOption { - type = types.listOf types.str; - default = []; - example = [ "Temporary-staff" "External-users" ]; - description = lib.mdDoc '' - Excluded group names. - ''; - }; - requiredGroups = mkOption { - type = types.listOf types.str; - default = []; - example = [ "Hedgedoc-Users" ]; - description = lib.mdDoc '' - Required group names. - ''; - }; - providerName = mkOption { - type = types.str; - default = ""; - example = "My institution"; - description = lib.mdDoc '' - Optional name to be displayed at login form indicating the SAML provider. - ''; - }; - attribute = { - id = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - Attribute map for `id`. - Defaults to `NameID` of SAML response. - ''; - }; - username = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - Attribute map for `username`. - Defaults to `NameID` of SAML response. - ''; - }; - email = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc '' - Attribute map for `email`. - Defaults to `NameID` of SAML response if - {option}`identifierFormat` has - the default value. - ''; - }; - }; + + # Declared because we change the default to false. + allowGravatar = mkOption { + type = types.bool; + default = false; + example = true; + description = mdDoc '' + Whether to enable [Libravatar](https://wiki.libravatar.org/) as + profile picture source on your instance. + + Despite the naming of the setting, Hedgedoc replaced Gravatar + with Libravatar in [CodiMD 1.4.0](https://hedgedoc.org/releases/1.4.0/) + ''; }; - }); - default = null; - description = lib.mdDoc "Configure the SAML integration."; - }; - }; in lib.mkOption { - type = lib.types.submodule { - freeformType = settingsFormat.type; - inherit options; + }; }; - description = lib.mdDoc '' + + description = mdDoc '' HedgeDoc configuration, see <https://docs.hedgedoc.org/configuration/> for documentation. @@ -1003,7 +202,7 @@ in type = with types; nullOr path; default = null; example = "/var/lib/hedgedoc/hedgedoc.env"; - description = lib.mdDoc '' + description = mdDoc '' Environment file as defined in {manpage}`systemd.exec(5)`. Secrets may be passed to the service without adding them to the world-readable @@ -1028,45 +227,94 @@ in }; }; - config = mkIf cfg.enable { - assertions = [ - { assertion = cfg.settings.db == {} -> ( - cfg.settings.dbURL != "" && cfg.settings.dbURL != null - ); - message = "Database configuration for HedgeDoc missing."; } - ]; - users.groups.${name} = {}; + config = lib.mkIf cfg.enable { + users.groups.${name} = { }; users.users.${name} = { description = "HedgeDoc service user"; group = name; - extraGroups = cfg.groups; - home = cfg.workDir; - createHome = true; isSystemUser = true; }; + services.hedgedoc.settings = { + defaultNotePath = lib.mkDefault "${cfg.package}/public/default.md"; + docsPath = lib.mkDefault "${cfg.package}/public/docs"; + viewPath = lib.mkDefault "${cfg.package}/public/views"; + }; + systemd.services.hedgedoc = { description = "HedgeDoc Service"; + documentation = [ "https://docs.hedgedoc.org/" ]; wantedBy = [ "multi-user.target" ]; after = [ "networking.target" ]; - preStart = '' - ${pkgs.envsubst}/bin/envsubst \ - -o ${cfg.workDir}/config.json \ - -i ${prettyJSON cfg.settings} - mkdir -p ${cfg.settings.uploadsPath} - ''; + preStart = + let + configFile = settingsFormat.generate "hedgedoc-config.json" { + production = cfg.settings; + }; + in + '' + ${pkgs.envsubst}/bin/envsubst \ + -o /run/${name}/config.json \ + -i ${configFile} + ${pkgs.coreutils}/bin/mkdir -p ${cfg.settings.uploadsPath} + ''; serviceConfig = { - WorkingDirectory = cfg.workDir; - StateDirectory = [ cfg.workDir cfg.settings.uploadsPath ]; - ExecStart = "${lib.getExe cfg.package}"; - EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + User = name; + Group = name; + + Restart = "always"; + ExecStart = "${cfg.package}/bin/hedgedoc"; + RuntimeDirectory = [ name ]; + StateDirectory = [ name ]; + WorkingDirectory = "/run/${name}"; + ReadWritePaths = [ + "-${cfg.settings.uploadsPath}" + ] ++ lib.optionals (cfg.settings.db ? "storage") [ "-${cfg.settings.db.storage}" ]; + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; Environment = [ - "CMD_CONFIG_FILE=${cfg.workDir}/config.json" + "CMD_CONFIG_FILE=/run/${name}/config.json" "NODE_ENV=production" ]; - Restart = "always"; - User = name; + + # Hardening + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + # Required for connecting to database sockets, + # and listening to unix socket at `cfg.settings.path` + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SocketBindAllow = lib.mkIf (cfg.settings.path == null) cfg.settings.port; + SocketBindDeny = "any"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged @obsolete" + "@pkey" + ]; + UMask = "0007"; }; }; }; diff --git a/nixos/modules/services/web-apps/hledger-web.nix b/nixos/modules/services/web-apps/hledger-web.nix index 0fc283ff5219..be8ecc645e59 100644 --- a/nixos/modules/services/web-apps/hledger-web.nix +++ b/nixos/modules/services/web-apps/hledger-web.nix @@ -7,7 +7,7 @@ in { enable = mkEnableOption (lib.mdDoc "hledger-web service"); - serveApi = mkEnableOption (lib.mdDoc "Serve only the JSON web API, without the web UI"); + serveApi = mkEnableOption (lib.mdDoc "serving only the JSON web API, without the web UI"); host = mkOption { type = types.str; diff --git a/nixos/modules/services/web-apps/isso.nix b/nixos/modules/services/web-apps/isso.nix index 1a852ec352f2..6cb2d9ec785e 100644 --- a/nixos/modules/services/web-apps/isso.nix +++ b/nixos/modules/services/web-apps/isso.nix @@ -12,11 +12,11 @@ in { options = { services.isso = { enable = mkEnableOption (lib.mdDoc '' - A commenting server similar to Disqus. + isso, a commenting server similar to Disqus. Note: The application's author suppose to run isso behind a reverse proxy. The embedded solution offered by NixOS is also only suitable for small installations - below 20 requests per second. + below 20 requests per second ''); settings = mkOption { diff --git a/nixos/modules/services/web-apps/jitsi-meet.nix b/nixos/modules/services/web-apps/jitsi-meet.nix index 3825b03c2449..21416be35877 100644 --- a/nixos/modules/services/web-apps/jitsi-meet.nix +++ b/nixos/modules/services/web-apps/jitsi-meet.nix @@ -105,9 +105,9 @@ in type = bool; default = true; description = lib.mdDoc '' - Whether to enable Jitsi Videobridge instance and configure it to connect to Prosody. + Jitsi Videobridge instance and configure it to connect to Prosody. - Additional configuration is possible with {option}`services.jitsi-videobridge`. + Additional configuration is possible with {option}`services.jitsi-videobridge` ''; }; diff --git a/nixos/modules/services/web-apps/lanraragi.nix b/nixos/modules/services/web-apps/lanraragi.nix new file mode 100644 index 000000000000..f1ab8b8b4eb4 --- /dev/null +++ b/nixos/modules/services/web-apps/lanraragi.nix @@ -0,0 +1,100 @@ +{ pkgs, lib, config, ... }: + +let + cfg = config.services.lanraragi; +in +{ + meta.maintainers = with lib.maintainers; [ tomasajt ]; + + options.services = { + lanraragi = { + enable = lib.mkEnableOption (lib.mdDoc "LANraragi"); + package = lib.mkPackageOptionMD pkgs "lanraragi" { }; + + port = lib.mkOption { + type = lib.types.port; + default = 3000; + description = lib.mdDoc "Port for LANraragi's web interface."; + }; + + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/lanraragi-password"; + description = lib.mdDoc '' + A file containing the password for LANraragi's admin interface. + ''; + }; + + redis = { + port = lib.mkOption { + type = lib.types.port; + default = 6379; + description = lib.mdDoc "Port for LANraragi's Redis server."; + }; + passwordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/redis-lanraragi-password"; + description = lib.mdDoc '' + A file containing the password for LANraragi's Redis server. + ''; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + services.redis.servers.lanraragi = { + enable = true; + port = cfg.redis.port; + requirePassFile = cfg.redis.passwordFile; + }; + + systemd.services.lanraragi = { + description = "LANraragi main service"; + after = [ "network.target" "redis-lanraragi.service" ]; + requires = [ "redis-lanraragi.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = lib.getExe cfg.package; + DynamicUser = true; + StateDirectory = "lanraragi"; + RuntimeDirectory = "lanraragi"; + LogsDirectory = "lanraragi"; + Restart = "on-failure"; + WorkingDirectory = "/var/lib/lanraragi"; + }; + environment = { + "LRR_TEMP_DIRECTORY" = "/run/lanraragi"; + "LRR_LOG_DIRECTORY" = "/var/log/lanraragi"; + "LRR_NETWORK" = "http://*:${toString cfg.port}"; + "HOME" = "/var/lib/lanraragi"; + }; + preStart = '' + REDIS_PASS=${lib.optionalString (cfg.redis.passwordFile != null) "$(head -n1 ${cfg.redis.passwordFile})"} + cat > lrr.conf <<EOF + { + redis_address => "127.0.0.1:${toString cfg.redis.port}", + redis_password => "$REDIS_PASS", + redis_database => "0", + redis_database_minion => "1", + redis_database_config => "2", + redis_database_search => "3", + } + EOF + '' + lib.optionalString (cfg.passwordFile != null) '' + PASS_HASH=$( + PASS=$(head -n1 ${cfg.passwordFile}) ${cfg.package.perlEnv}/bin/perl -I${cfg.package}/share/lanraragi/lib -e \ + 'use LANraragi::Controller::Config; print LANraragi::Controller::Config::make_password_hash($ENV{PASS})' \ + 2>/dev/null + ) + + ${lib.getExe pkgs.redis} -h 127.0.0.1 -p ${toString cfg.redis.port} -a "$REDIS_PASS" <<EOF + SELECT 2 + HSET LRR_CONFIG password $PASS_HASH + EOF + ''; + }; + }; +} diff --git a/nixos/modules/services/web-apps/meme-bingo-web.nix b/nixos/modules/services/web-apps/meme-bingo-web.nix index cb864321ef27..652dc8840252 100644 --- a/nixos/modules/services/web-apps/meme-bingo-web.nix +++ b/nixos/modules/services/web-apps/meme-bingo-web.nix @@ -8,9 +8,9 @@ in { options = { services.meme-bingo-web = { enable = mkEnableOption (mdDoc '' - A web app for the meme bingo, rendered entirely on the web server and made interactive with forms. + a web app for the meme bingo, rendered entirely on the web server and made interactive with forms. - Note: The application's author suppose to run meme-bingo-web behind a reverse proxy for SSL and HTTP/3. + Note: The application's author suppose to run meme-bingo-web behind a reverse proxy for SSL and HTTP/3 ''); package = mkOption { diff --git a/nixos/modules/services/web-apps/phylactery.nix b/nixos/modules/services/web-apps/phylactery.nix index 4801bd203b48..723b38ee75d9 100644 --- a/nixos/modules/services/web-apps/phylactery.nix +++ b/nixos/modules/services/web-apps/phylactery.nix @@ -4,7 +4,7 @@ with lib; let cfg = config.services.phylactery; in { options.services.phylactery = { - enable = mkEnableOption (lib.mdDoc "Whether to enable Phylactery server"); + enable = mkEnableOption (lib.mdDoc "Phylactery server"); host = mkOption { type = types.str; diff --git a/nixos/modules/services/web-apps/plausible.nix b/nixos/modules/services/web-apps/plausible.nix index e5deb6cf511f..576b54a7edf2 100644 --- a/nixos/modules/services/web-apps/plausible.nix +++ b/nixos/modules/services/web-apps/plausible.nix @@ -78,9 +78,9 @@ in { server = { disableRegistration = mkOption { default = true; - type = types.bool; + type = types.enum [true false "invite_only"]; description = lib.mdDoc '' - Whether to prohibit creating an account in plausible's UI. + Whether to prohibit creating an account in plausible's UI or allow on `invite_only`. ''; }; secretKeybaseFile = mkOption { @@ -209,7 +209,7 @@ in { # Configuration options from # https://plausible.io/docs/self-hosting-configuration PORT = toString cfg.server.port; - DISABLE_REGISTRATION = boolToString cfg.server.disableRegistration; + DISABLE_REGISTRATION = if isBool cfg.server.disableRegistration then boolToString cfg.server.disableRegistration else cfg.server.disableRegistration; RELEASE_TMP = "/var/lib/plausible/tmp"; # Home is needed to connect to the node with iex diff --git a/nixos/modules/services/web-apps/shiori.nix b/nixos/modules/services/web-apps/shiori.nix index f0505e052e1c..71b5ad4d4c06 100644 --- a/nixos/modules/services/web-apps/shiori.nix +++ b/nixos/modules/services/web-apps/shiori.nix @@ -29,6 +29,13 @@ in { default = 8080; description = lib.mdDoc "The port of the Shiori web application"; }; + + webRoot = mkOption { + type = types.str; + default = "/"; + example = "/shiori"; + description = lib.mdDoc "The root of the Shiori web application"; + }; }; }; @@ -40,7 +47,7 @@ in { environment.SHIORI_DIR = "/var/lib/shiori"; serviceConfig = { - ExecStart = "${package}/bin/shiori serve --address '${address}' --port '${toString port}'"; + ExecStart = "${package}/bin/shiori serve --address '${address}' --port '${toString port}' --webroot '${webRoot}'"; DynamicUser = true; StateDirectory = "shiori"; diff --git a/nixos/modules/services/web-apps/snipe-it.nix b/nixos/modules/services/web-apps/snipe-it.nix index e861a4185194..4fbf2bad750b 100644 --- a/nixos/modules/services/web-apps/snipe-it.nix +++ b/nixos/modules/services/web-apps/snipe-it.nix @@ -18,19 +18,23 @@ let inherit (snipe-it.passthru) phpPackage; # shell script for local administration - artisan = pkgs.writeScriptBin "snipe-it" '' + artisan = (pkgs.writeScriptBin "snipe-it" '' #! ${pkgs.runtimeShell} - cd ${snipe-it} + cd "${snipe-it}/share/php/snipe-it" sudo=exec if [[ "$USER" != ${user} ]]; then sudo='exec /run/wrappers/bin/sudo -u ${user}' fi $sudo ${phpPackage}/bin/php artisan $* - ''; + '').overrideAttrs (old: { + meta = old.meta // { + mainProgram = "snipe-it"; + }; + }); in { options.services.snipe-it = { - enable = mkEnableOption (lib.mdDoc "A free open source IT asset/license management system"); + enable = mkEnableOption (lib.mdDoc "snipe-it, a free open source IT asset/license management system"); user = mkOption { default = "snipeit"; @@ -357,7 +361,7 @@ in { services.nginx = { enable = mkDefault true; virtualHosts."${cfg.hostName}" = mkMerge [ cfg.nginx { - root = mkForce "${snipe-it}/public"; + root = mkForce "${snipe-it}/share/php/snipe-it/public"; extraConfig = optionalString (cfg.nginx.addSSL || cfg.nginx.forceSSL || cfg.nginx.onlySSL || cfg.nginx.enableACME) "fastcgi_param HTTPS on;"; locations = { "/" = { @@ -394,7 +398,7 @@ in { RuntimeDirectory = "snipe-it/cache"; RuntimeDirectoryMode = "0700"; }; - path = [ pkgs.replace-secret ]; + path = [ pkgs.replace-secret artisan ]; script = let isSecret = v: isAttrs v && v ? _secret && (isString v._secret || builtins.isPath v._secret); @@ -451,7 +455,7 @@ in { rm "${cfg.dataDir}"/bootstrap/cache/*.php || true # migrate db - ${phpPackage}/bin/php artisan migrate --force + ${lib.getExe artisan} migrate --force # A placeholder file for invalid barcodes invalid_barcode_location="${cfg.dataDir}/public/uploads/barcodes/invalid_barcode.gif" diff --git a/nixos/modules/services/web-apps/zitadel.nix b/nixos/modules/services/web-apps/zitadel.nix index f225d138cc43..99b0a0bc56f6 100644 --- a/nixos/modules/services/web-apps/zitadel.nix +++ b/nixos/modules/services/web-apps/zitadel.nix @@ -9,7 +9,7 @@ in options.services.zitadel = let inherit (lib) mkEnableOption mkOption mkPackageOption types; in { - enable = mkEnableOption "ZITADEL, a user and identity access management platform."; + enable = mkEnableOption "ZITADEL, a user and identity access management platform"; package = mkPackageOption pkgs "ZITADEL" { default = [ "zitadel" ]; }; |