From 9ad046f2be03d46f12ce91db2b74171e1face7ba Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L de Mello" Date: Sun, 30 Nov 2025 20:39:31 -0300 Subject: [PATCH] feat(capytal,peertube): capytal's peertube instance --- capytal/default.nix | 2 + capytal/videos.nix | 162 ++++++++++++++++++++++++++++++++++++++++++ common/postgresql.nix | 8 +-- secrets.nix | 13 ++++ secrets.yaml | 13 +++- 5 files changed, 191 insertions(+), 7 deletions(-) create mode 100644 capytal/videos.nix diff --git a/capytal/default.nix b/capytal/default.nix index bafcb80..2093eaf 100644 --- a/capytal/default.nix +++ b/capytal/default.nix @@ -1,5 +1,7 @@ {...}: { imports = [ + # ./admin.nix + ./peertube.nix ./analytics.nix ./forge.nix ./websites.nix diff --git a/capytal/videos.nix b/capytal/videos.nix new file mode 100644 index 0000000..ed77cd3 --- /dev/null +++ b/capytal/videos.nix @@ -0,0 +1,162 @@ +{ + config, + lib, + pkgs, + ... +}: let + cfg = config.services.peertube; + + systemCallsList = [ + "@cpu-emulation" + "@debug" + "@keyring" + "@ipc" + "@memlock" + "@mount" + "@obsolete" + "@privileged" + "@setuid" + ]; + + cfgService = { + # Proc filesystem + ProtectProc = "invisible"; + # Access write directories + UMask = "0027"; + # Capabilities + CapabilityBoundingSet = ""; + # Security + NoNewPrivileges = true; + # Sandboxing + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + ProtectClock = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + # System Call Filtering + SystemCallArchitectures = "native"; + }; +in { + services.peertube = { + enable = true; + # localDomain = "watch.capytal.cc"; + localDomain = "watch-test.capytal.cc"; + listenWeb = 9945; + listenHttp = 9945; + enableWebHttps = false; + database = { + # createLocally = true; + host = "/run/postgresql"; + port = config.services.postgresql.settings.port; + passwordFile = config.sops.secrets."peertube/database/password".path; + }; + redis.createLocally = true; + configureNginx = true; + settings = { + signup.enabled = false; + object_storage = { + enabled = true; + endpoint = "localhost:3461"; + region = "garage"; + videos = { + bucket_name = "peertube"; + prefix = "hls-videos:"; + }; + streaming_playlists = { + bucket_name = "peertube"; + prefix = "streaming-playlists:"; + }; + user_exports = { + bucket_name = "peertube"; + prefix = "user-exports:"; + }; + original_video_files = { + bucket_name = "peertube"; + prefix = "original-video-files:"; + }; + captions = { + bucket_name = "peertube"; + prefix = "captions:"; + }; + }; + webserver = { + hostname = cfg.localDomain; + port = lib.mkForce 443; + }; + }; + secrets.secretsFile = config.sops.secrets."peertube/secretsFile".path; + serviceEnvironmentFile = config.sops.secrets."peertube/environment".path; + # TODO: Set up postfix server for forms and contact + }; + + # TODO: Commit this to upstream nixpkgs? + # HACK: services.peertube.database.createLocally option doesn't respect port + systemd.services.peertube-init-db = { + description = "Initialization database for PeerTube daemon"; + after = [ + "network.target" + "postgresql.service" + ]; + requires = ["postgresql.service"]; + + script = let + psqlSetupCommands = pkgs.writeText "peertube-init.sql" '' + SELECT 'CREATE USER "${cfg.database.user}"' WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${cfg.database.user}')\gexec + 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 + \c '${cfg.database.name}' + CREATE EXTENSION IF NOT EXISTS pg_trgm; + CREATE EXTENSION IF NOT EXISTS unaccent; + ''; + in "${config.services.postgresql.package}/bin/psql -f ${psqlSetupCommands} -p ${toString config.services.postgresql.settings.port}"; + + serviceConfig = + { + Type = "oneshot"; + WorkingDirectory = cfg.package; + # User and group + User = "postgres"; + Group = "postgres"; + # Sandboxing + RestrictAddressFamilies = ["AF_UNIX"]; + MemoryDenyWriteExecute = true; + # System Call Filtering + SystemCallFilter = "~" + lib.concatStringsSep " " (systemCallsList ++ ["@resources"]); + } + // cfgService; + }; + + services.anubis.instances."peertube" = { + settings = { + BIND = ":${toString (cfg.listenWeb + 2)}"; + BIND_NETWORK = "tcp"; + METRICS_BIND = ":${toString (cfg.listenWeb + 3)}"; + METRICS_BIND_NETWORK = "tcp"; + SERVE_ROBOTS_TXT = true; + TARGET = "http://localhost:${toString cfg.listenWeb}"; + ED25519_PRIVATE_KEY_HEX_FILE = config.sops.secrets."anubis/peertube/hex_file".path; + }; + }; + + services.caddy.virtualHosts = { + ":${toString (cfg.listenWeb + 1)}" = { + extraConfig = '' + reverse_proxy http://localhost${config.services.anubis.instances."peertube".settings.BIND} { + header_up X-Http-Version {http.request.proto} + header_up X-Real-Ip {remote_host} + } + ''; + }; + }; +} diff --git a/common/postgresql.nix b/common/postgresql.nix index baf4312..b6a76ed 100644 --- a/common/postgresql.nix +++ b/common/postgresql.nix @@ -1,22 +1,21 @@ { config, lib, - pkgs, ... }: let cfg = config.services.postgresql; - cfgadm = config.services.pgadmin; in { services.postgresql = { + enable = true; + enableTCPIP = true; authentication = lib.mkForce '' #type database DBuser origin-address auth-method local all all trust # ipv4 - host all all 172.0.0.1/32 trust + host all all 127.0.0.1/32 trust # ipv6 host all all ::1/128 trust ''; - enable = true; ensureDatabases = [ "forgejo" "nextcloud" @@ -31,7 +30,6 @@ in { ensureDBOwnership = true; } ]; - enableTCPIP = true; settings = { port = 3245; }; diff --git a/secrets.nix b/secrets.nix index da2ab6d..faa6942 100644 --- a/secrets.nix +++ b/secrets.nix @@ -33,6 +33,7 @@ with lib; { # Anubis ${config.services.anubis.defaultOptions.user} = [ "anubis/gitea/hex_file" + "anubis/peertube/hex_file" "anubis/medama/hex_file" ]; @@ -61,6 +62,18 @@ with lib; { "keiko/env_file" ]; + # Peertube + ${config.services.peertube.user} = [ + "peertube/database/password" + "peertube/environment" + "peertube/secretsFile" + ]; + + # PostgreSQL + ${config.users.users.postgres.name} = [ + "postgresql/initialScript" + ]; + # Nextcloud ${config.services.phpfpm.pools.nextcloud.user} = [ "nextcloud/adminpass" diff --git a/secrets.yaml b/secrets.yaml index 35a2eae..67ac06b 100644 --- a/secrets.yaml +++ b/secrets.yaml @@ -3,6 +3,8 @@ anubis: hex_file: ENC[AES256_GCM,data:UlFkdy1MfwaQqDnxtMtg4kH/dMJVl8sk4DMfdaCczHGaPtPuP4ADxcBxqpNkzYnQPxbv5ZXqR4qz8Ur5QHWxUg==,iv:WQHkSMiJEV0IWMVvfxC/EuE/e8QabhJinRHADm7kdSg=,tag:1JRwMp94APRszgBuQ0yaQQ==,type:str] gitea: hex_file: ENC[AES256_GCM,data:VeF2FRqZdsYe3A002QLGG8jc5s+Tfr5V4dpO/aZ4Rbh9T/O3XQznocDsmUOvjIysH9wbVwvBXGdH1U3vd0qmVg==,iv:/3VQLK+C76HoCbpZAUQaxOFsiFKDuuP2KWAV0EBasp4=,tag:brqDAaHv7r9DRLBoMMmRqw==,type:str] + peertube: + hex_file: ENC[AES256_GCM,data:1G2MZRpGFVr2Pd2eRlaLyVfYY+DrCtqfaBaC3S/dVrDJr8s7Xw7w622ILNUflZAEcYKCvpI25oNNnCG0pw6L3g==,iv:1VHhQ5Y2gdZeZIadWy2YyCYA8k79Acm0sE4MjWZYChg=,tag:G3u80vSy3hTYcsGCy9HZrg==,type:str] medama: hex_file: ENC[AES256_GCM,data:wLRw34+uPWpR5GJuI8Q+nlX4hEx3sMn5mSl/lF5kX0Z8N99Eb6Qj4Emx2mK4dNukYNO8j9blw1/RAL94I+QCjQ==,iv:/dW5Z+S14dByXIUyOyEIxxRFl7e4lZZfBKtukV4s68M=,tag:fELbLVzwIgMJUjhNJw4kYg==,type:str] cloudflared: @@ -41,6 +43,13 @@ guz: password: ENC[AES256_GCM,data:zlO5xSFho7TXjFv62lgFir9SAgn+UE6XjdNEvIAgmQG9oDkthfgxO84wYdI0mQDwRIIs2PmSdBRfo0DPc3hji+ySCrItolPL8g==,iv:MZfhTxwfcbmXh5C6DkQhnY9NQGdE8zEwwvFOHQiUgKY=,tag:JjJN2bYcSXNN3ueGj5RNLg==,type:str] keiko: env_file: ENC[AES256_GCM,data:dgHWczdwDxz3yV66F+4lMTRIMvHDBYZ6ycVARQPVT7GcYhelA/5uNks3Sdn1n8vgie7TmZBT9mGv+ePtP4+GMyHo/bOJqvjcXyU9dB30CwxuYOCPefitbKxHwIJxkMJqmXvNr3pl2u0mZWUu3mdGMLI9fF3z8/Tk0xM/g4ZezLGaXcRhUSdQPDiOFt2VKA5IrERnpRP0ey5Jx3tf,iv:gpLQdIBGgMCgR0B7jEZDF+3t85nsOVkdxubBUR+QOWA=,tag:eTgQ2uvWsGPEXkpzj/3Szw==,type:str] +postgresql: + initialScript: ENC[AES256_GCM,data:9ByABGVJgE7+CpWTiRLvN8PM2N4UjRylcFR7zjSeROkpkJQfxaJas0G2kLo9wRXVbp82NlIb8A5kd7pFCfF/GC7G7bqfIiR65yevLJ+SScEnhx2YSd5U1dTNwgaK48Q2b9aACn5qOVCwA0WgKkUZMBH2G6u/9VCHjFWXnoVX1YqQ1IwiCE4aSwGdiSykMQXldLnVDB/CDhir7x6/M+jroW+hrkrmXVXZbM5JRTz4foUEafhjFInZXbPKJl+rgNv//DAG4tYWCOljruRVmtKo9CJm277/8C2jd5NwVUFsBmDuvIQjrSBo25r7UMV+US7JJO2gjw/81QraNy95nTxdIAphTqV4W1eeZIxWwDKul6WvyNwTsa/Zw8nUHmlf1i7NWiy+YaqJHrPWXPnytTNLuFsm34sU5Jair4l4LRkzUW/+wZk3977xbmVbUwimywO7,iv:rOP9dSSnWiJKe30hxD4+klj/JZygcEsskf+71zn5Eu4=,tag:nz11prtg2DiK+EODarIYFA==,type:str] +peertube: + database: + password: ENC[AES256_GCM,data:PUHAXOXMwDVFc7cHihhizQ==,iv:FgUKffolNJrK/hqTnm0ciYdQDl6VjCXeEp+tyfa+Wmo=,tag:Mcxjlcd4Hr+x91Cx4/9p7w==,type:str] + secretsFile: ENC[AES256_GCM,data:3ZlvLnxollbqo7tLKbq81cGcYkbVqhmRe/3h0XOyPDgXtOvaiVKkUeIbbTmhdai4ueQcEF5U7xn0Lc8FZqLE2Q==,iv:H2quDSKPaVNLq91nqHxVvOh/611Ej2prAf1Rd3/8AOQ=,tag:CGqTSJNqiaFoFR21PabwRA==,type:str] + environment: ENC[AES256_GCM,data:z4C957prGW1EoDnnjO1DiW6d4qlIkBwAdE/wXDVSvgwWczz2u6YgDPA+QuIC2OkfcSzlz5kslCoBLtVubiQRnjgUJhXAFXfilD0+cLq82Kak9LAZAkuGyhivTGmNg0rpOh9qamns5hpXXlbu8/VFyCX/XWv6gN0P3GeS+As7QNhm7M9O,iv:qb5kAhljVF45+bluZ6t3kNHZ2+C3g/8pnDjVe+1v6bs=,tag:GYmtgfcyCTxHNpq4rHSXvg==,type:str] nextcloud: adminpass: ENC[AES256_GCM,data:RY2BsFDSttpr,iv:Mv22/Ht4Uq0miQjKgbnu37UCk/wZMyc6t9jrWkyXsxI=,tag:ScYTA46R0ZpkeqjhRsYzYg==,type:str] s3: @@ -57,7 +66,7 @@ sops: amRmVkVoS2RqeEs3OXZVeTlsZUVEV28K1WcbGJHT8LMah5b7NN1psiucTl1OfZYO 4T3RDSQMB3qj1TGQSdixjwRRKbMGtL3LXnvkNd+caVi5Z9OkF1O9Yg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-10-10T21:47:17Z" - mac: ENC[AES256_GCM,data:4K5fNM05Mm3VCFTx2lntPUcaW/fznjchMdd26VJURBTED3Hr8wpLyNMFtWqWlKZvVuMyk7VQyyBmysb0clmydHpuDR9TtJSJA+IyIyK6IQJi86mQs7IpcSf4Z6uXA33ed3z2aJWhwA8l+5XtwQjYQbDeME1v/ir7xTeqz8P4STI=,iv:iaXcW+3UumdAR/v4/Pp8ZCqJQ2WmL6fucRFJwTugxrc=,tag:sxUajgkMkYjshIgU24o+/w==,type:str] + lastmodified: "2025-11-30T16:31:04Z" + mac: ENC[AES256_GCM,data:74FbU0xXoMhVt+gYFnl3T3GeWdAzXTR7f3SZztTRwtgyEIX/ktvZsKXaAUstTbz5zjybBr5zlwwXKSIL2bM3R5oSva7LVNTkbLBPSad8/O8iQtq8BSKVVHFhvjBfAbpVmZVlUgNzUCS2X+bZwHO3Tl0KgEYozXPQa66jwTUVF0w=,iv:XebXM0AP+53qxWJMKSjqVJsdwWXwglcGmx1mqKgzcf8=,tag:yniIwNDOrSY7KFYDggb+/g==,type:str] unencrypted_suffix: _unencrypted version: 3.10.2