ЧАСТЬ 1. От «чистой» платы до базово защищённой системы
(Orange Pi RV2 + Ubuntu Server)
0. Введение — что мы строим и зачем
В этой серии статей мы шаг за шагом превращаем Orange Pi RV2 в полноценный домашний медиахаб и сервисный узел, который:
- хранит фильмы и сериалы на внешнем SSD;
- раздаёт медиаконтент по DLNA на телевизоры и приставки;
- скачивает торренты без GUI через qBittorrent-nox;
- имеет собственный Web-интерфейс на Rust (Axum);
- готов к будущему WireGuard-доступу из интернета;
- работает стабильно и безопасно.
❗ Цель проекта — не «чтобы как-то работало», а построить правильную архитектуру, которую не стыдно оставить работать годами без постоянного обслуживания.

🔁 Шаг 0. Запись образа Ubuntu Server (microSD)
0.1 Скачивание образа
Используем официальный Ubuntu Server для Orange Pi RV2
(на момент написания — Ubuntu 24.04 Noble, riscv64).
📌 Важно:
- именно Server, не Desktop;
- именно образ под RV2 (RISC-V).
0.2 Запись через dd (осознанно)
Мы используем dd, потому что:
- он ничего не «улучшает» и не портит;
- показывает реальное устройство;
- исключает «магические» проблемы, которые любят графические утилиты.
Определяем microSD
lsblk
Пример:
sda 465G
mmcblk0 32G ← microSD
❗ НЕ перепутай диск.
Ошибка здесь = потеря данных.
Запись образа
sudo dd if=ubuntu-opi-rv2.img of=/dev/mmcblk0 bs=4M status=progress conv=fsync
После завершения:
sync
- вынимаем карту;
- вставляем в Orange Pi RV2;
- включаем питание.
1. Подготовка системы
1.1 Первый вход и проверка образа
Подключаемся по SSH (IP смотрим в роутере):
ssh orangepi@192.168.1.xxx
Пароль по умолчанию — orangepi.
Проверяем систему:
lsb_release -a
uname -a
Убеждаемся, что:
- Ubuntu Server;
- архитектура riscv64;
- система загружается стабильно.
Перенос системы с microSD на eMMC (штатный способ Orange Pi)
После первой загрузки Orange Pi RV2 с microSD логично перенести систему на встроенную eMMC:
- eMMC быстрее microSD
- стабильнее при долгой работе
- освобождает слот microSD
- официально поддерживается образом Orange Pi
❗ ВАЖНО
Мы НЕ используем dd, НЕ копируем вручную разделы, НЕ трогаем bootloader.
Всё делается через встроенную утилиту, которая уже есть в образе Orange Pi Ubuntu Server.
🔹 Что нам нужно перед началом
- Orange Pi RV2 загружен с microSD
- Вход под пользователем (root или sudo)
- Никаких важных данных на eMMC (она будет полностью очищена)
🔹 Проверяем, что eMMC определяется системой
lsblk
Обычно:
mmcblk0— microSDmmcblk1— eMMC
Пример:
mmcblk0 14.9G
└─mmcblk0p1
mmcblk1 29.1G
Если mmcblk1 присутствует — можно продолжать.
🔹 Запуск штатной утилиты Orange Pi
В образе уже есть фирменный скрипт:
sudo orangepi-config
Откроется текстовое меню (ncurses).
🔹 Путь в меню
System → Install system to eMMC
(формулировка может незначительно отличаться, но смысл именно такой)
🔹 Что делает утилита
Утилита автоматически:
- полностью очищает eMMC
- копирует систему с microSD
- переносит загрузчик
- корректно настраивает boot-раздел
- сохраняет совместимость с обновлениями
⚠️ Все данные на eMMC будут удалены — это подтверждается отдельным предупреждением.
Подтверждаем перенос.
🔹 Ожидание завершения
Процесс занимает обычно ~ 5 минут, зависит от скорости microSD.
Во время процесса:
- ничего не отключаем
- не перезагружаем плату
- не вынимаем питание
По завершении появится сообщение об успешной установке.
🔹 Перезагрузка и проверка
Выключаем плату:
sudo poweroff
- Вынимаем microSD
- Включаем питание обратно
Если всё сделано правильно — система загрузится уже с eMMC.
Проверяем:
lsblk
Теперь корневая система (/) должна быть на mmcblk1.








