9 cfg = config.services.rustus;
12 meta.maintainers = with maintainers; [ happysalada ];
14 options.services.rustus = {
16 enable = mkEnableOption "TUS protocol implementation in Rust";
21 The host that rustus will connect to.
23 default = "127.0.0.1";
24 example = "127.0.0.1";
30 The port that rustus will connect to.
36 log_level = mkOption {
49 max_body_size = mkOption {
52 Maximum body size in bytes
54 default = "10000000"; # 10 mb
55 example = "100000000";
66 disable_health_access_logs = mkOption {
69 disable access log for /health endpoint
75 type = types.listOf types.str;
77 list of origins allowed to upload
86 tus_extensions = mkOption {
92 "creation-with-upload"
93 "creation-defer-length"
99 Since TUS protocol offers extensibility you can turn off some protocol extensions.
105 "creation-with-upload"
106 "creation-defer-length"
112 remove_parts = mkOption {
115 remove parts files after successful concatenation
121 storage = lib.mkOption {
123 Storages are used to actually store your files. You can configure where you want to store files.
126 example = lib.literalExpression ''
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";
135 type = lib.types.submodule {
137 type = lib.mkOption {
138 type = lib.types.enum [
142 description = "Type of storage to use";
144 s3_access_key_file = lib.mkOption {
145 type = lib.types.str;
146 description = "File path that contains the S3 access key.";
148 s3_secret_key_file = lib.mkOption {
149 type = lib.types.path;
150 description = "File path that contains the S3 secret key.";
152 s3_region = lib.mkOption {
153 type = lib.types.str;
154 default = "us-east-1";
155 description = "S3 region name.";
157 s3_bucket = lib.mkOption {
158 type = lib.types.str;
159 description = "S3 bucket.";
161 s3_url = lib.mkOption {
162 type = lib.types.str;
163 description = "S3 url.";
166 force_sync = lib.mkOption {
167 type = lib.types.bool;
168 description = "calls fsync system call after every write to disk in local storage";
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";
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}";
185 info_storage = lib.mkOption {
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.
190 type = lib.types.submodule {
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";
198 type = lib.types.str;
199 description = "directory to store info about uploads";
200 default = "/var/lib/rustus";
207 config = lib.mkIf cfg.enable {
209 systemd.services.rustus =
211 isHybridS3 = cfg.storage.type == "hybrid-s3";
214 description = "Rustus server";
215 documentation = [ "https://s3rius.github.io/rustus/" ];
217 wantedBy = [ "multi-user.target" ];
218 after = [ "network.target" ];
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;
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
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}"
256 RestrictRealtime = true;
257 RestrictNamespaces = true;
258 LockPersonality = true;
259 ProtectKernelModules = true;
260 ProtectKernelTunables = true;
261 ProtectKernelLogs = true;
262 ProtectControlGroups = true;
263 ProtectHostUserNamespaces = true;
265 RestrictSUIDSGID = true;
266 SystemCallArchitectures = "native";
267 CapabilityBoundingSet = "";
268 ProtectProc = "invisible";
269 # TODO consider SystemCallFilter LimitAS ProcSubset