Подкастер платит за хостинг эпизодов: свой RSS и свои файлы
Подкаст растёт, счёт от хостинга подкастов растёт вместе с ним — это стандартная модель специализированных сервисов: либо лимит по числу часов прослушивания в месяц, либо по числу активных эпизодов, либо и то и другое сразу. При этом сама RSS-лента и аудиофайлы физически лежат не у вас: сменить площадку — значит переносить фид, менять enclosure-ссылки в каждом эпизоде и рисковать, что подписчики в Apple Podcasts и Spotify эту ленту потеряют. Ниже — как собрать всё то же самое на своём сервере: хранение файлов, генерация RSS вручную и раздача аудио без посредника.
Содержание
Что растёт вместе с аудиторией, а что нет
Логика тарифов у специализированных хостингов подкастов почти всегда завязана либо на трафик прослушиваний, либо на количество эпизодов в ленте. Пока подкаст маленький, это незаметно: несколько выпусков в месяц, скромная аудитория, минимальный тариф. Но стоит выпускам накопиться до сотни-другой или аудитории вырасти — тариф переходит на следующую ступень, и это происходит не потому, что вырос объём хранимых данных на диске (аудиофайлы за годы весят не так уж много), а потому что выросло количество запросов к файлам или число активных серий в фиде.
Второй момент — это не совсем ваш RSS. Формально лента доступна по прямой ссылке, и её можно скопировать в любой каталог подкастов. Но генерируется она движком хостинга, из его базы данных, по его правилам разбивки на страницы и его политике хранения старых выпусков. Если хостинг решит закрыться, сменить условия или заблокировать аккаунт — фид может исчезнуть вместе с историей выпусков, а восстанавливать ссылки на сотню эпизодов вручную, сверяя даты публикации и описания по скриншотам и локальным копиям файлов, — то ещё удовольствие.
Своя площадка снимает оба ограничения разом: диск на сервере стоит фиксированную сумму независимо от того, сколько раз выпуск скачали за месяц, а RSS-файл — это обычный текстовый файл, который лежит у вас и который вы контролируете полностью, вплоть до тегов, порядка сортировки и истории правок в git.
Что нужно, чтобы подкаст переехал на свой сервер
Набор минимальный и знакомый любому, кто разворачивал сайт на VPS:
- Домен — можно тот же, что у сайта подкаста, поддомен вида
feed.вашподкаст.ru, или отдельный. Если домена ещё нет, порядок регистрации на юрлицо и на физлицо описан в статье про регистрацию домена. - VPS — для аудио-подкаста не нужны серьёзные вычислительные мощности, это по сути файловый сервер плюс веб-сервер, отдающий статику. Значение имеют диск (аудиофайлы за несколько сезонов легко набегают на десятки гигабайт) и исходящий трафик, если аудитория заметная.
- HTTPS-сертификат — подкаст-приложения (особенно Apple Podcasts) требовательны к валидности TLS на адресе фида и enclosure-ссылок. Let's Encrypt через certbot закрывает это бесплатно, пошагово — в статье про установку Let's Encrypt на VPS.
- Веб-сервер — nginx отлично справляется с отдачей статичных mp3/m4a файлов и RSS-XML, поддерживает докачку (Range-запросы) из коробки.
- Место для файлов и структура каталогов — простое дерево вида
episodes/,feed.xml,assets/(обложки).
Структура на диске может выглядеть так:
/srv/podcast/
├── feed.xml
├── episodes/
│ ├── s01e01-nazvanie-vypuska.mp3
│ ├── s01e02-nazvanie-vypuska.mp3
│ └── ...
├── assets/
│ └── cover.jpg
└── episodes.json # метаданные для генератора ленты
Отдельный файл episodes.json с метаданными (заголовок, дата, длительность, описание, номер сезона/эпизода) удобнее, чем держать всё в голове или парсить имена файлов — он же становится источником истины при регенерации feed.xml.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверRSS-лента: как она устроена и как собрать её руками
Подкаст-RSS — это обычный RSS 2.0 с расширением itunes (де-факто стандарт, его понимают и Apple Podcasts, и Spotify, и большинство других каталогов). Ключевые элементы на уровне канала и на уровне эпизода:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>Название подкаста</title>
<link>https://вашподкаст.ru</link>
<language>ru</language>
<description>Короткое описание подкаста для каталогов.</description>
<itunes:author>Имя автора</itunes:author>
<itunes:owner>
<itunes:name>Имя автора</itunes:name>
<itunes:email>you@вашподкаст.ru</itunes:email>
</itunes:owner>
<itunes:image href="https://feed.вашподкаст.ru/assets/cover.jpg"/>
<itunes:category text="Technology"/>
<itunes:explicit>false</itunes:explicit>
<item>
<title>S01E01 — Название выпуска</title>
<description>Описание конкретного эпизода.</description>
<pubDate>Fri, 22 Aug 2026 09:00:00 +0300</pubDate>
<enclosure url="https://feed.вашподкаст.ru/episodes/s01e01-nazvanie-vypuska.mp3"
length="48213904"
type="audio/mpeg"/>
<guid isPermaLink="false">podcast-s01e01</guid>
<itunes:duration>00:52:14</itunes:duration>
<itunes:explicit>false</itunes:explicit>
</item>
</channel>
</rss>
Здесь важны три вещи, которые часто ломают в самодельных лентах:
lengthв enclosure — это точный размер файла в байтах, а не длительность. Берётся так:stat -c%s episodes/s01e01-nazvanie-vypuska.mp3. Если значение неверное или отсутствует, некоторые приложения-плееры некорректно показывают прогресс докачки.guid— уникальный и стабильный идентификатор эпизода. Если вы потом переименуете файл или поменяете URL,guidдолжен остаться прежним — иначе приложения подписчиков посчитают эпизод новым и он «всплывёт» повторно у всех в ленте.pubDateв формате RFC 822 — с явным часовым поясом. Разные библиотеки форматируют дату по-разному, но каталоги ожидают именно этот формат (Fri, 22 Aug 2026 09:00:00 +0300), а не ISO 8601.
Собирать этот XML вручную построчно для каждого выпуска утомительно и чревато опечатками в закрывающих тегах. Практичнее — маленький генератор, который читает episodes.json и рендерит feed.xml целиком при каждом обновлении.
Раздача аудио: nginx, докачка и кэш
Аудиофайлы в подкасте отдаются как обычная статика, но с нюансами: подкаст-приложения качают файл не всегда целиком за раз (докачка, фоновая загрузка, перемотка на середину эпизода), и им нужна поддержка Range-запросов. nginx поддерживает Range для статических файлов без дополнительной настройки — достаточно не проксировать файл через что-то, что эту поддержку обрезает.
Минимальный конфиг:
server {
listen 443 ssl http2;
server_name feed.вашподкаст.ru;
ssl_certificate /etc/letsencrypt/live/feed.вашподкаст.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/feed.вашподкаст.ru/privkey.pem;
root /srv/podcast;
# сама лента
location = /feed.xml {
default_type application/rss+xml;
add_header Cache-Control "public, max-age=300";
}
# обложка и статичные картинки
location /assets/ {
add_header Cache-Control "public, max-age=86400";
}
# аудиофайлы эпизодов
location /episodes/ {
types { audio/mpeg mp3; audio/mp4 m4a; }
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Accept-Ranges bytes;
sendfile on;
aio threads;
}
}
Cache-Control: immutable для файлов эпизодов оправдан, если вы не перезаписываете файл по тому же имени после публикации (а вы не должны — при правках лучше выкладывать новый файл и обновлять enclosure, чем перетирать старый под тем же URL, иначе у части подписчиков в кэше браузера или CDN зависнет старая версия). Для feed.xml, наоборот, кэш короткий — 5 минут, — потому что лента обновляется при каждом новом выпуске и каталоги подкастов её периодически перепроверяют.
Если аудитория ощутимо распределена географически или счёт за трафик становится заметным, перед сервером можно поставить CDN — базовая настройка для статики описана в статье про подключение CDN. Для подкаста это особенно уместно: аудиофайлы — идеальный кандидат для кеширования, они не меняются после публикации.
Публикация эпизода: рабочий процесс и автоматизация
Ручное редактирование XML на каждый новый выпуск — плохая идея, там легко забыть закрывающий тег или ошибиться с датой. Практичнее держать метаданные в простом JSON и генерировать feed.xml скриптом при каждой публикации.
episodes.json:
[
{
"slug": "s01e01-nazvanie-vypuska",
"title": "S01E01 — Название выпуска",
"description": "О чём этот выпуск.",
"pub_date": "2026-08-22 09:00:00 +0300",
"file": "episodes/s01e01-nazvanie-vypuska.mp3",
"duration": "00:52:14",
"explicit": false
}
]
Генератор на Python (использует библиотеку feedgen, ставится через pip install feedgen):
#!/usr/bin/env python3
import json
import os
from datetime import datetime
from feedgen.feed import FeedGenerator
BASE_URL = "https://feed.вашподкаст.ru"
ROOT = "/srv/podcast"
fg = FeedGenerator()
fg.load_extension("podcast")
fg.title("Название подкаста")
fg.link(href=f"{BASE_URL}", rel="alternate")
fg.description("Короткое описание подкаста для каталогов.")
fg.language("ru")
fg.podcast.itunes_author("Имя автора")
fg.podcast.itunes_category("Technology")
fg.podcast.itunes_image(f"{BASE_URL}/assets/cover.jpg")
with open(os.path.join(ROOT, "episodes.json"), encoding="utf-8") as f:
episodes = json.load(f)
for ep in episodes:
file_path = os.path.join(ROOT, ep["file"])
size_bytes = os.path.getsize(file_path)
fe = fg.add_entry()
fe.id(ep["slug"])
fe.title(ep["title"])
fe.description(ep["description"])
fe.enclosure(f"{BASE_URL}/{ep['file']}", str(size_bytes), "audio/mpeg")
fe.podcast.itunes_duration(ep["duration"])
fe.podcast.itunes_explicit("yes" if ep["explicit"] else "no")
fe.pubDate(ep["pub_date"])
fg.rss_file(os.path.join(ROOT, "feed.xml"))
print("feed.xml обновлён,", len(episodes), "эпизодов в ленте")
Скрипт читает размер файла с диска сам (os.path.getsize), так что руками длину в байтах указывать не нужно — только длительность, её проще взять из ffprobe:
ffprobe -i episodes/s01e01-nazvanie-vypuska.mp3 -show_entries format=duration -v quiet -of csv="p=0"
Рабочий процесс публикации нового выпуска сводится к четырём шагам: залить mp3-файл в episodes/ по scp или rsync, добавить запись в episodes.json, прогнать генератор, убедиться, что feed.xml обновился (валидный XML можно проверить локально через xmllint --noout feed.xml). При желании это оборачивается в один bash-скрипт или git-хук, если метаданные версионируются в репозитории.
Бэкапы, домен и надёжность
У специализированного хостинга подкастов инфраструктурная надёжность — их забота: они держат бэкапы, следят за аптаймом, разбираются с DDoS. На своём сервере эти задачи переходят к вам, и это честная цена за полный контроль.
Практический минимум:
- Резервная копия каталога
episodes/,assets/иepisodes.json— обычный rsync на другой сервер или облачное хранилище раз в сутки. Файлы эпизодов не меняются после публикации, так что инкрементальный бэкап (тот же rsync с--link-destили borg) практически не тратит место на повторных прогонах. - Домен держите отдельно от хостинг-провайдера сервера — это стандартная практика для любого self-hosted проекта, не только подкаста, и она развязывает вам руки при смене VPS.
- Мониторинг самого факта, что
feed.xmlотдаётся и содержит актуальный список эпизодов — простая проверка по расписанию (curl -sf https://feed.вашподкаст.ru/feed.xml | xmllint --noout -в cron с уведомлением при ошибке) закрывает большинство сценариев «лента отвалилась, а вы узнали об этом от слушателей в комментариях».
Если подкаст уже давно живёт на стороннем хостинге, миграция не требует останавливать выпуск новых эпизодов: закачайте архив аудиофайлов, соберите episodes.json по истории (даты и заголовки обычно можно выгрузить из старого фида тем же xmllint или простым парсингом XML), сгенерируйте feed.xml и переключите ссылку на новый фид в тех местах, где вы её публиковали (сайт, соцсети, шоуноты). В самих каталогах (Apple Podcasts, Spotify) обычно есть механизм «редиректа фида» — старый URL отдаёт <itunes:new-feed-url>, и подписчики переезжают на новый адрес без потери истории прослушиваний. Учтите: у некоторых каталогов на это уходит не один день, так что старую ленту стоит оставить рабочей на переходный период, а не выключать сразу после переезда.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Обязательно ли использовать feedgen, или можно собирать XML вручную?
Можно и вручную — RSS с itunes-расширением это обычный XML, но при ручной сборке легко ошибиться в экранировании спецсимволов в описании эпизода (амперсанды, угловые скобки) или в закрывающих тегах. Библиотека или простой шаблонизатор (Jinja2 поверх XML-шаблона) снимает этот класс ошибок.
Нужен ли отдельный поддомен под фид или можно раздавать с основного сайта подкаста?
Можно с основного домена — принципиальной разницы нет, важно лишь, чтобы адрес был стабильным и не менялся при смене хостинга сайта. Отдельный поддомен (feed.вашподкаст.ru) удобнее тем, что раздачу статики и HTTPS для него можно настроить и обновлять независимо от остального сайта.
Что будет с уже собранной аудиторией в Apple Podcasts и Spotify при переезде?
Подписчики привязаны к RSS-URL, а не к хостингу файлов. Если вы аккуратно перенесёте фид (см. раздел про миграцию выше) и используете механизм редиректа, подписки и история сохраняются. Резкая смена адреса фида без редиректа — то, чего стоит избегать.
Сколько места на диске реально нужно под подкаст?
Зависит от битрейта записи и числа выпусков, точную цифру дать нельзя — но ориентировочно час аудио в приемлемом для голоса битрейте (96–128 kbps) занимает от полусотни до сотни с небольшим мегабайт, так что даже несколько сезонов еженедельного подкаста обычно укладываются в десятки гигабайт, а не сотни.
Что делать с транскриптами и заметками к выпускам?
Их можно хранить в том же episodes.json или в отдельных markdown-файлах рядом с аудио и отдавать через тот же nginx — это отдельная тема, если транскрипты делаются автоматически через распознавание речи, а не руками.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →