Twaalf builds

Een seedbox op een 50 TB opslagnode, met permissions die standhouden

qBittorrent op een S-50 met een NVMe-stagingtier, een geharde unit, grouppermissions die elke nieuwe download overleven, en een proxy die de interface van het publieke internet afhoudt.

Wat dit oplevert

Een storage node die qBittorrent draait als een unprivileged service: onvolledige data wordt naar de NVMe-laag geschreven, voltooide data wordt verplaatst naar de vijftig-terabyte bulklaag, alles is eigendom van een gedeelde groep zodat een tweede account het via SFTP kan lezen zonder enig chmod-archeologiewerk, en een webinterface die alleen via een geverifieerde proxy bereikbaar is.

De voor de hand liggende aanpak is om het pakket te installeren, door de interface te klikken en door te gaan met je dag. Dat werkt voor een veertiental dagen, totdat het eerste bestand met de verkeerde groep arriveert en je synchronisatiegebruiker het niet kan lezen, en tegen die tijd zijn er veertigduizend bestanden met de verkeerde groep.

Voordat je begint

  • Een S-50: vijftig terabyte bulk achter een één-terabyte NVMe-laag, op een ten-gigabit-poort. Verkeer is ongelimiteerd onder fair use, en de acceptabelegebruikspolicy is kort en specifiek over wat eroverheen mag. Distributierechten zijn jouw probleem, geen voetnoot.
  • Debian 13, root, en een hostname zoals box.example.com.

1. Gebruikers, groepen, indeling

apt update && apt install -y qbittorrent-nox nginx apache2-utils acl
groupadd -g 3000 media
useradd -r -g media -u 3000 -d /srv/qbt -m -s /usr/sbin/nologin qbt
useradd -m -G media sync

Twee accounts, één groep. De daemon draait als qbt en logt nooit in; sync is het account waarmee je bestanden ophaalt en niets kan schrijven. Nu de mappen, en de twee vlaggen die dit permanent laten werken:

install -d -o qbt -g media -m 2775 /srv/nvme/incomplete
install -d -o qbt -g media -m 2775 /srv/bulk/complete
setfacl -d -m g:media:rwx /srv/bulk/complete
setfacl -d -m g:media:rwx /srv/nvme/incomplete

Mode 2775 zet de setgid-bit, zodat elk bestand dat daarin wordt gemaakt de media-groep erft in plaats van de primaire groep van de aanmaker. De standaard ACL geeft die groep dan lees- en schrijfrechten op nieuwe items, ongeacht de umask van het proces. Samen betekenen ze dat de toestemmingsvraag één keer wordt beantwoord in plaats van na elke download.

Op een S-50 zijn bulk-laag en NVMe aparte blokapparaten. Bevestig welke welke is voordat je je aan de paden vastlegt:

lsblk -o NAME,SIZE,ROTA,MOUNTPOINT

2. De daemon

Start hem één keer zodat hij een configuratiebestand schrijft, stop hem dan en bewerk dat bestand. Vechten tegen de interface voor instellingen die in een tekstbestand staan, is een verspilling van een middag.

sudo -u qbt qbittorrent-nox --webui-port=8080 &
sleep 5 && pkill -u qbt qbittorrent-nox

Bewerk /srv/qbt/.config/qBittorrent/qBittorrent.conf zodat de secties [BitTorrent] en [Preferences] dit bevatten:

[BitTorrent]
Session\DefaultSavePath=/srv/bulk/complete
Session\TempPath=/srv/nvme/incomplete
Session\TempPathEnabled=true
Session\Port=51413
Session\DiskCacheSize=2048
Session\MaxConnections=800
Session\MaxUploads=40
Session\GlobalMaxSeedingMinutes=-1
Session\Preallocation=true

[Preferences]
WebUI\Address=127.0.0.1
WebUI\Port=8080
WebUI\LocalHostAuth=false
WebUI\CSRFProtection=true
Downloads\UseIncompleteExtension=true

Staging op NVMe is de volledige truc. Torrent-schrijfbewerkingen zijn klein en verspreid, wat het slechtste mogelijke patroon is voor de bulk-laag; de NVMe absorbeert ze, en het voltooide bestand wordt als één sequentiële kopie overgezet. Preallocatie stopt fragmentatie aan de binnenkant.

3. Een unit die niet kan dwalen

/etc/systemd/system/qbittorrent.service:

