8 inherit (lib) mkOption types;
9 cfg = config.services.send;
14 enable = lib.mkEnableOption "Send, a file sharing web sevice for ffsend.";
16 package = lib.mkPackageOption pkgs "send" { };
18 environment = mkOption {
30 All the available config options and their defaults can be found here: https://github.com/timvisee/send/blob/master/server/config.js,
31 some descriptions can found here: https://github.com/timvisee/send/blob/master/docs/docker.md#environment-variables
33 Values under {option}`services.send.environment` will override the predefined values in the Send service.
34 - Time/duration should be in seconds
35 - Filesize values should be in bytes
38 DEFAULT_DOWNLOADS = 1;
39 DETECT_BASE_URL = true;
40 EXPIRE_TIMES_SECONDS = [
49 dataDir = lib.mkOption {
52 default = "/var/lib/send";
54 Directory for uploaded files.
55 Due to limitations in {option}`systemd.services.send.serviceConfig.DynamicUser`, this item is read only.
60 type = types.nullOr types.str;
63 Base URL for the Send service.
64 Leave it blank to automatically detect the base url.
70 default = "127.0.0.1";
71 description = "The hostname or IP address for Send to bind to.";
77 description = "Port the Send service listens on.";
80 openFirewall = lib.mkOption {
83 description = "Whether to open firewall ports for send";
87 createLocally = lib.mkOption {
90 description = "Whether to create a local redis automatically.";
97 Name of the redis server.
98 Only used if {option}`services.send.redis.createLocally` is set to true.
102 host = lib.mkOption {
104 default = "localhost";
105 description = "Redis server address.";
108 port = lib.mkOption {
111 description = "Port of the redis server.";
114 passwordFile = mkOption {
115 type = types.nullOr types.path;
117 example = "/run/agenix/send-redis-password";
119 The path to the file containing the Redis password.
121 If {option}`services.send.redis.createLocally` is set to true,
122 the content of this file will be used as the password for the locally created Redis instance.
124 Leave it blank if no password is required.
131 config = lib.mkIf cfg.enable {
133 services.send.environment.DETECT_BASE_URL = cfg.baseUrl == null;
137 assertion = cfg.redis.createLocally -> cfg.redis.host == "localhost";
138 message = "the redis host must be localhost if services.send.redis.createLocally is set to true";
142 networking.firewall.allowedTCPPorts = lib.optional cfg.openFirewall cfg.port;
144 services.redis = lib.optionalAttrs cfg.redis.createLocally {
145 servers."${cfg.redis.name}" = {
148 port = cfg.redis.port;
152 systemd.services.send = {
156 StateDirectory = "send";
157 WorkingDirectory = cfg.dataDir;
158 ReadWritePaths = cfg.dataDir;
159 LoadCredential = lib.optionalString (
160 cfg.redis.passwordFile != null
161 ) "redis-password:${cfg.redis.passwordFile}";
164 RestrictAddressFamilies = [
169 AmbientCapabilities = lib.optionalString (cfg.port < 1024) "cap_net_bind_service";
171 CapabilityBoundingSet = "";
172 NoNewPrivileges = true;
177 ProtectControlGroups = true;
179 ProtectHostname = true;
180 ProtectKernelLogs = true;
181 ProtectKernelModules = true;
182 ProtectKernelTunables = true;
183 ProtectProc = "invisible";
184 ProtectSystem = "full";
185 RestrictNamespaces = true;
186 RestrictRealtime = true;
187 RestrictSUIDSGID = true;
188 SystemCallArchitectures = "native";
193 IP_ADDRESS = cfg.host;
194 PORT = toString cfg.port;
195 BASE_URL = if (cfg.baseUrl == null) then "http://${cfg.host}:${toString cfg.port}" else cfg.baseUrl;
196 FILE_DIR = cfg.dataDir + "/uploads";
197 REDIS_HOST = cfg.redis.host;
198 REDIS_PORT = toString cfg.redis.port;
202 if lib.isList value then
203 "[" + lib.concatStringsSep ", " (map (x: toString x) value) + "]"
204 else if lib.isBool value then
205 lib.boolToString value
213 ++ lib.optionals cfg.redis.createLocally [
214 "redis-${cfg.redis.name}.service"
216 description = "Send web service";
217 wantedBy = [ "multi-user.target" ];
219 ${lib.optionalString (cfg.redis.passwordFile != null) ''
220 export REDIS_PASSWORD="$(cat $CREDENTIALS_DIRECTORY/redis-password)"
222 ${lib.getExe cfg.package}
227 meta.maintainers = with lib.maintainers; [ moraxyc ];