Что собираем
Накопительный узел под управлением qBittorrent как непривилегированный сервис: незавершённые данные пишутся на NVMe-уровень, завершённые перемещаются на уровень на пятьдесят терабайт, всё принадлежит общей группе, чтобы второй аккаунт мог читать их по SFTP без археологии с chmod, и веб-интерфейс доступен только через аутентифицированный прокси.
Очевидный подход — установить пакет, пройтись по интерфейсу и заняться своими делами. Это работает пару недель, пока не придёт первый файл с неверной группой, и ваш синхронизирующий пользователь не сможет его прочитать, а к тому моменту уже сорок тысяч файлов с неверной группой.
Перед началом
- S-50: пятьдесят терабайт bulk-хранилища за уровнем NVMe на один терабайт, порт на десять гигабит. Трафик безлимитен при честном использовании, а политика допустимого использования короткая и чёткая по поводу того, что через него можно пропускать. Права на распространение — ваша проблема, а не сноска.
- Debian 13, root, имя хоста вроде
box.example.com.
1. Пользователи, группы, структура
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Два аккаунта, одна группа. Демон работает как qbt и никогда не входит в систему; sync — аккаунт, которым вы забираете файлы и не можете ничего записывать. Теперь каталоги и два флага, которые делают это постоянным:
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Режим 2775 устанавливает бит setgid, поэтому каждый файл, созданный внутри, наследует группу media вместо основной группы создавшего пользователя. Затем ACM по умолчанию даёт этой группе права на чтение и запись для новых записей, независимо от umask процесса. Вместе они решают вопрос прав один раз, а не после каждой загрузки.
На S-50 bulk-уровень и NVMe — отдельные блочные устройства. Подтвердите, какое есть какое, прежде чем фиксировать пути:
lsblk -o NAME,SIZE,ROTA,MOUNTPOINT2. Демон
Запустите его один раз, чтобы он создал конфигурационный файл, затем остановите и отредактируйте этот файл. Бороться с интерфейсом за настройки, которые живут в текстовом файле — пустая трата дня.
sudo -u qbt qbittorrent-nox --webui-port=8080 &
sleep 5 && pkill -u qbt qbittorrent-noxОтредактируйте /srv/qbt/.config/qBittorrent/qBittorrent.conf так, чтобы секции [BitTorrent] и [Preferences] содержали:
[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Промежуточное хранение на NVMe — весь трюк. Записи торрентов малы и разрозненны — худший возможный паттерн для bulk-уровня; NVMe их поглощает, а завершённый файл перемещается одним последовательным копированием. Предварительное выделение предотвращает фрагментацию на входе.
3. Юнит, который не может отклоняться
/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.targetUMask=0002 и Group=media — то, что поддерживает права на запись для группы для новых файлов. Без первого setgid даёт правильную группу файлам, к которым никто в этой группе не может писать, — тонкий и раздражающий полууспех.
systemctl daemon-reload && systemctl enable --now qbittorrent4. Ядро и брандмауэр
Десять гигабит с несколькими сотнями пиров требует буферов сокетов побольше и таблицы соединений, которая не заполнится:
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Брандмауэр: порт для торрентов открыт для обоих семейств, SSH и HTTPS открыты, веб-интерфейс привязан к loopback, поэтому ему ничего не нужно.
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. Интерфейс за прокси
certbot certonly --standalone -d box.example.com
htpasswd -c /etc/nginx/qbt.htpasswd youserver {
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;
}
}Проверка
Используйте что-то с большим, хорошо раздающимся роем и однозначной лицензией. Текущий образ установщика Debian — традиционный выбор, и он загружает порт на десять гигабит более убедительно, чем всё остальное, с чем можно законно тестировать.
Добавьте торрент через интерфейс, затем наблюдайте, как наполняется промежуточный уровень:
watch -n2 "du -sh /srv/nvme/incomplete /srv/bulk/complete"Пока работает, подтвердите, что порт действительно доступен извне, а не просто открыт в вашем брандмауэре, поскольку недоступный порт даёт сидбокс, который загружает приемлемо и не раздаёт никому:
ss -tn state established sport = :51413 | wc -lВходящие соединения на этот порт означают, что пиры вас нашли. Ноль при обилии исходящих соединений означает, что наружу звоните только вы.
По завершении загрузки проверьте три вещи, ради которых это всё строилось:
ls -l /srv/nvme/incomplete
ls -ln /srv/bulk/complete
sudo -u sync cat /srv/bulk/complete/*.iso > /dev/null && echo "sync can read"Промежуточный каталог пуст, завершённые файлы показывают группу 3000 с правами на чтение и запись для группы, и аккаунт sync может читать их без ручного исправления прав. Третья команда — та, что доказывает, что setgid и ACM окупились.
Наконец, докажите, что интерфейс не открыт:
curl -m5 http://box.example.com:8080/ ; echo "exit $?"
curl -sI https://box.example.com/ | head -1Первая должна завершиться неудачей при соединении, вторая должна вернуть 401. Всё иное — привязка адреса на втором шаге не сработала.
Далее
Установите глобальное соотношение раздачи или лимит времени раздачи, если не собираетесь раздавать всё вечно, поскольку пятьдесят терабайт заполняются быстрее, чем кто-либо ожидает. Если до нас дойдёт жалоба на трафик с вашего экземпляра, процесс описан на странице злоупотреблений: она пересылается вам, и мы не копаемся в вашем диске.