[Unit]
Description=qBittorrent
After=network-online.target
Wants=network-online.target

[Service]
User=qbt
Group=media
UMask=0002
ExecStart=/usr/bin/qbittorrent-nox
Restart=on-failure
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
ReadWritePaths=/srv/qbt /srv/nvme/incomplete /srv/bulk/complete
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

UMask=0002 en Group=media zijn wat nieuwe bestanden groep-schrijfbaar houdt. Zonder de eerste geeft setgid je de juiste groep op bestanden die niemand in die groep kan schrijven, wat een subtiel en irritant halfsucces is.

systemctl daemon-reload && systemctl enable --now qbittorrent

4. Kernel en firewall

Tien gigabit met enkele honderden peers vereist grotere socketbuffers en een verbindingstabel die niet vol raakt:

cat > /etc/sysctl.d/70-seedbox.conf <<EOF
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.netfilter.nf_conntrack_max = 524288
EOF
sysctl --system

Firewall: de torrentpoort open op beide families, SSH en HTTPS open, de webinterface gebonden aan loopback en dus niets nodig hebbend.

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iif lo accept
    ip6 nexthdr icmpv6 accept
    ip protocol icmp accept
    tcp dport { 22, 443 } accept
    tcp dport 51413 accept
    udp dport 51413 accept
  }
}

5. De interface, achter een proxy

certbot certonly --standalone -d box.example.com
htpasswd -c /etc/nginx/qbt.htpasswd you
server {
  listen 443 ssl;
  server_name box.example.com;
  ssl_certificate     /etc/letsencrypt/live/box.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/box.example.com/privkey.pem;
  client_max_body_size 100m;

  location / {
    auth_basic "closed";
    auth_basic_user_file /etc/nginx/qbt.htpasswd;
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_http_version 1.1;
  }
}

Verifieer het

Gebruik iets met een groot, goed geseed zwerm en een ondubbelzinnige licentie. Een huidige Debian-installerimage is de traditionele keuze en verzadigt een ten-gigabit-poort overtuigender dan iets anders dat je legaal kunt testen.

Voeg de torrent via de interface toe en kijk dan toe hoe de staging-laag volloopt:

watch -n2 "du -sh /srv/nvme/incomplete /srv/bulk/complete"

Terwijl hij draait, bevestig dat de poort daadwerkelijk bereikbaar is in plaats van alleen open in je eigen firewall, aangezien een onbereikbare poort een seedbox oplevert die aanvaardbaar downloadt en naar niemand seedt:

ss -tn state established sport = :51413 | wc -l

Inkomende verbindingen op die poort betekenen dat peers je vonden. Nul, met veel uitgaande verbindingen, betekent dat alleen jij naar buiten belt.

Wanneer de download voltooid is, controleer dan de drie dingen waarvoor deze build bestaat:

ls -l /srv/nvme/incomplete
ls -ln /srv/bulk/complete
sudo -u sync cat /srv/bulk/complete/*.iso > /dev/null && echo "sync can read"

De staging-map is leeg, de voltooide bestanden tonen groep 3000 met groep lezen en schrijven, en het sync-account kan ze lezen zonder enige handmatige toestemmingsreparatie. Dat derde commando is degene die bewijst dat de setgid- en ACL-inspanning zijn vruchten heeft afgeworpen.

Controleer ten slotte dat de interface niet is blootgesteld:

curl -m5 http://box.example.com:8080/ ; echo "exit $?"
curl -sI https://box.example.com/ | head -1

De eerste moet mislukken op verbinding, de tweede moet 401 retourneren. Iets anders betekent dat de adresbinding in stap twee niet is doorgevoerd.

Nadien

Stel een globale seedverhouding of een deeltijdslimiet in, tenzij je van plan bent alles voor altijd te seeden, omdat vijftig terabyte sneller volloopt dan iemand verwacht. Als er ooit een klacht bij ons over verkeer van jouw instantie komt, wordt het proces beschreven op de misbruikpagina: het wordt naar jou doorgestuurd en wij gaan niet door je schijf zoeken.

Klaar wanneer jij dat bent

Kies een stad. Kies een formaat. Betaal in munt.

Geen formulieren over wie je bent, geen wachten op een mens die je goedkeurt, geen telefoontje om iets te verifiëren. De factuur wordt betaald en de inloggegevens belanden in je inbox.