diff options
| -rw-r--r-- | hosts/surtr/borg.nix | 50 | ||||
| -rw-r--r-- | hosts/surtr/default.nix | 2 | ||||
| -rw-r--r-- | hosts/surtr/matrix/default.nix | 4 | ||||
| -rw-r--r-- | modules/borgsnap/borgsnap/borgsnap/__main__.py | 4 | ||||
| -rw-r--r-- | modules/coturn.nix | 369 | ||||
| -rw-r--r-- | modules/zfssnap/default.nix | 34 |
6 files changed, 444 insertions, 19 deletions
diff --git a/hosts/surtr/borg.nix b/hosts/surtr/borg.nix new file mode 100644 index 00000000..b9fe53d7 --- /dev/null +++ b/hosts/surtr/borg.nix | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | { lib, config, ... }: | ||
| 2 | |||
| 3 | with lib; | ||
| 4 | |||
| 5 | { | ||
| 6 | config = { | ||
| 7 | services.borgsnap = { | ||
| 8 | enable = true; | ||
| 9 | target = "borg.vidhar:."; | ||
| 10 | |||
| 11 | extraConfig = mkForce { | ||
| 12 | daily = "31"; | ||
| 13 | monthly = "-1"; | ||
| 14 | }; | ||
| 15 | |||
| 16 | sshConfig = '' | ||
| 17 | Include /etc/ssh/ssh_config | ||
| 18 | |||
| 19 | ControlMaster auto | ||
| 20 | ControlPath /var/lib/borg/.borgssh-master-%r@%n:%p | ||
| 21 | ControlPersist yes | ||
| 22 | |||
| 23 | Host borg.vidhar | ||
| 24 | HostName vidhar.yggdrasil.li | ||
| 25 | User borg | ||
| 26 | IdentityFile ${config.sops.secrets."append.borg.vidhar".path} | ||
| 27 | IdentitiesOnly yes | ||
| 28 | |||
| 29 | BatchMode yes | ||
| 30 | ServerAliveInterval 10 | ||
| 31 | ServerAliveCountMax 30 | ||
| 32 | ''; | ||
| 33 | }; | ||
| 34 | |||
| 35 | sops.secrets."append.borg.vidhar" = { | ||
| 36 | format = "binary"; | ||
| 37 | sopsFile = ../vidhar/borg/jotnar/surtr; | ||
| 38 | owner = "borg"; | ||
| 39 | group = "borg"; | ||
| 40 | mode = "0400"; | ||
| 41 | }; | ||
| 42 | |||
| 43 | users.users.borg = { | ||
| 44 | useDefaultShell = true; | ||
| 45 | isSystemUser = true; | ||
| 46 | group = "borg"; | ||
| 47 | }; | ||
| 48 | users.groups.borg = {}; | ||
| 49 | }; | ||
| 50 | } | ||
diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix index f616d749..cebb2b6c 100644 --- a/hosts/surtr/default.nix +++ b/hosts/surtr/default.nix | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | { | 2 | { |
| 3 | imports = with flake.nixosModules.systemProfiles; [ | 3 | imports = with flake.nixosModules.systemProfiles; [ |
| 4 | tmpfs-root qemu-guest openssh rebuild-machines zfs | 4 | tmpfs-root qemu-guest openssh rebuild-machines zfs |
| 5 | ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql.nix ./prometheus ./email ./vpn | 5 | ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql.nix ./prometheus ./email ./vpn ./borg.nix |
| 6 | ]; | 6 | ]; |
| 7 | 7 | ||
| 8 | config = { | 8 | config = { |
diff --git a/hosts/surtr/matrix/default.nix b/hosts/surtr/matrix/default.nix index 46c2f338..f5a411ac 100644 --- a/hosts/surtr/matrix/default.nix +++ b/hosts/surtr/matrix/default.nix | |||
| @@ -228,10 +228,6 @@ with lib; | |||
| 228 | "turn.synapse.li" = { | 228 | "turn.synapse.li" = { |
| 229 | zone = "synapse.li"; | 229 | zone = "synapse.li"; |
| 230 | certCfg = { | 230 | certCfg = { |
| 231 | server = "https://acme.zerossl.com/v2/DV90"; | ||
| 232 | extraLegoFlags = [ | ||
| 233 | "--cert.timeout" "300" | ||
| 234 | ]; | ||
| 235 | postRun = '' | 231 | postRun = '' |
| 236 | ${pkgs.systemd}/bin/systemctl try-restart coturn.service | 232 | ${pkgs.systemd}/bin/systemctl try-restart coturn.service |
| 237 | ''; | 233 | ''; |
diff --git a/modules/borgsnap/borgsnap/borgsnap/__main__.py b/modules/borgsnap/borgsnap/borgsnap/__main__.py index 91144780..ad46a7bf 100644 --- a/modules/borgsnap/borgsnap/borgsnap/__main__.py +++ b/modules/borgsnap/borgsnap/borgsnap/__main__.py | |||
| @@ -246,7 +246,9 @@ def create(*, snapshot, target, archive_prefix, dry_run): | |||
| 246 | env['BORG_FILES_CACHE_SUFFIX'] = basename | 246 | env['BORG_FILES_CACHE_SUFFIX'] = basename |
| 247 | archive_name = _archive_name(snapshot, target, archive_prefix) | 247 | archive_name = _archive_name(snapshot, target, archive_prefix) |
| 248 | target_host, _, target_path = target.rpartition(':') | 248 | target_host, _, target_path = target.rpartition(':') |
| 249 | *parents_init, _ = list(Path(target_path).parents) | 249 | parents_init = list() |
| 250 | if Path(target_path).parents: | ||
| 251 | *parents_init, _ = list(Path(target_path).parents) | ||
| 250 | backup_patterns = [*(map(lambda p: Path('.backup') / f'{target_host}:{p}', [Path(target_path), *parents_init])), Path('.backup') / target_host, Path('.backup')] | 252 | backup_patterns = [*(map(lambda p: Path('.backup') / f'{target_host}:{p}', [Path(target_path), *parents_init])), Path('.backup') / target_host, Path('.backup')] |
| 251 | for pattern_file in backup_patterns: | 253 | for pattern_file in backup_patterns: |
| 252 | if (dir / pattern_file).is_file(): | 254 | if (dir / pattern_file).is_file(): |
diff --git a/modules/coturn.nix b/modules/coturn.nix new file mode 100644 index 00000000..faa4b5a2 --- /dev/null +++ b/modules/coturn.nix | |||
| @@ -0,0 +1,369 @@ | |||
| 1 | { config, lib, pkgs, ... }: | ||
| 2 | with lib; | ||
| 3 | let | ||
| 4 | cfg = config.services.coturn; | ||
| 5 | pidfile = "/run/turnserver/turnserver.pid"; | ||
| 6 | configFile = pkgs.writeText "turnserver.conf" '' | ||
| 7 | listening-port=${toString cfg.listening-port} | ||
| 8 | tls-listening-port=${toString cfg.tls-listening-port} | ||
| 9 | alt-listening-port=${toString cfg.alt-listening-port} | ||
| 10 | alt-tls-listening-port=${toString cfg.alt-tls-listening-port} | ||
| 11 | ${concatStringsSep "\n" (map (x: "listening-ip=${x}") cfg.listening-ips)} | ||
| 12 | ${concatStringsSep "\n" (map (x: "relay-ip=${x}") cfg.relay-ips)} | ||
| 13 | min-port=${toString cfg.min-port} | ||
| 14 | max-port=${toString cfg.max-port} | ||
| 15 | ${lib.optionalString cfg.lt-cred-mech "lt-cred-mech"} | ||
| 16 | ${lib.optionalString cfg.no-auth "no-auth"} | ||
| 17 | ${lib.optionalString cfg.use-auth-secret "use-auth-secret"} | ||
| 18 | ${lib.optionalString (cfg.static-auth-secret != null) ("static-auth-secret=${cfg.static-auth-secret}")} | ||
| 19 | ${lib.optionalString (cfg.static-auth-secret-file != null) ("static-auth-secret=#static-auth-secret#")} | ||
| 20 | realm=${cfg.realm} | ||
| 21 | ${lib.optionalString cfg.no-udp "no-udp"} | ||
| 22 | ${lib.optionalString cfg.no-tcp "no-tcp"} | ||
| 23 | ${lib.optionalString cfg.no-tls "no-tls"} | ||
| 24 | ${lib.optionalString cfg.no-dtls "no-dtls"} | ||
| 25 | ${lib.optionalString cfg.no-udp-relay "no-udp-relay"} | ||
| 26 | ${lib.optionalString cfg.no-tcp-relay "no-tcp-relay"} | ||
| 27 | ${lib.optionalString (cfg.cert != null) "cert=${cfg.cert}"} | ||
| 28 | ${lib.optionalString (cfg.pkey != null) "pkey=${cfg.pkey}"} | ||
| 29 | ${lib.optionalString (cfg.dh-file != null) ("dh-file=${cfg.dh-file}")} | ||
| 30 | no-stdout-log | ||
| 31 | syslog | ||
| 32 | pidfile=${pidfile} | ||
| 33 | ${lib.optionalString cfg.secure-stun "secure-stun"} | ||
| 34 | ${lib.optionalString cfg.no-cli "no-cli"} | ||
| 35 | cli-ip=${cfg.cli-ip} | ||
| 36 | cli-port=${toString cfg.cli-port} | ||
| 37 | ${lib.optionalString (cfg.cli-password != null) ("cli-password=${cfg.cli-password}")} | ||
| 38 | ${cfg.extraConfig} | ||
| 39 | ''; | ||
| 40 | in { | ||
| 41 | disabledModules = [ "services/networking/coturn.nix" ]; | ||
| 42 | |||
| 43 | options = { | ||
| 44 | services.coturn = { | ||
| 45 | enable = mkEnableOption (lib.mdDoc "coturn TURN server"); | ||
| 46 | listening-port = mkOption { | ||
| 47 | type = types.int; | ||
| 48 | default = 3478; | ||
| 49 | description = lib.mdDoc '' | ||
| 50 | TURN listener port for UDP and TCP. | ||
| 51 | Note: actually, TLS and DTLS sessions can connect to the | ||
| 52 | "plain" TCP and UDP port(s), too - if allowed by configuration. | ||
| 53 | ''; | ||
| 54 | }; | ||
| 55 | tls-listening-port = mkOption { | ||
| 56 | type = types.int; | ||
| 57 | default = 5349; | ||
| 58 | description = lib.mdDoc '' | ||
| 59 | TURN listener port for TLS. | ||
| 60 | Note: actually, "plain" TCP and UDP sessions can connect to the TLS and | ||
| 61 | DTLS port(s), too - if allowed by configuration. The TURN server | ||
| 62 | "automatically" recognizes the type of traffic. Actually, two listening | ||
| 63 | endpoints (the "plain" one and the "tls" one) are equivalent in terms of | ||
| 64 | functionality; but we keep both endpoints to satisfy the RFC 5766 specs. | ||
| 65 | For secure TCP connections, we currently support SSL version 3 and | ||
| 66 | TLS version 1.0, 1.1 and 1.2. | ||
| 67 | For secure UDP connections, we support DTLS version 1. | ||
| 68 | ''; | ||
| 69 | }; | ||
| 70 | alt-listening-port = mkOption { | ||
| 71 | type = types.int; | ||
| 72 | default = cfg.listening-port + 1; | ||
| 73 | defaultText = literalExpression "listening-port + 1"; | ||
| 74 | description = lib.mdDoc '' | ||
| 75 | Alternative listening port for UDP and TCP listeners; | ||
| 76 | default (or zero) value means "listening port plus one". | ||
| 77 | This is needed for RFC 5780 support | ||
| 78 | (STUN extension specs, NAT behavior discovery). The TURN Server | ||
| 79 | supports RFC 5780 only if it is started with more than one | ||
| 80 | listening IP address of the same family (IPv4 or IPv6). | ||
| 81 | RFC 5780 is supported only by UDP protocol, other protocols | ||
| 82 | are listening to that endpoint only for "symmetry". | ||
| 83 | ''; | ||
| 84 | }; | ||
| 85 | alt-tls-listening-port = mkOption { | ||
| 86 | type = types.int; | ||
| 87 | default = cfg.tls-listening-port + 1; | ||
| 88 | defaultText = literalExpression "tls-listening-port + 1"; | ||
| 89 | description = lib.mdDoc '' | ||
| 90 | Alternative listening port for TLS and DTLS protocols. | ||
| 91 | ''; | ||
| 92 | }; | ||
| 93 | listening-ips = mkOption { | ||
| 94 | type = types.listOf types.str; | ||
| 95 | default = []; | ||
| 96 | example = [ "203.0.113.42" "2001:DB8::42" ]; | ||
| 97 | description = lib.mdDoc '' | ||
| 98 | Listener IP addresses of relay server. | ||
| 99 | If no IP(s) specified in the config file or in the command line options, | ||
| 100 | then all IPv4 and IPv6 system IPs will be used for listening. | ||
| 101 | ''; | ||
| 102 | }; | ||
| 103 | relay-ips = mkOption { | ||
| 104 | type = types.listOf types.str; | ||
| 105 | default = []; | ||
| 106 | example = [ "203.0.113.42" "2001:DB8::42" ]; | ||
| 107 | description = lib.mdDoc '' | ||
| 108 | Relay address (the local IP address that will be used to relay the | ||
| 109 | packets to the peer). | ||
| 110 | Multiple relay addresses may be used. | ||
| 111 | The same IP(s) can be used as both listening IP(s) and relay IP(s). | ||
| 112 | |||
| 113 | If no relay IP(s) specified, then the turnserver will apply the default | ||
| 114 | policy: it will decide itself which relay addresses to be used, and it | ||
| 115 | will always be using the client socket IP address as the relay IP address | ||
| 116 | of the TURN session (if the requested relay address family is the same | ||
| 117 | as the family of the client socket). | ||
| 118 | ''; | ||
| 119 | }; | ||
| 120 | min-port = mkOption { | ||
| 121 | type = types.int; | ||
| 122 | default = 49152; | ||
| 123 | description = lib.mdDoc '' | ||
| 124 | Lower bound of UDP relay endpoints | ||
| 125 | ''; | ||
| 126 | }; | ||
| 127 | max-port = mkOption { | ||
| 128 | type = types.int; | ||
| 129 | default = 65535; | ||
| 130 | description = lib.mdDoc '' | ||
| 131 | Upper bound of UDP relay endpoints | ||
| 132 | ''; | ||
| 133 | }; | ||
| 134 | lt-cred-mech = mkOption { | ||
| 135 | type = types.bool; | ||
| 136 | default = false; | ||
| 137 | description = lib.mdDoc '' | ||
| 138 | Use long-term credential mechanism. | ||
| 139 | ''; | ||
| 140 | }; | ||
| 141 | no-auth = mkOption { | ||
| 142 | type = types.bool; | ||
| 143 | default = false; | ||
| 144 | description = lib.mdDoc '' | ||
| 145 | This option is opposite to lt-cred-mech. | ||
| 146 | (TURN Server with no-auth option allows anonymous access). | ||
| 147 | If neither option is defined, and no users are defined, | ||
| 148 | then no-auth is default. If at least one user is defined, | ||
| 149 | in this file or in command line or in usersdb file, then | ||
| 150 | lt-cred-mech is default. | ||
| 151 | ''; | ||
| 152 | }; | ||
| 153 | use-auth-secret = mkOption { | ||
| 154 | type = types.bool; | ||
| 155 | default = false; | ||
| 156 | description = lib.mdDoc '' | ||
| 157 | TURN REST API flag. | ||
| 158 | Flag that sets a special authorization option that is based upon authentication secret. | ||
| 159 | This feature can be used with the long-term authentication mechanism, only. | ||
| 160 | This feature purpose is to support "TURN Server REST API", see | ||
| 161 | "TURN REST API" link in the project's page | ||
| 162 | https://github.com/coturn/coturn/ | ||
| 163 | |||
| 164 | This option is used with timestamp: | ||
| 165 | |||
| 166 | usercombo -> "timestamp:userid" | ||
| 167 | turn user -> usercombo | ||
| 168 | turn password -> base64(hmac(secret key, usercombo)) | ||
| 169 | |||
| 170 | This allows TURN credentials to be accounted for a specific user id. | ||
| 171 | If you don't have a suitable id, the timestamp alone can be used. | ||
| 172 | This option is just turning on secret-based authentication. | ||
| 173 | The actual value of the secret is defined either by option static-auth-secret, | ||
| 174 | or can be found in the turn_secret table in the database. | ||
| 175 | ''; | ||
| 176 | }; | ||
| 177 | static-auth-secret = mkOption { | ||
| 178 | type = types.nullOr types.str; | ||
| 179 | default = null; | ||
| 180 | description = lib.mdDoc '' | ||
| 181 | 'Static' authentication secret value (a string) for TURN REST API only. | ||
| 182 | If not set, then the turn server | ||
| 183 | will try to use the 'dynamic' value in turn_secret table | ||
| 184 | in user database (if present). The database-stored value can be changed on-the-fly | ||
| 185 | by a separate program, so this is why that other mode is 'dynamic'. | ||
| 186 | ''; | ||
| 187 | }; | ||
| 188 | static-auth-secret-file = mkOption { | ||
| 189 | type = types.nullOr types.str; | ||
| 190 | default = null; | ||
| 191 | description = lib.mdDoc '' | ||
| 192 | Path to the file containing the static authentication secret. | ||
| 193 | ''; | ||
| 194 | }; | ||
| 195 | realm = mkOption { | ||
| 196 | type = types.str; | ||
| 197 | default = config.networking.hostName; | ||
| 198 | defaultText = literalExpression "config.networking.hostName"; | ||
| 199 | example = "example.com"; | ||
| 200 | description = lib.mdDoc '' | ||
| 201 | The default realm to be used for the users when no explicit | ||
| 202 | origin/realm relationship was found in the database, or if the TURN | ||
| 203 | server is not using any database (just the commands-line settings | ||
| 204 | and the userdb file). Must be used with long-term credentials | ||
| 205 | mechanism or with TURN REST API. | ||
| 206 | ''; | ||
| 207 | }; | ||
| 208 | cert = mkOption { | ||
| 209 | type = types.nullOr types.str; | ||
| 210 | default = null; | ||
| 211 | example = "/var/lib/acme/example.com/fullchain.pem"; | ||
| 212 | description = lib.mdDoc '' | ||
| 213 | Certificate file in PEM format. | ||
| 214 | ''; | ||
| 215 | }; | ||
| 216 | pkey = mkOption { | ||
| 217 | type = types.nullOr types.str; | ||
| 218 | default = null; | ||
| 219 | example = "/var/lib/acme/example.com/key.pem"; | ||
| 220 | description = lib.mdDoc '' | ||
| 221 | Private key file in PEM format. | ||
| 222 | ''; | ||
| 223 | }; | ||
| 224 | dh-file = mkOption { | ||
| 225 | type = types.nullOr types.str; | ||
| 226 | default = null; | ||
| 227 | description = lib.mdDoc '' | ||
| 228 | Use custom DH TLS key, stored in PEM format in the file. | ||
| 229 | ''; | ||
| 230 | }; | ||
| 231 | secure-stun = mkOption { | ||
| 232 | type = types.bool; | ||
| 233 | default = false; | ||
| 234 | description = lib.mdDoc '' | ||
| 235 | Require authentication of the STUN Binding request. | ||
| 236 | By default, the clients are allowed anonymous access to the STUN Binding functionality. | ||
| 237 | ''; | ||
| 238 | }; | ||
| 239 | no-cli = mkOption { | ||
| 240 | type = types.bool; | ||
| 241 | default = false; | ||
| 242 | description = lib.mdDoc '' | ||
| 243 | Turn OFF the CLI support. | ||
| 244 | ''; | ||
| 245 | }; | ||
| 246 | cli-ip = mkOption { | ||
| 247 | type = types.str; | ||
| 248 | default = "127.0.0.1"; | ||
| 249 | description = lib.mdDoc '' | ||
| 250 | Local system IP address to be used for CLI server endpoint. | ||
| 251 | ''; | ||
| 252 | }; | ||
| 253 | cli-port = mkOption { | ||
| 254 | type = types.int; | ||
| 255 | default = 5766; | ||
| 256 | description = lib.mdDoc '' | ||
| 257 | CLI server port. | ||
| 258 | ''; | ||
| 259 | }; | ||
| 260 | cli-password = mkOption { | ||
| 261 | type = types.nullOr types.str; | ||
| 262 | default = null; | ||
| 263 | description = lib.mdDoc '' | ||
| 264 | CLI access password. | ||
| 265 | For the security reasons, it is recommended to use the encrypted | ||
| 266 | for of the password (see the -P command in the turnadmin utility). | ||
| 267 | ''; | ||
| 268 | }; | ||
| 269 | no-udp = mkOption { | ||
| 270 | type = types.bool; | ||
| 271 | default = false; | ||
| 272 | description = lib.mdDoc "Disable UDP client listener"; | ||
| 273 | }; | ||
| 274 | no-tcp = mkOption { | ||
| 275 | type = types.bool; | ||
| 276 | default = false; | ||
| 277 | description = lib.mdDoc "Disable TCP client listener"; | ||
| 278 | }; | ||
| 279 | no-tls = mkOption { | ||
| 280 | type = types.bool; | ||
| 281 | default = false; | ||
| 282 | description = lib.mdDoc "Disable TLS client listener"; | ||
| 283 | }; | ||
| 284 | no-dtls = mkOption { | ||
| 285 | type = types.bool; | ||
| 286 | default = false; | ||
| 287 | description = lib.mdDoc "Disable DTLS client listener"; | ||
| 288 | }; | ||
| 289 | no-udp-relay = mkOption { | ||
| 290 | type = types.bool; | ||
| 291 | default = false; | ||
| 292 | description = lib.mdDoc "Disable UDP relay endpoints"; | ||
| 293 | }; | ||
| 294 | no-tcp-relay = mkOption { | ||
| 295 | type = types.bool; | ||
| 296 | default = false; | ||
| 297 | description = lib.mdDoc "Disable TCP relay endpoints"; | ||
| 298 | }; | ||
| 299 | extraConfig = mkOption { | ||
| 300 | type = types.lines; | ||
| 301 | default = ""; | ||
| 302 | description = lib.mdDoc "Additional configuration options"; | ||
| 303 | }; | ||
| 304 | }; | ||
| 305 | }; | ||
| 306 | |||
| 307 | config = mkIf cfg.enable (mkMerge ([ | ||
| 308 | { assertions = [ | ||
| 309 | { assertion = cfg.static-auth-secret != null -> cfg.static-auth-secret-file == null ; | ||
| 310 | message = "static-auth-secret and static-auth-secret-file cannot be set at the same time"; | ||
| 311 | } | ||
| 312 | ];} | ||
| 313 | |||
| 314 | { | ||
| 315 | users.users.turnserver = | ||
| 316 | { uid = config.ids.uids.turnserver; | ||
| 317 | group = "turnserver"; | ||
| 318 | description = "coturn TURN server user"; | ||
| 319 | }; | ||
| 320 | users.groups.turnserver = | ||
| 321 | { gid = config.ids.gids.turnserver; | ||
| 322 | members = [ "turnserver" ]; | ||
| 323 | }; | ||
| 324 | |||
| 325 | systemd.services.coturn = let | ||
| 326 | runConfig = "/run/coturn/turnserver.cfg"; | ||
| 327 | in { | ||
| 328 | description = "coturn TURN server"; | ||
| 329 | after = [ "network-online.target" ]; | ||
| 330 | wants = [ "network-online.target" ]; | ||
| 331 | wantedBy = [ "multi-user.target" ]; | ||
| 332 | |||
| 333 | unitConfig = { | ||
| 334 | Documentation = "man:coturn(1) man:turnadmin(1) man:turnserver(1)"; | ||
| 335 | }; | ||
| 336 | |||
| 337 | script = '' | ||
| 338 | cat ${configFile} > ${runConfig} | ||
| 339 | ${optionalString (cfg.static-auth-secret-file != null) '' | ||
| 340 | ${pkgs.replace-secret}/bin/replace-secret \ | ||
| 341 | "#static-auth-secret#" \ | ||
| 342 | ${cfg.static-auth-secret-file} \ | ||
| 343 | ${runConfig} | ||
| 344 | '' } | ||
| 345 | chmod 640 ${runConfig} | ||
| 346 | |||
| 347 | exec ${pkgs.coturn}/bin/turnserver -c ${runConfig} | ||
| 348 | ''; | ||
| 349 | serviceConfig = { | ||
| 350 | Type = "simple"; | ||
| 351 | RuntimeDirectory = "turnserver"; | ||
| 352 | User = "turnserver"; | ||
| 353 | Group = "turnserver"; | ||
| 354 | AmbientCapabilities = | ||
| 355 | mkIf ( | ||
| 356 | cfg.listening-port < 1024 || | ||
| 357 | cfg.alt-listening-port < 1024 || | ||
| 358 | cfg.tls-listening-port < 1024 || | ||
| 359 | cfg.alt-tls-listening-port < 1024 || | ||
| 360 | cfg.min-port < 1024 | ||
| 361 | ) "cap_net_bind_service"; | ||
| 362 | Restart = "on-abort"; | ||
| 363 | }; | ||
| 364 | }; | ||
| 365 | systemd.tmpfiles.rules = [ | ||
| 366 | "d /run/coturn 0700 turnserver turnserver - -" | ||
| 367 | ]; | ||
| 368 | }])); | ||
| 369 | } | ||
diff --git a/modules/zfssnap/default.nix b/modules/zfssnap/default.nix index f6f32852..23041c36 100644 --- a/modules/zfssnap/default.nix +++ b/modules/zfssnap/default.nix | |||
| @@ -27,19 +27,27 @@ in { | |||
| 27 | enable = mkEnableOption "zfssnap service"; | 27 | enable = mkEnableOption "zfssnap service"; |
| 28 | 28 | ||
| 29 | config = mkOption { | 29 | config = mkOption { |
| 30 | type = with types; attrsOf (attrsOf str); | 30 | type = types.submodule { |
| 31 | default = { | 31 | options = { |
| 32 | keep = { | 32 | keep = mkOption { |
| 33 | within = "15m"; | 33 | type = with types; attrsOf str; |
| 34 | "5m" = "48"; | 34 | default = { |
| 35 | "15m" = "32"; | 35 | within = "15m"; |
| 36 | hourly = "48"; | 36 | "5m" = "48"; |
| 37 | "4h" = "24"; | 37 | "15m" = "32"; |
| 38 | "12h" = "12"; | 38 | hourly = "48"; |
| 39 | daily = "62"; | 39 | "4h" = "24"; |
| 40 | halfweekly = "32"; | 40 | "12h" = "12"; |
| 41 | weekly = "24"; | 41 | daily = "62"; |
| 42 | monthly = "-1"; | 42 | halfweekly = "32"; |
| 43 | weekly = "24"; | ||
| 44 | monthly = "-1"; | ||
| 45 | }; | ||
| 46 | }; | ||
| 47 | exec = mkOption { | ||
| 48 | type = with types; attrsOf str; | ||
| 49 | default = {}; | ||
| 50 | }; | ||
| 43 | }; | 51 | }; |
| 44 | }; | 52 | }; |
| 45 | }; | 53 | }; |
