# dsm-mini
[English](README.md) · **Русский** · [Español](README_ES.md) · [Português](README_PT.md) · [Deutsch](README_DE.md) · [Français](README_FR.md) · [Italiano](README_IT.md) · [Türkçe](README_TR.md) · [Українська](README_UK.md) · [Polski](README_PL.md)
[](https://github.com/alexlnos/dsm-mini/actions/workflows/ci.yml)
[](LICENSE)
Telegram-бот с Mini App для управления домашним NAS Synology: закачки Download
Station и файлы File Station прямо из мессенджера, без VPN и веб-интерфейса DSM.
Кинули magnet-ссылку в чат — бот спросил кнопками, куда качать, и поставил в
очередь. Открыли приложение — видно, что качается, сколько осталось, что лежит
на дисках и как себя чувствует NAS.
> Работает: бот, Mini App и уведомления. Нужен DSM 7 или новее — на DSM 6
> пакет не встанет, и там его никто не проверял. Проверено на DSM 7.2.2 с
> Download Station 4.1.2 и File Station 1.4.4.
## Что это умеет
**Загрузки**
- Список задач: прогресс, скорость, оставшееся время, сиды и пиры
- Пауза, возобновление, удаление
- Добавление magnet-ссылкой, прямой ссылкой и файлом `.torrent`
- Выбор папки назначения с настраиваемым списком быстрого доступа
- Выбор файлов внутри раздачи и их приоритета
- Сообщение в чат, когда задача завершилась или упала
**Файлы**
- Обзор папок, предпросмотр, загрузка на NAS
- Переименование, копирование, перенос, удаление
**Состояние NAS**
- Загрузка процессора и памяти, время работы, сеть
- Диски, пулы и тома: температура, занятое место, здоровье
- Виртуальные машины и контейнеры: запуск и остановка
- Журнал событий DSM
**Уведомления и настройки**
- То, о чём сообщает сам DSM — советник по безопасности, диски, обновления, — приходит в чат
- Выбор, что бот может присылать: ничего, только загрузки, всё
- Свой экран в главном меню DSM: там пакет настраивается после установки и там же потом меняется любая настройка, без перезапуска
**Язык**
Приложение и бот говорят на языке, выбранном в Telegram: английский, русский,
испанский, португальский, немецкий, французский, итальянский, турецкий,
украинский, польский. Незнакомый язык получает английский.
---
## Установка
Полчаса, и большая часть уйдёт на сертификат, а не на сам сервис. Нужен NAS
Synology с DSM 7 и Download Station; больше ничего заранее ставить не надо.
> **Публичный адрес нужен только для Mini App.** Telegram открывает Mini App
> только по `https://` с настоящим сертификатом — локальный `192.168.…` и
> самоподписанный не откроются. Без адреса бот работает сам по себе — ссылки,
> файлы `.torrent`, `/status` и уведомления, — и открывать NAS наружу не нужно.
> Три способа получить адрес — в шаге 4, два из них обходятся без проброса
> портов на роутере.
**1. Создать бота.** [@BotFather](https://t.me/BotFather) → `/newbot` → имя и
логин, заканчивающийся на `bot`. В ответ придёт токен; сохраните его, это
пароль от вашего бота.
**2. Узнать свой номер.** [@userinfobot](https://t.me/userinfobot) → Start.
Он ответит строкой `Id`.
**3. Завести пользователя DSM для службы.** Панель управления → Пользователь и
группа → Создать. Доступ только к Download Station и File Station, без
двухэтапной проверки — одноразовый код неоткуда взять в файле настроек.
Администратора не давайте: служба умеет удалять файлы. Хватает ли этой учётной
записи прав, покажет кнопка **Проверить учётную запись** в окне DSM mini (шаг
6): она входит от имени этого пользователя и перечисляет, что DSM ему разрешает.
**4. Получить адрес для Mini App** — или пропустите этот шаг, и бот будет
работать сам по себе. Адрес должен открываться по `https://` на телефоне, где у
вас Telegram. Способов три. Первый — через DSM, с пробросом портов на роутере;
его можно пропустить, если у NAS уже есть домен с действующим сертификатом:
- Панель управления → Внешний доступ → DDNS → Добавить, поставщик `Synology` —
получится что-то вроде `alex-nas.synology.me`.
- На роутере пробросьте на NAS порты **80** и **443**. Без 80 не выпустится
сертификат, без 443 не откроется приложение.
- Панель управления → Безопасность → Сертификат → Добавить → от Let's Encrypt,
на то же имя.
Проверьте с телефона по мобильному интернету: `https://alex-nas.synology.me:5001`
должен открыть DSM без предупреждений.
Второй — **Cloudflare Tunnel**, без проброса портов; нужен домен, DNS которого в
Cloudflare. Создайте туннель в панели Cloudflare, поставьте пакет **Cloudflare
Tunnel** из [SynoCommunity](https://synocommunity.com) с токеном этого туннеля и
добавьте туннелю публичное имя — скажем, `mini.example.com` — со службой
`http://localhost:58080`.
Третий — **Tailscale**, только для своих устройств. Поставьте Tailscale на NAS и
на телефон, включите сертификаты HTTPS в настройках DNS своей сети Tailscale и
выполните на NAS `sudo tailscale serve --bg 58080`: он выдаст адрес вида
`https://nas.tail1234.ts.net`. Приложение будет открываться, пока телефон
подключён к Tailscale.
**5. Установить пакет.** Центр пакетов → Настройки → Источники пакетов →
Добавить, имя `dsm-mini` и адрес по вашей архитектуре:
- Intel и AMD, большинство моделей: `https://alexlnos.github.io/dsm-mini/amd64.json`
- ARM, бюджетные модели: `https://alexlnos.github.io/dsm-mini/arm64.json`
Дальше Настройки → Общие → Доверенный уровень → **Любой издатель**, и поставьте
**DSM mini — Telegram Mini App** из раздела **Сообщество**. Не уверены в
архитектуре? Пробуйте `amd64`: неподходящий пакет просто не поставится.
При установке ничего не спрашивается. Либо поставьте `.spk` из
[релизов](https://github.com/alexlnos/dsm-mini/releases) вручную, через Центр
пакетов → Ручная установка.
**6. Настроить.** Откройте **DSM mini** в главном меню DSM или нажмите
**Открыть** в Центре пакетов — он и сам подскажет это после установки. Заполните
значения, собранные на шагах выше, — окно объяснит каждое, — а в разделе
**Доступ к Mini App** выберите способ из шага 4 или
**Только бот, без Mini App**. Нажмите **Сохранить**, а затем **Запустить**
вверху окна. Статус там покажет, когда ответили DSM и бот, а если не ответили —
что не так.
Для первого способа правило обратного прокси окно создаёт само: впишите имя в
поле **Направить имя в службу**. Вручную это Панель управления → Портал входа →
Дополнительно → Обратный прокси-сервер → Создать. Источник: `HTTPS`, ваше имя,
порт `443`. Назначение: `HTTP`, `localhost`, порт `58080`. С туннелем или
Tailscale выберите **Другой способ** и впишите адрес, который они выдали.
> Порт **80** для этого имени не проксируйте: через него DSM продлевает
> сертификат, и перехват сломает продление через три месяца.
**7. Проверить.** Если адрес есть, `https://ваш-адрес/healthz` в браузере должен
ответить `{"status":"ok"}`. Без подписи Telegram наружу ничего не отдаётся.
**8. Открыть приложение.** Найдите бота по логину, нажмите Start — рядом с полем
ввода появится кнопка **Загрузки**. Пришлите ему любую magnet-ссылку, он
предложит папки кнопками. Без адреса кнопки не будет — ссылки просто присылайте
боту в чат.
## Если что-то пошло не так
| Что видите | В чём дело | Что делать |
|---|---|---|
| Бот молчит на `/start` | Бот выключен или не настроен, либо неверный токен | Откройте **DSM mini** в главном меню DSM: статус вверху скажет, что именно, а **Запустить** включит бота |
| «Доступ к этому боту закрыт» | Вашего ID нет в списке | Впишите номер из шага 2 в разрешённые ID в окне **DSM mini** |
| Кнопки приложения нет | Публичный адрес пуст — тогда работает только бот — или не `https://` | Окно **DSM mini**, раздел **Доступ к Mini App** |
| Кнопка есть, приложение не открывается | Не работает обратный прокси или сертификат | Откройте `https://ваш-адрес/healthz` в браузере |
| «Откройте приложение через бота» | Приложение открыто прямой ссылкой в браузере | Так и задумано: открывайте из бота |
| «Доступ закрыт: вашего Telegram ID…» | Сервис вас не узнал | В разрешённых ID только цифры, через запятую |
| Окно пишет, что DSM не принял вход | Пароль, 2FA или права пользователя | Шаг 3: пароль без опечаток, 2FA выключена, приложения разрешены |
| Окно пишет, что Download Station не запущена | Она не установлена или запрещена пользователю | Центр пакетов и права из шага 3 |
| Пакет останавливается сразу после запуска | Его порт занят чем-то другим — журнал так и скажет | Поменяйте `LISTEN_ADDR` в `config.env` по SSH (см. ниже) |
Первое, куда смотреть, — строка состояния вверху окна **DSM mini**: она говорит,
ответили ли DSM и Telegram, а если нет — почему. Подробности — в журнале пакета,
`/var/packages/dsm-mini/var/dsm-mini.log`, он же открывается из Центра пакетов.
Журнал ведётся по-английски, окно, интерфейс и сообщения бота — на вашем языке.
### Поменять настройки
**Откройте DSM mini в главном меню DSM** — там все настройки. Пароль и токен
только на запись: оставьте поле пустым, и оно сохранит прежнее. Сохранение
применяется сразу: служба сама перезапускается с новыми настройками, пакет
перезапускать не нужно.
Настройки лежат на NAS в одном файле `/var/packages/dsm-mini/var/config.env` с
правами `600`. Его можно поправить и по SSH (Панель управления → Терминал и SNMP
→ включить SSH), а потом перезапустить пакет:
```bash
sudo sed -i "s|^TELEGRAM_BOT_TOKEN=.*|TELEGRAM_BOT_TOKEN='ваш-новый-токен'|" /var/packages/dsm-mini/var/config.env
sudo synopkg restart dsm-mini
```
Обновление файл не трогает, поэтому настройки его переживают.
## Обновление
Если добавлен источник пакетов, Центр пакетов сам покажет обновление. Без
источника — скачайте свежий `.spk` из
[релизов](https://github.com/alexlnos/dsm-mini/releases) и поставьте поверх.
Настройки и база в обоих случаях останутся: они лежат в каталоге `var` пакета,
а его обновление не трогает.
## Где хранятся данные
Всё в `/var/packages/dsm-mini/var/`:
- `config.env` — настройки из окна DSM mini, права `600`;
- `dsm-mini.db` — база SQLite: закреплённые папки, язык и последние известные
статусы задач, по которым сервис понимает, о чём уже сообщал;
- `dsm-mini.log` — журнал.
Обновление пакета сохраняет все три. Удаление пакета — удаляет.
## Безопасность
Сервис выставлен в интернет и умеет удалять файлы на NAS, поэтому:
- **Отдельный пользователь DSM**, а не администратор (шаг 3).
- **Без двухэтапной проверки** у этой учётной записи: одноразовый код в
конфигурации работать не будет.
- **Разрешённые ID — белый список.** Пустой список закрывает доступ всем, а не
открывает.
- Каждый запрос к `/api/` проверяется дважды: подпись `initData` ключом от
токена бота и идентификатор в списке разрешённых. Подпись доказывает лишь
то, что человек открыл бота, — открыть его может любой.
- Наружу отдаётся общая фраза, подробности — в журнал: сообщение о том, что
именно не сошлось в подписи, подсказывало бы, как её подобрать.
- Токен бота и пароль DSM живут только в `config.env` на самом NAS с правами
`600` и в журнал не попадают: при отказе пишется причина, но не значение.
- Служба слушает только `127.0.0.1` — то есть с самого NAS. Всё снаружи идёт
через то, что обслуживает публичный адрес, — обратный прокси DSM, туннель или
Tailscale, — он же разбирает TLS. Без адреса снаружи до неё не доходит ничего.
## Разработка
```bash
cd web && npm install && npm run build # Mini App попадёт в internal/web/dist
cd .. && go build ./cmd/dsm-mini # бинарник со встроенным приложением
go test ./...
```
Фронтенд отдельно, с автообновлением:
```bash
cd web && npm run dev # ходит в бэкенд на localhost:58080
```
Локальный запуск бэкенда читает `config.env` из `STATE_DIR`, как и пакет, а
переменные окружения дополняют то, чего в файле нет. Удобно держать их в файле:
```bash
cp .env.example .env # заполните
set -a; . ./.env; set +a
go run ./cmd/dsm-mini
```
Собранный интерфейс лежит в репозитории (`internal/web/dist`) — его забирает
`go:embed`. После правок фронтенда пересоберите и закоммитьте результат, иначе
проверки не пройдут.
Интеграционные тесты работают против настоящего NAS и по умолчанию
пропускаются:
```bash
DSM_URL=https://192.168.1.10:5001 DSM_USER=... DSM_PASSWORD=... \
DSM_INSECURE_TLS=true go test -tags=integration ./...
```
Тесты, которые меняют состояние NAS, требуют отдельного разрешения:
`DSM_TEST_MUTATIONS=1`, а для файловых операций ещё и `DSM_TEST_FOLDER` —
папку, внутри которой можно создавать временные файлы. Всё созданное они
удаляют за собой.
Новый язык интерфейса — один файл словаря на каждой стороне:
`web/src/i18n/<код>.ts` и `internal/i18n/<код>.go`. Пропустить строку не выйдет:
на фронтенде за этим следит тип, на сервере — тест.
Код, комментарии и журнал в проекте — по-английски; русский живёт только в
словарях перевода. Подробности — в [CLAUDE.md](CLAUDE.md).
## Особенности Synology API
Web API Synology местами ведёт себя не так, как написано в документации: одно и
то же действие отвечает в трёх разных форматах, `limit = -1` роняет File
Station, а `_sid` при загрузке файла нужно передавать иначе, чем везде.
Всё, что выяснено на живом NAS, собрано в [docs/synology-api.md](docs/synology-api.md).
## Лицензия
[MIT](LICENSE)