MAATRIX / Блог / Funkwhale на сервере: частые ошибки и решения

Funkwhale на сервере: частые ошибки и решения

MAATRIX

Funkwhale — федеративная музыкальная платформа на ActivityPub, альтернатива SoundCloud без централизованного владельца. Звучит красиво до первого запуска: Django-бэкенд, Celery-воркеры, PostgreSQL, Redis, nginx и слой федерации одновременно — любое звено может подвести, а логи не всегда говорят прямо, в чём дело. Ниже — набор ошибок, с которыми реально сталкиваешься при развёртывании и эксплуатации Funkwhale, и рабочие способы их устранить.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Federation не работает: инстанс не виден другим серверам

Самая частая причина головной боли с Funkwhale — не музыка, а федерация. Если ваш инстанс не появляется в поиске у других серверов Fediverse или не подтягивает чужие треки, начните с проверки FUNKWHALE_HOSTNAME в .env — он обязан совпадать с доменом, который видит внешний мир, буква в букву, без http:// и без завершающего слэша.

FUNKWHALE_HOSTNAME=music.example.com
FUNKWHALE_PROTOCOL=https

Дальше — подпись HTTP-запросов (HTTP Signatures), на которой держится вся федерация ActivityPub. Проверьте, что nginx прокидывает заголовки, без которых Funkwhale не может корректно подписывать и верифицировать запросы:

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;

Если X-Forwarded-Proto не доходит до бэкенда, Funkwhale может генерировать ссылки на http:// вместо https://, и удалённые сервера будут отбрасывать такие ActivityPub-объекты как невалидные. Проверить, что видит наружу инстанс, можно через .well-known:

curl -s https://music.example.com/.well-known/webfinger?resource=acct:username@music.example.com

Если ответ пустой или 404 — проблема в маршрутизации nginx, а не в самом Funkwhale: location для /.well-known/ часто забывают прописать отдельно от общего location /.

Celery-воркер не подхватывает задачи (импорт зависает)

Импорт треков, транскодинг, обработка федеративных событий — всё это асинхронные задачи Celery. Если после загрузки файлов в интерфейсе они висят в статусе "pending" бесконечно, почти всегда виноват воркер, а не сам импорт.

Проверьте, что контейнер celeryworker вообще жив:

docker compose ps
docker compose logs -f celeryworker --tail=100

Типичная находка в логах — Celery не может достучаться до Redis, который используется как брокер очереди:

[ERROR] consumer: Cannot connect to redis://redis:6379/0: Error 111 connecting to redis:6379. Connection refused.

Убедитесь, что сервис redis в docker-compose.yml стартует раньше воркера и что переменная CACHE_URL / CELERY_BROKER_URL в .env указывает на правильный хост (в Docker-сети это имя сервиса, а не localhost):

CACHE_URL=redis://redis:6379/0
CELERY_BROKER_URL=redis://redis:6379/0

Если Redis жив, но задачи всё равно копятся — проверьте очередь напрямую:

docker compose exec redis redis-cli LLEN celery

Растущее число в очереди при "живом" воркере обычно означает, что воркеру не хватает конкурентности (--concurrency) под нагрузку транскодинга — по умолчанию она рассчитывается от числа ядер, и на слабом VPS с 1-2 vCPU транскодинг большой библиотеки будет идти заметно дольше, чем на выделенном сервере с 4+ ядрами.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Транскодинг не работает: треки не воспроизводятся в браузере

Funkwhale хранит оригиналы файлов как есть, но для воспроизведения в браузере часто нужен транскодинг в формат, который поддерживает клиент (например, из FLAC в Opus/MP3 на лету). Если плеер крутит "загрузку" и падает с ошибкой — почти всегда дело в отсутствии или неправильной сборке ffmpeg внутри контейнера.

docker compose exec api ffmpeg -version

Если команда не найдена, значит используется образ без ffmpeg — актуальный официальный образ Funkwhale (funkwhale/all-in-one или отдельные api/worker образы из документации проекта) уже включает ffmpeg, так что чаще проблема в кастомном или устаревшем образе. Пересоберите/обновите на актуальный тег, не полагайтесь на latest, зафиксируйте конкретную версию в docker-compose.yml.

Второй частый вариант — транскодинг физически работает, но браузер не получает файл из-за проблем с диапазонными запросами (Range-заголовками), на которых строится потоковое аудио. Если в nginx перед Funkwhale стоит дополнительный кэширующий слой или CDN без поддержки Range, перемотка и старт воспроизведения будут "залипать". Проверьте прямо:

curl -I -H "Range: bytes=0-1023" https://music.example.com/api/v1/listen/<uuid>/

Ответ должен быть 206 Partial Content, а не 200 OK.

Импорт "в место" (in-place import) не находит файлы

Если вы заливаете музыку прямо на сервер по SFTP/rsync и запускаете import-files, а Funkwhale не видит файлы — почти всегда виноваты права доступа или несовпадение путей между хостом и контейнером.

docker compose exec api python manage.py import_files <library-uuid> \
  "/music/**/*.flac" --recursive --in-place --noinput

Проверочный чек-лист:

  • каталог с музыкой примонтирован в контейнер api и в контейнер celeryworker одинаковым путём — если у API это /music, а у воркера случайно /data/music, задача импорта просто не найдёт файлы при фактической обработке;
  • владелец файлов на хосте позволяет читать их пользователю, под которым бежит контейнер (обычно UID 1000 в официальных образах) — chmod -R a+rX /path/to/music снимает большинство таких проблем на этапе диагностики, а на постоянку лучше выставить корректного владельца через chown;
  • путь в команде import_files указан относительно точки монтирования внутри контейнера, а не абсолютного пути на хосте.