1.2 ❗ Исправление APT (Ubuntu Ports) — КРИТИЧЕСКИ ВАЖНО
На ARM/RISC-V платах часто используются сломанные зеркала
(Huawei Cloud и т.п.).
Если не исправить это сейчас — дальше всё будет ломаться.
Открываем файл:
sudo nano /etc/apt/sources.list
Полностью заменяем содержимое:
deb http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports noble-backports main restricted universe multiverse
Сохраняем (Ctrl+O → Enter → Ctrl+X) и обновляем систему пакетов:
sudo apt clean
sudo apt update
❗ Если здесь есть ошибки — дальше идти нельзя.
1.3 Полное обновление системы
sudo apt upgrade -y
sudo reboot
После перезагрузки снова подключаемся по SSH
2. Базовая безопасность (обязательно)
2.1 Настройка hostname
Hostname используется:
- в логах;
- в systemd;
- в VPN;
- в Web UI.
Проверяем текущее имя:
hostname
Задаём корректное имя:
sudo hostnamectl set-hostname rv2-hub
Правим /etc/hosts:
sudo nano /etc/hosts
Приводим к виду:
127.0.0.1 localhost
127.0.1.1 rv2-hub
Перезагружаемся:
sudo reboot
2.2 Проверка имени и сети
hostname
hostname -I
Ожидаемо:
- hostname:
rv2-hub - IP:
192.168.1.xxx
2.3 Создание отдельного пользователя
❗ Никогда не работаем постоянно под orangepi или root.
Создаём пользователя:
sudo adduser hub
Даём права sudo:
sudo usermod -aG sudo hub
Проверяем:
su - hub
sudo whoami
Если вывод — root, всё в порядке.
👉 Дальше работаем только под пользователем hub.
2.4 SSH hardening (аккуратно)
Открываем конфиг:
sudo nano /etc/ssh/sshd_config
Проверяем / приводим строки:
PermitRootLogin no
PasswordAuthentication yes
PubkeyAuthentication yes
X11Forwarding no
UsePAM yes
📌 Если строки закомментированы — раскомментируй.
Перезапуск SSH:
sudo systemctl restart ssh
❗ ОБЯЗАТЕЛЬНО:
Открой новое SSH-подключение перед тем, как закрывать старое.
Проверка защиты:
ssh root@rv2-hub
Ожидаемо:
Permission denied
Проверяем открытые порты:
ss -tulpen
На этом этапе должен быть открыт только порт 22 (SSH).
⏭ Что дальше
На этом этапе у нас есть:
- корректный Ubuntu Server;
- исправленные репозитории;
- актуальная система;
- нормальный hostname;
- отдельный пользователь;
- базово защищённый SSH.
👉 В ЧАСТИ 2 мы займёмся сетевым периметром:
- UFW по-настоящему подробно;
- multicast и SSDP (без которых DLNA не работает);
- Fail2Ban с реальным конфигом;
- подготовка системы к WireGuard.
🧱 ЧАСТЬ 2. Firewall и защита
(UFW + multicast + Fail2Ban + подготовка к WireGuard)
В Части 1 мы сделали главное:
- установили Ubuntu Server;
- привели APT в порядок;
- обновили систему;
- настроили hostname
rv2-hub; - создали отдельного пользователя
hub; - аккуратно ужесточили SSH.
Теперь у нас чистая и управляемая система.
Но без сетевой защиты это всё — иллюзия безопасности.
👉 Часть 2 — это сетевой периметр.
Здесь чаще всего допускают критические ошибки:
- либо открывают всё подряд;
- либо боятся открыть даже нужное;
- либо «включают UFW, а потом DLNA не работает».
Мы пойдём правильным путём и сделаем всё сразу и навсегда.
Что мы делаем в этой части
В Части 2 мы:
- настраиваем UFW;
- разбираем multicast и SSDP, без которых DLNA не живёт;
- включаем Fail2Ban с реальным конфигом;
- готовим систему к будущему WireGuard, не устанавливая его.
1️⃣ UFW — firewall
На Ubuntu Server UFW — оптимальный выбор, потому что он:
- простой;
- предсказуемый;
- отлично дружит с systemd;
- не ломает multicast (если настроить правильно).
1.1 Проверяем и устанавливаем UFW
Работаем под пользователем hub.
sudo apt install ufw -y
Если UFW уже установлен — это нормально.
1.2 Политики по умолчанию (ОБЯЗАТЕЛЬНО)
Это основа безопасности, без этого UFW не имеет смысла.
sudo ufw default deny incoming
sudo ufw default allow outgoing
Что это означает:
- ❌ все входящие соединения запрещены;
- ✅ все исходящие разрешены.
📌 Сервер может сам ходить в интернет
📌 Но к нему нельзя подключиться, пока мы явно не разрешим порт
1.3 Разрешаем SSH (иначе отрежем себе доступ)
sudo ufw allow ssh
или явно:
sudo ufw allow 22/tcp
Проверяем:
sudo ufw status verbose
Ожидаемо:
22/tcp ALLOW Anywhere
2️⃣ Почему мы открываем порты СРАЗУ, а не «потом»
Это ключевой архитектурный момент.
❌ Плохая практика
- включить firewall;
- поставить сервис;
- «почему не работает?»;
- открыть порт;
- забыть;
- через месяц всё сломалось.
✅ Правильная практика
- заранее понимать архитектуру;
- открыть все нужные порты один раз;
- больше не возвращаться к firewall без причины.
Мы уже знаем, что на этом сервере будет:
- qBittorrent-nox;
- MiniDLNA;
- Web UI (RV2 Hub);
- WireGuard в будущем.
👉 Значит, закладываем всё сейчас.
3️⃣ Открываем порты для сервисов
🔹 Web UI (RV2 Hub)
sudo ufw allow 8081/tcp
🔹 qBittorrent-nox (Web UI)
По умолчанию qBittorrent использует 8080/tcp:
sudo ufw allow 8080/tcp
(порт можно изменить позже, логика останется той же)
🔹 MiniDLNA (HTTP)
MiniDLNA использует 8200/tcp:
sudo ufw allow 8200/tcp
4️⃣ Multicast и SSDP — главный затык DLNA
❗ Без multicast DLNA не работает, даже если сервис запущен.
Что такое SSDP
DLNA-клиенты:
- ❌ не ищут сервер по IP;
- ✅ используют multicast.
Параметры SSDP:
- адрес:
239.255.255.250 - порт:
1900/udp
Разрешаем SSDP
sudo ufw allow 1900/udp
📌 Это пункт, который:
- пропускают 90% инструкций;
- потом пишут «телевизор не видит DLNA».
Проверяем итоговые правила
sudo ufw status verbose
Ожидаемо:
22/tcp ALLOW
8080/tcp ALLOW
8081/tcp ALLOW
8200/tcp ALLOW
1900/udp ALLOW
5️⃣ Включаем firewall
⚠️ Перед этим ЕЩЁ РАЗ убедись, что SSH разрешён.
sudo ufw enable
Ответ:
Firewall is active and enabled on system startup
6️⃣ Проверка multicast на Orange Pi RV2
На Orange Pi интерфейс НЕ eth0.
Чаще всего это:
end0enx<mac>enP...
Проверяем:
ip a
Пример:
2: end0: <BROADCAST,MULTICAST,UP,LOWER_UP>
inet 192.168.1.108/24
📌 Ключевое — наличие флага MULTICAST
Если его нет — DLNA не заработает вообще
7️⃣ Fail2Ban — защита от перебора паролей
Fail2Ban:
- следит за логами;
- банит IP при подборе пароля;
- критически важен перед WireGuard.
7.1 Установка
sudo apt install fail2ban -y
Проверка:
systemctl status fail2ban
Ожидаемо:
Active: active (running)
7.2 Почему дефолт «почти норм», но мы делаем лучше
По умолчанию Fail2Ban:
- уже защищает SSH;
- использует
sshdjail.
👉 Это нормально, но мы делаем явный и читаемый конфиг.
7.3 Реальный рабочий конфиг
Создаём локальный файл:
sudo nano /etc/fail2ban/jail.local
Вставляем:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
findtime = 10m
bantime = 1h
Что это значит:
- 5 попыток;
- за 10 минут;
- бан на 1 час.
Перезапуск:
sudo systemctl restart fail2ban
Проверка:
sudo fail2ban-client status sshd
8️⃣ Подготовка к WireGuard (без установки)
Мы НЕ ставим WireGuard сейчас, но готовим систему.
Почему это важно:
- WireGuard = внешний доступ;
- внешний доступ = атаки;
- Fail2Ban + UFW = защита.
📌 Благодаря текущей настройке:
- SSH защищён;
- порты под контролем;
- multicast работает;
- система готова к VPN.
9️⃣ Финальная проверка Части 2
sudo ufw status verbose
systemctl status fail2ban
ss -tulpen
Ожидаемо:
- открыт только нужный минимум;
- лишних портов нет;
- Fail2Ban активен;
- multicast разрешён.
🔚 Итог Части 2
На этом этапе у нас:
- ✅ грамотно настроенный firewall;
- ✅ рабочий multicast для DLNA;
- ✅ защита от перебора паролей;
- ✅ готовность к WireGuard;
- ✅ и главное — к UFW больше не возвращаемся.
🧱 ЧАСТЬ 3. Подключение и подготовка SSD
Основа стабильности: данные, права, структура
В предыдущих частях мы:
- установили и обновили Ubuntu Server;
- привели APT в порядок;
- настроили базовую безопасность;
- выстроили правильный firewall, multicast и защиту.
Теперь переходим к фундаменту всего проекта — внешнему SSD.
Именно здесь чаще всего закладываются ошибки, которые потом «вылезают» в виде:
- MiniDLNA «не видит файлы»;
- qBittorrent не может писать;
- сервисы работают только от root;
- «после перезагрузки всё пропало».
⚠️ Если этот этап сделать правильно — дальше всё будет работать годами без вмешательства.
🔹 Зачем вообще SSD, если есть microSD / eMMC
microSD / eMMC:
- ограниченный ресурс записи;
- низкая скорость;
- не предназначены для постоянной нагрузки.
SSD:
- высокая скорость;
- надёжность;
- идеально подходит для:
- фильмов и сериалов (DLNA);
- загрузок qBittorrent;
- приложений (RV2 Hub);
- будущих сервисов и бэкапов.
👉 Правильная архитектура:
- microSD / eMMC → только система
- SSD → все данные и сервисы
4️⃣ Подключение и проверка SSD
4.1 Проверка — видит ли система диск
Подключаем SSD к Orange Pi RV2 (желательно USB 3.0).
Проверяем:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
Пример корректного вывода:
sda 465G disk
└─sda1 465G part exfat
mmcblk0 32G disk
├─mmcblk0p1 512M part /boot
└─mmcblk0p2 31G part /
Что здесь важно:
mmcblk0— системный носитель (microSD / eMMC)sda— наш SSDexfat— плохо для сервера
❌ Почему exFAT / NTFS — плохой выбор
Для серверной Linux-системы:
- ❌ нет нормальных Unix-прав;
- ❌ проблемы с systemd-сервисами;
- ❌ MiniDLNA часто не индексирует файлы;
- ❌ «магические» ошибки доступа.
👉 Выбор один: ext4.
🔥 4.2 Полная переразметка SSD (exFAT → ext4)
⚠️ ВСЕ ДАННЫЕ НА SSD БУДУТ УДАЛЕНЫ
Если на диске есть что-то важное — остановись.
Шаг 1. Проверяем, что диск не смонтирован
mount | grep sda
Если смонтирован:
sudo umount /dev/sda1
Шаг 2. Удаляем старую разметку
sudo fdisk /dev/sda
Вводим строго по шагам:
d ← удалить раздел
1 ← номер
n ← новый
p ← primary
1 ← номер
Enter ← начало
Enter ← конец (весь диск)
w ← записать и выйти
Шаг 3. Создаём файловую систему ext4
sudo mkfs.ext4 -L STORAGE /dev/sda1
Проверяем:
blkid /dev/sda1
Пример:
/dev/sda1: UUID="abcd-1234-efgh-5678" TYPE="ext4" LABEL="STORAGE"
👉 UUID обязательно сохраняем.
4.3 Автомонтирование через UUID (fstab)
Шаг 1. Создаём точку монтирования
sudo mkdir -p /srv/storage
📌 Почему /srv:
- стандарт Linux для сервисных данных;
- логично и читаемо;
- удобно для бэкапов и миграций.
Шаг 2. Правим /etc/fstab
Добавляем строку (UUID свой!):
UUID=abcd-1234-efgh-5678 /srv/storage ext4 defaults,noatime 0 2
💡 noatime — меньше лишних записей → SSD живёт дольше.
Шаг 3. Проверка без перезагрузки
sudo mount -a
❗ Ошибок быть не должно
Если есть ошибка — НЕ перезагружайся, исправляй сразу.
Проверка:
df -h | grep storage
Ожидаемо:
/dev/sda1 477G 1G 450G 1% /srv/storage
4.4 Права доступа — самый важный момент
80% проблем с DLNA и торрентами — это права.
Мы работаем под пользователем hub.
Шаг 1. Назначаем владельца
sudo chown -R hub:hub /srv/storage
Шаг 2. Базовые права
sudo chmod 755 /srv/storage
Что это даёт:
hub— полный доступ;- сервисы могут читать;
- MiniDLNA индексирует без проблем.
Шаг 3. Проверка
touch /srv/storage/test.txt
ls -l /srv/storage
Ожидаемо:
-rw-r--r-- 1 hub hub 0 test.txt
Если файл создаётся — всё сделано правильно.
4.5 Финальная структура каталогов
Создаём осмысленную структуру, а не свалку:
mkdir -p /srv/storage/{apps,downloads,media}
mkdir -p /srv/storage/media/{movies,tv,music}
mkdir -p /srv/storage/downloads/{watch,incomplete,complete}
📌 Почему watch оставляем:
- qBittorrent умеет «следить» за папкой;
- закинул
.torrent→ загрузка началась автоматически; - удобно и без Web UI.
tree /srv/storage -L 3
Ожидаемо:
/srv/storage
├── apps
├── downloads
│ ├── watch
│ ├── incomplete
│ └── complete
└── media
├── movies
├── music
└── tv
📌 Эта структура базовая и финальная:
media→ MiniDLNAdownloads→ qBittorrentapps→ RV2 Hub (Rust) и будущие сервисы
✅ Итог Части 3
На этом этапе у нас:
- SSD в
ext4; - стабильное автомонтирование по UUID;
- корректные права под
hub; - продуманная структура каталогов;
- нулевые предпосылки к будущим проблемам.
🧱 ЧАСТЬ 4. MiniDLNA — полноценный медиасервер
(Orange Pi RV2 · Ubuntu Server · SSD · DLNA)
В предыдущих частях мы сделали самое важное:
- подготовили систему и безопасность;
- настроили firewall и multicast (SSDP);
- корректно подключили SSD;
- создали правильную структуру каталогов.
👉 Теперь пришло время запустить MiniDLNA — сервис, ради которого вся эта инфраструктура и строилась.
❗ MiniDLNA — простой, стабильный и предсказуемый DLNA-сервер.
Он не требует GUI, не тянет лишних зависимостей и отлично работает на слабых ARM / RISC-V платах.
1️⃣ Что такое MiniDLNA и почему именно он
MiniDLNA (ReadyMedia):
- раздаёт видео, музыку и фото по DLNA;
- автоматически обнаруживается ТВ, приставками, консолями;
- работает без браузера, аккаунтов и облаков;
- не индексирует «магически» — всё прозрачно и под контролем.
Почему НЕ Plex / Jellyfin:
- требуют больше ресурсов;
- сложнее в обслуживании;
- зависят от web-стека и БД;
- часто избыточны для «просто смотреть фильмы».
👉 Наша цель — надёжный медиасервер, который просто работает годами.
2️⃣ Установка MiniDLNA
Устанавливаем пакет из официальных репозиториев Ubuntu:
sudo apt install minidlna -y
Проверяем, что сервис появился:
systemctl status minidlna
На этом этапе он может быть запущен, но:
- медиакаталог не задан;
- права не настроены;
- индекс пустой.
👉 Всё это исправляем дальше.
3️⃣ Основной конфиг MiniDLNA — строка за строкой
3.1 Открываем конфигурацию
sudo nano /etc/minidlna.conf
⚠️ Важно: файл большой, но нас интересует конкретный набор параметров.
Не нужно «улучшать» всё подряд.
3.2 media_dir — где лежат медиафайлы
Мы уже создали правильную структуру в Части 3:
/srv/storage/media
├── movies
├── tv
└── music
Прописываем их явно:
media_dir=V,/srv/storage/media/movies
media_dir=V,/srv/storage/media/tv
media_dir=A,/srv/storage/media/music
Обозначения:
V— VideoA— Audio
📌 Не используем общий media_dir без типа — так индексирование стабильнее.
3.3 friendly_name — имя сервера в ТВ
friendly_name=RV2 Media Server
👉 Именно это имя ты увидишь в меню телевизора / приставки.
3.4 db_dir и log_dir — база и логи
По умолчанию MiniDLNA хранит базу в /var/cache/minidlna,
но мы оставляем это так, потому что:
- база небольшая;
- не критична к скорости;
- не требует SSD.
Проверяем, что строки НЕ закомментированы:
db_dir=/var/cache/minidlna
log_dir=/var/log
3.5 user — под кем работает MiniDLNA
По умолчанию:
user=minidlna
❗ Мы НЕ меняем пользователя.
Почему:
- у нас уже корректные права (
755); - DLNA нужен только READ-доступ;
- меньше риска сломать сервис.
3.6 inotify — автообновление библиотеки
inotify=yes
Что это даёт:
- добавил фильм → он появился без рескана;
- не нужно перезапускать сервис каждый раз.
📌 Работает отлично на ext4 (поэтому exFAT был плохой идеей).
3.7 notify_interval — как часто анонсировать себя в сети
notify_interval=60
Оптимальное значение:
- ТВ быстрее «видит» сервер;
- нет лишнего сетевого шума.
3.8 Итоговый минимальный конфиг (фрагмент)
В результате у тебя в minidlna.conf обязательно должны быть:
media_dir=V,/srv/storage/media/movies
media_dir=V,/srv/storage/media/tv
media_dir=A,/srv/storage/media/music
friendly_name=RV2 Media Server
db_dir=/var/cache/minidlna
log_dir=/var/log
user=minidlna
inotify=yes
notify_interval=60
Остальное можно оставить по умолчанию.
💾 Сохраняем файл:
Ctrl + OEnterCtrl + X
4️⃣ Права доступа — почему у нас всё работает
Мы уже сделали всё правильно в Части 3, но важно зафиксировать логику.
Каталог:
ls -ld /srv/storage/media
Ожидаемо:
drwxr-xr-x hub hub /srv/storage/media
Что это значит:
hub— владелец, полный доступ;minidlna(другой пользователь) — может читать;- DLNA индексирует без ошибок.
❌ Типовая ошибка:
root:root 700
👉 В этом случае DLNA не увидит файлы, даже если сервис «работает».
5️⃣ Первый запуск и сканирование
5.1 Перезапуск сервиса
sudo systemctl restart minidlna
Проверяем статус:
systemctl status minidlna
Ожидаемо:
Active: active (running)
5.2 Принудительный рескан (один раз)
При первом запуске рекомендуется пересобрать базу:
sudo systemctl stop minidlna
sudo minidlnad -R
sudo systemctl start minidlna
Что делает -R:
- удаляет старую базу;
- пересканирует все каталоги;
- создаёт чистый индекс.
5.3 Проверка логов (если что-то не так)
journalctl -u minidlna -n 50
Или:
cat /var/log/minidlna.log
Ищем:
- ошибки доступа;
- проблемы с каталогами;
- сообщения о добавленных файлах.
6️⃣ Проверка с ТВ или приставки
На телевизоре / Android TV / приставке:
- Заходим в Источники / DLNA / Медиа-серверы
- Ищем:
RV2 Media Server- Заходим → Movies / TV / Music
- Запускаем любой файл
👉 Если:
- сервер виден;
- файлы открываются;
- перемотка работает —
🎉 MiniDLNA настроен правильно.
7️⃣ Типовые проблемы и решения
❌ Сервер не виден
Почти всегда причина НЕ в MiniDLNA:
- multicast был не разрешён;
- интерфейс без флага MULTICAST;
- firewall настроен неправильно.
👉 Мы это уже решили в Части 2.
❌ Сервер виден, но папки пустые
Проверь:
ls /srv/storage/media/movies
Если файлы есть — значит проблема в правах:
sudo chown -R hub:hub /srv/storage
sudo chmod 755 /srv/storage
Пересканируй базу (minidlnad -R).
❌ Новые фильмы не появляются
Убедись, что включено:
inotify=yes
И файловая система — ext4, не exFAT.
✅ Итог Части 4
Теперь у нас есть:
- полностью рабочий DLNA-сервер;
- корректная индексация;
- автоматическое обновление медиатеки;
- стабильная работа без Docker и GUI.
MiniDLNA использует всё, что мы сделали ранее, и именно поэтому он работает правильно, а не «через раз».
🧱 ЧАСТЬ 5. qBittorrent-nox
В предыдущих частях мы:
- подготовили систему и безопасность;
- настроили firewall и защиту;
- корректно подготовили SSD;
- развернули и проверили MiniDLNA.
Теперь добавляем источник контента — qBittorrent-nox.
⚠️ Важно:
Мы НЕ делаем «торрент-помойку».
Наша цель:
- качать аккуратно;
- сразу класть файлы туда, где их увидит MiniDLNA;
- не городить лишние костыли и скрипты.
5️⃣ Почему именно qBittorrent-nox
qBittorrent-nox — это:
- тот же qBittorrent, но без GUI;
- Web-интерфейс через браузер;
- минимальная нагрузка на систему;
- идеален для ARM/RISC-V и headless-серверов.
👉 Это лучший вариант для Orange Pi RV2.
5.1 Установка qBittorrent-nox
Устанавливаем из репозиториев Ubuntu:
sudo apt install qbittorrent-nox -y
Проверяем, что бинарник есть:
qbittorrent-nox --version
5.2 Первый запуск и ВРЕМЕННЫЙ пароль (ОЧЕНЬ ВАЖНО)
❗ Это пункт, который пропускают почти все, а потом «не могут войти».
Запускаем вручную один раз:
qbittorrent-nox
В терминале появится сообщение вида:
Web UI: http://localhost:8080
Username: admin
Password: <RANDOM_PASSWORD>
📌 Скопируй этот пароль — он одноразовый.
Останавливаем процесс:
Ctrl + C
5.3 Первый вход в Web UI
В браузере открываем:
http://IP_ORANGE_PI:8080
Логин:
admin
Пароль:
тот самый временный
👉 После входа сразу меняем пароль.
5.4 Базовая и безопасная настройка
5.4.1 Меняем пароль
Settings → Web UI
- Username:
admin(оставляем) - Password: задай нормальный
- ☑️ Bypass authentication for clients on localhost — ❌ выключено
Сохраняем.
5.4.2 Привязываем Web UI к LAN
Settings → Web UI
- Web UI address:
0.0.0.0 - Web UI port:
8080
📌 Порт уже открыт в UFW — мы это сделали заранее.
5.5 Каталоги загрузки — КЛЮЧЕВАЯ ЧАСТЬ
❗ Важное архитектурное решение
Мы НЕ будем:
- качать в
/downloads, а потом переносить; - писать скрипты-переносчики;
- городить automation, который ломается.
👉 Самый надёжный вариант:
qBittorrent качает СРАЗУ в нужный медиакаталог
MiniDLNA увидит файлы автоматически.
5.6 Каталог загрузки по умолчанию
Settings → Downloads
Default Save Path
/srv/storage/media/movies
📌 Почему именно так:
- фильмы — самый частый тип контента;
- MiniDLNA уже смотрит в
/srv/storage/media; - файл появляется → DLNA его индексирует.
5.7 Как быть с сериалами и музыкой
Когда добавляешь торрент через Web UI:
👉 Просто выбираешь нужный каталог:
- 🎬 Фильмы
/srv/storage/media/movies
📺 Сериалы
/srv/storage/media/tv
🎵 Музыка
/srv/storage/media/music
📌 Это нормальный, ручной, контролируемый процесс
и он на практике удобнее любых автоматических скриптов.
5.8 А что делать с /downloads?
Каталог /srv/storage/downloads оставляем, но используем осмысленно.
Предлагаемая роль:
/srv/storage/downloads
├── complete
├── incomplete
└── watch
complete— НЕ медиаконтент- образы
- архивы
- софт
- ISO
incomplete— временные файлы (если понадобится)watch— опционально, не основной сценарий
5.9 Про папку watch — честно и без мифов
❗ ВАЖНОЕ УТОЧНЕНИЕ
Watch НЕ спрашивает путь сохранения.
Если включить:
Automatically add torrents from:
/srv/storage/downloads/watch
➡ торрент автоматически стартует
➡ в каталог по умолчанию
5.10 Права доступа (обязательно проверяем)
qBittorrent работает от пользователя hub.
Проверяем владельца:
ls -ld /srv/storage/media
Если вдруг не hub:hub:
sudo chown -R hub:hub /srv/storage
5.11 systemd-сервис для qBittorrent-nox
Создаём сервис:
sudo nano /etc/systemd/system/qbittorrent-nox.service
Содержимое:
[Unit]
Description=qBittorrent-nox
After=network.target
[Service]
User=hub
ExecStart=/usr/bin/qbittorrent-nox
Restart=on-failure
LimitNOFILE=4096
[Install]
WantedBy=multi-user.target
Активируем:
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable qbittorrent-nox
sudo systemctl start qbittorrent-nox
Проверка:
systemctl status qbittorrent-nox
5.12 Проверка всей цепочки
1️⃣ Добавь торрент фильма
2️⃣ Выбери /srv/storage/media/movies
3️⃣ Дождись окончания
4️⃣ Проверь на ТВ / приставке
👉 Фильм должен появиться без перезапуска MiniDLNA
✅ Итог Части 5
Теперь у нас:
qBittorrent-noxбез GUI, но с Web UI;- безопасный доступ;
- никаких скриптов-переносчиков;
- файлы сразу попадают туда, где их ждёт MiniDLNA;
watchиспользуется осознанно.
🧱 ЧАСТЬ 6. RV2 Hub — собственный Web UI на Rust (Axum)
(без Docker, без Node.js, с понятной архитектурой)
К этому моменту у нас уже есть полностью рабочий медиахаб:
- SSD смонтирован в
/srv/storage - MiniDLNA раздаёт контент на ТВ
- qBittorrent-nox качает файлы сразу в нужные каталоги
- firewall, multicast и безопасность настроены
👉 Но управлять всем этим по SSH неудобно.
Нам нужен локальный Web-интерфейс, который:
- показывает состояние системы;
- показывает, что лежит в медиакаталогах;
- в будущем может расширяться (WireGuard, статистика, сервисы).
Так появляется RV2 Hub.
6.1 Зачем вообще нужен RV2 Hub
Важно сразу понять философию.
❌ Мы НЕ делаем:
- замену Plex / Jellyfin;
- торрент-клиент в браузере;
- сложную панель управления.
✅ Мы делаем:
- лёгкий Web UI для владельца сервера;
- обзор состояния узла;
- точку расширения проекта.
Почему Rust + Axum:
- минимальное потребление ресурсов (важно для RV2);
- бинарник без зависимостей;
- быстрый старт и стабильность;
- идеально для systemd.
6.2 Где живёт RV2 Hub в нашей структуре
Мы уже заложили каталог /srv/storage/apps.
Именно там будут жить все наши сервисы.
Финальный путь проекта:
/srv/storage/apps/rv2-hub
Это важно:
- не в
/home; - не в
/opt; - не вперемешку с медиа.
6.3 Установка Rust (официально и правильно)
Работаем под пользователем hub.
6.3.1 Устанавливаем зависимости
sudo apt install -y build-essential pkg-config libssl-dev
6.3.2 Установка Rust через rustup
curl https://sh.rustup.rs -sSf | sh
Выбираем:
1) Proceed with installation (default)
Подгружаем окружение:
source ~/.cargo/env
Проверка:
rustc --version
cargo --version
6.4 Создание проекта RV2 Hub
cd /srv/storage/apps
cargo new rv2-hub
cd rv2-hub
Удаляем лишнее и сразу приводим к финальной структуре.
6.5 Финальная структура проекта (ОКОНЧАТЕЛЬНАЯ)
rv2-hub/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── state.rs
│ └── routes/
│ ├── mod.rs
│ └── index.rs
├── templates/
│ └── index.html
└── static/
└── style.css
📌 Это не «пример», а финальная, рабочая структура.
6.6 Cargo.toml (проверенный и минимальный)
Открываем:
nano Cargo.toml
Заменяем полностью:
[package]
name = "rv2-hub"
version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
tower-http = { version = "0.5", features = ["fs"] }
askama = "0.12"
Почему так:
axum 0.7— актуальная версия;tokio full— без сюрпризов;tower-http fs— раздача CSS;askama— шаблоны без JS.
6.7 main.rs — запуск без axum::Server
nano src/main.rs
use axum::{Router, routing::get};
use tower_http::services::ServeDir;
mod routes;
mod state;
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/", get(routes::index::index))
.nest_service("/static", ServeDir::new("static"));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8081")
.await
.unwrap();
println!("🚀 RV2 Hub running on http://0.0.0.0:8081");
axum::serve(listener, app).await.unwrap();
}
📌 Важно:
- никакого
axum::Server— он устарел; - слушаем
0.0.0.0, чтобы открыть доступ по сети; - порт
8081мы уже открыли в UFW.
6.8 routes и state — разделяем логику
6.8.1 routes/mod.rs
nano src/routes/mod.rs
pub mod index;
6.8.2 routes/index.rs
nano src/routes/index.rs
use axum::response::Html;
use askama::Template;
use crate::state;
#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
system: String,
movies: Vec<String>,
dlna: String,
}
pub async fn index() -> Html<String> {
let tpl = IndexTemplate {
system: state::system_status(),
movies: state::movies(),
dlna: state::dlna_status(),
};
Html(tpl.render().unwrap())
}
6.8.3 state.rs — логика без Web-кода
nano src/state.rs
use std::fs;
pub fn system_status() -> String {
"OK".to_string()
}
pub fn dlna_status() -> String {
"Running".to_string()
}
pub fn movies() -> Vec<String> {
let path = "/srv/storage/media/movies";
fs::read_dir(path)
.map(|entries| {
entries
.filter_map(|e| e.ok())
.filter(|e| e.path().is_file())
.map(|e| e.file_name().to_string_lossy().to_string())
.collect()
})
.unwrap_or_default()
}
📌 Здесь мы:
- читаем реальный каталог с фильмами;
- не используем shell-команды;
- не ломаем безопасность.
6.9 Шаблон index.html (красивый, но простой)
nano templates/index.html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>RV2 Hub</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header>
<h1>RV2 Hub</h1>
<p>Orange Pi RV2 • Media & Services Hub</p>
</header>
<main>
<section class="card">
<h2>📊 System</h2>
<p>Status: <b>{{ system }}</b></p>
</section>
<section class="card">
<h2>🎬 Movies</h2>
<ul>
{% for movie in movies %}
<li>{{ movie }}</li>
{% endfor %}
</ul>
</section>
<section class="card">
<h2>📡 DLNA</h2>
<p>Status: <b>{{ dlna }}</b></p>
</section>
</main>
<footer>
RV2 Hub • Rust + Axum
</footer>
</body>
</html>
6.10 CSS — НЕ лаконичный, а «приятный»
nano static/style.css
body {
margin: 0;
font-family: system-ui, sans-serif;
background: #0f172a;
color: #e5e7eb;
}
header {
background: linear-gradient(90deg, #2563eb, #1e40af);
padding: 20px;
text-align: center;
}
header h1 {
margin: 0;
font-size: 32px;
}
main {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
padding: 30px;
}
.card {
background: #020617;
border-radius: 12px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.4);
}
.card h2 {
margin-top: 0;
color: #60a5fa;
}
ul {
padding-left: 20px;
}
li {
margin-bottom: 6px;
}
footer {
text-align: center;
padding: 15px;
color: #94a3b8;
}
6.11 Сборка и запуск
cargo clean
cargo build --release
./target/release/rv2-hub
Открываем в браузере:
http://192.168.1.xxx:8081
6.12 systemd-сервис для RV2 Hub
Создаём сервис:
sudo nano /etc/systemd/system/rv2-hub.service
[Unit]
Description=RV2 Hub Web UI
After=network.target
[Service]
User=hub
WorkingDirectory=/srv/storage/apps/rv2-hub
ExecStart=/srv/storage/apps/rv2-hub/target/release/rv2-hub
Restart=always
[Install]
WantedBy=multi-user.target
Активируем:
sudo systemctl daemon-reexec
sudo systemctl enable rv2-hub
sudo systemctl start rv2-hub
Проверка:
systemctl status rv2-hub
🔚 Итог Части 6
Теперь у нас есть:
✅ собственный Web UI
✅ без Docker и JS-зоопарка
✅ быстрый и стабильный
✅ логично встроенный в архитектуру
✅ идеальная база для расширения
🧱 ЧАСТЬ 7. Ошибки, тупики и финальная проверка системы
(что было сделано правильно, что неправильно и почему итоговая схема — лучшая)
К этому моменту у нас полностью готовый медиахаб на Orange Pi RV2:
- Ubuntu Server настроен правильно
- SSD подключён, размечен и смонтирован корректно
- MiniDLNA стабильно раздаёт медиатеку
- qBittorrent-nox качает без GUI и без бардака
- Firewall и защита настроены один раз и навсегда
- Архитектура готова к WireGuard и дальнейшему развитию
Теперь самое важное — разобрать ошибки и тупики, которые обычно убивают такие проекты через 1–2 недели эксплуатации.
1️⃣ Docker — почему он здесь был лишним
Очень популярный, но неправильный путь для этого сценария.
Почему Docker кажется хорошей идеей
- «изолировано»
- «красиво»
- «все так делают»
- «одной командой поднял»
Почему Docker ЗДЕСЬ — плохое решение
❌ Проблемы с DLNA
- multicast + Docker = боль
- SSDP внутри контейнера работает нестабильно
- проброс UDP 1900 — нестандартный и ненадёжный
DLNA любит работать напрямую с сетью хоста.
❌ Проблемы с правами на SSD
- host → container → volume
- UID/GID не совпадают
- MiniDLNA и qBittorrent начинают «не видеть» файлы
В итоге:
«вроде всё работает, но иногда нет»
❌ Избыточность
У нас:
- один сервер
- фиксированный набор сервисов
- systemd уже есть
Docker не даёт преимуществ, но добавляет сложность.
✅ Почему systemd + нативные сервисы лучше
- прямой доступ к сети
- прямые пути к файлам
- нормальные логи
- предсказуемый запуск
- проще отлаживать
👉 Вывод: Docker здесь был лишним, и мы правильно от него отказались.
2️⃣ Типовые ошибки с MiniDLNA (и почему они ломают всё)
❌ Ошибка №1: неправильные права
Самая частая причина:
/srv/storage принадлежит root:root
В итоге:
- MiniDLNA запускается
- DLNA-сервер «есть»
- медиатеки нет
✔️ Правильно:
chown -R hub:hub /srv/storage
chmod 755 /srv/storage
❌ Ошибка №2: exFAT / NTFS на SSD
Почему не работает нормально:
- нет Unix-прав
- проблемы с inotify
- нестабильная индексация
✔️ Правильно:
- ext4
- UUID в fstab
- noatime
❌ Ошибка №3: multicast не работает
Симптомы:
- MiniDLNA запущен
- порт 8200 открыт
- ТВ не видит сервер
Причина:
- SSDP (239.255.255.250:1900/udp) блокируется
✔️ Мы сделали правильно:
- разрешили 1900/udp в UFW
- проверили флаг MULTICAST на интерфейсе
❌ Ошибка №4: ожидание «мгновенного» DLNA
DLNA не индексирует мгновенно.
Правильный цикл:
sudo systemctl restart minidlna
sudo journalctl -u minidlna -f
И только потом проверка на ТВ.
3️⃣ Типовые ошибки с qBittorrent-nox
❌ Ошибка №1: качать всё в одну папку
Так делать нельзя:
/srv/storage/downloads
Почему:
- DLNA не понимает структуру
- мусор в медиатеке
- сложно управлять
✅ Мы сделали правильно
- default download:
/srv/storage/media/movies
если это сериал:
/srv/storage/media/tv
если музыка:
/srv/storage/media/music- downloads/complete:
- для «прочих» загрузок
- ISO, образы, архивы
❌ Ошибка №2: переоценка watch-каталога
Важно зафиксировать:
watch-каталог НЕ спрашивает путь загрузки
Он просто стартует загрузку в default directory.
✔️ Поэтому мы:
- оставили watch как удобную опцию
- основной контроль — через Web UI
4️⃣ Финальная проверка всей системы
Перед тем как считать систему готовой, проверяем всё по чеклисту.
🔹 Сервисы
systemctl status minidlna
systemctl status qbittorrent-nox
systemctl status fail2ban
Все должны быть active (running).
🔹 Порты
ss -tulpen
Ожидаемо:
- 22/tcp — SSH
- 8080/tcp — qBittorrent Web UI
- 8200/tcp — MiniDLNA
- 1900/udp — SSDP
❌ Никаких лишних портов.
🔹 DLNA
- ТВ / приставка видит сервер
- медиатека отображается
- файлы воспроизводятся
🔹 SSD
df -h | grep storage
mount | grep storage
- ext4
- UUID
- смонтирован автоматически
5️⃣ Куда развивать медиахаб дальше
Теперь у тебя чистая и правильная база.
Вот логичные направления развития:
🔜 WireGuard
- безопасный доступ из интернета
- без проброса сервисов наружу
- готовность системы уже есть
🔜 RV2 Hub (Rust + Axum)
- Web UI для:
- статуса системы
- списка фильмов
- состояния DLNA
- управления сервисами
Мы сознательно оставили это отдельной частью, потому что это уже приложение, а не администрирование.
🔜 Бэкапы
- rsync
- borg
- внешний диск или NAS
🏁 Итог всей серии
Ты не просто “поднял DLNA”.
Ты построил:
- правильную файловую архитектуру
- предсказуемую сетевую модель
- безопасную систему
- медиахаб, который можно:
- расширять
- поддерживать
- не бояться обновлять
👉 Это именно тот случай, когда “один раз сделать правильно” экономит десятки часов в будущем.