diff --git a/content/posts/i_now_host_my_own_videos/note.md b/content/posts/i_now_host_my_own_videos/note.md new file mode 100644 index 0000000..c2d2ed8 --- /dev/null +++ b/content/posts/i_now_host_my_own_videos/note.md @@ -0,0 +1,87 @@ +X-Date: 2023-10-26T00:50:00Z +X-Note-Id: 333c449a-d74b-4691-b769-45036424e79f +Subject: I now host my own videos (with PeerTube) +X-Slug: i_now_host_my_own_videos + +Today I've launched a separate server that contains my own PeerTube instance: [videos.knazarov.com](https://videos.knazarov.com). +All videos that I produce will be mirrored there, because I care about giving people an alternative to centralized platforms. + +If you're curious how this is set up, here's [a link to the configuration repo](https://git.sr.ht/~knazarov/nixos/tree/master/item/nodes/videos/configuration.nix). +The most interesting part that's not mentioned in the [official wiki article](https://nixos.wiki/wiki/PeerTube) on NixOS is the +security. The way the article does this will keep the world-readable plain-text passwords in the configuration on the +filesystem. My approach is to use SOPS and use a principle of minimal access permissions, and as such I've figured out how +to store the passwords encrypted and expose them to only the required users. + +For example, take the postgres init script. In this init script, you are setting up a peertube user. This is how +the authors did it: + +``` + postgresql = { + enable = true; + enableTCPIP = true; + authentication = '' + hostnossl peertube_local peertube_test 127.0.0.1/32 md5 + ''; + initialScript = pkgs.writeText "postgresql_init.sql" '' + CREATE ROLE peertube_test LOGIN PASSWORD 'test123'; + CREATE DATABASE peertube_local TEMPLATE template0 ENCODING UTF8; + GRANT ALL PRIVILEGES ON DATABASE peertube_local TO peertube_test; + \connect peertube_local + CREATE EXTENSION IF NOT EXISTS pg_trgm; + CREATE EXTENSION IF NOT EXISTS unaccent; + ''; + }; +``` + +Notice that the password is in plain text here. This would put the password to `/nix/store/` which is world-readable. +Since the postgres recipe doesn't have a separate configuration parameter for users/passwords, I've stuffed the whole initialScript into SOPS secret, like this: + +``` + services.postgresql = { + enable = true; + enableTCPIP = true; + authentication = '' + hostnossl peertube_local peertube_test 127.0.0.1/32 md5 + ''; + initialScript = config.sops.secrets.postgresql_init.path; + }; + + sops.secrets = { + postgresql_init = { + mode = "0440"; + group = config.users.groups.postgres.name; + }; + }; +``` + +And then put the whole init script into the SOPS-managed secret file. + +Another nice thing that I did is plugging LetsEncrypt SSL certificate generation right into this config. The +wiki doesn't bother with doing this, but you can actually combine: + +``` + services.peertube = { + enable = true; + localDomain = "videos.knazarov.com"; + configureNginx = true; + ... + }; + services.nginx = { + enable = true; + virtualHosts = { + "videos.knazarov.com" = { + enableACME = true; + forceSSL = true; + locations."/" = { proxyPass = "http://127.0.0.1:9000"; }; + }; + }; + ... + }; +``` + +Initially I thought that specifying `virtualHosts` with `enableACME` would conflict with the autogenerated configuration +that `services.peertube` is creating, but it didn't! + +With this config, I can now reproduce this server again from scratch in one single command. + +What's left to do is to set up fail2ban to get a bit more security and also configure backups.