-
-
Notifications
You must be signed in to change notification settings - Fork 20k
Second attempt at adding PeerTube package #106492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -347,6 +347,7 @@ in | |
| #mailman = 316; # removed 2019-08-30 | ||
| zigbee2mqtt = 317; | ||
| # shadow = 318; # unused | ||
| peertube = 319; | ||
|
|
||
| # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! | ||
|
|
||
|
|
@@ -649,6 +650,7 @@ in | |
| #mailman = 316; # removed 2019-08-30 | ||
| zigbee2mqtt = 317; | ||
| shadow = 318; | ||
| peertube = 319; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't we used
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I don't know what DynamicUser is in this case, how would that work? One thing that I know I have to do is use the tmpfiles.rules to set the datadirs of the project as being owned by the peertube user. (The actual datadir is only set in the config file, not using the module.) So I think it makes sense to have a username here that one could access using a variable in order to set certain permissions. (As long as we don't auto-generate the entire PeerTube config file from within the module. But it's really complete, I would not advise that.)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DynamicUser can be used to dynamically allocate an ephemeral user/group when the service starts. That is usually possible if the users data does not need to be accessed by other users.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think in this case it would be hard, because the user needs to externally set the permission of some directories to be owned accessible by that user. I don't intend to do the full PeerTube configuration in the nixos module.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's why systemd provides
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But those directories are only used in the PeerTube's internal config file, NixOS never knows about them at the module level. |
||
|
|
||
| # When adding a gid, make sure it doesn't match an existing | ||
| # uid. Users and groups with the same name should have equal | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,186 @@ | ||||||||
| { lib, pkgs, config, ... }: | ||||||||
|
|
||||||||
| let | ||||||||
| name = "peertube"; | ||||||||
| cfg = config.services.peertube; | ||||||||
|
|
||||||||
| uid = config.ids.uids.peertube; | ||||||||
| gid = config.ids.gids.peertube; | ||||||||
| in | ||||||||
| { | ||||||||
| options.services.peertube = { | ||||||||
| enable = lib.mkEnableOption "Enable Peertube’s service"; | ||||||||
|
|
||||||||
| user = lib.mkOption { | ||||||||
| type = lib.types.str; | ||||||||
| default = name; | ||||||||
| description = "User account under which Peertube runs"; | ||||||||
| }; | ||||||||
|
|
||||||||
| group = lib.mkOption { | ||||||||
| type = lib.types.str; | ||||||||
| default = name; | ||||||||
| description = "Group under which Peertube runs"; | ||||||||
| }; | ||||||||
|
|
||||||||
| configFile = lib.mkOption { | ||||||||
| type = lib.types.path; | ||||||||
| description = '' | ||||||||
| The configuration file path for Peertube. | ||||||||
| ''; | ||||||||
| }; | ||||||||
|
|
||||||||
| database = { | ||||||||
| createLocally = lib.mkOption { | ||||||||
| description = "Configure local PostgreSQL database server for PeerTube."; | ||||||||
| type = lib.types.bool; | ||||||||
| default = true; | ||||||||
| }; | ||||||||
|
|
||||||||
| name = lib.mkOption { | ||||||||
| type = lib.types.str; | ||||||||
| default = "peertube_prod"; | ||||||||
| description = "Database name."; | ||||||||
| }; | ||||||||
|
|
||||||||
| user = lib.mkOption { | ||||||||
| type = lib.types.str; | ||||||||
| default = "peertube"; | ||||||||
| description = "Database user."; | ||||||||
| }; | ||||||||
| }; | ||||||||
|
|
||||||||
| smtp = { | ||||||||
| createLocally = lib.mkOption { | ||||||||
| description = "Configure local Postfix SMTP server for PeerTube."; | ||||||||
| type = lib.types.bool; | ||||||||
| default = true; | ||||||||
| }; | ||||||||
| }; | ||||||||
|
|
||||||||
| redis = { | ||||||||
| createLocally = lib.mkOption { | ||||||||
| description = "Configure local Redis server for PeerTube."; | ||||||||
| type = lib.types.bool; | ||||||||
| default = true; | ||||||||
| }; | ||||||||
| }; | ||||||||
|
|
||||||||
| runtimeDir = lib.mkOption { | ||||||||
| type = lib.types.path; | ||||||||
| default = "/var/lib/${name}"; | ||||||||
| description = "The directory where Peertube stores its runtime data."; | ||||||||
| }; | ||||||||
|
|
||||||||
| package = lib.mkOption { | ||||||||
| type = lib.types.package; | ||||||||
| default = pkgs.peertube; | ||||||||
| description = '' | ||||||||
| Peertube package to use. | ||||||||
| ''; | ||||||||
| }; | ||||||||
| }; | ||||||||
|
|
||||||||
| config = lib.mkIf cfg.enable { | ||||||||
| users.users = lib.optionalAttrs (cfg.user == name) { | ||||||||
| "${name}" = { | ||||||||
| inherit uid; | ||||||||
| group = cfg.group; | ||||||||
| description = "Peertube user"; | ||||||||
| home = cfg.runtimeDir; | ||||||||
| useDefaultShell = true; | ||||||||
| # todo: fix this. needed for postgres authentication | ||||||||
| password = "peertube"; | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would need to be fixed I think. Does peertube not support unix socket authentication for postgresql as I think this is the approach other services take?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, it might do, but I didn't work that out yet. Yeah that's why I suggested maybe just getting the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I will look into this later.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stevenroose see stevenroose#2. Feel free to squash the commits after merging. You can keep me as co-author if you like. |
||||||||
| }; | ||||||||
| }; | ||||||||
| users.groups = lib.optionalAttrs (cfg.group == name) { | ||||||||
| "${name}" = { | ||||||||
| inherit gid; | ||||||||
| }; | ||||||||
| }; | ||||||||
|
|
||||||||
| services.postgresql = lib.mkIf cfg.database.createLocally { | ||||||||
| enable = true; | ||||||||
| ensureUsers = [ { name = cfg.database.user; }]; | ||||||||
| # The database is created as a startup script of the peertube service. | ||||||||
| authentication = '' | ||||||||
| host ${cfg.database.name} ${cfg.database.user} 127.0.0.1/32 trust | ||||||||
| host ${cfg.database.name} ${cfg.database.user} 127.0.0.1/32 md5 | ||||||||
| ''; | ||||||||
| }; | ||||||||
|
|
||||||||
| services.postfix = lib.mkIf cfg.smtp.createLocally { | ||||||||
| enable = true; | ||||||||
| }; | ||||||||
|
|
||||||||
| services.redis = lib.mkIf cfg.redis.createLocally { | ||||||||
| enable = true; | ||||||||
| }; | ||||||||
|
|
||||||||
| # Make sure the runtimeDir exists with the desired permissions. | ||||||||
| systemd.tmpfiles.rules = [ | ||||||||
| "d \"${cfg.runtimeDir}\" - ${cfg.user} ${cfg.group} - -" | ||||||||
| ]; | ||||||||
|
|
||||||||
| systemd.services.peertube = { | ||||||||
| description = "Peertube"; | ||||||||
| wantedBy = [ "multi-user.target" ]; | ||||||||
| after = [ "network.target" "postgresql.service" "redis.service" ]; | ||||||||
| wants = [ "postgresql.service" "redis.service" ]; | ||||||||
|
|
||||||||
| environment.NODE_CONFIG_DIR = "${cfg.runtimeDir}/config"; | ||||||||
| environment.NODE_ENV = "production"; | ||||||||
| environment.HOME = cfg.package; | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just an proposal but this make it work for me out of the box with self-signed certificates added to my local trust store.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, where does that magic string
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/ca.nix#L85 it's called the canonical location for NixOS so should be fine.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also many other packages/modules reference it or the old |
||||||||
|
|
||||||||
| path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl pkgs.sudo pkgs.youtube-dl ]; | ||||||||
|
|
||||||||
| script = '' | ||||||||
| install -m 0750 -d ${cfg.runtimeDir}/config | ||||||||
| ln -sf ${cfg.configFile} ${cfg.runtimeDir}/config/production.yaml | ||||||||
| exec npm start | ||||||||
| ''; | ||||||||
|
|
||||||||
| serviceConfig = { | ||||||||
| User = cfg.user; | ||||||||
| Group = cfg.group; | ||||||||
| WorkingDirectory = cfg.package; | ||||||||
| StateDirectory = "peertube"; | ||||||||
| StateDirectoryMode = "0750"; | ||||||||
| PrivateTmp = true; | ||||||||
| ProtectHome = true; | ||||||||
| ProtectControlGroups = true; | ||||||||
| ProtectSystem = "full"; | ||||||||
| Restart = "always"; | ||||||||
| Type = "simple"; | ||||||||
| TimeoutSec = 60; | ||||||||
| CapabilityBoundingSet = "~CAP_SYS_ADMIN"; | ||||||||
| ExecStartPre = let script = pkgs.writeScript "peertube-pre-start.sh" '' | ||||||||
| #!/bin/sh | ||||||||
| set -e | ||||||||
|
|
||||||||
| if ! [ -e "${cfg.runtimeDir}/.first_run" ]; then | ||||||||
| set -v | ||||||||
| if [ -e "${cfg.runtimeDir}/.first_run_partial" ]; then | ||||||||
| echo "Warn: first run was interrupted" | ||||||||
| fi | ||||||||
| touch "${cfg.runtimeDir}/.first_run_partial" | ||||||||
|
|
||||||||
| echo "Running PeerTube's PostgreSQL initialization..." | ||||||||
| echo "PeerTube is known to work with PostgreSQL v12, if any error occurs, please check your version." | ||||||||
|
|
||||||||
| sudo -u postgres "${config.services.postgresql.package}/bin/createdb" -O ${cfg.database.user} -E UTF8 -T template0 ${cfg.database.name} | ||||||||
| sudo -u postgres "${config.services.postgresql.package}/bin/psql" -c "CREATE EXTENSION pg_trgm;" ${cfg.database.name} | ||||||||
| sudo -u postgres "${config.services.postgresql.package}/bin/psql" -c "CREATE EXTENSION unaccent;" ${cfg.database.name} | ||||||||
|
|
||||||||
| touch "${cfg.runtimeDir}/.first_run" | ||||||||
| rm "${cfg.runtimeDir}/.first_run_partial" | ||||||||
| fi | ||||||||
| ''; | ||||||||
| in "+${script}"; | ||||||||
| }; | ||||||||
|
|
||||||||
| unitConfig.RequiresMountsFor = cfg.runtimeDir; | ||||||||
| }; | ||||||||
| }; | ||||||||
| } | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| { yarnModulesConfig, mkYarnModulesFixed, server, sources, version, nodejs, stdenv }: | ||
| rec { | ||
| modules = mkYarnModulesFixed rec { | ||
| inherit version; | ||
| pname = "peertube-client-yarn-modules"; | ||
| name = "${pname}-${version}"; | ||
| packageJSON = "${sources}/client/package.json"; | ||
| yarnLock = "${sources}/client/yarn.lock"; | ||
| pkgConfig = yarnModulesConfig; | ||
| }; | ||
| dist = stdenv.mkDerivation { | ||
| inherit version; | ||
| pname = "peertube-client"; | ||
| src = sources; | ||
| buildPhase = '' | ||
| ln -s ${server.modules}/node_modules . | ||
| cp -a ${modules}/node_modules client/ | ||
| chmod -R +w client/node_modules | ||
| patchShebangs . | ||
| npm run build:client | ||
| ''; | ||
|
|
||
| installPhase = '' | ||
| mkdir $out | ||
| cp -a client/dist $out | ||
| ''; | ||
|
|
||
| buildInputs = [ nodejs ]; | ||
| }; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| { light ? null, pkgs, stdenv, lib, fetchurl, fetchFromGitHub, callPackage | ||
| , nodejs ? pkgs.nodejs-12_x | ||
| , jq, youtube-dl, nodePackages, yarn2nix-moretea }: | ||
|
|
||
| let | ||
| version = "3.0.1"; | ||
|
|
||
| source = fetchFromGitHub { | ||
| owner = "Chocobozzz"; | ||
| repo = "PeerTube"; | ||
| rev = "v${version}"; | ||
| sha256 = "bIXt5bQiBBlNDFXYzcdQA8qp4nse5epUx/XQOguDOX8="; | ||
| }; | ||
|
|
||
| patchedSource = stdenv.mkDerivation { | ||
| pname = "peertube"; | ||
| inherit version; | ||
| src = source; | ||
| phases = [ "unpackPhase" "patchPhase" "installPhase" ]; | ||
| patches = [ ./fix_yarn_lock.patch ]; | ||
| installPhase = '' | ||
| mkdir $out | ||
| cp -a . $out/ | ||
| ''; | ||
| }; | ||
| yarnModulesConfig = { | ||
| bcrypt = { | ||
| buildInputs = [ nodePackages.node-pre-gyp ]; | ||
|
|
||
| postInstall = let | ||
| bcrypt_version = "5.0.0"; | ||
| bcrypt_lib = fetchurl { | ||
| url = "https://github.com/kelektiv/node.bcrypt.js/releases/download/v${bcrypt_version}/bcrypt_lib-v${bcrypt_version}-napi-v3-linux-x64-glibc.tar.gz"; | ||
| sha256 = "0j3p2px1xb17sw3gpm8l4apljajxxfflal1yy552mhpzhi21wccn"; | ||
| }; | ||
| in '' | ||
| if [ "${bcrypt_version}" != "$(cat package.json | ${jq}/bin/jq -r .version)" ]; then | ||
| echo "Mismatching version please update bcrypt in derivation" | ||
| false | ||
| fi | ||
| mkdir -p lib/binding && tar -C lib/binding -xf ${bcrypt_lib} | ||
| patchShebangs ../node-pre-gyp | ||
| npm run install | ||
| ''; | ||
| }; | ||
|
|
||
| utf-8-validate = { | ||
| buildInputs = [ nodePackages.node-gyp-build ]; | ||
| }; | ||
|
|
||
| youtube-dl = { | ||
| postInstall = '' | ||
| mkdir bin | ||
| ln -s ${youtube-dl}/bin/youtube-dl bin/youtube-dl | ||
| cat > bin/details <<EOF | ||
| {"version":"${youtube-dl.version}","path":null,"exec":"youtube-dl"} | ||
| EOF | ||
| ''; | ||
| }; | ||
| }; | ||
|
|
||
| mkYarnModulesFixed = args: (yarn2nix-moretea.mkYarnModules args).overrideAttrs(old: { | ||
| # This hack permits to workaround the fact that the yarn.lock | ||
| # file doesn't respect the semver requirements | ||
| buildPhase = builtins.replaceStrings [" ./package.json"] [" /dev/null; cp deps/*/package.json ."] old.buildPhase; | ||
| }); | ||
|
|
||
| server = callPackage ./server.nix { | ||
| inherit version yarnModulesConfig mkYarnModulesFixed; | ||
| sources = patchedSource; | ||
| }; | ||
|
|
||
| client = callPackage ./client.nix { | ||
| inherit server version yarnModulesConfig mkYarnModulesFixed; | ||
| sources = patchedSource; | ||
| }; | ||
|
|
||
| in stdenv.mkDerivation rec { | ||
| inherit version; | ||
| pname = "peertube"; | ||
| src = patchedSource; | ||
|
|
||
| buildPhase = '' | ||
| ln -s ${server.modules}/node_modules . | ||
| rm -rf dist && cp -a ${server.dist}/dist dist | ||
| rm -rf client/dist && cp -a ${client.dist}/dist client/ | ||
| ''; | ||
|
|
||
| installPhase = '' | ||
| mkdir $out | ||
| cp -a * $out | ||
| ln -s /tmp $out/.cache | ||
| ''; | ||
|
|
||
| meta = { | ||
| description = "A free software to take back control of your videos"; | ||
|
|
||
| longDescription = '' | ||
| PeerTube aspires to be a decentralized and free/libre alternative to video | ||
| broadcasting services. | ||
| PeerTube is not meant to become a huge platform that would centralize | ||
| videos from all around the world. Rather, it is a network of | ||
| inter-connected small videos hosters. | ||
| Anyone with a modicum of technical skills can host a PeerTube server, aka | ||
| an instance. Each instance hosts its users and their videos. In this way, | ||
| every instance is created, moderated and maintained independently by | ||
| various administrators. | ||
| You can still watch from your account videos hosted by other instances | ||
| though if the administrator of your instance had previously connected it | ||
| with other instances. | ||
| ''; | ||
|
|
||
| license = lib.licenses.agpl3Plus; | ||
|
|
||
| homepage = "https://joinpeertube.org/"; | ||
| platforms = lib.platforms.unix; | ||
|
|
||
| maintainers = with lib.maintainers; [ immae stevenroose ]; | ||
| }; | ||
| } | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.