Раздача видео и больших файлов в Nginx: рабочие приёмы
Видео начинает тормозить не только из-за канала. Ошибки в Range-запросах, буферизации прокси и выборе способа отдачи заставляют Nginx тратить CPU, память и дисковый I/O там, где этого можно избежать.
Видео на 2 ГБ может начать перематываться с задержкой, а сервер — упереться в диск и исходящий канал, если отдавать файл через приложение или проксировать его без настройки Range-запросов. В этой практике разберём четыре рабочих подхода для Nginx 1.24+ и критерии выбора: прямую раздачу, внутренний редирект через X-Accel-Redirect, проксирование и связку с объектным хранилищем. Синтаксис конфигурации рассчитан на обычный Nginx с HTTP-модулем; редкие директивы для потокового MP4 отдельно помечены.
Сначала определите, кто должен отдавать файл
Главная ошибка — заставить PHP, Python или Node.js читать видео и пересылать его клиенту. Приложение в этом случае становится посредником между диском и браузером: занимает воркер, расходует память на буферы и усложняет поддержку докачки.
Для каждого запроса стоит разделить две задачи:
- приложение проверяет пользователя, срок доступа и права;
- Nginx или объектное хранилище передаёт байты клиенту.
Такой раздел особенно важен для файлов, которые скачивают одновременно десятки пользователей. Авторизация остаётся в приложении, а тяжёлый поток данных уходит на уровень веб-сервера.
Приложение должно решать, можно ли отдавать файл. Но не обязано само пересылать каждый его байт.
Range-запрос1 — HTTP-запрос только за частью файла. Браузер использует его для перемотки, докачки и параллельного скачивания фрагментов.
Четыре способа раздачи и их цена
| Подход | Когда подходит | Что выигрываете | За что платите |
|---|---|---|---|
Прямой root или alias | Публичные файлы или доступ контролируется на уровне URL | Минимум CPU и задержки, встроенная поддержка Range для статических файлов | Сложнее скрыть реальный путь и ограничить доступ к отдельному объекту |
X-Accel-Redirect | Приватные файлы с проверкой в приложении | Приложение не прокачивает файл, внутренний путь не виден клиенту | Нужно согласовать заголовок и внутренний location |
proxy_pass | Файл приходит с другого HTTP-сервиса | Можно объединить несколько источников за одним доменом | Появляется второй поток и риск лишней буферизации на прокси |
| Объектное хранилище или CDN | Большой трафик, несколько регионов, много параллельных скачиваний | Снижает нагрузку на ваш сервер и канал | Стоимость хранения и исходящего трафика, отдельная схема подписанных URL |
Прямые файлы: базовая конфигурация без приложения
Для публичного каталога начните с обычной статической раздачи. Версия Nginx 1.24+ поддерживает нужные здесь директивы; сама модель не зависит от конкретного патч-релиза.
server {
listen 443 ssl;
server_name media.example.com;
location /videos/ {
alias /srv/media/videos/;
sendfile on;
tcp_nopush on;
types {
video/mp4 mp4;
video/webm webm;
}
}
}
alias сопоставляет URL с каталогом на диске. Слеш в конце обоих путей важен: запрос /videos/course.mp4 должен вести к файлу /srv/media/videos/course.mp4. sendfile позволяет ядру передавать файл без лишнего копирования через пользовательское пространство, а tcp_nopush помогает собирать крупные TCP-пакеты при использовании sendfile.
Проверка — откройте файл в браузере и выполните запрос заголовков:
curl -I https://media.example.com/videos/course.mp4
В ответе ожидайте 200, корректный Content-Type и размер файла. Для проверки перемотки запросите диапазон:
curl -i -H "Range: bytes=0-1023" \
https://media.example.com/videos/course.mp4
Рабочая раздача обычно возвращает 206 Partial Content, заголовок Content-Range и около 1024 байт тела. Если всегда приходит 200, сначала проверьте, что запрос действительно доходит до этого location, а файл не отдаёт приложение или другой прокси.
Приватные файлы через X-Accel-Redirect
Когда URL нельзя сделать публичным, не передавайте содержимое через контроллер. Приложение проверяет сессию, подписку или разрешение, а затем отвечает без тела файла и добавляет внутренний редирект.
server {
listen 443 ssl;
server_name media.example.com;
location /_protected_media/ {
internal;
alias /srv/private-media/;
}
location /download/ {
proxy_pass http://app_backend;
}
}
Приложение после успешной проверки должно вернуть заголовок вида X-Accel-Redirect: /_protected_media/course.mp4. Внешний клиент не сможет напрямую запросить путь, отмеченный internal: такой запрос завершится ошибкой Nginx, а внутренний редирект будет обработан сервером.
Критичный момент — соответствие URL и пути. При alias /srv/private-media/ файл /srv/private-media/course.mp4 соответствует внутреннему адресу /_protected_media/course.mp4. Если в приложении формируется полный путь вроде /srv/private-media/course.mp4, Nginx не обязан обработать его как ожидаемый внутренний URI.
Проверяйте не только первый ответ приложения, но и скачивание из браузера. В логах Nginx должны появиться запрос к публичному URL и успешная отдача файла; сам внутренний URI клиент видеть не должен.
Если файл приходит через proxy_pass
Иногда Nginx получает видео от отдельного медиасервиса, а не с локального диска. Тогда основное внимание нужно уделить буферизации. Прокси может читать ответ upstream быстрее, чем клиент принимает его, и временно складывать данные в память или во временные файлы.
location /remote-video/ {
proxy_pass http://video_backend;
proxy_http_version 1.1;
# Передаём диапазон запроса upstream-сервису.
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
# Не заставляем Nginx заранее буферизовать большой ответ.
proxy_buffering off;
}
Этот вариант имеет смысл, если upstream действительно понимает Range и возвращает 206. Если сервис всегда отдаёт весь файл, настройка Nginx не добавит ему поддержку перемотки: исправлять нужно источник или переносить раздачу на локальный статический location.
proxy_buffering off не является универсальным ускорителем. Он снижает накопление ответа на прокси, но увеличивает зависимость upstream от медленного клиента. Для локального приложения и стабильных клиентов это обычно приемлемо; для большого публичного трафика лучше вынести раздачу в CDN или объектное хранилище.
Что ломается чаще всего
Приложение возвращает 200 вместо 206
Проверьте цепочку запроса: браузер, CDN, Nginx, upstream. Один слой может удалять или игнорировать заголовок Range. Снимите заголовки на каждом участке и убедитесь, что диапазон не теряется.
Перемотка работает только после полной загрузки
Для MP4 важна не только поддержка диапазонов. Метаданные контейнера могут находиться в конце файла. Такой ролик формально отдаётся корректно, но плееру приходится ждать больше данных. Пересоберите файл с метаданными в начале отдельным инструментом обработки видео, а не пытайтесь решать проблему директивой Nginx.
Диск загружен на 100 процентов
Проверьте количество одновременных скачиваний, размер файлов и скорость диска. sendfile уменьшает копирование данных, но не отменяет чтение с накопителя. Для часто запрашиваемых объектов помогают CDN, кэш на внешнем уровне и разнесение медиаданных по отдельному диску или хранилищу.
Скачивание обрывается после тайм-аута
Разделите тайм-аут установления соединения и ожидания ответа от upstream. Для локальной статики проблема обычно не в proxy_read_timeout, а в сети, лимите клиента, балансировщике или ограничении CDN. Не увеличивайте тайм-аут вслепую: сначала определите слой, который закрывает соединение.
Запрос получает 404 после добавления alias
Сверьте слеши и фактическое имя файла. Для alias путь строится иначе, чем для root. Посмотрите error log Nginx и временно проверьте один известный файл, а не каталог с пользовательским именем.
Как выбрать подход
Выбирайте прямой alias, если файл можно безопасно сделать публичным и доступ не зависит от пользователя. Это самый короткий путь от диска до клиента.
Используйте X-Accel-Redirect, если доступ проверяет приложение, но сами файлы лежат на том же сервере. Это хороший компромисс для личных кабинетов, платных курсов и приватных документов.
Оставляйте proxy_pass, когда источник уже является отдельным HTTP-сервисом или когда контент нельзя смонтировать в файловую систему Nginx. Проверьте поддержку Range на upstream до запуска в проде.
Переходите к объектному хранилищу и CDN, когда ограничением становится не CPU приложения, а исходящий канал, география пользователей или число параллельных просмотров. Подписанные URL, срок их действия и отзыв доступа — отдельная задача, которую не стоит прятать в настройках Nginx.
Что измерить перед публикацией
Сделайте тест на файле, близком к реальному размеру, и зафиксируйте условия: тип диска, доступный канал, число параллельных клиентов и наличие CDN. Не сравнивайте результаты с домашнего Wi-Fi и одного запроса.
- доля ответов
206и ошибок4xx/5xx; - время до первого байта и скорость передачи;
- загрузка диска, сети и CPU Nginx;
- число одновременных скачиваний;
- объём временных файлов, если включена буферизация прокси.
После теста проверьте доступ к приватному файлу без авторизации, запрос диапазона с конца файла и повторную загрузку после обрыва. Именно эти сценарии быстрее всего показывают, где конфигурация отличается от ожидаемой.
Что делать дальше
Сначала вынесите один тестовый файл из приложения в прямой статический location и сравните заголовки и нагрузку. Затем добавьте приватную схему через X-Accel-Redirect, если требуется авторизация. В проде наблюдайте не только среднюю скорость, но и долю диапазонных запросов, ошибки при перемотке и исходящий трафик по каждому источнику.
Локализатор видео: Перевод и озвучка видео на другой язык с укладкой в исходный тайминг. Глоссарий терминов, отметки проблемных реплик.
Спросить за 250 ₽Источники: Nginx documentation: ngx_http_core_module, Nginx documentation: ngx_http_proxy_module
Частые вопросы
Нужно ли включать отдельную директиву для поддержки Range в обычных статических файлах?
Что лучше для приватных видео: proxy_pass или X-Accel-Redirect?
Почему видео перематывается медленно, хотя Nginx возвращает 206?
Безопасно ли использовать alias для пользовательских файлов?
Когда Nginx нужно заменить CDN или объектным хранилищем?
Нужно ли отключать proxy_buffering для любого большого файла?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.