Запуск власного сервера
Мінімальна конфігурація не потребує ні хмарного сховища, ні бази даних — достатньо Node.js і теки з музикою.
Вимоги
- Node.js 18+
- FFmpeg — лише для stream-режиму і завантаження з YouTube
- Python 3 +
pip install -r server/src/tools/ytbdown/requirements.txt— лише для завантаження з YouTube
Установка
git clone <репозиторій>
cd Radio
npm run install-all
cp server/.env.example server/.env
cp client/.env.example client/.envМінімальний server/.env
Три обов'язкові значення, решта має робочі типові:
JWT_SECRET=<довгий випадковий рядок>
ADMIN_LOGIN=admin
ADMIN_PASS=<bcrypt-хеш>
DATA_PROVIDER=json
MEDIA_STORAGE=localХеш пароля генерується скриптом:
cd server && node scripts/hash-password.jsADMIN_PASS має бути саме хешем — сервер не приймає пароль у відкритому вигляді. Без JWT_SECRET сервер відмовиться стартувати.
Дозвольте походження свого клієнта
Це той крок, який найчастіше пропускають:
CLIENT_ORIGIN=http://localhost:3000,http://localhost:5173Значення перелічуються через кому й застосовуються і до HTTP, і до Socket.io. Клієнт з іншого походження буде заблокований браузером. Після зміни — перезапуск.
Музика
Покладіть аудіофайли у теки за режимами:
server/media/music/day/ ← денна ротація
server/media/music/night/ ← нічна ротаціяІдентифікатор треку в API — це шлях виду day/Виконавець - Назва.mp3.
Якщо нічний режим не потрібен, вимкніть його й радіо працюватиме цілодобово в денному:
NIGHT_MODE=falseЗапуск
npm run dev --prefix server # бекенд у режимі стеження
npm run dev --prefix client # Vite dev-серверУ продакшені клієнт збирається і роздається самим сервером:
npm run build-client
npm startЩо вмикати далі
| Хочу | Треба |
|---|---|
| Кілька адмінів з ролями | нічого — обидва провайдери зберігають облікові записи |
| Завантаження пісень з адмінки | нічого — працює і на локальному диску |
| Джингли між піснями | STREAM_MODE=true (сховище будь-яке) |
| Живий ефір з мікрофоном | STREAM_MODE=true + RADIO_HOSTS_MODE=true |
| Автоматичні тексти пісень | нічого — LRCLIB не потребує ні акаунта, ні ключа |
| Імпорт з YouTube | FFmpeg + python3 з pip-залежностями ytbdown (сховище будь-яке) |
Як налаштувати кожен пункт — у Повній конфігурації. Зверніть увагу: жодна з можливостей не потребує хмарних сервісів — увесь функціонал доступний на локальному диску й локальній базі. Хмара і зовнішня база потрібні лише тоді, коли хостинг стирає файлову систему при деплої (див. Ефемерний хостинг).
RADIO_HOSTS_MODE=true без STREAM_MODE=true не спиняє сервер: живий ефір просто лишається вимкненим, а решта радіо працює.
Повний перелік змінних — у server/.env.example, кожна з коментарем.
Документація на своєму піддомені
Цю документацію віддає той самий сервіс, що й радіо: запити розводяться за іменем хоста. Що прийшло на документаційний хост — отримує зібраний VitePress з docs/.vitepress/dist, решта — клієнт радіо.
DOCS_HOST=docs.example.comЗмінну можна не задавати: тоді документація віддається на будь-якому хості, перша мітка якого — docs.
Збирати треба обидва боки:
npm run build # клієнт + документація
npm startСенс тримати їх в одному деплої не лише в зручності. Довідник API генерується з коду сервера, тож спільне розгортання — це те, що гарантує: довідник описує саме той сервер, який зараз працює.
Розгортання на Render
Один Web Service, Build Command — npm run install-all && npm run build, Start Command — npm start. До цього ж сервісу додаються обидва домени (основний і docs.), сертифікати видаються автоматично.
install-all передає --include=dev для клієнта й документації: Render виставляє NODE_ENV=production, а без цього прапорця npm пропускає devDependencies, де й живуть Vite та VitePress.