flake.nix 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. {
  2. description = "Transfer.sh";
  3. inputs.flake-utils.url = "github:numtide/flake-utils";
  4. outputs = { self, nixpkgs, flake-utils }:
  5. let
  6. transfer-sh = pkgs: pkgs.buildGoModule {
  7. src = self;
  8. name = "transfer.sh";
  9. vendorSha256 = "sha256-bgQUMiC33yVorcKOWhegT1/YU+fvxsz2pkeRvjf3R7g=";
  10. };
  11. in
  12. flake-utils.lib.eachDefaultSystem (
  13. system:
  14. let
  15. pkgs = nixpkgs.legacyPackages.${system};
  16. in
  17. rec {
  18. packages = flake-utils.lib.flattenTree {
  19. transfer-sh = transfer-sh pkgs;
  20. };
  21. defaultPackage = packages.transfer-sh;
  22. apps.transfer-sh = flake-utils.lib.mkApp { drv = packages.transfer-sh; };
  23. defaultApp = apps.transfer-sh;
  24. }
  25. ) // rec {
  26. nixosModules = {
  27. transfer-sh = { config, lib, pkgs, ... }: with lib; let
  28. RUNTIME_DIR = "/var/lib/transfer.sh";
  29. cfg = config.services.transfer-sh;
  30. general_options = {
  31. enable = mkEnableOption "Transfer.sh service";
  32. listener = mkOption { default = 80; type = types.int; description = "port to use for http (:80)"; };
  33. profile-listener = mkOption { default = 6060; type = types.int; description = "port to use for profiler (:6060)"; };
  34. force-https = mkOption { type = types.nullOr types.bool; description = "redirect to https"; };
  35. tls-listener = mkOption { default = 443; type = types.int; description = "port to use for https (:443)"; };
  36. tls-listener-only = mkOption { type = types.nullOr types.bool; description = "flag to enable tls listener only"; };
  37. tls-cert-file = mkOption { type = types.nullOr types.str; description = "path to tls certificate"; };
  38. tls-private-key = mkOption { type = types.nullOr types.str; description = "path to tls private key "; };
  39. http-auth-user = mkOption { type = types.nullOr types.str; description = "user for basic http auth on upload"; };
  40. http-auth-pass = mkOption { type = types.nullOr types.str; description = "pass for basic http auth on upload"; };
  41. http-auth-htpasswd = mkOption { type = types.nullOr types.str; description = "htpasswd file path for basic http auth on upload"; };
  42. http-auth-ip-whitelist = mkOption { type = types.nullOr types.str; description = "comma separated list of ips allowed to upload without being challenged an http auth"; };
  43. ip-whitelist = mkOption { type = types.nullOr types.str; description = "comma separated list of ips allowed to connect to the service"; };
  44. ip-blacklist = mkOption { type = types.nullOr types.str; description = "comma separated list of ips not allowed to connect to the service"; };
  45. temp-path = mkOption { type = types.nullOr types.str; description = "path to temp folder"; };
  46. web-path = mkOption { type = types.nullOr types.str; description = "path to static web files (for development or custom front end)"; };
  47. proxy-path = mkOption { type = types.nullOr types.str; description = "path prefix when service is run behind a proxy"; };
  48. proxy-port = mkOption { type = types.nullOr types.str; description = "port of the proxy when the service is run behind a proxy"; };
  49. ga-key = mkOption { type = types.nullOr types.str; description = "google analytics key for the front end"; };
  50. email-contact = mkOption { type = types.nullOr types.str; description = "email contact for the front end"; };
  51. uservoice-key = mkOption { type = types.nullOr types.str; description = "user voice key for the front end"; };
  52. lets-encrypt-hosts = mkOption { type = types.nullOr (types.listOf types.str); description = "hosts to use for lets encrypt certificates"; };
  53. log = mkOption { type = types.nullOr types.str; description = "path to log file"; };
  54. cors-domains = mkOption { type = types.nullOr (types.listOf types.str); description = "comma separated list of domains for CORS, setting it enable CORS "; };
  55. clamav-host = mkOption { type = types.nullOr types.str; description = "host for clamav feature"; };
  56. rate-limit = mkOption { type = types.nullOr types.int; description = "request per minute"; };
  57. max-upload-size = mkOption { type = types.nullOr types.int; description = "max upload size in kilobytes "; };
  58. purge-days = mkOption { type = types.nullOr types.int; description = "number of days after the uploads are purged automatically "; };
  59. random-token-length = mkOption { type = types.nullOr types.int; description = "length of the random token for the upload path (double the size for delete path)"; };
  60. };
  61. provider_options = {
  62. aws = {
  63. enable = mkEnableOption "Enable AWS backend";
  64. aws-access-key = mkOption { type = types.str; description = "aws access key"; };
  65. aws-secret-key = mkOption { type = types.str; description = "aws secret key"; };
  66. bucket = mkOption { type = types.str; description = "aws bucket "; };
  67. s3-endpoint = mkOption {
  68. type = types.nullOr types.str;
  69. description = ''
  70. Custom S3 endpoint.
  71. If you specify the s3-region, you don't need to set the endpoint URL since the correct endpoint will used automatically.
  72. '';
  73. };
  74. s3-region = mkOption { type = types.str; description = "region of the s3 bucket eu-west-"; };
  75. s3-no-multipart = mkOption { type = types.nullOr types.bool; description = "disables s3 multipart upload "; };
  76. s3-path-style = mkOption { type = types.nullOr types.str; description = "Forces path style URLs, required for Minio. "; };
  77. };
  78. storj = {
  79. enable = mkEnableOption "Enable storj backend";
  80. storj-access = mkOption { type = types.str; description = "Access for the project"; };
  81. storj-bucket = mkOption { type = types.str; description = "Bucket to use within the project"; };
  82. };
  83. gdrive = {
  84. enable = mkEnableOption "Enable gdrive backend";
  85. gdrive-client-json = mkOption { type = types.str; description = "oauth client json config for gdrive provider"; };
  86. gdrive-chunk-size = mkOption { default = 8; type = types.nullOr types.int; description = "chunk size for gdrive upload in megabytes, must be lower than available memory (8 MB)"; };
  87. basedir = mkOption { type = types.str; description = "path storage for gdrive provider"; default = "${cfg.stateDir}/store"; };
  88. purge-interval = mkOption { type = types.nullOr types.int; description = "interval in hours to run the automatic purge for (not applicable to S3 and Storj)"; };
  89. };
  90. local = {
  91. enable = mkEnableOption "Enable local backend";
  92. basedir = mkOption { type = types.str; description = "path storage for local provider"; default = "${cfg.stateDir}/store"; };
  93. purge-interval = mkOption { type = types.nullOr types.int; description = "interval in hours to run the automatic purge for (not applicable to S3 and Storj)"; };
  94. };
  95. };
  96. in
  97. {
  98. options.services.transfer-sh = fold recursiveUpdate {} [
  99. general_options
  100. {
  101. provider = provider_options;
  102. user = mkOption {
  103. type = types.str;
  104. description = "User to run the service under";
  105. default = "transfer.sh";
  106. };
  107. group = mkOption {
  108. type = types.str;
  109. description = "Group to run the service under";
  110. default = "transfer.sh";
  111. };
  112. stateDir = mkOption {
  113. type = types.path;
  114. description = "Variable state directory";
  115. default = RUNTIME_DIR;
  116. };
  117. }
  118. ];
  119. config = let
  120. mkFlags = cfg: options:
  121. let
  122. mkBoolFlag = option: if cfg.${option} then [ "--${option}" ] else [];
  123. mkFlag = option:
  124. if isBool cfg.${option}
  125. then mkBoolFlag option
  126. else [ "--${option}" "${cfg.${option}}" ];
  127. in
  128. lists.flatten (map (mkFlag) (filter (option: cfg.${option} != null && option != "enable") options));
  129. aws-config = (mkFlags cfg.provider.aws (attrNames provider_options)) ++ [ "--provider" "aws" ];
  130. gdrive-config = mkFlags cfg.provider.gdrive (attrNames provider_options.gdrive) ++ [ "--provider" "gdrive" ];
  131. storj-config = mkFlags cfg.provider.storj (attrNames provider_options.storj) ++ [ "--provider" "storj" ];
  132. local-config = mkFlags cfg.provider.local (attrNames provider_options.local) ++ [ "--provider" "local" ];
  133. general-config = concatStringsSep " " (mkFlags cfg (attrNames general_options));
  134. provider-config = concatStringsSep " " (
  135. if cfg.provider.aws.enable && !cfg.provider.storj.enable && !cfg.provider.gdrive.enable && !cfg.provider.local.enable then aws-config
  136. else if !cfg.provider.aws.enable && cfg.provider.storj.enable && !cfg.provider.gdrive.enable && !cfg.provider.local.enable then storj-config
  137. else if !cfg.provider.aws.enable && !cfg.provider.storj.enable && cfg.provider.gdrive.enable && !cfg.provider.local.enable then gdrive-config
  138. else if !cfg.provider.aws.enable && !cfg.provider.storj.enable && !cfg.provider.gdrive.enable && cfg.provider.local.enable then local-config
  139. else throw "transfer.sh requires exactly one provider (aws, storj, gdrive, local)"
  140. );
  141. in
  142. lib.mkIf cfg.enable
  143. {
  144. systemd.tmpfiles.rules = [
  145. "d ${cfg.stateDir} 0750 ${cfg.user} ${cfg.group} - -"
  146. ] ++ optional cfg.provider.gdrive.enable cfg.provider.gdrive.basedir
  147. ++ optional cfg.provider.local.enable cfg.provider.local.basedir;
  148. systemd.services.transfer-sh = {
  149. wantedBy = [ "multi-user.target" ];
  150. after = [ "network.target" ];
  151. serviceConfig = {
  152. User = cfg.user;
  153. Group = cfg.group;
  154. ExecStart = "${transfer-sh pkgs}/bin/transfer.sh ${general-config} ${provider-config} ";
  155. };
  156. };
  157. networking.firewall.allowedTCPPorts = [ cfg.listener cfg.profile-listener cfg.tls-listener ];
  158. };
  159. };
  160. default = { self, pkgs, ... }: {
  161. imports = [ nixosModules.transfer-sh ];
  162. # Network configuration.
  163. # useDHCP is generally considered to better be turned off in favor
  164. # of <adapter>.useDHCP
  165. networking.useDHCP = false;
  166. networking.firewall.allowedTCPPorts = [];
  167. # Enable the inventaire server.
  168. services.transfer-sh = {
  169. enable = true;
  170. provider.local = {
  171. enable = true;
  172. };
  173. };
  174. nixpkgs.config.allowUnfree = true;
  175. };
  176. };
  177. nixosConfigurations."container" = nixpkgs.lib.nixosSystem {
  178. system = "x86_64-linux";
  179. modules = [
  180. nixosModules.default
  181. ({ ... }: { boot.isContainer = true; })
  182. ];
  183. };
  184. };
  185. }