diff options
author | h7x4 <h7x4@nani.wtf> | 2024-01-19 20:19:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-19 20:19:06 +0100 |
commit | 99e3c0032aa0830beb647cab35b977b0ebf320b3 (patch) | |
tree | 6c91bba616b3e8760153d43a77e345179e37824e /nixos | |
parent | 2489c434f94aa09a6ff24c1db7082e5b7907562e (diff) | |
parent | d32bb1112910e08ed4f0b56550ba16fc3208f8f5 (diff) |
Merge pull request #281871 from RatCornu/tachidesk-server
nixos/suwayomi-server: init at 0.7.0
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2405.section.md | 2 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/suwayomi-server.md | 108 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/suwayomi-server.nix | 260 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/suwayomi-server.nix | 46 |
6 files changed, 418 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index c53a1dcce3201..bae98714077b9 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -37,6 +37,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable). The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server softwares. +- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable). + - [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable). - [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index e6fffd4716de9..ea3fcea48b834 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1339,6 +1339,7 @@ ./services/web-apps/restya-board.nix ./services/web-apps/rimgo.nix ./services/web-apps/sftpgo.nix + ./services/web-apps/suwayomi-server.nix ./services/web-apps/rss-bridge.nix ./services/web-apps/selfoss.nix ./services/web-apps/shiori.nix diff --git a/nixos/modules/services/web-apps/suwayomi-server.md b/nixos/modules/services/web-apps/suwayomi-server.md new file mode 100644 index 0000000000000..ff1e06c8a53ae --- /dev/null +++ b/nixos/modules/services/web-apps/suwayomi-server.md @@ -0,0 +1,108 @@ +# Suwayomi-Server {#module-services-suwayomi-server} + +A free and open source manga reader server that runs extensions built for Tachiyomi. + +## Basic usage {#module-services-suwayomi-server-basic-usage} + +By default, the module will execute Suwayomi-Server backend and web UI: + +```nix +{ ... }: + +{ + services.suwayomi-server = { + enable = true; + }; +} +``` + +It runs in the systemd service named `suwayomi-server` in the data directory `/var/lib/suwayomi-server`. + +You can change the default parameters with some other parameters: +```nix +{ ... }: + +{ + services.suwayomi-server = { + enable = true; + + dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server" + openFirewall = true; + + settings = { + server.port = 4567; + }; + }; +} +``` + +If you want to create a desktop icon, you can activate the system tray option: + +```nix +{ ... }: + +{ + services.suwayomi-server = { + enable = true; + + dataDir = "/var/lib/suwayomi"; # Default is "/var/lib/suwayomi-server" + openFirewall = true; + + settings = { + server.port = 4567; + server.enableSystemTray = true; + }; + }; +} +``` + +## Basic authentication {#module-services-suwayomi-server-basic-auth} + +You can configure a basic authentication to the web interface with: + +```nix +{ ... }: + +{ + services.suwayomi-server = { + enable = true; + + openFirewall = true; + + settings = { + server.port = 4567; + server = { + basicAuthEnabled = true; + basicAuthUsername = "username"; + + # NOTE: this is not a real upstream option + basicAuthPasswordFile = ./path/to/the/password/file; + }; + }; + }; +} +``` + +## Extra configuration {#module-services-suwayomi-server-extra-config} + +Not all the configuration options are available directly in this module, but you can add the other options of suwayomi-server with: + +```nix +{ ... }: + +{ + services.suwayomi-server = { + enable = true; + + openFirewall = true; + + settings = { + server = { + port = 4567; + autoDownloadNewChapters = false; + maxSourcesInParallel" = 6; + }; + }; + }; +} +``` diff --git a/nixos/modules/services/web-apps/suwayomi-server.nix b/nixos/modules/services/web-apps/suwayomi-server.nix new file mode 100644 index 0000000000000..c4c1540edbee5 --- /dev/null +++ b/nixos/modules/services/web-apps/suwayomi-server.nix @@ -0,0 +1,260 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.suwayomi-server; + inherit (lib) mkOption mdDoc mkEnableOption mkIf types; +in +{ + options = { + services.suwayomi-server = { + enable = mkEnableOption (mdDoc "Suwayomi, a free and open source manga reader server that runs extensions built for Tachiyomi."); + + package = lib.mkPackageOptionMD pkgs "suwayomi-server" { }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/suwayomi-server"; + example = "/var/data/mangas"; + description = mdDoc '' + The path to the data directory in which Suwayomi-Server will download scans. + ''; + }; + + user = mkOption { + type = types.str; + default = "suwayomi"; + example = "root"; + description = mdDoc '' + User account under which Suwayomi-Server runs. + ''; + }; + + group = mkOption { + type = types.str; + default = "suwayomi"; + example = "medias"; + description = mdDoc '' + Group under which Suwayomi-Server runs. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to open the firewall for the port in {option}`services.suwayomi-server.settings.server.port`. + ''; + }; + + settings = mkOption { + type = types.submodule { + freeformType = + let + recursiveAttrsType = with types; attrsOf (nullOr (oneOf [ + str + path + int + float + bool + (listOf str) + (recursiveAttrsType // { description = "instances of this type recursively"; }) + ])); + in + recursiveAttrsType; + options = { + server = { + ip = mkOption { + type = types.str; + default = "0.0.0.0"; + example = "127.0.0.1"; + description = mdDoc '' + The ip that Suwayomi will bind to. + ''; + }; + + port = mkOption { + type = types.port; + default = 8080; + example = 4567; + description = mdDoc '' + The port that Suwayomi will listen to. + ''; + }; + + basicAuthEnabled = mkEnableOption (mdDoc '' + Add basic access authentication to Suwayomi-Server. + Enabling this option is useful when hosting on a public network/the Internet + ''); + + basicAuthUsername = mkOption { + type = types.nullOr types.str; + default = null; + description = mdDoc '' + The username value that you have to provide when authenticating. + ''; + }; + + # NOTE: this is not a real upstream option + basicAuthPasswordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/var/secrets/suwayomi-server-password"; + description = mdDoc '' + The password file containing the value that you have to provide when authenticating. + ''; + }; + + downloadAsCbz = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Download chapters as `.cbz` files. + ''; + }; + + localSourcePath = mkOption { + type = types.path; + default = cfg.dataDir; + defaultText = lib.literalExpression "suwayomi-server.dataDir"; + example = "/var/data/local_mangas"; + description = mdDoc '' + Path to the local source folder. + ''; + }; + + systemTrayEnabled = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Whether to enable a system tray icon, if possible. + ''; + }; + }; + }; + }; + description = mdDoc '' + Configuration to write to {file}`server.conf`. + See <https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Suwayomi-Server> for more information. + ''; + default = { }; + example = { + server.socksProxyEnabled = true; + server.socksProxyHost = "yourproxyhost.com"; + server.socksProxyPort = "8080"; + }; + }; + }; + }; + + config = mkIf cfg.enable { + + assertions = [{ + assertion = with cfg.settings.server; basicAuthEnabled -> (basicAuthUsername != null && basicAuthPasswordFile != null); + message = '' + [suwayomi-server]: the username and the password file cannot be null when the basic auth is enabled + ''; + }]; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ]; + + users.groups = mkIf (cfg.group == "suwayomi") { + suwayomi = { }; + }; + + users.users = mkIf (cfg.user == "suwayomi") { + suwayomi = { + group = cfg.group; + # Need to set the user home because the package writes to ~/.local/Tachidesk + home = cfg.dataDir; + description = "Suwayomi Daemon user"; + isSystemUser = true; + }; + }; + + systemd.tmpfiles.settings."10-suwayomi-server" = { + "${cfg.dataDir}/.local/share/Tachidesk".d = { + mode = "0700"; + inherit (cfg) user group; + }; + }; + + systemd.services.suwayomi-server = + let + flattenConfig = prefix: config: + lib.foldl' + lib.mergeAttrs + { } + (lib.attrValues + (lib.mapAttrs + (k: v: + if !(lib.isAttrs v) + then { "${prefix}${k}" = v; } + else flattenConfig "${prefix}${k}." v + ) + config + ) + ); + + # HOCON is a JSON superset that suwayomi-server use for configuration + toHOCON = attr: + let + attrType = builtins.typeOf attr; + in + if builtins.elem attrType [ "string" "path" "int" "float" ] + then ''"${toString attr}"'' + else if attrType == "bool" + then lib.boolToString attr + else if attrType == "list" + then "[\n${lib.concatMapStringsSep ",\n" toHOCON attr}\n]" + else # attrs, lambda, null + throw '' + [suwayomi-server]: invalid config value type '${attrType}'. + ''; + + configFile = pkgs.writeText "server.conf" (lib.pipe cfg.settings [ + (settings: lib.recursiveUpdate settings { + server.basicAuthPasswordFile = null; + server.basicAuthPassword = + if settings.server.basicAuthEnabled + then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD" + else null; + }) + (flattenConfig "") + (lib.filterAttrs (_: x: x != null)) + (lib.mapAttrsToList (name: value: ''${name} = ${toHOCON value}'')) + lib.concatLines + ]); + + in + { + description = "A free and open source manga reader server that runs extensions built for Tachiyomi."; + + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + script = '' + ${lib.optionalString cfg.settings.server.basicAuthEnabled '' + export TACHIDESK_SERVER_BASIC_AUTH_PASSWORD="$(<${cfg.settings.server.basicAuthPasswordFile})" + ''} + ${lib.getExe pkgs.envsubst} -i ${configFile} -o ${cfg.dataDir}/.local/share/Tachidesk/server.conf + ${lib.getExe cfg.package} -Dsuwayomi.tachidesk.config.server.rootDir=${cfg.dataDir} + ''; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + + Type = "simple"; + Restart = "on-failure"; + + StateDirectory = mkIf (cfg.dataDir == "/var/lib/suwayomi-server") "suwayomi-server"; + }; + }; + }; + + meta = { + maintainers = with lib.maintainers; [ ratcornu ]; + doc = ./suwayomi-server.md; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 8f452ac7c76ea..a6cfd22d541f2 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -809,6 +809,7 @@ in { stunnel = handleTest ./stunnel.nix {}; sudo = handleTest ./sudo.nix {}; sudo-rs = handleTest ./sudo-rs.nix {}; + suwayomi-server = handleTest ./suwayomi-server.nix {}; swap-file-btrfs = handleTest ./swap-file-btrfs.nix {}; swap-partition = handleTest ./swap-partition.nix {}; swap-random-encryption = handleTest ./swap-random-encryption.nix {}; diff --git a/nixos/tests/suwayomi-server.nix b/nixos/tests/suwayomi-server.nix new file mode 100644 index 0000000000000..36072028380b8 --- /dev/null +++ b/nixos/tests/suwayomi-server.nix @@ -0,0 +1,46 @@ +{ system ? builtins.currentSystem +, pkgs +, lib ? pkgs.lib +}: +let + inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; + inherit (lib) recursiveUpdate; + + baseTestConfig = { + meta.maintainers = with lib.maintainers; [ ratcornu ]; + nodes.machine = { pkgs, ... }: { + services.suwayomi-server = { + enable = true; + settings.server.port = 1234; + }; + }; + testScript = '' + machine.wait_for_unit("suwayomi-server.service") + machine.wait_for_open_port(1234) + machine.succeed("curl --fail http://localhost:1234/") + ''; + }; +in + +{ + without-auth = makeTest (recursiveUpdate baseTestConfig { + name = "suwayomi-server-without-auth"; + }); + + with-auth = makeTest (recursiveUpdate baseTestConfig { + name = "suwayomi-server-with-auth"; + + nodes.machine = { pkgs, ... }: { + services.suwayomi-server = { + enable = true; + + settings.server = { + port = 1234; + basicAuthEnabled = true; + basicAuthUsername = "alice"; + basicAuthPasswordFile = pkgs.writeText "snakeoil-pass.txt" "pass"; + }; + }; + }; + }); +} |