at 24.11-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 lib.optional (value != null) ''${name}="${toString value}"'' 56 ) env)))); 57 58 peertubeEnv = pkgs.writeShellScriptBin "peertube-env" '' 59 set -a 60 source "${envFile}" 61 eval -- "\$@" 62 ''; 63 64 nginxCommonHeaders = lib.optionalString config.services.nginx.virtualHosts.${cfg.localDomain}.forceSSL '' 65 add_header Strict-Transport-Security 'max-age=31536000'; 66 '' + lib.optionalString (config.services.nginx.virtualHosts.${cfg.localDomain}.quic && config.services.nginx.virtualHosts.${cfg.localDomain}.http3) '' 67 add_header Alt-Svc 'h3=":$server_port"; ma=604800'; 68 ''; 69 70 nginxCommonHeadersExtra = '' 71 add_header Access-Control-Allow-Origin '*'; 72 add_header Access-Control-Allow-Methods 'GET, OPTIONS'; 73 add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; 74 ''; 75 76in { 77 options.services.peertube = { 78 enable = lib.mkEnableOption "Peertube"; 79 80 user = lib.mkOption { 81 type = lib.types.str; 82 default = "peertube"; 83 description = "User account under which Peertube runs."; 84 }; 85 86 group = lib.mkOption { 87 type = lib.types.str; 88 default = "peertube"; 89 description = "Group under which Peertube runs."; 90 }; 91 92 localDomain = lib.mkOption { 93 type = lib.types.str; 94 example = "peertube.example.com"; 95 description = "The domain serving your PeerTube instance."; 96 }; 97 98 listenHttp = lib.mkOption { 99 type = lib.types.port; 100 default = 9000; 101 description = "The port that the local PeerTube web server will listen on."; 102 }; 103 104 listenWeb = lib.mkOption { 105 type = lib.types.port; 106 default = 9000; 107 description = "The public-facing port that PeerTube will be accessible at (likely 80 or 443 if running behind a reverse proxy). Clients will try to access PeerTube at this port."; 108 }; 109 110 enableWebHttps = lib.mkOption { 111 type = lib.types.bool; 112 default = false; 113 description = "Whether clients will access your PeerTube instance with HTTPS. Does NOT configure the PeerTube webserver itself to listen for incoming HTTPS connections."; 114 }; 115 116 dataDirs = lib.mkOption { 117 type = lib.types.listOf lib.types.path; 118 default = [ ]; 119 example = [ "/opt/peertube/storage" "/var/cache/peertube" ]; 120 description = "Allow access to custom data locations."; 121 }; 122 123 serviceEnvironmentFile = lib.mkOption { 124 type = lib.types.nullOr lib.types.path; 125 default = null; 126 example = "/run/keys/peertube/password-init-root"; 127 description = '' 128 Set environment variables for the service. Mainly useful for setting the initial root password. 129 For example write to file: 130 PT_INITIAL_ROOT_PASSWORD=changeme 131 ''; 132 }; 133 134 settings = lib.mkOption { 135 type = settingsFormat.type; 136 example = lib.literalExpression '' 137 { 138 listen = { 139 hostname = "0.0.0.0"; 140 }; 141 log = { 142 level = "debug"; 143 }; 144 storage = { 145 tmp = "/opt/data/peertube/storage/tmp/"; 146 logs = "/opt/data/peertube/storage/logs/"; 147 cache = "/opt/data/peertube/storage/cache/"; 148 }; 149 } 150 ''; 151 description = "Configuration for peertube."; 152 }; 153 154 configureNginx = lib.mkOption { 155 type = lib.types.bool; 156 default = false; 157 description = "Configure nginx as a reverse proxy for peertube."; 158 }; 159 160 secrets = { 161 secretsFile = lib.mkOption { 162 type = lib.types.nullOr lib.types.path; 163 default = null; 164 example = "/run/secrets/peertube"; 165 description = '' 166 Secrets to run PeerTube. 167 Generate one using `openssl rand -hex 32` 168 ''; 169 }; 170 }; 171 172 database = { 173 createLocally = lib.mkOption { 174 type = lib.types.bool; 175 default = false; 176 description = "Configure local PostgreSQL database server for PeerTube."; 177 }; 178 179 host = lib.mkOption { 180 type = lib.types.str; 181 default = if cfg.database.createLocally then "/run/postgresql" else null; 182 defaultText = lib.literalExpression '' 183 if config.${opt.database.createLocally} 184 then "/run/postgresql" 185 else null 186 ''; 187 example = "192.168.15.47"; 188 description = "Database host address or unix socket."; 189 }; 190 191 port = lib.mkOption { 192 type = lib.types.port; 193 default = 5432; 194 description = "Database host port."; 195 }; 196 197 name = lib.mkOption { 198 type = lib.types.str; 199 default = "peertube"; 200 description = "Database name."; 201 }; 202 203 user = lib.mkOption { 204 type = lib.types.str; 205 default = "peertube"; 206 description = "Database user."; 207 }; 208 209 passwordFile = lib.mkOption { 210 type = lib.types.nullOr lib.types.path; 211 default = null; 212 example = "/run/keys/peertube/password-postgresql"; 213 description = "Password for PostgreSQL database."; 214 }; 215 }; 216 217 redis = { 218 createLocally = lib.mkOption { 219 type = lib.types.bool; 220 default = false; 221 description = "Configure local Redis server for PeerTube."; 222 }; 223 224 host = lib.mkOption { 225 type = lib.types.nullOr lib.types.str; 226 default = if cfg.redis.createLocally && !cfg.redis.enableUnixSocket then "127.0.0.1" else null; 227 defaultText = lib.literalExpression '' 228 if config.${opt.redis.createLocally} && !config.${opt.redis.enableUnixSocket} 229 then "127.0.0.1" 230 else null 231 ''; 232 description = "Redis host."; 233 }; 234 235 port = lib.mkOption { 236 type = lib.types.nullOr lib.types.port; 237 default = if cfg.redis.createLocally && cfg.redis.enableUnixSocket then null else 31638; 238 defaultText = lib.literalExpression '' 239 if config.${opt.redis.createLocally} && config.${opt.redis.enableUnixSocket} 240 then null 241 else 6379 242 ''; 243 description = "Redis port."; 244 }; 245 246 passwordFile = lib.mkOption { 247 type = lib.types.nullOr lib.types.path; 248 default = null; 249 example = "/run/keys/peertube/password-redis-db"; 250 description = "Password for redis database."; 251 }; 252 253 enableUnixSocket = lib.mkOption { 254 type = lib.types.bool; 255 default = cfg.redis.createLocally; 256 defaultText = lib.literalExpression "config.${opt.redis.createLocally}"; 257 description = "Use Unix socket."; 258 }; 259 }; 260 261 smtp = { 262 createLocally = lib.mkOption { 263 type = lib.types.bool; 264 default = false; 265 description = "Configure local Postfix SMTP server for PeerTube."; 266 }; 267 268 passwordFile = lib.mkOption { 269 type = lib.types.nullOr lib.types.path; 270 default = null; 271 example = "/run/keys/peertube/password-smtp"; 272 description = "Password for smtp server."; 273 }; 274 }; 275 276 package = lib.mkOption { 277 type = lib.types.package; 278 default = pkgs.peertube; 279 defaultText = lib.literalExpression "pkgs.peertube"; 280 description = "PeerTube package to use."; 281 }; 282 }; 283 284 config = lib.mkIf cfg.enable { 285 assertions = [ 286 { assertion = cfg.serviceEnvironmentFile == null || !lib.hasPrefix builtins.storeDir cfg.serviceEnvironmentFile; 287 message = '' 288 <option>services.peertube.serviceEnvironmentFile</option> points to 289 a file in the Nix store. You should use a quoted absolute path to 290 prevent this. 291 ''; 292 } 293 { assertion = cfg.secrets.secretsFile != null; 294 message = '' 295 <option>services.peertube.secrets.secretsFile</option> needs to be set. 296 ''; 297 } 298 { assertion = !(cfg.redis.enableUnixSocket && (cfg.redis.host != null || cfg.redis.port != null)); 299 message = '' 300 <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. 301 ''; 302 } 303 { assertion = cfg.redis.enableUnixSocket || (cfg.redis.host != null && cfg.redis.port != null); 304 message = '' 305 <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. 306 ''; 307 } 308 { assertion = cfg.redis.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.redis.passwordFile; 309 message = '' 310 <option>services.peertube.redis.passwordFile</option> points to 311 a file in the Nix store. You should use a quoted absolute path to 312 prevent this. 313 ''; 314 } 315 { assertion = cfg.database.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.database.passwordFile; 316 message = '' 317 <option>services.peertube.database.passwordFile</option> points to 318 a file in the Nix store. You should use a quoted absolute path to 319 prevent this. 320 ''; 321 } 322 { assertion = cfg.smtp.passwordFile == null || !lib.hasPrefix builtins.storeDir cfg.smtp.passwordFile; 323 message = '' 324 <option>services.peertube.smtp.passwordFile</option> points to 325 a file in the Nix store. You should use a quoted absolute path to 326 prevent this. 327 ''; 328 } 329 ]; 330 331 environment.systemPackages = [ cfg.package.cli ]; 332 333 services.peertube.settings = lib.mkMerge [ 334 { 335 listen = { 336 port = cfg.listenHttp; 337 }; 338 webserver = { 339 https = (if cfg.enableWebHttps then true else false); 340 hostname = "${cfg.localDomain}"; 341 port = cfg.listenWeb; 342 }; 343 database = { 344 hostname = "${cfg.database.host}"; 345 port = cfg.database.port; 346 name = "${cfg.database.name}"; 347 username = "${cfg.database.user}"; 348 }; 349 redis = { 350 hostname = "${toString cfg.redis.host}"; 351 port = (lib.optionalString (cfg.redis.port != null) cfg.redis.port); 352 }; 353 storage = { 354 tmp = lib.mkDefault "/var/lib/peertube/storage/tmp/"; 355 tmp_persistent = lib.mkDefault "/var/lib/peertube/storage/tmp_persistent/"; 356 bin = lib.mkDefault "/var/lib/peertube/storage/bin/"; 357 avatars = lib.mkDefault "/var/lib/peertube/storage/avatars/"; 358 web_videos = lib.mkDefault "/var/lib/peertube/storage/web-videos/"; 359 streaming_playlists = lib.mkDefault "/var/lib/peertube/storage/streaming-playlists/"; 360 redundancy = lib.mkDefault "/var/lib/peertube/storage/redundancy/"; 361 logs = lib.mkDefault "/var/lib/peertube/storage/logs/"; 362 previews = lib.mkDefault "/var/lib/peertube/storage/previews/"; 363 thumbnails = lib.mkDefault "/var/lib/peertube/storage/thumbnails/"; 364 storyboards = lib.mkDefault "/var/lib/peertube/storage/storyboards/"; 365 torrents = lib.mkDefault "/var/lib/peertube/storage/torrents/"; 366 captions = lib.mkDefault "/var/lib/peertube/storage/captions/"; 367 cache = lib.mkDefault "/var/lib/peertube/storage/cache/"; 368 plugins = lib.mkDefault "/var/lib/peertube/storage/plugins/"; 369 well_known = lib.mkDefault "/var/lib/peertube/storage/well_known/"; 370 client_overrides = lib.mkDefault "/var/lib/peertube/storage/client-overrides/"; 371 }; 372 import = { 373 videos = { 374 http = { 375 youtube_dl_release = { 376 python_path = "${pkgs.python3}/bin/python"; 377 }; 378 }; 379 }; 380 }; 381 } 382 (lib.mkIf cfg.redis.enableUnixSocket { redis = { socket = "/run/redis-peertube/redis.sock"; }; }) 383 ]; 384 385 systemd.tmpfiles.rules = [ 386 "d '/var/lib/peertube/config' 0700 ${cfg.user} ${cfg.group} - -" 387 "z '/var/lib/peertube/config' 0700 ${cfg.user} ${cfg.group} - -" 388 "d '/var/lib/peertube/www' 0750 ${cfg.user} ${cfg.group} - -" 389 "z '/var/lib/peertube/www' 0750 ${cfg.user} ${cfg.group} - -" 390 ]; 391 392 systemd.services.peertube-init-db = lib.mkIf cfg.database.createLocally { 393 description = "Initialization database for PeerTube daemon"; 394 after = [ "network.target" "postgresql.service" ]; 395 requires = [ "postgresql.service" ]; 396 397 script = let 398 psqlSetupCommands = pkgs.writeText "peertube-init.sql" '' 399 SELECT 'CREATE USER "${cfg.database.user}"' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${cfg.database.user}')\gexec 400 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 401 \c '${cfg.database.name}' 402 CREATE EXTENSION IF NOT EXISTS pg_trgm; 403 CREATE EXTENSION IF NOT EXISTS unaccent; 404 ''; 405 in "${config.services.postgresql.package}/bin/psql -f ${psqlSetupCommands}"; 406 407 serviceConfig = { 408 Type = "oneshot"; 409 WorkingDirectory = cfg.package; 410 # User and group 411 User = "postgres"; 412 Group = "postgres"; 413 # Sandboxing 414 RestrictAddressFamilies = [ "AF_UNIX" ]; 415 MemoryDenyWriteExecute = true; 416 # System Call Filtering 417 SystemCallFilter = "~" + lib.concatStringsSep " " (systemCallsList ++ [ "@resources" ]); 418 } // cfgService; 419 }; 420 421 systemd.services.peertube = { 422 description = "PeerTube daemon"; 423 after = [ "network.target" ] 424 ++ lib.optional cfg.redis.createLocally "redis-peertube.service" 425 ++ lib.optionals cfg.database.createLocally [ "postgresql.service" "peertube-init-db.service" ]; 426 requires = lib.optional cfg.redis.createLocally "redis-peertube.service" 427 ++ lib.optionals cfg.database.createLocally [ "postgresql.service" "peertube-init-db.service" ]; 428 wantedBy = [ "multi-user.target" ]; 429 430 environment = env; 431 432 path = with pkgs; [ nodejs_18 yarn ffmpeg-headless openssl ]; 433 434 script = '' 435 #!/bin/sh 436 umask 077 437 cat > /var/lib/peertube/config/local.yaml <<EOF 438 ${lib.optionalString (cfg.secrets.secretsFile != null) '' 439 secrets: 440 peertube: '$(cat ${cfg.secrets.secretsFile})' 441 ''} 442 ${lib.optionalString ((!cfg.database.createLocally) && (cfg.database.passwordFile != null)) '' 443 database: 444 password: '$(cat ${cfg.database.passwordFile})' 445 ''} 446 ${lib.optionalString (cfg.redis.passwordFile != null) '' 447 redis: 448 auth: '$(cat ${cfg.redis.passwordFile})' 449 ''} 450 ${lib.optionalString (cfg.smtp.passwordFile != null) '' 451 smtp: 452 password: '$(cat ${cfg.smtp.passwordFile})' 453 ''} 454 EOF 455 umask 027 456 ln -sf ${configFile} /var/lib/peertube/config/production.json 457 ln -sf ${cfg.package}/config/default.yaml /var/lib/peertube/config/default.yaml 458 ln -sf ${cfg.package}/client/dist -T /var/lib/peertube/www/client 459 ln -sf ${cfg.settings.storage.client_overrides} -T /var/lib/peertube/www/client-overrides 460 node dist/server 461 ''; 462 serviceConfig = { 463 Type = "simple"; 464 Restart = "always"; 465 RestartSec = 20; 466 TimeoutSec = 60; 467 WorkingDirectory = cfg.package; 468 SyslogIdentifier = "peertube"; 469 # User and group 470 User = cfg.user; 471 Group = cfg.group; 472 # State directory and mode 473 StateDirectory = "peertube"; 474 StateDirectoryMode = "0750"; 475 # Cache directory and mode 476 CacheDirectory = "peertube"; 477 CacheDirectoryMode = "0750"; 478 # Access write directories 479 ReadWritePaths = cfg.dataDirs; 480 # Environment 481 EnvironmentFile = cfg.serviceEnvironmentFile; 482 # Sandboxing 483 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ]; 484 MemoryDenyWriteExecute = false; 485 # System Call Filtering 486 SystemCallFilter = [ ("~" + lib.concatStringsSep " " systemCallsList) "pipe" "pipe2" ]; 487 } // cfgService; 488 }; 489 490 services.nginx = lib.mkIf cfg.configureNginx { 491 enable = true; 492 upstreams."peertube".servers = { 493 "127.0.0.1:${toString cfg.listenHttp}".fail_timeout = "0"; 494 }; 495 virtualHosts."${cfg.localDomain}" = { 496 root = "/var/lib/peertube/www"; 497 498 # Application 499 locations."/" = { 500 tryFiles = "/dev/null @api"; 501 priority = 1110; 502 }; 503 504 locations."~ ^/api/v1/videos/(upload-resumable|([^/]+/source/replace-resumable))$" = { 505 tryFiles = "/dev/null @api"; 506 priority = 1120; 507 508 extraConfig = '' 509 client_max_body_size 0; 510 proxy_request_buffering off; 511 '' + nginxCommonHeaders; 512 }; 513 514 locations."~ ^/api/v1/videos/(upload|([^/]+/studio/edit))$" = { 515 tryFiles = "/dev/null @api"; 516 root = cfg.settings.storage.tmp; 517 priority = 1130; 518 519 extraConfig = '' 520 limit_except POST HEAD { deny all; } 521 522 client_max_body_size 12G; 523 add_header X-File-Maximum-Size 8G always; 524 '' + nginxCommonHeaders; 525 }; 526 527 locations."~ ^/api/v1/runners/jobs/[^/]+/(update|success)$" = { 528 tryFiles = "/dev/null @api"; 529 root = cfg.settings.storage.tmp; 530 priority = 1135; 531 532 extraConfig = '' 533 client_max_body_size 12G; 534 add_header X-File-Maximum-Size 8G always; 535 '' + nginxCommonHeaders; 536 }; 537 538 locations."~ ^/api/v1/(videos|video-playlists|video-channels|users/me)" = { 539 tryFiles = "/dev/null @api"; 540 priority = 1140; 541 542 extraConfig = '' 543 client_max_body_size 6M; 544 add_header X-File-Maximum-Size 4M always; 545 '' + nginxCommonHeaders; 546 }; 547 548 locations."@api" = { 549 proxyPass = "http://peertube"; 550 priority = 1150; 551 552 extraConfig = '' 553 proxy_set_header Host $host; 554 proxy_set_header X-Real-IP $remote_addr; 555 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 556 557 proxy_connect_timeout 10m; 558 559 proxy_send_timeout 10m; 560 proxy_read_timeout 10m; 561 562 client_max_body_size 100k; 563 send_timeout 10m; 564 ''+ nginxCommonHeaders; 565 }; 566 567 # Websocket 568 locations."/socket.io" = { 569 tryFiles = "/dev/null @api_websocket"; 570 priority = 1210; 571 }; 572 573 locations."/tracker/socket" = { 574 tryFiles = "/dev/null @api_websocket"; 575 priority = 1220; 576 577 extraConfig = '' 578 proxy_read_timeout 15m; 579 ''; 580 }; 581 582 locations."~ ^/plugins/[^/]+(/[^/]+)?/ws/" = { 583 tryFiles = "/dev/null @api_websocket"; 584 priority = 1230; 585 }; 586 587 locations."@api_websocket" = { 588 proxyPass = "http://peertube"; 589 priority = 1240; 590 591 extraConfig = '' 592 proxy_http_version 1.1; 593 proxy_set_header Upgrade $http_upgrade; 594 proxy_set_header Connection 'upgrade'; 595 proxy_set_header Host $host; 596 proxy_set_header X-Real-IP $remote_addr; 597 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 598 599 '' + nginxCommonHeaders; 600 }; 601 602 # Bypass PeerTube for performance reasons. 603 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))$" = { 604 tryFiles = "/client-overrides/$1 /client/$1 $1"; 605 priority = 1310; 606 607 extraConfig = nginxCommonHeaders; 608 }; 609 610 locations."~ ^/client/(.*\.(js|css|png|svg|woff2|otf|ttf|woff|eot))$" = { 611 alias = "${cfg.package}/client/dist/$1"; 612 priority = 1320; 613 extraConfig = '' 614 add_header Cache-Control 'public, max-age=604800, immutable'; 615 '' + nginxCommonHeaders; 616 }; 617 618 locations."^~ /download/" = { 619 proxyPass = "http://peertube"; 620 priority = 1410; 621 extraConfig = '' 622 proxy_set_header Host $host; 623 proxy_set_header X-Real-IP $remote_addr; 624 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 625 626 proxy_limit_rate 5M; 627 '' + nginxCommonHeaders; 628 }; 629 630 locations."^~ /static/streaming-playlists/hls/private/" = { 631 proxyPass = "http://peertube"; 632 priority = 1420; 633 extraConfig = '' 634 proxy_set_header Host $host; 635 proxy_set_header X-Real-IP $remote_addr; 636 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 637 638 proxy_limit_rate 5M; 639 '' + nginxCommonHeaders; 640 }; 641 642 locations."^~ /static/web-videos/private/" = { 643 proxyPass = "http://peertube"; 644 priority = 1430; 645 extraConfig = '' 646 proxy_set_header Host $host; 647 proxy_set_header X-Real-IP $remote_addr; 648 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 649 650 proxy_limit_rate 5M; 651 '' + nginxCommonHeaders; 652 }; 653 654 locations."^~ /static/webseed/private/" = { 655 proxyPass = "http://peertube"; 656 priority = 1440; 657 extraConfig = '' 658 proxy_set_header Host $host; 659 proxy_set_header X-Real-IP $remote_addr; 660 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 661 662 proxy_limit_rate 5M; 663 '' + nginxCommonHeaders; 664 }; 665 666 locations."^~ /static/redundancy/" = { 667 tryFiles = "$uri @api"; 668 root = cfg.settings.storage.redundancy; 669 priority = 1450; 670 extraConfig = '' 671 set $peertube_limit_rate 800k; 672 673 if ($request_uri ~ -fragmented.mp4$) { 674 set $peertube_limit_rate 5M; 675 } 676 677 if ($request_method = 'OPTIONS') { 678 ${nginxCommonHeaders} 679 ${nginxCommonHeadersExtra} 680 add_header Access-Control-Max-Age 1728000; 681 add_header Content-Type 'text/plain charset=UTF-8'; 682 add_header Content-Length 0; 683 return 204; 684 } 685 if ($request_method = 'GET') { 686 ${nginxCommonHeaders} 687 ${nginxCommonHeadersExtra} 688 689 access_log off; 690 } 691 692 aio threads; 693 sendfile on; 694 sendfile_max_chunk 1M; 695 696 limit_rate $peertube_limit_rate; 697 limit_rate_after 5M; 698 699 rewrite ^/static/redundancy/(.*)$ /$1 break; 700 ''; 701 }; 702 703 locations."^~ /static/streaming-playlists/" = { 704 tryFiles = "$uri @api"; 705 root = cfg.settings.storage.streaming_playlists; 706 priority = 1460; 707 extraConfig = '' 708 set $peertube_limit_rate 800k; 709 710 if ($request_uri ~ -fragmented.mp4$) { 711 set $peertube_limit_rate 5M; 712 } 713 714 if ($request_method = 'OPTIONS') { 715 ${nginxCommonHeaders} 716 ${nginxCommonHeadersExtra} 717 add_header Access-Control-Max-Age 1728000; 718 add_header Content-Type 'text/plain charset=UTF-8'; 719 add_header Content-Length 0; 720 return 204; 721 } 722 if ($request_method = 'GET') { 723 ${nginxCommonHeaders} 724 ${nginxCommonHeadersExtra} 725 726 access_log off; 727 } 728 729 aio threads; 730 sendfile on; 731 sendfile_max_chunk 1M; 732 733 limit_rate $peertube_limit_rate; 734 limit_rate_after 5M; 735 736 rewrite ^/static/streaming-playlists/(.*)$ /$1 break; 737 ''; 738 }; 739 740 locations."^~ /static/web-videos/" = { 741 tryFiles = "$uri @api"; 742 root = cfg.settings.storage.web_videos; 743 priority = 1470; 744 extraConfig = '' 745 set $peertube_limit_rate 800k; 746 747 if ($request_uri ~ -fragmented.mp4$) { 748 set $peertube_limit_rate 5M; 749 } 750 751 if ($request_method = 'OPTIONS') { 752 ${nginxCommonHeaders} 753 ${nginxCommonHeadersExtra} 754 add_header Access-Control-Max-Age 1728000; 755 add_header Content-Type 'text/plain charset=UTF-8'; 756 add_header Content-Length 0; 757 return 204; 758 } 759 if ($request_method = 'GET') { 760 ${nginxCommonHeaders} 761 ${nginxCommonHeadersExtra} 762 763 access_log off; 764 } 765 766 aio threads; 767 sendfile on; 768 sendfile_max_chunk 1M; 769 770 limit_rate $peertube_limit_rate; 771 limit_rate_after 5M; 772 773 rewrite ^/static/web-videos/(.*)$ /$1 break; 774 ''; 775 }; 776 777 locations."^~ /static/webseed/" = { 778 tryFiles = "$uri @api"; 779 root = cfg.settings.storage.web_videos; 780 priority = 1480; 781 extraConfig = '' 782 set $peertube_limit_rate 800k; 783 784 if ($request_uri ~ -fragmented.mp4$) { 785 set $peertube_limit_rate 5M; 786 } 787 788 if ($request_method = 'OPTIONS') { 789 ${nginxCommonHeaders} 790 ${nginxCommonHeadersExtra} 791 add_header Access-Control-Max-Age 1728000; 792 add_header Content-Type 'text/plain charset=UTF-8'; 793 add_header Content-Length 0; 794 return 204; 795 } 796 if ($request_method = 'GET') { 797 ${nginxCommonHeaders} 798 ${nginxCommonHeadersExtra} 799 800 access_log off; 801 } 802 803 aio threads; 804 sendfile on; 805 sendfile_max_chunk 1M; 806 807 limit_rate $peertube_limit_rate; 808 limit_rate_after 5M; 809 810 rewrite ^/static/webseed/(.*)$ /web-videos/$1 break; 811 ''; 812 }; 813 }; 814 }; 815 816 services.postgresql = lib.mkIf cfg.database.createLocally { 817 enable = true; 818 }; 819 820 services.redis.servers.peertube = lib.mkMerge [ 821 (lib.mkIf cfg.redis.createLocally { 822 enable = true; 823 }) 824 (lib.mkIf (cfg.redis.createLocally && !cfg.redis.enableUnixSocket) { 825 bind = "127.0.0.1"; 826 port = cfg.redis.port; 827 }) 828 (lib.mkIf (cfg.redis.createLocally && cfg.redis.enableUnixSocket) { 829 unixSocket = "/run/redis-peertube/redis.sock"; 830 unixSocketPerm = 660; 831 }) 832 ]; 833 834 services.postfix = lib.mkIf cfg.smtp.createLocally { 835 enable = true; 836 hostname = lib.mkDefault "${cfg.localDomain}"; 837 }; 838 839 users.users = lib.mkMerge [ 840 (lib.mkIf (cfg.user == "peertube") { 841 peertube = { 842 isSystemUser = true; 843 group = cfg.group; 844 home = cfg.package; 845 }; 846 }) 847 (lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ peertubeEnv pkgs.nodejs_18 pkgs.yarn pkgs.ffmpeg-headless ]) 848 (lib.mkIf cfg.redis.enableUnixSocket {${config.services.peertube.user}.extraGroups = [ "redis-peertube" ];}) 849 ]; 850 851 users.groups = { 852 ${cfg.group} = { 853 members = lib.optional cfg.configureNginx config.services.nginx.user; 854 }; 855 }; 856 }; 857}