zoekt: 3.7.2-2-unstable-2024-10-24 -> 3.7.2-2-unstable-2024-12-09 (#363818)
[NixPkgs.git] / nixos / modules / services / web-servers / rustus.nix
blob9ca87bb16bf3b6da755c11d200b4104f6ddfbc56
2   lib,
3   pkgs,
4   config,
5   ...
6 }:
7 with lib;
8 let
9   cfg = config.services.rustus;
12   meta.maintainers = with maintainers; [ happysalada ];
14   options.services.rustus = {
16     enable = mkEnableOption "TUS protocol implementation in Rust";
18     host = mkOption {
19       type = types.str;
20       description = ''
21         The host that rustus will connect to.
22       '';
23       default = "127.0.0.1";
24       example = "127.0.0.1";
25     };
27     port = mkOption {
28       type = types.port;
29       description = ''
30         The port that rustus will connect to.
31       '';
32       default = 1081;
33       example = 1081;
34     };
36     log_level = mkOption {
37       type = types.enum [
38         "DEBUG"
39         "INFO"
40         "ERROR"
41       ];
42       description = ''
43         Desired log level
44       '';
45       default = "INFO";
46       example = "ERROR";
47     };
49     max_body_size = mkOption {
50       type = types.str;
51       description = ''
52         Maximum body size in bytes
53       '';
54       default = "10000000"; # 10 mb
55       example = "100000000";
56     };
58     url = mkOption {
59       type = types.str;
60       description = ''
61         url path for uploads
62       '';
63       default = "/files";
64     };
66     disable_health_access_logs = mkOption {
67       type = types.bool;
68       description = ''
69         disable access log for /health endpoint
70       '';
71       default = false;
72     };
74     cors = mkOption {
75       type = types.listOf types.str;
76       description = ''
77         list of origins allowed to upload
78       '';
79       default = [ "*" ];
80       example = [
81         "*.staging.domain"
82         "*.prod.domain"
83       ];
84     };
86     tus_extensions = mkOption {
87       type = types.listOf (
88         types.enum [
89           "getting"
90           "creation"
91           "termination"
92           "creation-with-upload"
93           "creation-defer-length"
94           "concatenation"
95           "checksum"
96         ]
97       );
98       description = ''
99         Since TUS protocol offers extensibility you can turn off some protocol extensions.
100       '';
101       default = [
102         "getting"
103         "creation"
104         "termination"
105         "creation-with-upload"
106         "creation-defer-length"
107         "concatenation"
108         "checksum"
109       ];
110     };
112     remove_parts = mkOption {
113       type = types.bool;
114       description = ''
115         remove parts files after successful concatenation
116       '';
117       default = true;
118       example = false;
119     };
121     storage = lib.mkOption {
122       description = ''
123         Storages are used to actually store your files. You can configure where you want to store files.
124       '';
125       default = { };
126       example = lib.literalExpression ''
127         {
128           type = "hybrid-s3"
129           s3_access_key_file = konfig.age.secrets.R2_ACCESS_KEY.path;
130           s3_secret_key_file = konfig.age.secrets.R2_SECRET_KEY.path;
131           s3_bucket = "my_bucket";
132           s3_url = "https://s3.example.com";
133         }
134       '';
135       type = lib.types.submodule {
136         options = {
137           type = lib.mkOption {
138             type = lib.types.enum [
139               "file-storage"
140               "hybrid-s3"
141             ];
142             description = "Type of storage to use";
143           };
144           s3_access_key_file = lib.mkOption {
145             type = lib.types.str;
146             description = "File path that contains the S3 access key.";
147           };
148           s3_secret_key_file = lib.mkOption {
149             type = lib.types.path;
150             description = "File path that contains the S3 secret key.";
151           };
152           s3_region = lib.mkOption {
153             type = lib.types.str;
154             default = "us-east-1";
155             description = "S3 region name.";
156           };
157           s3_bucket = lib.mkOption {
158             type = lib.types.str;
159             description = "S3 bucket.";
160           };
161           s3_url = lib.mkOption {
162             type = lib.types.str;
163             description = "S3 url.";
164           };
166           force_sync = lib.mkOption {
167             type = lib.types.bool;
168             description = "calls fsync system call after every write to disk in local storage";
169             default = true;
170           };
171           data_dir = lib.mkOption {
172             type = lib.types.str;
173             description = "path to the local directory where all files are stored";
174             default = "/var/lib/rustus";
175           };
176           dir_structure = lib.mkOption {
177             type = lib.types.str;
178             description = "pattern of a directory structure locally and on s3";
179             default = "{year}/{month}/{day}";
180           };
181         };
182       };
183     };
185     info_storage = lib.mkOption {
186       description = ''
187         Info storages are used to store information about file uploads. These storages must be persistent, because every time chunk is uploaded rustus updates information about upload. And when someone wants to download file, information about it requested from storage to get actual path of an upload.
188       '';
189       default = { };
190       type = lib.types.submodule {
191         options = {
192           type = lib.mkOption {
193             type = lib.types.enum [ "file-info-storage" ];
194             description = "Type of info storage to use";
195             default = "file-info-storage";
196           };
197           dir = lib.mkOption {
198             type = lib.types.str;
199             description = "directory to store info about uploads";
200             default = "/var/lib/rustus";
201           };
202         };
203       };
204     };
205   };
207   config = lib.mkIf cfg.enable {
209     systemd.services.rustus =
210       let
211         isHybridS3 = cfg.storage.type == "hybrid-s3";
212       in
213       {
214         description = "Rustus server";
215         documentation = [ "https://s3rius.github.io/rustus/" ];
217         wantedBy = [ "multi-user.target" ];
218         after = [ "network.target" ];
220         environment = {
221           RUSTUS_SERVER_HOST = cfg.host;
222           RUSTUS_SERVER_PORT = toString cfg.port;
223           RUSTUS_LOG_LEVEL = cfg.log_level;
224           RUSTUS_MAX_BODY_SIZE = cfg.max_body_size;
225           RUSTUS_URL = cfg.url;
226           RUSTUS_DISABLE_HEALTH_ACCESS_LOG = lib.mkIf cfg.disable_health_access_logs "true";
227           RUSTUS_CORS = lib.concatStringsSep "," cfg.cors;
228           RUSTUS_TUS_EXTENSIONS = lib.concatStringsSep "," cfg.tus_extensions;
229           RUSTUS_REMOVE_PARTS = if cfg.remove_parts then "true" else "false";
230           RUSTUS_STORAGE = cfg.storage.type;
231           RUSTUS_DATA_DIR = cfg.storage.data_dir;
232           RUSTUS_DIR_STRUCTURE = cfg.storage.dir_structure;
233           RUSTUS_FORCE_FSYNC = if cfg.storage.force_sync then "true" else "false";
234           RUSTUS_S3_URL = mkIf isHybridS3 cfg.storage.s3_url;
235           RUSTUS_S3_BUCKET = mkIf isHybridS3 cfg.storage.s3_bucket;
236           RUSTUS_S3_REGION = mkIf isHybridS3 cfg.storage.s3_region;
237           RUSTUS_S3_ACCESS_KEY_PATH = mkIf isHybridS3 "%d/S3_ACCESS_KEY_PATH";
238           RUSTUS_S3_SECRET_KEY_PATH = mkIf isHybridS3 "%d/S3_SECRET_KEY_PATH";
239           RUSTUS_INFO_STORAGE = cfg.info_storage.type;
240           RUSTUS_INFO_DIR = cfg.info_storage.dir;
241         };
243         serviceConfig = {
244           ExecStart = "${pkgs.rustus}/bin/rustus";
245           StateDirectory = "rustus";
246           # User name is defined here to enable restoring a backup for example
247           # You will run the backup restore command as sudo -u rustus in order
248           # to have write permissions to /var/lib
249           User = "rustus";
250           DynamicUser = true;
251           LoadCredential = lib.optionals isHybridS3 [
252             "S3_ACCESS_KEY_PATH:${cfg.storage.s3_access_key_file}"
253             "S3_SECRET_KEY_PATH:${cfg.storage.s3_secret_key_file}"
254           ];
255           # hardening
256           RestrictRealtime = true;
257           RestrictNamespaces = true;
258           LockPersonality = true;
259           ProtectKernelModules = true;
260           ProtectKernelTunables = true;
261           ProtectKernelLogs = true;
262           ProtectControlGroups = true;
263           ProtectHostUserNamespaces = true;
264           ProtectClock = true;
265           RestrictSUIDSGID = true;
266           SystemCallArchitectures = "native";
267           CapabilityBoundingSet = "";
268           ProtectProc = "invisible";
269           # TODO consider SystemCallFilter LimitAS ProcSubset
270         };
271       };
272   };