at master 10 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7 8let 9 cfg = config.services.szurubooru; 10 inherit (lib) 11 mkOption 12 mkEnableOption 13 mkIf 14 mkPackageOption 15 types 16 ; 17 format = pkgs.formats.yaml { }; 18 python = pkgs.python3; 19in 20 21{ 22 options = { 23 services.szurubooru = { 24 enable = mkEnableOption "Szurubooru, an image board engine dedicated for small and medium communities"; 25 26 user = mkOption { 27 type = types.str; 28 default = "szurubooru"; 29 description = '' 30 User account under which Szurubooru runs. 31 ''; 32 }; 33 34 group = mkOption { 35 type = types.str; 36 default = "szurubooru"; 37 description = '' 38 Group under which Szurubooru runs. 39 ''; 40 }; 41 42 dataDir = mkOption { 43 type = types.path; 44 default = "/var/lib/szurubooru"; 45 example = "/var/lib/szuru"; 46 description = '' 47 The path to the data directory in which Szurubooru will store its data. 48 ''; 49 }; 50 51 openFirewall = mkOption { 52 type = types.bool; 53 default = false; 54 example = true; 55 description = '' 56 Whether to open the firewall for the port in {option}`services.szurubooru.server.port`. 57 ''; 58 }; 59 60 server = { 61 package = mkPackageOption pkgs [ 62 "szurubooru" 63 "server" 64 ] { }; 65 66 port = mkOption { 67 type = types.port; 68 default = 8080; 69 example = 9000; 70 description = '' 71 Port to expose HTTP service. 72 ''; 73 }; 74 75 threads = mkOption { 76 type = types.int; 77 default = 4; 78 example = 6; 79 description = ''Number of waitress threads to start.''; 80 }; 81 82 settings = mkOption { 83 type = types.submodule { 84 freeformType = format.type; 85 options = { 86 name = mkOption { 87 type = types.str; 88 default = "szurubooru"; 89 example = "Szuru"; 90 description = ''Name shown in the website title and on the front page.''; 91 }; 92 93 domain = mkOption { 94 type = types.str; 95 example = "http://example.com"; 96 description = ''Full URL to the homepage of this szurubooru site (with no trailing slash).''; 97 }; 98 99 # NOTE: this is not a real upstream option 100 secretFile = mkOption { 101 type = types.path; 102 example = "/run/secrets/szurubooru-server-secret"; 103 description = '' 104 File containing a secret used to salt the users' password hashes and generate filenames for static content. 105 ''; 106 }; 107 108 delete_source_files = mkOption { 109 type = types.enum [ 110 "yes" 111 "no" 112 ]; 113 default = "no"; 114 example = "yes"; 115 description = ''Whether to delete thumbnails and source files on post delete.''; 116 }; 117 118 smtp = { 119 host = mkOption { 120 type = types.nullOr types.str; 121 default = null; 122 example = "localhost"; 123 description = ''Host of the SMTP server used to send reset password.''; 124 }; 125 126 port = mkOption { 127 type = types.nullOr types.port; 128 default = null; 129 example = 25; 130 description = ''Port of the SMTP server.''; 131 }; 132 133 user = mkOption { 134 type = types.nullOr types.str; 135 default = null; 136 example = "bot"; 137 description = ''User to connect to the SMTP server.''; 138 }; 139 140 # NOTE: this is not a real upstream option 141 passFile = mkOption { 142 type = types.nullOr types.path; 143 default = null; 144 example = "/run/secrets/szurubooru-smtp-pass"; 145 description = ''File containing the password associated to the given user for the SMTP server.''; 146 }; 147 }; 148 149 data_url = mkOption { 150 type = types.str; 151 default = "${cfg.server.settings.domain}/data/"; 152 defaultText = lib.literalExpression ''"''${services.szurubooru.server.settings.domain}/data/"''; 153 example = "http://example.com/content/"; 154 description = ''Full URL to the data endpoint.''; 155 }; 156 157 data_dir = mkOption { 158 type = types.path; 159 default = "${cfg.dataDir}/data"; 160 defaultText = lib.literalExpression ''"''${services.szurubooru.dataDir}/data"''; 161 example = "/srv/szurubooru/data"; 162 description = ''Path to the static files.''; 163 }; 164 165 debug = mkOption { 166 type = types.int; 167 default = 0; 168 example = 1; 169 description = ''Whether to generate server logs.''; 170 }; 171 172 show_sql = mkOption { 173 type = types.int; 174 default = 0; 175 example = 1; 176 description = ''Whether to show SQL in server logs.''; 177 }; 178 }; 179 }; 180 description = '' 181 Configuration to write to {file}`config.yaml`. 182 See <https://github.com/rr-/szurubooru/blob/master/server/config.yaml.dist> for more information. 183 ''; 184 }; 185 }; 186 187 client = { 188 package = mkPackageOption pkgs [ 189 "szurubooru" 190 "client" 191 ] { }; 192 }; 193 194 database = { 195 host = mkOption { 196 type = types.str; 197 default = "localhost"; 198 example = "192.168.1.2"; 199 description = ''Host on which the PostgreSQL database runs.''; 200 }; 201 202 port = mkOption { 203 type = types.port; 204 default = 5432; 205 description = ''The port under which PostgreSQL listens to.''; 206 }; 207 208 name = mkOption { 209 type = types.str; 210 default = cfg.database.user; 211 defaultText = lib.literalExpression "szurubooru.database.name"; 212 example = "szuru"; 213 description = ''Name of the PostgreSQL database.''; 214 }; 215 216 user = mkOption { 217 type = types.str; 218 default = "szurubooru"; 219 example = "szuru"; 220 description = ''PostgreSQL user.''; 221 }; 222 223 passwordFile = mkOption { 224 type = types.path; 225 example = "/run/secrets/szurubooru-db-password"; 226 description = ''A file containing the password for the PostgreSQL user.''; 227 }; 228 }; 229 }; 230 }; 231 232 config = mkIf cfg.enable { 233 234 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.server.port ]; 235 236 users.groups = mkIf (cfg.group == "szurubooru") { 237 szurubooru = { }; 238 }; 239 240 users.users = mkIf (cfg.user == "szurubooru") { 241 szurubooru = { 242 group = cfg.group; 243 description = "Szurubooru Daemon user"; 244 isSystemUser = true; 245 }; 246 }; 247 248 systemd.services.szurubooru = 249 let 250 configFile = format.generate "config.yaml" ( 251 lib.pipe cfg.server.settings [ 252 ( 253 settings: 254 lib.recursiveUpdate settings { 255 secretFile = null; 256 secret = "$SZURUBOORU_SECRET"; 257 258 smtp.pass = if settings.smtp.passFile != null then "$SZURUBOORU_SMTP_PASS" else null; 259 smtp.passFile = null; 260 smtp.enable = null; 261 262 database = "postgresql://${cfg.database.user}:$SZURUBOORU_DATABASE_PASSWORD@${cfg.database.host}:${toString cfg.database.port}/${cfg.database.name}"; 263 } 264 ) 265 (lib.filterAttrsRecursive (_: x: x != null)) 266 ] 267 ); 268 pyenv = python.buildEnv.override { 269 extraLibs = [ (python.pkgs.toPythonModule cfg.server.package) ]; 270 }; 271 in 272 { 273 description = "Server of Szurubooru, an image board engine dedicated for small and medium communities"; 274 275 wantedBy = [ 276 "multi-user.target" 277 "szurubooru-client.service" 278 ]; 279 before = [ "szurubooru-client.service" ]; 280 after = [ 281 "network.target" 282 "network-online.target" 283 ]; 284 wants = [ "network-online.target" ]; 285 286 environment = { 287 PYTHONPATH = "${pyenv}/${pyenv.sitePackages}/"; 288 }; 289 290 path = 291 with pkgs; 292 [ 293 envsubst 294 ffmpeg_4-full 295 ] 296 ++ (with python.pkgs; [ 297 alembic 298 waitress 299 ]); 300 301 script = '' 302 export SZURUBOORU_SECRET="$(<${cfg.server.settings.secretFile})" 303 export SZURUBOORU_DATABASE_PASSWORD="$(<${cfg.database.passwordFile})" 304 ${lib.optionalString (cfg.server.settings.smtp.passFile != null) '' 305 export SZURUBOORU_SMTP_PASS=$(<${cfg.server.settings.smtp.passFile}) 306 ''} 307 install -m0640 ${cfg.server.package.src}/config.yaml.dist ${cfg.dataDir}/config.yaml.dist 308 envsubst -i ${configFile} -o ${cfg.dataDir}/config.yaml 309 sed 's|script_location = |script_location = ${cfg.server.package.src}/|' ${cfg.server.package.src}/alembic.ini > ${cfg.dataDir}/alembic.ini 310 alembic upgrade head 311 waitress-serve --port ${toString cfg.server.port} --threads ${toString cfg.server.threads} szurubooru.facade:app 312 ''; 313 314 serviceConfig = { 315 User = cfg.user; 316 Group = cfg.group; 317 318 Type = "simple"; 319 Restart = "on-failure"; 320 321 StateDirectory = mkIf (cfg.dataDir == "/var/lib/szurubooru") "szurubooru"; 322 WorkingDirectory = cfg.dataDir; 323 }; 324 }; 325 }; 326 327 meta = { 328 maintainers = with lib.maintainers; [ ratcornu ]; 329 doc = ./szurubooru.md; 330 }; 331}