Создание онлайн-радио GrindFM: опыт развертывания AzuraCast в Яндекс Облаке
Я давно и активно играю в STALCRAFT (ныне STALZONE). Одной из самых атмосферных деталей игры является радиостанция Grind FM, ненавязчиво звучащая фоном на базах. Однако у нее есть существенный минус: зона покрытия ограничена лишь отдельными безопасными уголками. Мне же захотелось слушать этот саундтрек прямо во время боевых вылазок, рейдов и зачистки мутантов.
Изучив доступные варианты без необходимости иметь навыки системного администрирования, я остановился на оптимальном решении: арендовать облачный VPS и развернуть готовый радиосервер с удобным веб-интерфейсом.
Необходимые компоненты
-
Виртуальный сервер (VPS) в Яндекс Облаке — базово достаточно 1 ядра, 2 ГБ ОЗУ и 20 ГБ SSD.
-
Доменное имя (по желанию, подключаться можно напрямую по IP).
-
Коллекция треков в формате MP3.
-
Около двух часов свободного времени.
Шаг 1. Развертывание виртуальной машины
В консоли Яндекс Облака переходим к созданию виртуального инстанса со следующими характеристиками:
|
Параметр |
Значение |
|---|---|
|
ОС |
Ubuntu 24.04 LTS |
|
Процессор (vCPU) |
4 ядра |
|
Оперативная память |
12 ГБ |
|
Накопитель |
150 ГБ SSD |
|
SSH-ключ |
Автоматическая генерация в панели |
Шаг 2. Установка платформы AzuraCast
AzuraCast — это мощная панель управления веб-радиостанцией, функционирующая в изолированных контейнерах Docker.
Подключаемся к терминалу сервера через встроенный Cloud Shell:
Ставим Docker:
sudo apt update
sudo apt install curl -y
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
Перезаходим в сессию SSH, чтобы обновились права пользователя для группы docker.
Загружаем и запускаем скрипт установки AzuraCast:
curl -s https://raw.githubusercontent.com/AzuraCast/AzuraCast/main/docker.sh > docker.sh
chmod a+x docker.sh
./docker.sh install
Отвечаем на базовые вопросы конфигуратора в терминале.
На этом инсталляция AzuraCast успешно завершена.

Шаг 3. Первичная настройка через веб-интерфейс
Открываем в браузере адрес сервера: http://51.250.51.60 (IP вашего хоста).
Создаем профиль суперадминистратора: задаем адрес почты и надежный пароль.
Затем запускаем мастер настройки новой станции и последовательно проходим по вкладкам:
Профиль
-
Название станции: Grind FM
-
Жанровая направленность: Рок, пост-панк, альтернатива
-
Часовой пояс: UTC+3
-
Отображаемая история треков: 5
-
Воспроизведение по запросу: отключено

Вещание
-
Сервер вещания: локальный Icecast
-
Остальные параметры: по умолчанию

Автодиджей
-
Движок: Liquidsoap
-
Режим: Умный (Smart Mode)
-
Функции AutoCue и выравнивание ReplayGain: включены

Прочие параметры
-
HLS-потоки: отключены
-
Заказ композиций: отключен
-
Учетные записи стримеров: отключены
Шаг 4. Загрузка медиатеки
Самый трудоемкий этап — собрать оригинальный треклист из игры. Порывшись в сообществе Steam, я нашел ссылку на Яндекс Диск со всеми необходимыми аудиозаписями.
В панели управления переходим в Медиафайлы, жмем «Загрузить» и переносим директорию с файлами MP3.
AzuraCast в автоматическом режиме прочитает ID3-теги: наименование, исполнителя и графику обложек.
Шаг 5. Формирование плейлиста
В меню Плейлисты создаем новую ротацию со следующими параметрами:
|
Параметр |
Значение |
|---|---|
|
Название |
GrindFM |
|
Источник |
Стандартные треки |
|
Тип |
Общая ротация |
|
Порядок проигрывания |
В случайном порядке (Shuffle) |

Сохраняем конфигурацию, выделяем загруженные треки в медиатеке и связываем их с созданным плейлистом.
Шаг 6. Старт трансляции
Открываем вкладку Вещание и нажимаем ПЕРЕЗАПУСТИТЬ ВЕЩАНИЕ.
Буквально через минуту службы переходят в активное состояние: Icecast и Liquidsoap успешно транслируют поток.

Шаг 7. Проверка трансляции
В блоке Обзор копируем ссылку на готовый стрим.
Открываем в Яндекс Браузере — воспроизведение идет без задержек. Отправляю друзьям — у них тоже всё играет четко.
Публичный веб-плеер: http://51.250.51.60/public/grindfm_radio
Шаг 8. Стилизация в духе STALCRAFT
Чтобы стандартный плеер приобрел аутентичный сталкерский колорит, был написан кастомный CSS:
-
Глубокий темный фон с радиальным свечением
-
Характерная оранжево-янтарная подсветка
-
Стилизованный скроллбар
-
Скрытие ненужных стандартных кнопок
-
Тематический фон и кастомная заглушка обложек
Код вставляется в настройках внешнего вида в поле «Пользовательский CSS».
/* GrindFM — Сталкерский стиль */
body {
background: #0f0c08;
background-image:
radial-gradient(ellipse at 50% 0%, #2a1f14 0%, #0f0c08 70%);
color: #c4b5a0;
font-family: 'Courier New', monospace;
}
.player-container {
background: rgba(20, 15, 10, 0.85);
border: 2px solid #5a3d2b;
border-radius: 12px;
box-shadow: 0 0 40px rgba(80, 40, 20, 0.3);
backdrop-filter: blur(10px);
}
.navbar, .header {
background: rgba(10, 8, 6, 0.9);
border-bottom: 1px solid #4a3020;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.8);
}
h1, h2, h3, .station-name {
color: #d4c5b0;
text-shadow: 0 0 20px rgba(180, 100, 50, 0.3);
letter-spacing: 3px;
text-transform: uppercase;
}
.station-name {
font-size: 2.5rem;
font-weight: bold;
color: #e8d5b8;
text-shadow:
0 0 30px rgba(200, 120, 60, 0.4),
0 0 60px rgba(150, 80, 30, 0.2);
}
.now-playing {
background: rgba(30, 22, 16, 0.7);
border-left: 4px solid #8B5A2B;
padding: 20px;
border-radius: 8px;
}
.song-title {
color: #e8d5b8;
font-weight: bold;
font-size: 1.4rem;
text-shadow: 0 0 15px rgba(200, 150, 80, 0.2);
}
.song-artist {
color: #a8957a;
font-style: italic;
}
.btn, .button {
background: #2a1f14;
border: 1px solid #6a4d35;
color: #d4c5b0;
padding: 10px 25px;
border-radius: 6px;
text-transform: uppercase;
letter-spacing: 2px;
transition: all 0.3s ease;
}
.btn:hover, .button:hover {
background: #4a3120;
border-color: #b8885a;
box-shadow: 0 0 30px rgba(180, 100, 50, 0.2);
color: #f0e0c8;
}
.offline-text {
color: #8a7a6a;
font-style: italic;
font-size: 1.2rem;
border-left: 3px solid #5a3d2b;
padding-left: 20px;
background: rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.schedule-item {
background: rgba(30, 22, 16, 0.5);
border-bottom: 1px solid #3a2a1e;
padding: 12px;
}
.schedule-item:hover {
background: rgba(50, 35, 25, 0.6);
}
/ Анимированный градиент для фона /
@keyframes zoneGlow {
0% { opacity: 0.3; }
50% { opacity: 0.6; }
100% { opacity: 0.3; }
}
.glow-border {
border: 1px solid #6a4d35;
animation: zoneGlow 3s ease-in-out infinite;
}
/ Стиль для ссылок /
a {
color: #b8885a;
text-decoration: none;
border-bottom: 1px dashed #4a3020;
transition: color 0.3s;
}
a:hover {
color: #d4a87a;
border-bottom-color: #b8885a;
}
/ Стиль для изображений-заглушек /
.default-album-art {
filter: sepia(0.3) brightness(0.7) contrast(1.2);
border: 2px solid #4a3020;
border-radius: 8px;
}
/ Полоса прокрутки в стиле сталкер /
::-webkit-scrollbar {
width: 10px;
background: #1a1410;
}
::-webkit-scrollbar-thumb {
background: #4a3525;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #6a4d35;
}
/ Кнопка play /
.play-btn {
background: #3a2a1e;
border: 2px solid #6a4d35;
color: #e8d5b8;
width: 60px;
height: 60px;
border-radius: 50%;
font-size: 24px;
transition: all 0.3s;
box-shadow: 0 0 30px rgba(180, 100, 50, 0.2);
}
.play-btn:hover {
background: #5a3d2b;
border-color: #b8885a;
box-shadow: 0 0 50px rgba(200, 120, 60, 0.3);
transform: scale(1.05);
}
/ Дополнительный текст в стиле радио Зоны /
.radio-frequency {
color: #6a5a4a;
font-size: 0.8rem;
letter-spacing: 6px;
text-transform: uppercase;
border-top: 1px solid #3a2a1e;
padding-top: 10px;
}
/ ============================================= /
/ 🚫 СКРЫВАЕМ КНОПКУ "ПЛЕЙЛИСТ" (точный класс) /
/ ============================================= /
a.btn.btn-link.text-secondary[href*="playlist"] {
display: none !important;
}
Пользовательский JavaScript для добавления интерактивных элементов:
// GrindFM — Сталкерский JS document.addEventListener('DOMContentLoaded', function() { console.log('☢️ GrindFM — Радио Зоны запущено');// Добавляем радио-частоту в заголовок const header = document.querySelector('.station-name'); if (header) { const freq = document.createElement('span'); freq.className="radio-frequency"; freq.textContent="🔴 103.7 FM — Зона"; freq.style.cssText = ` display: block; font-size: 0.8rem; color: #6a5a4a; letter-spacing: 6px; text-transform: uppercase; border-top: 1px solid #3a2a1e; padding-top: 10px; margin-top: 8px; `; header.appendChild(freq); } // Добавляем сталкерскую приписку к статусу "оффлайн" const offlineText = document.querySelector('.offline-text, .station-offline'); if (offlineText) { const stalkerMsg = document.createElement('div'); stalkerMsg.style.cssText = ` font-size: 0.9rem; color: #8a7a6a; margin-top: 10px; border-left: 3px solid #5a3d2b; padding-left: 20px; font-style: italic; background: rgba(0, 0, 0, 0.3); border-radius: 4px; padding: 12px; `; stalkerMsg.textContent="☢️ "Тихо в эфире. Жди сигнала.""; offlineText.parentNode.insertBefore(stalkerMsg, offlineText.nextSibling); } // Меняем заголовок вкладки document.title="☢️ GrindFM — Радио Зоны"; // Добавляем иконку радио (если есть) const favicon = document.querySelector('link[rel="icon"]'); if (favicon) { // favicon уже есть — ничего не делаем } // Анимация мигания для активного статуса const statusDot = document.querySelector('.status-dot, .live-indicator'); if (statusDot) { setInterval(() => { statusDot.style.opacity = Math.random() > 0.9 ? '0.3' : '1'; }, 2000); } // Консольная заставка console.log('%c☢️ GRIND FM — РАДИО ЗОНЫ', 'font-size: 20px; color: #e8d5b8; background: #1a1410; padding: 10px 20px; border: 2px solid #6a4d35; border-radius: 6px;'); console.log('%c"Здесь не место для слабых духом."', 'color: #8a7a6a; font-style: italic; font-size: 14px;'); // Обработка ошибок плеера с сталкерскими сообщениями const audio = document.querySelector('audio'); if (audio) { audio.addEventListener('error', function(e) { console.log('⚠️ Потеря сигнала. Внимание, аномалия!'); }); audio.addEventListener('playing', function() { console.log('📡 Сигнал принят. Эфир активен.'); }); audio.addEventListener('waiting', function() { console.log('⏳ Буферизация... Перезагрузка в зоне.'); }); } console.log('✅ GrindFM — готов к работе!');});
Скрипт был сгенерирован при помощи DeepSeek, так как я не обладаю навыками фронтенд-разработки.
Итоговые результаты
|
Компонент |
Текущее состояние |
|---|---|
|
Радиостанция |
Стабильная работа 24/7 |
|
Публичная страница |
|
|
Ротация музыки |
Перемешивание треков без повторов чаще одного раза в 2 часа |
|
Автодиджей |
AutoDJ — автономное непрерывное вещание |

Планы по улучшению проекта
-
Подключить персональный домен и настроить SSL (HTTPS)
-
Активировать интерактивный заказ треков для слушателей
-
Интегрировать тематические джинглы, реплики и шутки диджеев из игры
-
Сверстать отдельный автономный сайт для радио
Стоимость содержания
В Яндекс Облаке на старте предоставляется приветственный грант, после чего расходы составят:
-
VPS: от ~1500–2000 ₽/мес (выбранная мною усиленная сборка обходится примерно в 8800 ₽/мес)
-
Трафик: первые 100 ГБ ежемесячно бесплатно, далее — 1,53 ₽ за каждый ГБ
При нагрузке порядка 100 одновременных слушателей с качеством потока 128 кбит/с трафик полностью укладывается в бесплатную квоту.
Спасибо за прочтение! Я преданный фанат STALCRAFT и провожу в игре очень много времени. Надеюсь, разработчики оценят эту фанатскую инициативу. А если они вдруг увидят эту статью — огромная просьба: добавьте внутриигровой квест на получение плеера с наушниками, чтобы атмосферную музыку можно было слушать прямо во время рейдов!
По данным инсайдеров, Xbox готовит крупный сюрприз на Gamescom 2026
Самый популярный сериал о Человеке-пауке продлили на рекордный для франшизы седьмой сезон
Четвёртая часть третьего сезона «Покемон» получила дату выхода и новый ролик
Автор манги «Детектив Конан» уже подготовил раскадровку финальной главы
Косплеер представила образ Софии Монад из Lies of P
Как уязвимость на Shareware-диске позволила взломать полную версию Quake
Threezero начнет принимать предзаказы на фигурку ржавой силовой брони T-60 из Fallout 18 августа
JoyToy продемонстрировала распаковку фигурки первого капитана «Повелителей Ночи» Севатара из Warhammer: The Horus Heresy