запись звонка в Битрикс24 не перематывается

Запись звонка в Битрикс24 не перематывается: bx_fast_download, X-Accel-Redirect и S3

Запись звонка в Битрикс24 не перематывается — типичный симптом, когда менеджер не может перейти к нужному моменту разговора, а плеер сбрасывает позицию в начало. Проблема возникает из-за того, что сервер отдаёт файл целиком (статус 200 OK) вместо поддержки частичной загрузки (206 Partial Content). Браузерный плеер физически не может перемотать аудио или видео без заголовков Content-Range и Accept-Ranges.

Корень зла кроется в настройках отдачи файлов из облачного хранилища S3. Если включён режим PHP, система игнорирует запросы Range, нагружая воркеры и блокируя навигацию по файлу. Решение требует переключения на быструю отдачу через nginx с использованием X-Accel-Redirect и правильной конфигурации проксирования для провайдеров вроде Reg.ru или FirstVDS.

Запись звонка в Битрикс24 не перематывается: bx_fast_download, X-Accel-Redirect и S3

Коротко: чтобы запись звонка в Битрикс24 перематывалась, мы включаем флаг bx_fast_download и добавляем в nginx блок проксирования S3 — это переводит отдачу файлов с медленного PHP на быстрый X-Accel-Redirect с поддержкой 206 Partial Content.

Содержание

Симптом, который сбивает с толку

Этот симптом мы регулярно встречаем на коробочных порталах с облачным S3, которые берём на сопровождение.

Менеджер открывает карточку сделки в коробочном Битрикс24, нажимает на запись разговора — и не может перемотать к нужному месту. Бегунок плеера прыгает в начало, файл проигрывается только с нуля и каждый раз заново. В мобильном приложении та же запись перематывается нормально (у него свой плеер), а в вебе — нет. Иногда вложения из чатов и Диска вообще не открываются: вместо файла приходит пустой ответ или 403.

Первая реакция — «битый файл» или «глючит браузер». На деле проблема не в файле и не в браузере. Откройте DevTools браузера (вкладка Network), кликните по записи и посмотрите заголовки ответа. Тревожные признаки:

  • статус 200 OK вместо 206 Partial Content;
  • нет заголовка Content-Range;
  • нет Accept-Ranges: bytes.

Это значит, что сервер отдаёт файл целиком и не умеет отдавать произвольный кусок. А перемотка аудио и видео в браузере работает ровно на этом: плеер запрашивает нужный байтовый диапазон через заголовок Range, и сервер обязан ответить 206 с этим куском. Если сервер всегда возвращает 200 и весь файл с начала — перемотки не будет физически. Это не баг плеера и не глюк интерфейса Битрикса, а поведение бэкенда, который отдаёт файл.

Дальше разберём, почему так происходит на коробочном Битрикс24 с облачным S3-хранилищем, и приведём два рабочих конфига nginx — для Reg.ru и для FirstVDS — снятых с боевых серверов.

Симптом, который сбивает с толку

Как Битрикс отдаёт файлы: два режима

В коробочном Битрикс24 файл из облачного S3-хранилища (Reg.ru, FirstVDS, Selectel, Timeweb и других совместимых) может уйти клиенту двумя принципиально разными путями. Какой именно сработает — определяет одна настройка в админке.

Режим 1 — через PHP (медленный, без Range). Запрос на файл попадает в PHP, модуль clouds скачивает объект из S3 и отдаёт его клиенту через readfile()/fread(). Проблем здесь две. Во-первых, на каждый файл занимается отдельный воркер PHP-FPM на всё время отдачи плюс TLS-рукопожатие к S3 — и когда S3 отвечает медленно, воркер висит секунды вместо миллисекунд. Во-вторых, этот код отдаёт файл целиком, с нулевого байта и не обрабатывает заголовок Range. Отсюда 200 вместо 206 и сломанная перемотка.

Режим 2 — через nginx (быстрый, с Range). Битрикс отдаёт nginx внутренний редирект X-Accel-Redirect, nginx сам идёт в S3 через proxy_pass, прозрачно пробрасывает Range и возвращает 206 Partial Content с нужным куском. PHP-воркер при этом освобождается мгновенно. Перемотка работает, нагрузка на FPM падает.

Переключение между режимами — один флаг Битрикса в опциях модуля main: bx_fast_download. Когда он в Y, Битрикс начинает отдавать X-Accel-Redirect, рассчитывая, что nginx знает, как проксировать запрос в ваше конкретное S3-хранилище. И вот тут главная ловушка: в стандартном bitrix-env nginx «из коробки» не знает про Reg.ru и FirstVDS.

Как Битрикс отдаёт файлы: два режима

Гэп: каких S3-провайдеров нет в дефолтном конфиге

В свежем bitrix-env файл /etc/nginx/bx/conf/bitrix_general.conf уже содержит готовые proxy_pass-блоки для ходовых облаков, но список конечный. Из коробки nginx умеет проксировать только в s3.*.amazonaws.com (AWS, все регионы), *.rackcdn.com (Rackspace), *.clodo.ru (Clodo), *.commondatastorage.googleapis.com (Google CDN) и *.selcdn.ru (Selectel).

Reg.ru S3 (s3.regru.cloud) и FirstVDS S3 (s3.firstvds.ru) — generic-провайдеры, совместимые с протоколом S3, но с собственными доменами. В дефолтном конфиге их нет. Запрос вида /upload/bx_cloud_upload/https.s3.regru.cloud/… проходит мимо всех заготовленных блоков и доезжает до финального правила location ~* .*$ { deny all; } — и nginx возвращает 403.

Получается замкнутый круг: включаешь bx_fast_download=Y — файлы из S3 отдают 403, в чатах вместо вложений ошибка, запись звонка не открывается вовсе; откатываешь в N — файлы открываются, но запись звонка не перематывается, а PHP-FPM захлёбывается под нагрузкой.

Правильное решение — не выбирать из двух зол, а закрыть гэп: добавить в bx/conf/bitrix_general.conf собственный location-блок под ваше S3-хранилище и оставить bx_fast_download=Y. Блок занимает около десятка строк, ставится один раз; правки кладём в отдельный include-файл, чтобы их не затёр апдейтер bitrix-env.

Шаг 1. Включаем bx_fast_download

Быструю отдачу файлов можно включить двумя способами — через интерфейс администратора или через API; результат одинаковый.

Через интерфейс. Переходим в раздел Настройки → Настройки продукта → Настройка модулей и выбираем модуль «Главный модуль». В подразделе «Файлы» ставим галочку «Быстрая отдача файлов через Nginx» и сохраняем настройки.

Галочка «Быстрая отдача файлов через Nginx» в настройках Главного модуля Битрикс24

Через API. Если флаг включается скриптом (например, при автоматизации развёртывания), то же самое делается из PHP-консоли (Настройки → Инструменты → Командная PHP-строка). Первая строка пишет значение, вторая сбрасывает кэш опций — иначе старое значение ещё какое-то время отдаётся из памяти:

После этого перезагружаем PHP-FPM, чтобы пул воркеров перечитал состояние. Имя сервиса зависит от сборки (php8.1-fpm, php8.3-fpm, bx-phpХХ-fpm); точное имя покажет systemctl list-units --type=service | grep fpm:

После включения Битрикс начинает отдавать X-Accel-Redirect вместо тела файла. Если nginx ещё не настроен под ваше S3-хранилище, файлы временно начнут отдавать 403 — это ожидаемо, следующий шаг закрывает гэп.

				
					COption::SetOptionString('main', 'bx_fast_download', 'Y');
$GLOBALS['CACHE_MANAGER']->CleanDir('b_option');
				
			
				
					systemctl reload php8.3-fpm
				
			

Шаг 2. Конфиг nginx для Reg.ru S3

Конфиг ниже снят с боевого сервера с хранилищем Reg.ru S3 (AlmaLinux 9), который мы сопровождаем. Блок вставляется внутри location ^~ /upload/bx_cloud_upload/ в файле /etc/nginx/bx/conf/bitrix_general.conf строго перед финальным location ~* .*$ { deny all; }. Иначе совпадение никогда не сработает: запрос будет отрезан раньше.

Разберём ключевые директивы. internal запрещает прямой доступ к этому location снаружи: попасть в него можно только по внутреннему редиректу от Битрикса (X-Accel-Redirect). Без этой строки location можно было бы использовать как открытый прокси к вашему S3.

resolver 77.88.8.8 ipv6=off нужен, потому что nginx должен резолвить s3.regru.cloud в рантайме на каждый запрос. Публичный DNS Яндекса; IPv6 выключаем, чтобы не ловить таймауты на хостах, где IPv6-стек не настроен.

Самая тонкая строка — more_clear_input_headers 'Authorization'. Она удаляет клиентский заголовок Authorization до того, как nginx сформирует запрос в S3. Если этот заголовок прилетит из браузера, он перетрёт собственную подпись Reg.ru, и хранилище вернёт 403 на корректный по виду запрос. Директива требует модуля headers_more — в bitrix-env он скомпилирован по умолчанию (nginx -V 2>&1 | grep headers_more).

proxy_pass $1://s3.regru.cloud/$2 использует path-style addressing: имя бакета ($2) уходит в путь URL, а не в поддомен. Reg.ru работает именно так, как и большинство generic-S3. У AWS обратная схема (virtual-hosted style, бакет в поддомене), и слепое копирование AWS-шаблона на Reg.ru даст 404 от хранилища.

После добавления блока выполняем nginx -t && nginx -s reload — шаг закрыт.

				
					# Reg.ru S3 compatible storage
location ~ ^/upload/bx_cloud_upload/(http[s]?)\.s3\.regru\.cloud/([^\s].+)$ {
    internal;
    resolver 77.88.8.8 ipv6=off;
    proxy_method GET;
    proxy_set_header X-Real-IP        $remote_addr;
    proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Server $host;
    more_clear_input_headers 'Authorization';
    proxy_set_header "cookie"         "";
    proxy_set_header "content-type"   "";
    proxy_set_header "content-length" "";
    proxy_pass $1://s3.regru.cloud/$2;
}
				
			

Шаг 3. Конфиг nginx для FirstVDS S3

На сервере с хранилищем FirstVDS S3 (Debian 12), который мы тоже ведём, шаблон тот же, но с одной поправкой: модуль headers_more на этой сборке nginx не собран. more_clear_input_headers не сработает, поэтому Authorization чистим штатной директивой proxy_set_header:

proxy_set_header Authorization "" устанавливает пустое значение, и nginx не передаёт заголовок в апстрим. Эффект тот же, что у more_clear_input_headers, но без дополнительного модуля. Сравнительная таблица, чтобы выбрать вариант под вашу сборку:

ПараметрReg.ru S3FirstVDS S3
Очистка Authorizationmore_clear_input_headers ‘Authorization’proxy_set_header Authorization “”
Требует headers_moreданет
Адресация бакетаpath-stylepath-style
Endpoints3.regru.clouds3.firstvds.ru
Резолвер77.88.8.877.88.8.8

Перед применением проверьте, что у вас на nginx: nginx -V 2>&1 | grep -o headers_more. Если модуль есть — годится любой вариант; если нет — только нижний.

Отдельно про path-style. Оба generic-провайдера выдают бакеты по схеме s3.<provider>/<bucket>/<key>, а не по AWS-схеме <bucket>.s3.<provider>/<key>. Поэтому в proxy_pass имя бакета должно уходить в путь. По нашему опыту миграций эта ошибка встречается чаще, чем проблемы с подписью: конфиг внешне валиден, а файлов нет.

Endpoint, прописанный для конкретного бакета, должен совпадать с тем, что в proxy_pass. Сверить можно в /home/bitrix/www/bitrix/.settings.php, ключ endpoint секции cloud-провайдера. Несовпадение даёт 403 от хранилища при корректном на вид nginx.

				
					# FirstVDS S3 compatible storage (s3.firstvds.ru)
location ~ ^/upload/bx_cloud_upload/(http[s]?)\.s3\.firstvds\.ru/([^\s].+)$ {
    internal;
    resolver 77.88.8.8 ipv6=off;
    proxy_method GET;
    proxy_set_header X-Real-IP        $remote_addr;
    proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header Authorization "";
    proxy_set_header Cookie        "";
    proxy_set_header Content-Type  "";
    proxy_set_header Content-Length "";
    proxy_pass $1://s3.firstvds.ru/$2;
}
				
			

Шаг 4. Проверка

Сначала проверяем синтаксис и применяем конфиг (команда ниже). Если nginx -t ругается на неизвестную директиву more_clear_input_headers — у вас не собран headers_more, возьмите вариант для FirstVDS. Если жалуется на резолвер — снимите ipv6=off (на старых nginx опция не поддерживается).

Дальше проверяем главное — отдаёт ли сервер 206 Partial Content на запрос с заголовком Range. Из терминала идём прямо к файлу записи звонка или вложению (команда ниже). Ключевое: статус 206 и заголовок Content-Range. Если пришёл 200 OK и полный файл — либо bx_fast_download всё ещё N, либо запрос не попал в наш location-блок (проверьте регулярку и домен S3). Если 403 — Битрикс отдал редирект, nginx попытался проксировать, но S3 отказал; смотрите endpoint в .settings.php и /var/log/nginx/error.log.

Затем боевая проверка из браузера: открываем карточку сделки, кликаем на запись звонка и тащим бегунок к нужной минуте. Если бегунок прыгнул и звук пошёл с нужного места — победа. В DevTools (вкладка Network) на запросе к файлу должен быть заголовок Range: bytes=… и ответ 206 Partial Content. Заодно убедитесь, что вложения из чатов и файлы с Битрикс24.Диска открываются без 403 — это та же связка bx_fast_download + nginx.

Шаг 5. Откат

Если что-то пошло не так, быстро верните как было: снимите галочку «Быстрая отдача файлов через Nginx» в Главном модуле или выполните COption::SetOptionString('main', 'bx_fast_download', 'N') с последующим сбросом кэша ($GLOBALS['CACHE_MANAGER']->CleanDir('b_option')) и перезагрузкой PHP-FPM. Файлы снова пойдут через PHP: перемотка пропадёт, но сервис продолжит работать. Блок nginx можно оставить — без bx_fast_download=Y он просто не используется.

Бонус: заодно включите Brotli

Раз уж вы залезли в bx/site_settings/default/*.conf, проверьте сжатие. В bitrix-env модуль ngx_brotli обычно уже скомпилирован (nginx -V 2>&1 | grep brotli подтвердит), но /etc/nginx/bx/site_settings/default/brotli.conf пустой — и сжатия нет. Рабочий блок:

brotli on;
brotli_comp_level 4;
brotli_types text/css text/plain text/javascript text/xml text/x-js
             application/xml application/xml+rss application/json
             application/x-javascript application/javascript
             image/svg+xml;

Level 4 — оптимальный баланс нагрузки на процессор и степени сжатия (level 11 даст лишь +5% ценою роста нагрузки в 10 раз). После nginx -t && nginx -s reload проверьте в браузере заголовок Content-Encoding: br — JS, CSS и JSON ужимаются на 20–30% по сравнению с gzip.

				
					nginx -t && nginx -s reload
				
			
				
					curl -I -H "Range: bytes=0-1023" https://example.com/upload/disk/abc/file.mp3
# должно вернуть: HTTP/1.1 206 Partial Content + Content-Range: bytes 0-1023/...
				
			

Итог

Часто задаваемые вопросы

Ответы на часто задаваемые вопросы по теме статьи.

Файл отдаётся через PHP, который не обрабатывает HTTP-заголовок Range и всегда возвращает статус 200 OK с файлом целиком. Перемотка в браузере работает только при ответе 206 Partial Content. Чтобы получить корректный ответ, файл должен отдавать nginx через X-Accel-Redirect, для чего необходим включённый флаг bx_fast_download и настроенный блок проксирования в S3.
Это настройка модуля main в Битрикс24. При значении Y система отдаёт файлы из облачного хранилища не через PHP-скрипт, а через внутренний редирект nginx (X-Accel-Redirect). Это включает поддержку заголовков Range/206 для перемотки медиафайлов и значительно снижает нагрузку на пул процессов PHP-FPM, освобождая воркеры мгновенно после инициирования отдачи.
Ошибка 403 возникает потому, что в стандартной поставке bitrix-env nginx не знает, как проксировать запросы к хранилищам Reg.ru или FirstVDS — для них отсутствуют готовые proxy_pass-блоки. В результате запрос попадает под финальное правило deny all. Для исправления необходимо вручную добавить location-блок с настройками проксирования под конкретное S3-хранилище.
Основное различие заключается в способе очистки заголовка Authorization перед отправкой запроса в хранилище. Для Reg.ru используется директива more_clear_input_headers (требует модуля headers_more), а для FirstVDS — штатная конструкция proxy_set_header Authorization “”. Оба варианта используют path-style addressing, где имя бакета является частью URI.

Константин Тютюнник — ведущий инженер IT For Prof. Специализируется на высоконагруженных проектах на базе Битрикс24, оптимизации стека LEMP и настройке отказоустойчивых кластеров. Имеет многолетний опыт устранения сложных проблем с отдачей статического контента и интеграцией облачных хранилищ.

Если вы столкнулись с тем, что запись звонка в Битрикс24 не перематывается, или наблюдаете общее замедление работы CRM, проблема может крыться в неоптимальной настройке сервера. Это одна из частых причин тормозов коробки — полный разбор всех десяти смотрите в материале «Почему тормозит коробочный Битрикс24». Мы проводим полный аудит конфигурации nginx, PHP-FPM и СУБД, устраняя узкие места производительности. Закажите сопровождение сервера Битрикс24, чтобы обеспечить стабильную работу портала и быструю отдачу медиафайлов.

Поделиться: