at 24.11-pre 7.2 kB view raw
1{ config, pkgs, lib, ... }: 2 3let 4 cfg = config.services.suwayomi-server; 5 inherit (lib) mkOption mkEnableOption mkIf types; 6 7 format = pkgs.formats.hocon { }; 8in 9{ 10 options = { 11 services.suwayomi-server = { 12 enable = mkEnableOption "Suwayomi, a free and open source manga reader server that runs extensions built for Tachiyomi."; 13 14 package = lib.mkPackageOptionMD pkgs "suwayomi-server" { }; 15 16 dataDir = mkOption { 17 type = types.path; 18 default = "/var/lib/suwayomi-server"; 19 example = "/var/data/mangas"; 20 description = '' 21 The path to the data directory in which Suwayomi-Server will download scans. 22 ''; 23 }; 24 25 user = mkOption { 26 type = types.str; 27 default = "suwayomi"; 28 example = "root"; 29 description = '' 30 User account under which Suwayomi-Server runs. 31 ''; 32 }; 33 34 group = mkOption { 35 type = types.str; 36 default = "suwayomi"; 37 example = "medias"; 38 description = '' 39 Group under which Suwayomi-Server runs. 40 ''; 41 }; 42 43 openFirewall = mkOption { 44 type = types.bool; 45 default = false; 46 description = '' 47 Whether to open the firewall for the port in {option}`services.suwayomi-server.settings.server.port`. 48 ''; 49 }; 50 51 settings = mkOption { 52 type = types.submodule { 53 freeformType = format.type; 54 options = { 55 server = { 56 ip = mkOption { 57 type = types.str; 58 default = "0.0.0.0"; 59 example = "127.0.0.1"; 60 description = '' 61 The ip that Suwayomi will bind to. 62 ''; 63 }; 64 65 port = mkOption { 66 type = types.port; 67 default = 8080; 68 example = 4567; 69 description = '' 70 The port that Suwayomi will listen to. 71 ''; 72 }; 73 74 basicAuthEnabled = mkEnableOption '' 75 Add basic access authentication to Suwayomi-Server. 76 Enabling this option is useful when hosting on a public network/the Internet 77 ''; 78 79 basicAuthUsername = mkOption { 80 type = types.nullOr types.str; 81 default = null; 82 description = '' 83 The username value that you have to provide when authenticating. 84 ''; 85 }; 86 87 # NOTE: this is not a real upstream option 88 basicAuthPasswordFile = mkOption { 89 type = types.nullOr types.path; 90 default = null; 91 example = "/var/secrets/suwayomi-server-password"; 92 description = '' 93 The password file containing the value that you have to provide when authenticating. 94 ''; 95 }; 96 97 downloadAsCbz = mkOption { 98 type = types.bool; 99 default = false; 100 description = '' 101 Download chapters as `.cbz` files. 102 ''; 103 }; 104 105 extensionRepos = mkOption { 106 type = types.listOf types.str; 107 default = []; 108 example = [ 109 "https://raw.githubusercontent.com/MY_ACCOUNT/MY_REPO/repo/index.min.json" 110 ]; 111 description = '' 112 URL of repositories from which the extensions can be installed. 113 ''; 114 }; 115 116 localSourcePath = mkOption { 117 type = types.path; 118 default = cfg.dataDir; 119 defaultText = lib.literalExpression "suwayomi-server.dataDir"; 120 example = "/var/data/local_mangas"; 121 description = '' 122 Path to the local source folder. 123 ''; 124 }; 125 126 systemTrayEnabled = mkOption { 127 type = types.bool; 128 default = false; 129 description = '' 130 Whether to enable a system tray icon, if possible. 131 ''; 132 }; 133 }; 134 }; 135 }; 136 description = '' 137 Configuration to write to {file}`server.conf`. 138 See <https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Suwayomi-Server> for more information. 139 ''; 140 default = { }; 141 example = { 142 server.socksProxyEnabled = true; 143 server.socksProxyHost = "yourproxyhost.com"; 144 server.socksProxyPort = "8080"; 145 }; 146 }; 147 }; 148 }; 149 150 config = mkIf cfg.enable { 151 152 assertions = [{ 153 assertion = with cfg.settings.server; basicAuthEnabled -> (basicAuthUsername != null && basicAuthPasswordFile != null); 154 message = '' 155 [suwayomi-server]: the username and the password file cannot be null when the basic auth is enabled 156 ''; 157 }]; 158 159 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.server.port ]; 160 161 users.groups = mkIf (cfg.group == "suwayomi") { 162 suwayomi = { }; 163 }; 164 165 users.users = mkIf (cfg.user == "suwayomi") { 166 suwayomi = { 167 group = cfg.group; 168 # Need to set the user home because the package writes to ~/.local/Tachidesk 169 home = cfg.dataDir; 170 description = "Suwayomi Daemon user"; 171 isSystemUser = true; 172 }; 173 }; 174 175 systemd.tmpfiles.settings."10-suwayomi-server" = { 176 "${cfg.dataDir}/.local/share/Tachidesk".d = { 177 mode = "0700"; 178 inherit (cfg) user group; 179 }; 180 }; 181 182 systemd.services.suwayomi-server = 183 let 184 configFile = format.generate "server.conf" (lib.pipe cfg.settings [ 185 (settings: lib.recursiveUpdate settings { 186 server.basicAuthPasswordFile = null; 187 server.basicAuthPassword = 188 if settings.server.basicAuthEnabled 189 then "$TACHIDESK_SERVER_BASIC_AUTH_PASSWORD" 190 else null; 191 }) 192 (lib.filterAttrsRecursive (_: x: x != null)) 193 ]); 194 in 195 { 196 description = "A free and open source manga reader server that runs extensions built for Tachiyomi."; 197 198 wantedBy = [ "multi-user.target" ]; 199 wants = [ "network-online.target" ]; 200 after = [ "network-online.target" ]; 201 202 script = '' 203 ${lib.optionalString cfg.settings.server.basicAuthEnabled '' 204 export TACHIDESK_SERVER_BASIC_AUTH_PASSWORD="$(<${cfg.settings.server.basicAuthPasswordFile})" 205 ''} 206 ${lib.getExe pkgs.envsubst} -i ${configFile} -o ${cfg.dataDir}/.local/share/Tachidesk/server.conf 207 ${lib.getExe cfg.package} -Dsuwayomi.tachidesk.config.server.rootDir=${cfg.dataDir} 208 ''; 209 210 serviceConfig = { 211 User = cfg.user; 212 Group = cfg.group; 213 214 Type = "simple"; 215 Restart = "on-failure"; 216 217 StateDirectory = mkIf (cfg.dataDir == "/var/lib/suwayomi-server") "suwayomi-server"; 218 }; 219 }; 220 }; 221 222 meta = { 223 maintainers = with lib.maintainers; [ ratcornu ]; 224 doc = ./suwayomi-server.md; 225 }; 226}