Когда вы запускаете интернет-радио, вы неизбежно сталкиваетесь с вопросом: «А где будет жить сайт?». Классический подход подразумевает разделение ответственности. Icecast работает на одном порту, отдавая аудиопоток. Nginx или Apache — на другом, раздавая HTML-страницы, PHP-скрипты для плеера, формы обратной связи и, возможно, WordPress для блога. Между ними — мосты, прокси, CORS-настройки и куча мест, где всё может пойти не так.
Мы пошли другим путем. В нашем решении на Go веб-сервер встроен в радио-ядро. Это не просто «удобная фича», это архитектурное решение, которое меняет подход к управлению станцией. Никаких больше sudo apt install apache php mysql, никаких виртуальных хостов и танцев с FastCGI. Просто запустили приложение — и у вас есть и радио, и сайт, и API.
Но самое интересное — это то, как мы реализовали управление контентом. Без админки, без базы данных для текстов, без сложных CMS. Всё строится на простой файловой структуре.
Почему классический стек разделяет сайт и радио
Исторически сложилось, что Icecast — это специализированный инструмент, который умеет только отдавать аудио. Всё, что связано с веб-интерфейсом, ложится на плечи сторонних решений:
- Icecast + Nginx/Apache: Вам нужно поднимать отдельный веб-сервер. Настроить виртуальные хосты, пробросить порты, обеспечить, чтобы плеер на сайте мог обращаться к Icecast без CORS-ошибок. Это означает дополнительные файлы конфигурации, отдельные сервисы в systemd, отдельные логи.
- CMS для сайта: Если вы хотите вести блог, публиковать новости, вам понадобится WordPress, Jekyll или что-то подобное. Это база данных, PHP-интерпретатор, настройка прав доступа, обновления безопасности. Всё это — дополнительная поверхность для атак и головная боль.
- Обработка форм: Форма обратной связи? Подписка на уведомления? В классической схеме вам нужен PHP-скрипт (или Python/Node.js), который примет POST-запрос, отправит письмо через SMTP и сохранит данные в базу. Это ещё один компонент, который может упасть.
- Проблема связности: Каждый дополнительный компонент — это точка отказа. Если Nginx упал, сайт недоступен, но радио может работать. Если упал Icecast — радио молчит, а сайт висит. Вы получаете два независимых сервиса, за которыми нужно следить.
Наш подход: один бинарник, один процесс, один порт
Наше Go-приложение объединяет в себе всё необходимое. При запуске оно поднимает HTTP-сервер, который одновременно:
- Отдает аудиопоток (как Icecast).
- Раздает HTML-страницы вашего сайта.
- Обслуживает API для плеера.
- Обрабатывает формы обратной связи.
- Показывает админку для управления радио.
Всё это работает на одном порту (обычно 8080), что упрощает настройку SSL (один сертификат на всё), проксирование и фаерволы. Но главное — это организация контента.
Сайт — это просто папка с файлами
Мы отказались от идеи «админки для сайта» (но в будущем при спросе может появится). Вы не заходите в редактор, не сохраняете посты в базу данных. Вы просто создаете файлы в определенной структуре папок на сервере. И они становятся доступны по HTTP. Мгновенно. Без перезагрузки, без кэширования, без лишних телодвижений.
/var/radio/
├── radio_app # бинарник приложения
├── config.toml # конфигурация
├── data/ # папка с музыкой, плейлистами
└── www/ # 👈 ЭТО ВАШ САЙТ
├── index.html # главная страница
├── about.html # страница "о радио"
├── blog/ # папка для блога
│ ├── 2025-03-20-novinki.html
│ ├── 2025-03-15-intervyu.html
│ └── index.html # архив записей
├── contacts.html # страница с формой
├── css/
│ └── style.css
└── js/
└── player.js
Чтобы добавить новую статью в блог, вы просто:
- Создаете HTML-файл в папке
www/content/blog/. - Готово. Статья доступна по адресу
http://ваше-радио/blog/2025-03-20-novinki.html.
Никакой базы данных, никаких SQL-инъекций, никаких обновлений WordPress. Просто файлы. Это надежно, прозрачно и легко поддается бэкапам.
Встроенная система обработки форм
Это отдельная история. Мы понимаем, что просто раздавать статику — мало. Нужно получать сообщения от слушателей: заявки на ротацию, вопросы, поздравления.
В наше приложение встроен обработчик форм. Вы просто добавляете на любую HTML-страницу форму с определенным классом или атрибутом, и система автоматически:
- Принимает POST-запрос.
- Валидирует поля (CSRF-защита, проверка email).
- Сохраняет сообщение во встроенную админку.
- Отправляет уведомление на email администратора.
Пример формы:
<form action="/api/form/submit" method="POST">
<input type="text" name="name" placeholder="Ваше имя" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Ваше сообщение"></textarea>
<button type="submit">Отправить</button>
</form>
Всю остальную логику (сохранение, отправку почты, защиту от спама) берет на себя приложение.
Встроенная админка для сообщений
Все присланные через формы сообщения попадают в админку вашего радио. Вам не нужно заходить в почтовый ящик или смотреть логи.
- Список сообщений — хронология обращений, статусы (прочитано/не прочитано).
- Просмотр — имя, email, текст сообщения, время отправки, IP-адрес.
- Управление — можно посмотреть и пометить как обработанное.
И да, уведомления на почту приходят автоматически. Но даже если вы не проверили почту — сообщение никуда не денется, оно будет ждать вас в админке.
Почему файловая структура — это не «упрощение», а осознанный выбор
Может показаться, что отсутствие веб-админки для контента — это шаг назад. Но давайте посмотрим правде в глаза:
- Безопасность: Нет базы данных — нет SQL-инъекций. Нет PHP — нет уязвимостей уровня «запустил скрипт из папки uploads». Ваш сайт — это статические файлы, которые можно проверять через Git.
- Прозрачность: Вы всегда знаете, какие файлы лежат на сервере. Никаких скрытых записей в базе данных, никакого «магического» поведения CMS.
- Контроль версий: Положите папку
www/в Git. Теперь у вас есть история всех изменений на сайте. Ошиблись? Откатились. Никаких «я случайно нажал "Сохранить" и испортил верстку». - Простота бэкапов: Вся ваша станция — это папка с бинарником, конфигом, музыкой и сайтом. Скопировали — восстановили. Не нужно дампить базы данных и помнить, как настраивался WordPress 3 года назад.
- Скорость: Go-сервер раздает статику с невероятной скоростью. Никаких интерпретаторов, никаких оверхедов. Просто читаем файл → отдаем в сокет.
Что насчет динамического контента?
Вы можете спросить: «А если мне нужен не просто блог, а что-то сложнее — например, голосования, комментарии, личные кабинеты?»
Для этого у нас есть встроенное API. Вы можете писать любую клиентскую логику на JavaScript, которая будет обращаться к эндпоинтам нашего приложения:
GET /api/status— текущий трек, количество слушателей.POST /api/vote/like— поставить лайк треку.
Если вам нужна полноценная CMS — никто не мешает поставить ее отдельно, на поддомене, и проксировать через Nginx. Но наш опыт показывает: для 90% радиостанций возможностей встроенного веб-сервера более чем достаточно. Вы получаете сайт, блог, формы обратной связи, плеер и админку в одном флаконе, без необходимости разбираться в связке из пяти разных технологий.
Итог: радиовещание как монолит — это удобно
Мы не боимся слова «монолит». В эпоху микросервисов и распределенных систем часто забывают, что для маленьких и средних проектов монолит — это спасение. Один процесс, который умеет всё:
- Отдает аудио.
- Раздает сайт.
- Принимает лайки.
- Обрабатывает формы.
- Хранит сообщения.
- Отправляет письма.
Вы устанавливаете один бинарник, кладете рядом папку www/ с вашим сайтом, запускаете — и готово. Сервер работает. Не нужно настраивать Nginx, писать PHP-обработчики форм, мучиться с CORS, поднимать отдельную базу данных для сообщений.
И главное: вы всегда знаете, как это устроено. Файловая структура прозрачна. Если через год вы решите переехать на другой хостинг — просто копируете папку. Никаких «а где у нас лежит база данных от WordPress?» и «какой пароль от SMTP был прописан в том скрипте, который мы написали в 2023-м?».
Мы сделали так, чтобы радио было не сложнее, чем запустить личный блог на статическом генераторе. Но с мощью профессионального аудиосервера внутри.