at 23.05-pre 29 kB view raw
1{ lib, pkgs, config, options, ... }: 2 3let 4 cfg = config.services.peertube; 5 opt = options.services.peertube; 6 7 settingsFormat = pkgs.formats.json {}; 8 configFile = settingsFormat.generate "production.json" cfg.settings; 9 10 env = { 11 NODE_CONFIG_DIR = "/var/lib/peertube/config"; 12 NODE_ENV = "production"; 13 NODE_EXTRA_CA_CERTS = "/etc/ssl/certs/ca-certificates.crt"; 14 NPM_CONFIG_CACHE = "/var/cache/peertube/.npm"; 15 NPM_CONFIG_PREFIX = cfg.package; 16 HOME = cfg.package; 17 }; 18 19 systemCallsList = [ "@cpu-emulation" "@debug" "@keyring" "@ipc" "@memlock" "@mount" "@obsolete" "@privileged" "@setuid" ]; 20 21 cfgService = { 22 # Proc filesystem 23 ProcSubset = "pid"; 24 ProtectProc = "invisible"; 25 # Access write directories 26 UMask = "0027"; 27 # Capabilities 28 CapabilityBoundingSet = ""; 29 # Security 30 NoNewPrivileges = true; 31 # Sandboxing 32 ProtectSystem = "strict"; 33 ProtectHome = true; 34 PrivateTmp = true; 35 PrivateDevices = true; 36 PrivateUsers = true; 37 ProtectClock = true; 38 ProtectHostname = true; 39 ProtectKernelLogs = true; 40 ProtectKernelModules = true; 41 ProtectKernelTunables = true; 42 ProtectControlGroups = true; 43 RestrictNamespaces = true; 44 LockPersonality = true; 45 RestrictRealtime = true; 46 RestrictSUIDSGID = true; 47 RemoveIPC = true; 48 PrivateMounts = true; 49 # System Call Filtering 50 SystemCallArchitectures = "native"; 51 }; 52 53 envFile = pkgs.writeText "peertube.env" (lib.concatMapStrings (s: s + "\n") ( 54 (lib.concatLists (lib.mapAttrsToList (name: value: 55 if value != null then [ 56 "${name}=\"${toString value}\"" 57 ] else [] 58 ) env)))); 59 60 peertubeEnv = pkgs.writeShellScriptBin "peertube-env" '' 61 set -a 62 source "${envFile}" 63 eval -- "\$@" 64 ''; 65 66 peertubeCli = pkgs.writeShellScriptBin "peertube" '' 67 node ~/dist/server/tools/peertube.js $@ 68 ''; 69 70 nginxCommonHeaders = lib.optionalString cfg.enableWebHttps '' 71 add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains'; 72 '' + lib.optionalString config.services.nginx.virtualHosts.${cfg.localDomain}.http3 '' 73 add_header Alt-Svc 'h3=":443"; ma=86400'; 74 '' + '' 75 add_header Access-Control-Allow-Origin '*'; 76 add_header Access-Control-Allow-Methods 'GET, OPTIONS'; 77 add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; 78 ''; 79 80in { 81 options.services.peertube = { 82 enable = lib.mkEnableOption (lib.mdDoc "Peertube"); 83 84 user = lib.mkOption { 85 type = lib.types.str; 86 default = "peertube"; 87 description = lib.mdDoc "User account under which Peertube runs."; 88 }; 89 90 group = lib.mkOption { 91 type = lib.types.str; 92 default = "peertube"; 93 description = lib.mdDoc "Group under which Peertube runs."; 94 }; 95 96 localDomain = lib.mkOption { 97 type = lib.types.str; 98 example = "peertube.example.com"; 99 description = lib.mdDoc "The domain serving your PeerTube instance."; 100 }; 101 102 listenHttp = lib.mkOption { 103 type = lib.types.port; 104 default = 9000; 105 description = lib.mdDoc "listen port for HTTP server."; 106 }; 107 108 listenWeb = lib.mkOption { 109 type = lib.types.port; 110 default = 9000; 111 description = lib.mdDoc "listen port for WEB server."; 112 }; 113 114 enableWebHttps = lib.mkOption { 115 type = lib.types.bool; 116 default = false; 117 description = lib.mdDoc "Enable or disable HTTPS protocol."; 118 }; 119 120 dataDirs = lib.mkOption { 121 type = lib.types.listOf lib.types.path; 122 default = [ ]; 123 example = [ "/opt/peertube/storage" "/var/cache/peertube" ]; 124 description = lib.mdDoc "Allow access to custom data locations."; 125 }; 126 127 serviceEnvironmentFile = lib.mkOption { 128 type = lib.types.nullOr lib.types.path; 129 default = null; 130 example = "/run/keys/peertube/password-init-root"; 131 description = lib.mdDoc '' 132 Set environment variables for the service. Mainly useful for setting the initial root password. 133 For example write to file: 134 PT_INITIAL_ROOT_PASSWORD=changeme 135 ''; 136 }; 137 138 settings = lib.mkOption { 139 type = settingsFormat.type; 140 example = lib.literalExpression '' 141 { 142 listen = { 143 hostname = "0.0.0.0"; 144 }; 145 log = { 146 level = "debug"; 147 }; 148 storage = { 149 tmp = "/opt/data/peertube/storage/tmp/"; 150 logs = "/opt/data/peertube/storage/logs/"; 151 cache = "/opt/data/peertube/storage/cache/"; 152 }; 153 } 154 ''; 155 description = lib.mdDoc "Configuration for peertube."; 156 }; 157 158 configureNginx = lib.mkOption { 159 type = lib.types.bool; 160 default = false; 161 description = lib.mdDoc "Configure nginx as a reverse proxy for peertube."; 162 }; 163 164 database = { 165 createLocally = lib.mkOption { 166 type = lib.types.bool; 167 default = false; 168 description = lib.mdDoc "Configure local PostgreSQL database server for PeerTube."; 169 }; 170 171 host = lib.mkOption { 172 type = lib.types.str; 173 default = if cfg.database.createLocally then "/run/postgresql" else null; 174 defaultText = lib.literalExpression '' 175 if config.${opt.database.createLocally} 176 then "/run/postgresql" 177 else null 178 ''; 179 example = "192.168.15.47"; 180 description = lib.mdDoc "Database host address or unix socket."; 181 }; 182 183 port = lib.mkOption { 184 type = lib.types.port; 185 default = 5432; 186 description = lib.mdDoc "Database host port."; 187 }; 188 189 name = lib.mkOption { 190 type = lib.types.str; 191 default = "peertube"; 192 description = lib.mdDoc "Database name."; 193 }; 194 195 user = lib.mkOption { 196 type = lib.types.str; 197 default = "peertube"; 198 description = lib.mdDoc "Database user."; 199 }; 200 201 passwordFile = lib.mkOption { 202 type = lib.types.nullOr lib.types.path; 203 default = null; 204 example = "/run/keys/peertube/password-posgressql-db"; 205 description = lib.mdDoc "Password for PostgreSQL database."; 206 }; 207 }; 208 209 redis = { 210 createLocally = lib.mkOption { 211 type = lib.types.bool; 212 default = false; 213 description = lib.mdDoc "Configure local Redis server for PeerTube."; 214 }; 215 216 host = lib.mkOption { 217 type = lib.types.nullOr lib.types.str; 218 default = if cfg.redis.createLocally && !cfg.redis.enableUnixSocket then "127.0.0.1" else null; 219 defaultText = lib.literalExpression '' 220 if config.${opt.redis.createLocally} && !config.${opt.redis.enableUnixSocket} 221 then "127.0.0.1" 222 else null 223 ''; 224 description = lib.mdDoc "Redis host."; 225 }; 226 227 port = lib.mkOption { 228 type = lib.types.nullOr lib.types.port; 229 default = if cfg.redis.createLocally && cfg.redis.enableUnixSocket then null else 31638; 230 defaultText = lib.literalExpression '' 231 if config.${opt.redis.createLocally} && config.${opt.redis.enableUnixSocket} 232 then null 233 else 6379 234 ''; 235 description = lib.mdDoc "Redis port."; 236 }; 237 238 passwordFile = lib.mkOption { 239 type = lib.types.nullOr lib.types.path; 240 default = null; 241 example = "/run/keys/peertube/password-redis-db"; 242 description = lib.mdDoc "Password for redis database."; 243 }; 244 245 enableUnixSocket = lib.mkOption { 246 type = lib.types.bool; 247 default = cfg.redis.createLocally; 248 defaultText = lib.literalExpression "config.${opt.redis.createLocally}"; 249 description = lib.mdDoc "Use Unix socket."; 250 }; 251 }; 252 253 smtp = { 254 createLocally = lib.mkOption { 255 type = lib.types.bool; 256 default = false; 257 description = lib.mdDoc "Configure local Postfix SMTP server for PeerTube."; 258 }; 259 260 passwordFile = lib.mkOption { 261 type = lib.types.nullOr lib.types.path; 262 default = null; 263 example = "/run/keys/peertube/password-smtp"; 264 description = lib.mdDoc "Password for smtp server."; 265 }; 266 }; 267 268 package = lib.mkOption { 269 type = lib.types.package; 270 default = pkgs.peertube; 271 defaultText = lib.literalExpression "pkgs.peertube"; 272 description = lib.mdDoc "Peertube package to use."; 273 }; 274 }; 275 276 config = lib.mkIf cfg.enable { 277 assertions = [ 278 { assertion = cfg.serviceEnvironmentFile == null || !lib.hasPrefix builtins.storeDir cfg.serviceEnvironmentFile; 279 message = '' 280 <option>services.peertube.serviceEnvironmentFile</option> points to 281 a file in the Nix store. You should use a quoted absolute path to 282 prevent this. 283 ''; 284 } 285 { assertion = !(cfg.redis.enableUnixSocket && (cfg.redis.host != null || cfg.redis.port != null)); 286 message = '' 287 <option>services.peertube.redis.createLocally</option> and redis network connection (<option>services.peertube.redis.host</option> or <option>services.peertube.redis.port</option>) enabled. Disable either of them. 288 ''; 289 } 290 { assertion = cfg.redis.enableUnixSocket || (cfg.redis.host != null && cfg.redis.port != null); 291 message = '' 292 <option>services.peertube.redis.host</option> and <option>services.peertube.redis.port</option> needs to be set if <option>services.peertube.redis.enableUnixSocket</option> is not enabled. 293 ''; 294 } 295 { assertion = cfg.redis.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.redis.passwordFile; 296 message = '' 297 <option>services.peertube.redis.passwordFile</option> points to 298 a file in the Nix store. You should use a quoted absolute path to 299 prevent this. 300 ''; 301 } 302 { assertion = cfg.database.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.database.passwordFile; 303 message = '' 304 <option>services.peertube.database.passwordFile</option> points to 305 a file in the Nix store. You should use a quoted absolute path to 306 prevent this. 307 ''; 308 } 309 { assertion = cfg.smtp.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.smtp.passwordFile; 310 message = '' 311 <option>services.peertube.smtp.passwordFile</option> points to 312 a file in the Nix store. You should use a quoted absolute path to 313 prevent this. 314 ''; 315 } 316 ]; 317 318 services.peertube.settings = lib.mkMerge [ 319 { 320 listen = { 321 port = cfg.listenHttp; 322 }; 323 webserver = { 324 https = (if cfg.enableWebHttps then true else false); 325 hostname = "${cfg.localDomain}"; 326 port = cfg.listenWeb; 327 }; 328 database = { 329 hostname = "${cfg.database.host}"; 330 port = cfg.database.port; 331 name = "${cfg.database.name}"; 332 username = "${cfg.database.user}"; 333 }; 334 redis = { 335 hostname = "${toString cfg.redis.host}"; 336 port = (if cfg.redis.port == null then "" else cfg.redis.port); 337 }; 338 storage = { 339 tmp = lib.mkDefault "/var/lib/peertube/storage/tmp/"; 340 bin = lib.mkDefault "/var/lib/peertube/storage/bin/"; 341 avatars = lib.mkDefault "/var/lib/peertube/storage/avatars/"; 342 videos = lib.mkDefault "/var/lib/peertube/storage/videos/"; 343 streaming_playlists = lib.mkDefault "/var/lib/peertube/storage/streaming-playlists/"; 344 redundancy = lib.mkDefault "/var/lib/peertube/storage/redundancy/"; 345 logs = lib.mkDefault "/var/lib/peertube/storage/logs/"; 346 previews = lib.mkDefault "/var/lib/peertube/storage/previews/"; 347 thumbnails = lib.mkDefault "/var/lib/peertube/storage/thumbnails/"; 348 torrents = lib.mkDefault "/var/lib/peertube/storage/torrents/"; 349 captions = lib.mkDefault "/var/lib/peertube/storage/captions/"; 350 cache = lib.mkDefault "/var/lib/peertube/storage/cache/"; 351 plugins = lib.mkDefault "/var/lib/peertube/storage/plugins/"; 352 client_overrides = lib.mkDefault "/var/lib/peertube/storage/client-overrides/"; 353 }; 354 import = { 355 videos = { 356 http = { 357 youtube_dl_release = { 358 python_path = "${pkgs.python3}/bin/python"; 359 }; 360 }; 361 }; 362 }; 363 } 364 (lib.mkIf cfg.redis.enableUnixSocket { redis = { socket = "/run/redis-peertube/redis.sock"; }; }) 365 ]; 366 367 systemd.tmpfiles.rules = [ 368 "d '/var/lib/peertube/config' 0700 ${cfg.user} ${cfg.group} - -" 369 "z '/var/lib/peertube/config' 0700 ${cfg.user} ${cfg.group} - -" 370 "d '/var/lib/peertube/www' 0750 ${cfg.user} ${cfg.group} - -" 371 "z '/var/lib/peertube/www' 0750 ${cfg.user} ${cfg.group} - -" 372 ]; 373 374 systemd.services.peertube-init-db = lib.mkIf cfg.database.createLocally { 375 description = "Initialization database for PeerTube daemon"; 376 after = [ "network.target" "postgresql.service" ]; 377 requires = [ "postgresql.service" ]; 378 379 script = let 380 psqlSetupCommands = pkgs.writeText "peertube-init.sql" '' 381 SELECT 'CREATE USER "${cfg.database.user}"' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${cfg.database.user}')\gexec 382 SELECT 'CREATE DATABASE "${cfg.database.name}" OWNER "${cfg.database.user}" TEMPLATE template0 ENCODING UTF8' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${cfg.database.name}')\gexec 383 \c '${cfg.database.name}' 384 CREATE EXTENSION IF NOT EXISTS pg_trgm; 385 CREATE EXTENSION IF NOT EXISTS unaccent; 386 ''; 387 in "${config.services.postgresql.package}/bin/psql -f ${psqlSetupCommands}"; 388 389 serviceConfig = { 390 Type = "oneshot"; 391 WorkingDirectory = cfg.package; 392 # User and group 393 User = "postgres"; 394 Group = "postgres"; 395 # Sandboxing 396 RestrictAddressFamilies = [ "AF_UNIX" ]; 397 MemoryDenyWriteExecute = true; 398 # System Call Filtering 399 SystemCallFilter = "~" + lib.concatStringsSep " " (systemCallsList ++ [ "@resources" ]); 400 } // cfgService; 401 }; 402 403 systemd.services.peertube = { 404 description = "PeerTube daemon"; 405 after = [ "network.target" ] 406 ++ lib.optional cfg.redis.createLocally "redis-peertube.service" 407 ++ lib.optionals cfg.database.createLocally [ "postgresql.service" "peertube-init-db.service" ]; 408 requires = lib.optional cfg.redis.createLocally "redis-peertube.service" 409 ++ lib.optionals cfg.database.createLocally [ "postgresql.service" "peertube-init-db.service" ]; 410 wantedBy = [ "multi-user.target" ]; 411 412 environment = env; 413 414 path = with pkgs; [ bashInteractive ffmpeg nodejs-16_x openssl yarn python3 ]; 415 416 script = '' 417 #!/bin/sh 418 umask 077 419 cat > /var/lib/peertube/config/local.yaml <<EOF 420 ${lib.optionalString ((!cfg.database.createLocally) && (cfg.database.passwordFile != null)) '' 421 database: 422 password: '$(cat ${cfg.database.passwordFile})' 423 ''} 424 ${lib.optionalString (cfg.redis.passwordFile != null) '' 425 redis: 426 auth: '$(cat ${cfg.redis.passwordFile})' 427 ''} 428 ${lib.optionalString (cfg.smtp.passwordFile != null) '' 429 smtp: 430 password: '$(cat ${cfg.smtp.passwordFile})' 431 ''} 432 EOF 433 umask 027 434 ln -sf ${configFile} /var/lib/peertube/config/production.json 435 ln -sf ${cfg.package}/config/default.yaml /var/lib/peertube/config/default.yaml 436 ln -sf ${cfg.package}/client/dist -T /var/lib/peertube/www/client 437 ln -sf ${cfg.settings.storage.client_overrides} -T /var/lib/peertube/www/client-overrides 438 npm start 439 ''; 440 serviceConfig = { 441 Type = "simple"; 442 Restart = "always"; 443 RestartSec = 20; 444 TimeoutSec = 60; 445 WorkingDirectory = cfg.package; 446 # User and group 447 User = cfg.user; 448 Group = cfg.group; 449 # State directory and mode 450 StateDirectory = "peertube"; 451 StateDirectoryMode = "0750"; 452 # Cache directory and mode 453 CacheDirectory = "peertube"; 454 CacheDirectoryMode = "0750"; 455 # Access write directories 456 ReadWritePaths = cfg.dataDirs; 457 # Environment 458 EnvironmentFile = cfg.serviceEnvironmentFile; 459 # Sandboxing 460 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ]; 461 MemoryDenyWriteExecute = false; 462 # System Call Filtering 463 SystemCallFilter = [ ("~" + lib.concatStringsSep " " systemCallsList) "pipe" "pipe2" ]; 464 } // cfgService; 465 }; 466 467 services.nginx = lib.mkIf cfg.configureNginx { 468 enable = true; 469 virtualHosts."${cfg.localDomain}" = { 470 root = "/var/lib/peertube"; 471 472 # Application 473 locations."/" = { 474 tryFiles = "/dev/null @api"; 475 priority = 1110; 476 }; 477 478 locations."= /api/v1/videos/upload-resumable" = { 479 tryFiles = "/dev/null @api"; 480 priority = 1120; 481 482 extraConfig = '' 483 client_max_body_size 0; 484 proxy_request_buffering off; 485 ''; 486 }; 487 488 locations."~ ^/api/v1/videos/(upload|([^/]+/studio/edit))$" = { 489 tryFiles = "/dev/null @api"; 490 root = cfg.settings.storage.tmp; 491 priority = 1130; 492 493 extraConfig = '' 494 client_max_body_size 12G; 495 add_header X-File-Maximum-Size 8G always; 496 '' + lib.optionalString cfg.enableWebHttps '' 497 add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains'; 498 '' + lib.optionalString config.services.nginx.virtualHosts.${cfg.localDomain}.http3 '' 499 add_header Alt-Svc 'h3=":443"; ma=86400'; 500 ''; 501 }; 502 503 locations."~ ^/api/v1/(videos|video-playlists|video-channels|users/me)" = { 504 tryFiles = "/dev/null @api"; 505 priority = 1140; 506 507 extraConfig = '' 508 client_max_body_size 6M; 509 add_header X-File-Maximum-Size 4M always; 510 '' + lib.optionalString cfg.enableWebHttps '' 511 add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains'; 512 '' + lib.optionalString config.services.nginx.virtualHosts.${cfg.localDomain}.http3 '' 513 add_header Alt-Svc 'h3=":443"; ma=86400'; 514 ''; 515 }; 516 517 locations."@api" = { 518 proxyPass = "http://127.0.0.1:${toString cfg.listenHttp}"; 519 priority = 1150; 520 521 extraConfig = '' 522 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 523 proxy_set_header Host $host; 524 proxy_set_header X-Real-IP $remote_addr; 525 526 proxy_connect_timeout 10m; 527 528 proxy_send_timeout 10m; 529 proxy_read_timeout 10m; 530 531 client_max_body_size 100k; 532 send_timeout 10m; 533 ''; 534 }; 535 536 # Websocket 537 locations."/socket.io" = { 538 tryFiles = "/dev/null @api_websocket"; 539 priority = 1210; 540 }; 541 542 locations."/tracker/socket" = { 543 tryFiles = "/dev/null @api_websocket"; 544 priority = 1220; 545 546 extraConfig = '' 547 proxy_read_timeout 15m; 548 ''; 549 }; 550 551 locations."@api_websocket" = { 552 proxyPass = "http://127.0.0.1:${toString cfg.listenHttp}"; 553 priority = 1230; 554 555 extraConfig = '' 556 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 557 proxy_set_header Host $host; 558 proxy_set_header X-Real-IP $remote_addr; 559 proxy_set_header Upgrade $http_upgrade; 560 proxy_set_header Connection 'upgrade'; 561 562 proxy_http_version 1.1; 563 ''; 564 }; 565 566 # Bypass PeerTube for performance reasons. 567 locations."~ ^/client/(assets/images/(icons/icon-36x36\.png|icons/icon-48x48\.png|icons/icon-72x72\.png|icons/icon-96x96\.png|icons/icon-144x144\.png|icons/icon-192x192\.png|icons/icon-512x512\.png|logo\.svg|favicon\.png|default-playlist\.jpg|default-avatar-account\.png|default-avatar-account-48x48\.png|default-avatar-video-channel\.png|default-avatar-video-channel-48x48\.png))$" = { 568 tryFiles = "/www/client-overrides/$1 /www/client/$1 $1"; 569 priority = 1310; 570 }; 571 572 locations."~ ^/client/(.*\.(js|css|png|svg|woff2|otf|ttf|woff|eot))$" = { 573 alias = "${cfg.package}/client/dist/$1"; 574 priority = 1320; 575 extraConfig = '' 576 add_header Cache-Control 'public, max-age=604800, immutable'; 577 '' + lib.optionalString cfg.enableWebHttps '' 578 add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains'; 579 '' + lib.optionalString config.services.nginx.virtualHosts.${cfg.localDomain}.http3 '' 580 add_header Alt-Svc 'h3=":443"; ma=86400'; 581 ''; 582 }; 583 584 locations."~ ^/lazy-static/(avatars|banners)/" = { 585 tryFiles = "$uri @api"; 586 root = cfg.settings.storage.avatars; 587 priority = 1330; 588 extraConfig = '' 589 if ($request_method = 'OPTIONS') { 590 ${nginxCommonHeaders} 591 add_header Access-Control-Max-Age 1728000; 592 add_header Cache-Control 'no-cache'; 593 add_header Content-Type 'text/plain charset=UTF-8'; 594 add_header Content-Length 0; 595 return 204; 596 } 597 598 ${nginxCommonHeaders} 599 add_header Cache-Control 'public, max-age=7200'; 600 601 rewrite ^/lazy-static/avatars/(.*)$ /$1 break; 602 rewrite ^/lazy-static/banners/(.*)$ /$1 break; 603 ''; 604 }; 605 606 locations."^~ /lazy-static/previews/" = { 607 tryFiles = "$uri @api"; 608 root = cfg.settings.storage.previews; 609 priority = 1340; 610 extraConfig = '' 611 if ($request_method = 'OPTIONS') { 612 ${nginxCommonHeaders} 613 add_header Access-Control-Max-Age 1728000; 614 add_header Cache-Control 'no-cache'; 615 add_header Content-Type 'text/plain charset=UTF-8'; 616 add_header Content-Length 0; 617 return 204; 618 } 619 620 ${nginxCommonHeaders} 621 add_header Cache-Control 'public, max-age=7200'; 622 623 rewrite ^/lazy-static/previews/(.*)$ /$1 break; 624 ''; 625 }; 626 627 locations."^~ /static/thumbnails/" = { 628 tryFiles = "$uri @api"; 629 root = cfg.settings.storage.thumbnails; 630 priority = 1350; 631 extraConfig = '' 632 if ($request_method = 'OPTIONS') { 633 ${nginxCommonHeaders} 634 add_header Access-Control-Max-Age 1728000; 635 add_header Cache-Control 'no-cache'; 636 add_header Content-Type 'text/plain charset=UTF-8'; 637 add_header Content-Length 0; 638 return 204; 639 } 640 641 ${nginxCommonHeaders} 642 add_header Cache-Control 'public, max-age=7200'; 643 644 rewrite ^/static/thumbnails/(.*)$ /$1 break; 645 ''; 646 }; 647 648 locations."^~ /static/redundancy/" = { 649 tryFiles = "$uri @api"; 650 root = cfg.settings.storage.redundancy; 651 priority = 1360; 652 extraConfig = '' 653 if ($request_method = 'OPTIONS') { 654 ${nginxCommonHeaders} 655 add_header Access-Control-Max-Age 1728000; 656 add_header Content-Type 'text/plain charset=UTF-8'; 657 add_header Content-Length 0; 658 return 204; 659 } 660 if ($request_method = 'GET') { 661 ${nginxCommonHeaders} 662 663 access_log off; 664 } 665 aio threads; 666 sendfile on; 667 sendfile_max_chunk 1M; 668 669 limit_rate_after 5M; 670 671 set $peertube_limit_rate 800k; 672 set $limit_rate $peertube_limit_rate; 673 674 rewrite ^/static/redundancy/(.*)$ /$1 break; 675 ''; 676 }; 677 678 locations."^~ /static/streaming-playlists/" = { 679 tryFiles = "$uri @api"; 680 root = cfg.settings.storage.streaming_playlists; 681 priority = 1370; 682 extraConfig = '' 683 if ($request_method = 'OPTIONS') { 684 ${nginxCommonHeaders} 685 add_header Access-Control-Max-Age 1728000; 686 add_header Content-Type 'text/plain charset=UTF-8'; 687 add_header Content-Length 0; 688 return 204; 689 } 690 if ($request_method = 'GET') { 691 ${nginxCommonHeaders} 692 693 access_log off; 694 } 695 696 aio threads; 697 sendfile on; 698 sendfile_max_chunk 1M; 699 700 limit_rate_after 5M; 701 702 set $peertube_limit_rate 5M; 703 set $limit_rate $peertube_limit_rate; 704 705 rewrite ^/static/streaming-playlists/(.*)$ /$1 break; 706 ''; 707 }; 708 709 locations."~ ^/static/webseed/" = { 710 tryFiles = "$uri @api"; 711 root = cfg.settings.storage.videos; 712 priority = 1380; 713 extraConfig = '' 714 if ($request_method = 'OPTIONS') { 715 ${nginxCommonHeaders} 716 add_header Access-Control-Max-Age 1728000; 717 add_header Content-Type 'text/plain charset=UTF-8'; 718 add_header Content-Length 0; 719 return 204; 720 } 721 if ($request_method = 'GET') { 722 ${nginxCommonHeaders} 723 724 access_log off; 725 } 726 727 aio threads; 728 sendfile on; 729 sendfile_max_chunk 1M; 730 731 limit_rate_after 5M; 732 733 set $peertube_limit_rate 800k; 734 set $limit_rate $peertube_limit_rate; 735 736 rewrite ^/static/webseed/(.*)$ /$1 break; 737 ''; 738 }; 739 740 extraConfig = lib.optionalString cfg.enableWebHttps '' 741 add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains'; 742 ''; 743 }; 744 }; 745 746 services.postgresql = lib.mkIf cfg.database.createLocally { 747 enable = true; 748 }; 749 750 services.redis.servers.peertube = lib.mkMerge [ 751 (lib.mkIf cfg.redis.createLocally { 752 enable = true; 753 }) 754 (lib.mkIf (cfg.redis.createLocally && !cfg.redis.enableUnixSocket) { 755 bind = "127.0.0.1"; 756 port = cfg.redis.port; 757 }) 758 (lib.mkIf (cfg.redis.createLocally && cfg.redis.enableUnixSocket) { 759 unixSocket = "/run/redis-peertube/redis.sock"; 760 unixSocketPerm = 660; 761 }) 762 ]; 763 764 services.postfix = lib.mkIf cfg.smtp.createLocally { 765 enable = true; 766 hostname = lib.mkDefault "${cfg.localDomain}"; 767 }; 768 769 users.users = lib.mkMerge [ 770 (lib.mkIf (cfg.user == "peertube") { 771 peertube = { 772 isSystemUser = true; 773 group = cfg.group; 774 home = cfg.package; 775 }; 776 }) 777 (lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ cfg.package peertubeEnv peertubeCli pkgs.ffmpeg pkgs.nodejs-16_x pkgs.yarn ]) 778 (lib.mkIf cfg.redis.enableUnixSocket {${config.services.peertube.user}.extraGroups = [ "redis-peertube" ];}) 779 ]; 780 781 users.groups = { 782 ${cfg.group} = { 783 members = lib.optional cfg.configureNginx config.services.nginx.user; 784 }; 785 }; 786 }; 787}