at 25.11-pre 4.7 kB view raw
1{ 2 config, 3 pkgs, 4 lib, 5 ... 6}: 7 8let 9 cfg = config.services.pinchflat; 10 inherit (lib) 11 mkEnableOption 12 mkPackageOption 13 mkOption 14 types 15 mkIf 16 getExe 17 literalExpression 18 optional 19 attrValues 20 mapAttrs 21 ; 22 23 stateDir = "/var/lib/pinchflat"; 24in 25{ 26 options = { 27 services.pinchflat = { 28 enable = mkEnableOption "pinchflat"; 29 30 mediaDir = mkOption { 31 type = types.path; 32 default = "${stateDir}/media"; 33 description = "The directory into which Pinchflat downloads videos."; 34 }; 35 36 port = mkOption { 37 type = types.port; 38 default = 8945; 39 description = "Port on which the Pinchflat web interface is available."; 40 }; 41 42 openFirewall = mkOption { 43 type = types.bool; 44 default = false; 45 description = "Open ports in the firewall for the Pinchflat web interface"; 46 }; 47 48 selfhosted = mkOption { 49 type = types.bool; 50 default = false; 51 description = "Use a weak secret. If true, you are not required to provide a {env}`SECRET_KEY_BASE` through the `secretsFile` option. Do not use this option in production!"; 52 }; 53 54 logLevel = mkOption { 55 type = types.enum [ 56 "debug" 57 "info" 58 "warning" 59 "error" 60 ]; 61 default = "info"; 62 description = "Log level for Pinchflat."; 63 }; 64 65 extraConfig = mkOption { 66 type = 67 with types; 68 attrsOf ( 69 nullOr (oneOf [ 70 bool 71 int 72 str 73 ]) 74 ); 75 default = { }; 76 example = literalExpression '' 77 { 78 YT_DLP_WORKER_CONCURRENCY = 1; 79 } 80 ''; 81 description = '' 82 The configuration of Pinchflat is handled through environment variables. 83 The available configuration options can be found in [the Pinchflat README](https://github.com/kieraneglin/pinchflat/README.md#environment-variables). 84 ''; 85 }; 86 87 secretsFile = mkOption { 88 type = with types; nullOr path; 89 default = null; 90 example = "/run/secrets/pinchflat"; 91 description = '' 92 Secrets like {env}`SECRET_KEY_BASE` and {env}`BASIC_AUTH_PASSWORD` 93 should be passed to the service without adding them to the world-readable Nix store. 94 95 Note that either this file needs to be available on the host on which `pinchflat` is running, 96 or the option `selfhosted` must be `true`. 97 Further, {env}`SECRET_KEY_BASE` has a minimum length requirement of 64 bytes. 98 One way to generate such a secret is to use `openssl rand -hex 64`. 99 100 As an example, the contents of the file might look like this: 101 ``` 102 SECRET_KEY_BASE=...copy-paste a secret token here... 103 BASIC_AUTH_USERNAME=...basic auth username... 104 BASIC_AUTH_PASSWORD=...basic auth password... 105 ``` 106 ''; 107 }; 108 109 package = mkPackageOption pkgs "pinchflat" { }; 110 }; 111 }; 112 113 config = mkIf cfg.enable { 114 assertions = [ 115 { 116 assertion = cfg.selfhosted || !builtins.isNull cfg.secretsFile; 117 message = "Either `selfhosted` must be true, or a `secretsFile` must be configured."; 118 } 119 ]; 120 121 systemd.services.pinchflat = { 122 description = "pinchflat"; 123 after = [ "network.target" ]; 124 wantedBy = [ "multi-user.target" ]; 125 126 serviceConfig = { 127 Type = "simple"; 128 DynamicUser = true; 129 StateDirectory = baseNameOf stateDir; 130 Environment = 131 [ 132 "PORT=${builtins.toString cfg.port}" 133 "TZ=${config.time.timeZone}" 134 "MEDIA_PATH=${cfg.mediaDir}" 135 "CONFIG_PATH=${stateDir}" 136 "DATABASE_PATH=${stateDir}/db/pinchflat.db" 137 "LOG_PATH=${stateDir}/logs/pinchflat.log" 138 "METADATA_PATH=${stateDir}/metadata" 139 "EXTRAS_PATH=${stateDir}/extras" 140 "TMPFILE_PATH=${stateDir}/tmp" 141 "TZ_DATA_PATH=${stateDir}/extras/elixir_tz_data" 142 "LOG_LEVEL=${cfg.logLevel}" 143 "PHX_SERVER=true" 144 ] 145 ++ optional cfg.selfhosted [ "RUN_CONTEXT=selfhosted" ] 146 ++ attrValues (mapAttrs (name: value: name + "=" + builtins.toString value) cfg.extraConfig); 147 EnvironmentFile = optional (cfg.secretsFile != null) cfg.secretsFile; 148 ExecStartPre = "${lib.getExe' cfg.package "migrate"}"; 149 ExecStart = "${getExe cfg.package} start"; 150 Restart = "on-failure"; 151 }; 152 }; 153 154 networking.firewall = mkIf cfg.openFirewall { 155 allowedTCPPorts = [ cfg.port ]; 156 }; 157 }; 158}