Создание онлайн-радио 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 и провожу в игре очень много времени. Надеюсь, разработчики оценят эту фанатскую инициативу. А если они вдруг увидят эту статью — огромная просьба: добавьте внутриигровой квест на получение плеера с наушниками, чтобы атмосферную музыку можно было слушать прямо во время рейдов!
Вышел новый трейлер Minecraft Dungeons II за неделю до релиза игры
Для Xbox создают аналог «платиновых» трофеев под названием Mythic Achievement
Hot Toys показала обзорный видеоролик с прототипом фигурки Королевы Чужих из ленты «Чужие»
Mad King Redemption появилась в сервисе Xbox Game Pass
Новая прошивка для PlayStation 5 вызвала проблемы со звуком у гарнитуры Pulse Elite
Сравнение GPT-6 Astra и Opus 5.5 в создании игры «Ну, погоди!» («Электроника ИМ-02»)
Создатель Final Fantasy VII прошел Revelation 46 раз и заявил, что игра масштабнее Rebirth
Blizzard рассказала о главной особенности Diablo V, которая предложит игрокам сразу три сюжетные линии