Если файлы находятся, но не импортируются с ошибкой формата — проверьте, что расширение и реальный кодек файла совпадают: переименованный .mp3 файл, который на деле является .wav, ffprobe отклонит на этапе анализа метаданных.

PostgreSQL: миграции не применились после обновления

При обновлении Funkwhale на новую версию easy забыть выполнить миграции базы данных — интерфейс при этом может открываться, но выдавать 500-е ошибки на конкретных страницах (чаще всего на плейлистах или профилях пользователей, где структура таблиц менялась).

docker compose exec api python manage.py migrate
docker compose logs api --tail=50 | grep -i error

Если миграция падает с ошибкой блокировки таблицы — скорее всего, старый процесс API или воркер всё ещё держит соединение со старой схемой. Остановите все контейнеры, кроме postgres, накатите миграции, и только потом поднимайте остальное:

docker compose stop api celeryworker celerybeat
docker compose exec api python manage.py migrate
docker compose up -d

Общие проблемы подключения к PostgreSQL (не принимает соединения, "role does not exist", исчерпание connection pool) в Funkwhale ничем не отличаются от любого другого Django-приложения — базовую диагностику стоит проверить по нашему материалу о том, что делать, когда PostgreSQL не принимает подключения, а общий разбор частых ошибок PostgreSQL на сервере смотрите в отдельной статье.

Диск заполняется: библиотека растёт быстрее, чем планировалось

Funkwhale хранит оригиналы файлов плюс кэш транскодированных версий — вторая часть часто недооценивается на старте. Если библиотека на несколько тысяч альбомов, кэш транскодинга в Opus/MP3 может добавить заметный процент к объёму оригиналов, особенно если у вас включено несколько битрейтов для разных клиентов.

Проверить, что реально ест место:

docker compose exec api du -sh /music /data/media /data/staticfiles 2>/dev/null
docker system df -v

Кэш транскодинга можно безопасно очищать — Funkwhale перегенерирует его при следующем запросе:

docker compose exec api python manage.py clear_transcode_cache

Если места на локальном диске в принципе мало, а библиотека растёт — рассмотрите вынос медиафайлов на S3-совместимое объектное хранилище через переменные AWS_* в .env (Funkwhale поддерживает django-storages). Поднять свой S3-совместимый бэкенд без привязки к внешнему облаку можно на MinIO — конфигурация в docker-compose описана в статье про MinIO в Docker Compose. Но учтите честно: для активно федерирующего инстанса с частой отдачей аудио сетевой сторонний storage добавляет задержку по сравнению с локальным NVMe, так что для небольших и средних инстансов локальный диск обычно практичнее.

Таблица ориентировочного расхода места (условные цифры, у вас будет отличаться от кодеков, битрейта источника и настроек качества):

КомпонентПримерная доля диска
Оригиналы файлов (FLAC/MP3 источник)базовый объём библиотеки
Кэш транскодинга (несколько битрейтов)заметная надбавка сверху, зависит от числа профилей
PostgreSQL (метаданные, теги, федерация)обычно небольшая доля от общего объёма
Логи и временные файлырастут постепенно, требуют ротации

Уведомления и письма не приходят

Регистрация, сброс пароля, уведомления о новых подписчиках в Funkwhale идут через SMTP — если письма не доходят, чаще всего .env просто не настроен или указан на несуществующий relay.

EMAIL_CONFIG=smtp+tls://user:password@smtp.example.com:587
DEFAULT_FROM_EMAIL=noreply@music.example.com

Проверить конфигурацию можно прямо из Django shell, не дожидаясь реального пользователя:

docker compose exec api python manage.py shell -c "
from django.core.mail import send_mail
send_mail('Test', 'Funkwhale SMTP test', 'noreply@music.example.com', ['you@example.com'])
"

Если команда падает с таймаутом — проверьте, что исходящий 587/465 порт не блокируется файрволом хостинга (у части провайдеров исходящий SMTP закрыт по умолчанию из-за спам-политики, это стоит уточнить заранее, а не после развёртывания). Если письмо ушло, но не пришло — смотрите в логи SMTP-сервера на предмет отклонения по SPF/DKIM для домена отправителя.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Funkwhale обязательно разворачивать через Docker Compose?

Нет, есть вариант ручной установки на Python/systemd, но Docker Compose — основной и наиболее документированный путь для проекта, и подавляющее большинство советов из этой статьи предполагают именно его.

Сколько ресурсов сервера нужно для небольшого инстанса на 5-10 пользователей?

Для старта достаточно 2 vCPU и 2-4 ГБ RAM, если библиотека умеренная и активного транскодинга много одновременных потоков нет; при росте числа одновременных слушателей и объёма библиотеки в первую очередь упираетесь в CPU из-за транскодинга и в дисковое пространство.

Почему федерация работает, но чужие треки не проигрываются у меня?

Часто это не проблема самого Funkwhale, а политика удалённого инстанса — не все сервера разрешают проксирование аудио сторонним подписчикам, это настраивается на их стороне.

Нужен ли Redis обязательно, или можно обойтись без него?

Redis используется и как брокер Celery, и как кэш — без него не заработают асинхронные задачи (импорт, федерация, транскодинг), поэтому в продакшене он обязателен, а не опционален.

Как понять, что проблема в сети/файрволе, а не в самом Funkwhale?

Проверьте .well-known/webfinger и доступность API-эндпоинтов curl'ом снаружи сервера — если снаружи 502/таймаут, а изнутри контейнеры отвечают локально, ищите проблему в nginx или в правилах файрвола, а не в приложении.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →