Веб-серверы 10 мин чтения 2026-10-04

Ошибка 413 Request Entity Too Large: причины блокировки загрузки файлов и способы увеличения лимитов в Nginx, PHP, Cloudflare и Docker

Сайт или CMS срывает загрузку больших файлов с ошибкой 413 Request Entity Too Large? Разбираем всю цепочку лимитов: client_max_body_size в Nginx, параметры upload_max_filesize и post_max_size в PHP-FPM, потолок в 100 МБ на бесплатном Cloudflare и проброс через Docker-прокси.

Инженерная редакция SysKit Проверено инженерами SysKit.ru

1. Анатомия ошибки 413: Request Entity Too Large против Payload Too Large

Сбой с кодом HTTP 413 возникает в момент, когда клиент (веб-браузер, мобильное приложение, скрипт интеграции или фоновый воркер) отправляет на сервер HTTP-запрос (обычно методом POST или PUT), размер тела которого (Content-Length) превышает установленный лимит на стороне принимающего узла.

В зависимости от используемой версии протокола HTTP и типа промежуточного прокси сервер возвращает один из двух стандартных статусов:

  • 413 Request Entity Too Large (RFC 2616): классическая историческая формулировка из ранней спецификации HTTP/1.1, которая по-прежнему сохраняется по умолчанию в веб-серверах Nginx и Apache. Указывает, что тело (entity) запроса физически больше, чем готов принять сервер.
  • 413 Payload Too Large (RFC 7231, RFC 7540 и RFC 9110): стандартизированная современная терминология для HTTP/1.1, HTTP/2 и HTTP/3, закрепленная в актуальных стандартах IETF и используемая в современных API-шлюзах, Node.js-сервисах и логах Envoy/Traefik.

⚠️ Коварство поведения браузеров при ошибке 413

Когда Nginx фиксирует превышение лимита в заголовке Content-Length или в процессе чтения потока, он немедленно обрывает TCP-сессию и отправляет заголовки ответа 413 с директивой Connection: close. Из-за этого браузер не всегда успевает корректно отрисовать страницу ошибки, выдавая пользователю обобщенные сообщения вроде «ERR_CONNECTION_RESET» или «Не удалось загрузить файл» в интерфейсе WordPress, Nextcloud или CRM.

В современной архитектуре веб-проектов запрос редко идет напрямую к бэкенду. Обычно он проходит цепочку из нескольких независимых уровней:

  1. Периферийный CDN / WAF (Cloudflare, DDoS-Guard): проверяет размер запроса на входе в глобальную сеть.
  2. Фронтальный веб-сервер / Reverse Proxy (Nginx, Caddy, Traefik, NPM): принимает внешний трафик и отсекает тяжелые запросы до их передачи в локальную сеть сервера.
  3. Бэкенд-интерпретатор (PHP-FPM, uWSGI, Node.js, Go): считывает данные во временный каталог и накладывает лимиты языка программирования.
  4. Прикладной уровень (CMS / Фреймворк): проверяет права пользователя и допустимый размер вложений в медиабиблиотеку.

Если лимит исчерпан хотя бы на одном из этих уровней, передача файла прерывается с ошибкой 413. Чтобы быстро локализовать, какой именно узел блокирует соединение, проверьте заголовки ответа и статус веб-сервера через онлайн-инструмент Анализ HTTP-заголовков онлайн и чекер инфраструктуры Проверка хостинга и CMS.

2. Уровень веб-сервера: тонкая настройка client_max_body_size в Nginx

Главный барьер в подавляющем большинстве стеков на базе Linux — директива client_max_body_size модуля ngx_http_core_module в Nginx.

По умолчанию значение этой директивы составляет всего 1 МБ (1m). Любая попытка загрузить качественную фотографию (3–5 МБ), PDF-каталог, плагин для CMS или архив бэкапа мгновенно натыкается на блокировку с записью в журнале ошибок /var/log/nginx/error.log:

# Типичная запись в error.log Nginx при превышении лимита
[error] 14822#14822: *4192 client intended to send too large body: 15728640 bytes, client: 198.51.100.45, server: example.com, request: "POST /wp-admin/async-upload.php HTTP/2.0"

Директива client_max_body_size может задаваться на трех уровнях иерархии конфигурации Nginx:

Контекст Файл конфигурации Зона действия
http { ... } /etc/nginx/nginx.conf Глобально для всех сайтов и виртуальных хостов на данном VDS.
server { ... } /etc/nginx/sites-available/site.conf Только для конкретного домена (рекомендуемый стандарт изоляции).
location { ... } location /upload/ { ... } Изолированно для конкретного URL/эндпоинта загрузки без риска для остальных страниц.

Пример грамотной конфигурации виртуального хоста Nginx для сайта с повышенными требованиями к объему загружаемых файлов (до 64 МБ):

server {
    listen 443 ssl http2;
    server_name example.com;

    # Увеличиваем лимит тела клиентского запроса до 64 МБ
    client_max_body_size 64M;

    # Буферизация тела запроса в оперативной памяти (16K для 64-bit систем)
    client_body_buffer_size 128k;

    # Временный каталог для сброса тела запроса на NVMe-диск, если файл больше буфера
    client_body_temp_path /var/cache/nginx/client_temp 1 2;

    # Таймаут на чтение тела запроса между двумя последовательными операциями чтения
    client_body_timeout 60s;

    root /var/www/example.com/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_read_timeout 300;
    }
}

💡 Как Nginx обрабатывает файлы больше размера буфера без падения RAM

Параметр client_body_buffer_size 128k задает объем оперативной памяти, выделяемый под буфер одного клиентского соединения. Если загружаемый файл весит 50 МБ, Nginx не пытается аллоцировать 50 МБ RAM. Он прозрачно записывает тело запроса во временный файл в каталоге client_body_temp_path частями по 128 КБ. Поэтому увеличение client_max_body_size до 100 МБ или 1 ГБ абсолютно безопасно для серверов даже с 1 ГБ RAM, если каталог /var/cache/nginx/ расположен на быстром NVMe-накопителе.

После редактирования конфигурационного файла обязательно протестируйте синтаксис и примените настройки без прерывания соединений:

# Проверка корректности синтаксиса Nginx
sudo nginx -t

# Мягкая перезагрузка конфигурации
sudo systemctl reload nginx

Готовый оптимизированный шаблон виртуального хоста Nginx с кэшированием FastCGI и защитой админки доступен в нашем конфигураторе Конфигурация Nginx для WordPress с FastCGI-кэшем.

3. Уровень PHP и PHP-FPM: синхронизация цепочки взаимозависимых директив

После того как Nginx пропустил запрос в бэкенд, управление переходит к PHP-FPM. Если размер файла укладывается в client_max_body_size, но превосходит лимиты в php.ini, веб-сервер уже не вернет ошибку 413 — бэкенд молча отбросит тело запроса, и в массиве $_FILES окажется пустой список, либо PHP сгенерирует ошибку UPLOAD_ERR_INI_SIZE.

В конфигурации PHP существует строгое правило иерархии четырех параметров:

💡 Золотое правило иерархии параметров в php.ini

Размер лимитов обязан строго удовлетворять математическому неравенству:
memory_limit > post_max_size >= upload_max_filesize
Например: memory_limit = 256M, post_max_size = 64M, upload_max_filesize = 64M. Если задать post_max_size меньше upload_max_filesize, файл будет отклонен еще до начала обработки скриптом.

Найдите активный файл конфигурации PHP-FPM для вашей версии PHP (например, Ubuntu 24.04 с PHP 8.3):

# Проверяем, какой php.ini загружен в системе
php --ini | grep "Loaded Configuration"

# Открываем конфигурацию для пула PHP-FPM
sudo nano /etc/php/8.3/fpm/php.ini

Отредактируйте ключевые параметры загрузки и таймаутов:

; Максимальный размер одного загружаемого файла
upload_max_filesize = 64M

; Максимальный размер всего тела POST-запроса (включая все файлы и поля формы)
post_max_size = 64M

; Лимит оперативной памяти на выполнение одного скрипта
memory_limit = 256M

; Максимальное время (в секундах), отведенное на чтение входящих данных POST/GET
max_input_time = 300

; Максимальное время выполнения скрипта (обработка файла, создание превью, сжатие)
max_execution_time = 300

⚠️ Почему директива max_input_time критична при загрузке тяжелых файлов

По умолчанию параметр max_input_time равен 60 секундам. Если пользователь загружает видеоролик или архив весом 60 МБ через мобильный интернет со скоростью 5–7 Мбит/с, передача данных займет около 80–90 секунд. Ровно на 60-й секунде PHP принудительно разорвет соединение. Для сайтов с тяжелым медиаконтентом задавайте max_input_time = 300 или используйте -1 (безлимитный парсинг входящих данных).

После внесения правок перезапустите службу PHP-FPM:

# Перезапуск службы PHP 8.3 FPM
sudo systemctl restart php8.3-fpm

Если вы используете изолированные пулы на один сайт, параметры можно жестко задать прямо в файле пула /etc/php/8.3/fpm/pool.d/www.conf:

; Переопределение настроек для конкретного пула
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
php_admin_value[memory_limit] = 256M

Для детального расчета количества процессов воркеров и экономии RAM ознакомьтесь с нашей статьей PHP-FPM на VDS: расчет pm.max_children и тюнинг пулов без OOM Killer.

4. Уровень Reverse Proxy: Nginx Proxy Manager, Docker Compose и Caddy

Когда веб-приложение развернуто в контейнерах Docker за обратным прокси-сервером (Nginx Proxy Manager, Traefik или Caddy), стандартный лимит 413 часто срабатывает именно на внешнем прокси-шлюзе.

Рассмотрим типовые сценарии для популярных прокси-серверов:

1. Настройка в Nginx Proxy Manager (NPM)

По умолчанию контейнер NPM имеет дефолтный лимит Nginx в 1 МБ. Чтобы разрешить загрузку файлов большего объема:

  1. Откройте панель управления Nginx Proxy Manager.
  2. Перейдите в редактирование нужного Proxy Host.
  3. Откройте вкладку Advanced.
  4. В поле Custom Nginx Configuration добавьте следующие директивы:
# Увеличиваем лимит тела запроса до 100 МБ
client_max_body_size 100M;

# Отключаем буферизацию запроса на диск прокси для потоковой передачи в контейнер
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;

💡 Почему директива proxy_request_buffering off ускоряет загрузку

При включенной буферизации (proxy_request_buffering on) Reverse Proxy сначала полностью сохраняет весь загружаемый файл в локальный буфер, и только после полной загрузки начинает передавать его во внутренний контейнер. Отключение буферизации (off) включает прямой сквозной стриминг (chunked transfer) в целевой сервис, что критично для облачных хранилищ вроде Nextcloud или MinIO.

2. Настройка лимитов в современном веб-сервере Caddy 2

В веб-сервере Caddy ограничение входящего тела запроса настраивается через блок директивы request_body в файле Caddyfile:

example.com {
    # Задаем максимальный объем тела запроса
    request_body {
        max_size 100MB
    }

    reverse_proxy 127.0.0.1:8080 {
        # Сквозная передача заголовков
        header_up Host {upstream_hostport}
    }

    encode gzip zstd
    tls admin@example.com
}

Подробное руководство по современным возможностям Caddy читайте в статье Caddy 2 вместо Nginx: настройка веб-сервера с автоматическим SSL и Reverse Proxy для Docker.

5. Уровень Cloudflare: преодоление жесткого потолка в 100 МБ

Многие администраторы сталкиваются с ситуацией: в Nginx установлен client_max_body_size 500M, в PHP-FPM параметры upload_max_filesize и post_max_size увеличены до 500M, но при загрузке файла весом 105 МБ браузер мгновенно возвращает фирменную страницу ошибки:

Error 413: Request Entity Too Large
Cloudflare Ray ID: 894f2b10a8c43210 • Your IP: 198.51.100.24 • Performance & security by Cloudflare

Причина кроется в архитектурных лимитах самого сервиса Cloudflare:

Тарифный план Cloudflare Максимальный размер тела HTTP-запроса Возможность увеличения
Free 100 МБ Жесткий лимит без возможности расширения.
Pro 100 МБ Аналогичен бесплатному тарифу.
Business 200 МБ Включено в рамки тарифного плана.
Enterprise 500 МБ+ (до 5 ГБ) По умолчанию 500 МБ, увеличение вплоть до 5 ГБ в панели управления или через запрос в поддержку.

Если ваш проект работает на бесплатном тарифе Cloudflare, существует три проверенных инженерных решения для передачи файлов более 100 МБ:

  1. Выделенный прямой субдомен без проксирования («серое облако» в DNS):
    Создайте субдомен вида upload.example.com или direct.example.com, направьте A-запись на IP-адрес вашего VDS и отключите оранжевое облако проксирования (режим DNS only). Загрузку файлов перенаправляйте на этот субдомен напрямую в Nginx, минуя промежуточные узлы Cloudflare.
  2. Потоковая загрузка частями (Chunked Upload / протокол TUS):
    Фронтенд-библиотека (например, Uppy, Dropzone или Resumable.js) нарезает большой файл (например, архив 2 ГБ) на небольшие чанки размером по 20–50 МБ. Каждый чанк отправляется отдельным запросом в рамках лимита Cloudflare, а бэкенд склеивает их в единый файл на NVMe-диске сервера.
  3. Прямая загрузка в S3 через Pre-signed URLs:
    Веб-сервер генерирует временную подписанную ссылку на объектное хранилище (MinIO или S3), после чего браузер клиента заливает файл напрямую в бакет по протоколу HTTPS. Сам VDS и Cloudflare не расходуют трафик и процессорное время на обработку тяжелых байтов.

6. Сводная таблица диагностики: от симптома к решению

Используйте эту матрицу для быстрой локализации и устранения сбоя при загрузке файлов:

Симптом в логах или браузере Где искать причину Уровень сбоя Что исправить
client intended to send too large body /var/log/nginx/error.log Фронтальный Nginx Увеличить client_max_body_size в server { ... }.
Загрузка доходит до 100 МБ и обрывается Браузерная консоль (Сеть) Cloudflare Edge Использовать «серый» субдомен или Chunked Upload.
Массив $_FILES пуст, статус 200 OK /var/log/php8.3-fpm.log PHP-FPM Core Синхронизировать post_max_size и upload_max_filesize.
Сбой ровно через 60 секунд (504 Timeout) nginx/error.log PHP Парсинг входных данных Задать max_input_time = 300 и fastcgi_read_timeout 300.
open() failed (13: Permission denied) client_body_temp Права в файловой системе Назначить права chown -R www-data:www-data /var/cache/nginx.

Для комплексной проверки сетевых портов и доступности вашего сервера воспользуйтесь онлайн-утилитой Сканер портов онлайн и мониторингом SSL-сертификатов в Проверка SSL-сертификата.

Разверните отказоустойчивый стек для медиапроектов на быстром VDS

Для стабильной работы ресурсоемких CMS, обработки потокового видео и быстрой буферизации файлов на NVMe-накопители выбирайте надежные серверы с широким каналом до 1 Гбит/с и защитой от сетевых перегрузок.

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud — Быстрые NVMe VDS

Надежные облачные серверы с быстрыми NVMe-дисками, выделенным статическим IP и открытыми портами 80/443 для безотказной работы SSL и Nginx.

Конфигурация
1 vCPU 3.3 ГГц • 1 ГБ RAM • 15 ГБ NVMe • Трафик без лимита
Премиум Tier III
🔷

Selectel — Премиальные облачные серверы

Инфраструктура корпоративного уровня в дата-центрах Tier III: почасовая тарификация, приватные VLAN и прямое подключение к ведущим точкам обмена трафиком.

Конфигурация
1 vCPU • 2 ГБ RAM • 30 ГБ NVMe • Канал 100 Мбит/с
Для вебмастеров
🟠

Beget — Простота и стабильность VDS

Удобная интуитивная панель управления, автоматические ежедневные бэкапы и мгновенное развертывание LEMP-стека с предустановленным Nginx.

Конфигурация
1 vCPU 3.0 ГГц • 1 ГБ RAM • 20 ГБ NVMe • Трафик без лимита

Инструменты SysKit по теме статьи

Бесплатные утилиты для проверки и диагностики вашего сервера

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Почему в WordPress директивы ini_set в wp-config.php не увеличивают лимит загрузки?
Директивы upload_max_filesize и post_max_size в PHP имеют уровень доступа PHP_INI_PERDIR. Это означает, что их невозможно изменить во время выполнения скрипта через функцию ini_set() в коде или в wp-config.php. Их необходимо настраивать исключительно в основном файле php.ini, через файл пула PHP-FPM, в .user.ini в корне сайта или в директивах веб-сервера.
Как защитить сервер от DoS-атак при увеличении client_max_body_size до 500 МБ или 1 ГБ?
Не открывайте большой лимит глобально в блоке http {}. Применяйте client_max_body_size только точечно внутри location для URL загрузки (например, location /upload/ или location /wp-admin/). Ограничьте количество одновременных подключений с одного IP через директивы limit_conn_zone и limit_req_zone, а также настройте клиентский таймаут client_body_timeout 30s, чтобы медленные атакующие клиенты не удерживали сокеты сервера (Slowloris/Slow POST attack).
Где физически хранятся временные файлы во время загрузки и как очистить /var/cache/nginx?
Nginx сбрасывает данные в каталог, указанный директивой client_body_temp_path (обычно /var/cache/nginx/client_temp или /var/lib/nginx/body). Временные файлы автоматически удаляются сразу после передачи бэкенду. Если на диске закончилось место из-за аварийных сбоев процессов, безопасно удалите зависшие временные файлы командой find /var/cache/nginx/client_temp -type f -delete и проверьте права пользователя www-data.
Как проверить реальный максимальный лимит загрузки без загрузки гигантских файлов вручную?
Используйте утилиту curl в терминале, сгенерировав фиктивное тело запроса заданного размера: curl -X POST -H 'Content-Type: application/octet-stream' --data-binary @<(head -c 65M /dev/zero) https://example.com/upload-test. Если веб-сервер вернет HTTP 413, значит лимит сработал; если запрос дошел до скрипта и вернул 200 или 404 — Nginx успешно пропустил данный объем.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи