Context: Would YOU donate your idle CPU cycles to TankieTube?
Linux Steps
*Feel free to ask me any questions by PM, email, or commenting here.*
1. Install dependencies
Debian
$ sudo apt update
$ sudo apt install nodejs npm ffmpeg
$ sudo npm install -g @peertube/peertube-runner
Arch Linux
$ sudo pacman -Syu nodejs npm ffmpeg
$ sudo npm install -g @peertube/peertube-runner
2. Create the dedicated system user
$ sudo useradd -m -d /srv/prunner -s /bin/bash -p <random_password> prunner
3. Create the systemd unit
$ sudo nano /etc/systemd/system/prunner.service
Paste and save this.
spoiler
[Unit]
After=network.target
Description=PeerTube runner daemon
[Service]
CapabilityBoundingSet=~CAP_SYS_ADMIN
Environment=NODE_ENV=production
ExecStart=peertube-runner server --enable-job vod-web-video-transcoding --enable-job vod-hls-transcoding --enable-job vod-audio-merge-transcoding
Group=prunner
LockPersonality=true
NoNewPrivileges=true
PrivateDevices=false
PrivateMounts=true
PrivateTmp=true
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectSystem=strict
ReadWritePaths=/srv/prunner
Restart=always
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=true
RestrictSUIDSGID=true
SyslogIdentifier=prunner
SystemCallArchitectures=native
Type=simple
User=prunner
WorkingDirectory=/srv/prunner
[Install]
WantedBy=multi-user.target
4. Enable & start the systemd unit
Starting the process for the first time will generate the config file.
$ sudo systemctl daemon-reload
$ sudo systemctl enable prunner.service
$ sudo systemctl restart prunner.service
5. Edit the config file
$ sudo nano /srv/prunner/.config/peertube-runner-nodejs/default/config.toml
a. Under [jobs]
, set concurrency
equal to the number of virtual cores your CPU has.
b. Under, [
, set ]threads = 1
.
c. Save and exit.
6. Restart to load the configuration changes
$ sudo systemctl restart prunner.service
7. Email TankieTanuki@tankie.tube
a. OpSec: Use an email detached from your legal identity. Attachment to your Hexbear/Lemmy username is optional.
b. Put "TinyTanks" in the subject line.
c. In the body, request a nickname for your runner.
d. I'll reply with the final command to enter, which includes your secret token!
Windows/MacOS/Docker
*Comrades are welcome to contribute steps for alternate installations. I'm only good with Linux.*
Why can't this be "strict"? What directories does prunner need to write to?
If it's just WorkingDirectory, a
ReadWritePaths=/srv/prunner
is all that is needed.Edit: If anyone want's to actually run this, I can help you harden the systemd service.
prunner only needs to write inside its home directory.
I changed ProtectSystem to strict. Thanks for the suggestion.
What other edits do you recommend?
With ProtectSystem=strict you also need
ReadWritePaths=/srv/prunner
, WorkingDirectory is not excluded from being read-only.I could recommend a lot of stuff.
Feel free to rewrite it and I'll test it out on my runners. I only know systemd basics.
This is a list of things that could help harden, some of these I am not as sure about
PrivateTmp=true # Does prunner use tmp? Does ffmpeg use tmp? PrivateMounts=true # prunner/ffmpeg shouldn't need to mount stuff anyways... right? ProtectClock=true # prunner and ffmpeg do not need to set hardware clock ProtectKernelTunables=true # "Few services need to write to these at runtime" ProtectKernelModules=true # I don't see prunner/ffmpeg needing to mod_probe ProtectKernelLogs=true # prunner/ffmpeg do not need to write to dmesg ProtectControlGroups=true # Not a container manager ProtectProc=invisible # Keep an eye out RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 # Other socket types are rare LockPersonality=true # prunner/ffmpeg shouldn't need to change personality? #MemoryDenyWriteExecute=true # Wait, prunner is a JS app isn't it? Hoping no JIT is needed **EDIT**: Yes, this is a problem RestrictSUIDSGID=true # No privilege elevation RestrictNamespaces=true # ffmpeg does not need namespaces SystemCallArchitectures=native # hardens other options ProtectHostname=true # Actually, seems like it might not be a problem. Hostname is "copied from callers namespace" # Not setting: # PrivateUsers=true # Meh. Problem I had with it in bind should not be the case here. If you feel like it, try it out. # SystemCallFilter # Can't be bothered to go through the list # ProcSubset=pid # Kernel APIs, not sure if ffmpeg needs them # PrivateDevices=true # afraid ffmpeg needs it # RestrictRealtime=true # prunner sets the niceness of ffmpeg
Terrific! I'm testing it now as I type.
I've made some changes between when I posted it and now (actually I just made a change, ProtectHostname) so make sure you get everything.
I tried setting it up myself, I was correct that MemoryDenyWriteExecute would be a problem.
Ah, that might be why it looks stalled.
Yea, make sure to
journalctl -eu prunner
every time you restart it to check the logsAll these systemd options are documented in the man page, see https://man7.org/linux/man-pages/man5/systemd.exec.5.html
Can you audit the unit file in my latest edit, please?
ProtectSystem is full, not strict. Otherwise seems fine
Will it be able to write inside /srv/prunner if that's set to strict?
If you add the ReadWritePaths I told you to
i'm learning a lot today
Btw, once these options are added, you can run
systemd-analyze security prunner
to check which options haven't been enabled (it doesn't know if it should be enabled though. Add --no-pager if you want to copy it)What's a pager? You mean those things people used to wear on their belts before cellphones were commonplace?
https://unix.stackexchange.com/questions/144016/what-is-a-pager
Oh, I see! Page like in pagination. Now I know the proper name for less's function. 🙂 Thanks!