]> git.immae.eu Git - perso/Immae/Config/Nix.git/blob - flakes/peertube/flake.nix
Write peertube flake
[perso/Immae/Config/Nix.git] / flakes / peertube / flake.nix
1 {
2 description = "A free software to take back control of your videos";
3 inputs.myuids = {
4 url = "https://git.immae.eu/perso/Immae/Config/Nix.git";
5 type = "git";
6 dir = "flakes/myuids";
7 };
8 inputs.flake-utils.url = "github:numtide/flake-utils";
9 inputs.nixpkgs.url = "github:NixOS/nixpkgs";
10 inputs.peertube = {
11 url = "github:Chocobozzz/PeerTube/v3.0.1";
12 flake = false;
13 };
14
15 outputs = { self, myuids, nixpkgs, peertube, flake-utils }: flake-utils.lib.eachSystem ["x86_64-linux"] (system:
16 let
17 version = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.peertube.locked.rev;
18 pkgs = import nixpkgs { inherit system; overlays = [
19 (self: super: { nodejs = self.nodejs-12_x; })
20 ]; };
21 inherit (pkgs) callPackage stdenv jq youtube-dl fetchurl nodePackages yarn2nix-moretea;
22
23 patchedSource = stdenv.mkDerivation {
24 pname = "peertube";
25 inherit version;
26 src = peertube;
27 phases = [ "unpackPhase" "patchPhase" "installPhase" ];
28 patches = [ ./fix_yarn_lock.patch ];
29 installPhase = ''
30 mkdir $out
31 cp -a . $out/
32 '';
33 };
34 yarnModulesConfig = {
35 bcrypt = {
36 buildInputs = [ nodePackages.node-pre-gyp ];
37 postInstall = let
38 bcrypt_version = "5.0.0";
39 bcrypt_lib = fetchurl {
40 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";
41 sha256 = "0j3p2px1xb17sw3gpm8l4apljajxxfflal1yy552mhpzhi21wccn";
42 };
43 in
44 ''
45 if [ "${bcrypt_version}" != "$(cat package.json | ${jq}/bin/jq -r .version)" ]; then
46 echo "Mismatching version please update bcrypt in derivation"
47 false
48 fi
49 mkdir -p lib/binding && tar -C lib/binding -xf ${bcrypt_lib}
50 patchShebangs ../node-pre-gyp
51 npm run install
52 '';
53 };
54 utf-8-validate = {
55 buildInputs = [ nodePackages.node-gyp-build ];
56 };
57 youtube-dl = {
58 postInstall = ''
59 mkdir bin
60 ln -s ${youtube-dl}/bin/youtube-dl bin/youtube-dl
61 cat > bin/details <<EOF
62 {"version":"${youtube-dl.version}","path":null,"exec":"youtube-dl"}
63 EOF
64 '';
65 };
66 };
67 mkYarnModules' = args: (yarn2nix-moretea.mkYarnModules args).overrideAttrs(old: {
68 # This hack permits to workaround the fact that the yarn.lock
69 # file doesn't respect the semver requirements
70 buildPhase = builtins.replaceStrings [" ./package.json"] [" /dev/null; cp deps/*/package.json ."] old.buildPhase;
71 });
72
73 server = callPackage ./server.nix {
74 inherit version yarnModulesConfig mkYarnModules';
75 sources = patchedSource;
76 };
77 client = callPackage ./client.nix {
78 inherit server version yarnModulesConfig mkYarnModules';
79 sources = patchedSource;
80 };
81
82 in rec {
83 packages.peertube = stdenv.mkDerivation rec {
84 inherit version;
85 pname = "peertube";
86 src = patchedSource;
87 buildPhase = ''
88 ln -s ${server.modules}/node_modules .
89 rm -rf dist && cp -a ${server.dist}/dist dist
90 rm -rf client/dist && cp -a ${client.dist}/dist client/
91 '';
92 installPhase = ''
93 mkdir $out
94 cp -a * $out
95 ln -s /tmp $out/.cache
96 '';
97
98 meta = {
99 description = "A free software to take back control of your videos";
100
101 longDescription = ''
102 PeerTube aspires to be a decentralized and free/libre alternative to video
103 broadcasting services.
104 PeerTube is not meant to become a huge platform that would centralize
105 videos from all around the world. Rather, it is a network of
106 inter-connected small videos hosters.
107 Anyone with a modicum of technical skills can host a PeerTube server, aka
108 an instance. Each instance hosts its users and their videos. In this way,
109 every instance is created, moderated and maintained independently by
110 various administrators.
111 You can still watch from your account videos hosted by other instances
112 though if the administrator of your instance had previously connected it
113 with other instances.
114 '';
115
116 license = stdenv.lib.licenses.agpl3Plus;
117
118 homepage = "https://joinpeertube.org/";
119
120 platforms = stdenv.lib.platforms.unix;
121 };
122 };
123 defaultPackage = packages.peertube;
124 legacyPackages.peertube = packages.peertube;
125 checks = {
126 build = defaultPackage;
127 } // pkgs.lib.optionalAttrs (builtins.elem system pkgs.lib.systems.doubles.linux) {
128 test =
129 let testing = import (nixpkgs + "/nixos/lib/testing-python.nix") { inherit system; };
130 in testing.makeTest {
131 nodes = {
132 client = { pkgs, ... }: {};
133
134 server = { pkgs, ... }: {
135 imports = [ self.nixosModule ];
136 config.networking.firewall.allowedTCPPorts = [ 8888 ];
137 config.services.redis.enable = true;
138 config.services.postgresql = {
139 enable = true;
140 initialScript = pkgs.writeText "peertube.sql" ''
141 CREATE ROLE "peertube" WITH LOGIN PASSWORD 'peertube';
142 CREATE DATABASE "peertube_prod" WITH OWNER "peertube"
143 TEMPLATE template0
144 LC_COLLATE = "C"
145 LC_CTYPE = "C";
146 \c peertube_prod
147 CREATE EXTENSION unaccent;
148 CREATE EXTENSION pg_trgm;
149 '';
150 };
151 config.services.peertube.enable = true;
152 config.services.peertube.configFile = pkgs.writeText "peertube.conf" ''
153 listen:
154 hostname: '0.0.0.0'
155 port: 8888
156 webserver:
157 https: false
158 hostname: 'localhost.tld'
159 port: 8888
160 database:
161 hostname: 'localhost'
162 port: 5432
163 suffix: '_prod'
164 username: 'peertube'
165 password: 'peertube'
166 pool:
167 max: 5
168 redis:
169 socket: 'localhost'
170 auth: null
171 db: 0
172 storage:
173 tmp: '/var/lib/peertube/storage/tmp/'
174 avatars: '/var/lib/peertube/storage/avatars/'
175 videos: '/var/lib/peertube/storage/videos/'
176 streaming_playlists: '/var/lib/peertube/storage/streaming-playlists/'
177 redundancy: '/var/lib/peertube/storage/videos/'
178 logs: '/var/lib/peertube/storage/logs/'
179 previews: '/var/lib/peertube/storage/previews/'
180 thumbnails: '/var/lib/peertube/storage/thumbnails/'
181 torrents: '/var/lib/peertube/storage/torrents/'
182 captions: '/var/lib/peertube/storage/captions/'
183 cache: '/var/lib/peertube/storage/cache/'
184 plugins: '/var/lib/peertube/storage/plugins/'
185 client_overrides: '/var/lib/peertube/storage/client-overrides/'
186 '';
187 };
188 };
189 testScript = ''
190 start_all()
191 server.wait_for_unit("peertube.service")
192 server.wait_for_open_port(8888)
193 client.succeed("curl http://server:8888")
194 client.succeed("curl http://server:8888/client/fr-FR/index.html")
195 '';
196 };
197 };
198 }
199 ) // {
200 nixosModule = { lib, pkgs, config, ... }:
201 let
202 name = "peertube";
203 cfg = config.services.peertube;
204 in
205 {
206 options.services.peertube = {
207 enable = lib.mkEnableOption "Enable Peertube’s service";
208 user = lib.mkOption {
209 type = lib.types.str;
210 default = name;
211 description = "User account under which Peertube runs";
212 };
213 group = lib.mkOption {
214 type = lib.types.str;
215 default = name;
216 description = "Group under which Peertube runs";
217 };
218 dataDir = lib.mkOption {
219 type = lib.types.path;
220 default = "/var/lib/${name}";
221 description = ''
222 The directory where Peertube stores its data.
223 '';
224 };
225 configFile = lib.mkOption {
226 type = lib.types.path;
227 description = ''
228 The configuration file path for Peertube.
229 '';
230 };
231 package = lib.mkOption {
232 type = lib.types.package;
233 default = self.defaultPackage."${pkgs.system}";
234 description = ''
235 Peertube package to use.
236 '';
237 };
238 # Output variables
239 systemdStateDirectory = lib.mkOption {
240 type = lib.types.str;
241 # Use ReadWritePaths= instead if varDir is outside of /var/lib
242 default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
243 lib.strings.removePrefix "/var/lib/" cfg.dataDir;
244 description = ''
245 Adjusted Peertube data directory for systemd
246 '';
247 readOnly = true;
248 };
249 };
250
251 config = lib.mkIf cfg.enable {
252 users.users = lib.optionalAttrs (cfg.user == name) {
253 "${name}" = {
254 uid = myuids.lib.uids.peertube;
255 group = cfg.group;
256 description = "Peertube user";
257 home = cfg.dataDir;
258 useDefaultShell = true;
259 };
260 };
261 users.groups = lib.optionalAttrs (cfg.group == name) {
262 "${name}" = {
263 gid = myuids.lib.gids.peertube;
264 };
265 };
266
267 systemd.services.peertube = {
268 description = "Peertube";
269 wantedBy = [ "multi-user.target" ];
270 after = [ "network.target" "postgresql.service" ];
271 wants = [ "postgresql.service" ];
272
273 environment.NODE_CONFIG_DIR = "${cfg.dataDir}/config";
274 environment.NODE_ENV = "production";
275 environment.HOME = cfg.package;
276
277 path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl ];
278
279 script = ''
280 install -m 0750 -d ${cfg.dataDir}/config
281 ln -sf ${cfg.configFile} ${cfg.dataDir}/config/production.yaml
282 ln -sf ${cfg.package}/config/default.yaml ${cfg.dataDir}/config/default.yaml
283 exec npm run start
284 '';
285
286 serviceConfig = {
287 User = cfg.user;
288 Group = cfg.group;
289 WorkingDirectory = cfg.package;
290 StateDirectory = cfg.systemdStateDirectory;
291 StateDirectoryMode = 0750;
292 PrivateTmp = true;
293 ProtectHome = true;
294 ProtectControlGroups = true;
295 Restart = "always";
296 Type = "simple";
297 TimeoutSec = 60;
298 };
299
300 unitConfig.RequiresMountsFor = cfg.dataDir;
301 };
302 };
303 };
304
305 };
306 }