НейроАгент

Исправление проблемы с client_max_body_size в Nginx Docker Proxy

Полное руководство по исправлению проблемы с client_max_body_size в Nginx Docker proxy. Решение ошибок 413 с помощью правильной конфигурации и обходных решений для Cloudflare.

Вопрос

client_max_body_size не работает в Nginx proxy с Docker. Получаю ошибку 413 Payload too large

Я использую JWilder Nginx-proxy с Docker и сталкиваюсь с ошибкой “413 Payload too large” при попытке загрузки файлов. Несмотря на настройку client_max_body_size в моей конфигурации Nginx, эта настройка, кажется, не оказывает никакого эффекта.

Моя настройка:

  • Nginx proxy (JWilder/nginx-proxy) с Docker
  • Django & Gunicorn как приложение
  • Cloudflare как CDN

Что я уже пробовал:

  1. Добавил client_max_body_size 500m; в блок server в моей конфигурации Nginx
  2. Добавил client_max_body_size 500m; в блок location
  3. Добавил client_max_body_size 500m; в секцию http в основной конфигурации Nginx
  4. Перезапустил контейнер, удалил его, удалил образ и пересобрал его
  5. Увеличил лимиты загрузки файлов в Django & Gunicorn

Моя конфигурация Nginx:

Основная конфигурация (секция http):

nginx
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' 
                      '$status $body_bytes_sent "$http_referer" ' 
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

Конфигурация сервера:

nginx
server {
    server_name mysite.io;
    access_log /var/log/nginx/access.log vhost;
    http2 on;
    listen 443 ssl;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /etc/nginx/certs/swyve.io.crt;
    ssl_certificate_key /etc/nginx/certs/swyve.io.key;
    set $sts_header "";
    if ($https) {
        set $sts_header "max-age=31536000";
    }
    add_header Strict-Transport-Security $sts_header always;
    include /etc/nginx/vhost.d/mysite.io;
    location / {
        proxy_pass http://swyve.io;
        set $upstream_keepalive true;
        include /etc/nginx/vhost.d/mysite.io_location;
    }
}

Конфигурация виртуального хоста (/etc/nginx/vhost.d/mysite.io):

nginx
client_max_body_size 500m;

location /static/ {
    alias /app/staticfiles/;
    expires 1y;
    add_header Cache-Control "public, immutable";
}

Конфигурация location (/etc/nginx/vhost.d/mysite.io_location):

nginx
client_max_body_size 500m;

proxy_request_buffering off;
proxy_buffering off;

proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
send_timeout 600s;

Дополнительная информация:

Я заметил в заголовках ответа идентификатор Cloudflare: “cf-ray: 999aa8574833c251-VIE”. Не ограничивает ли Cloudflare загрузку файлов до 100MB на своем бесплатном плане?

Найденное решение:

Я создал новый поддомен (upload.mysite.com) специально для загрузки файлов, который обходит Cloudflare. Это решило проблему, но мне пришлось обновить мою конфигурацию Nginx для поддержки нового поддомена.

Вопрос:

Почему client_max_body_size не работает в моей конфигурации Nginx proxy, и как правильно настроить его для разрешения загрузки больших файлов при использовании Cloudflare?

НейроАгент

Проблема с неработающим параметром client_max_body_size в вашей конфигурации Nginx-прокси, скорее всего, вызвана несколькими факторами, при этом Cloudflare является основной причиной, исходя из вашей настройки. Ошибка 413 возникает, когда запросы на загрузку файлов превышают настроенные лимиты размера, но проблема обычно не в самом Nginx при использовании JWilder nginx-proxy.

Содержание

Cloudflare как основная проблема

Наличие заголовка cf-ray в вашем ответе подтверждает, что Cloudflare перехватывает ваши запросы до того, как они достигнут вашего сервера Nginx. Бесплатный план Cloudflare имеет строгий лимит в 100 МБ для загрузки файлов, и это, скорее всего, является причиной ваших ошибок 413. Согласно документации Cloudflare, они проверяют и блокируют запросы, превышающие их лимиты размеров, прежде чем перенаправлять их на ваш исходный сервер.

Это объясняет, почему ваши изменения в конфигурации Nginx не подействовали — запросы никогда не достигают вашего прокси-сервера Nginx. Если лимит Cloudflare составляет 100 МБ, а вы пытаетесь загружать файлы большего размера, Cloudflare ответит ошибкой 413 независимо от ваших настроек Nginx.

Конфигурация JWilder nginx-proxy

Образ JWilder nginx-proxy имеет лимит загрузки по умолчанию 2 МБ, что значительно ниже ваших требований. Этот лимит по умолчанию имеет приоритет, если он не переопределен явно. Прокси использует динамическую генерацию конфигурации на основе переменных окружения и смонтированных файлов конфигурации.

Когда вы вручную добавляете client_max_body_size в свои файлы конфигурации, эти настройки могут быть перезаписаны динамической системой конфигурации nginx-proxy. Прокси генерирует файлы конфигурации во время выполнения на основе:

  • Переменных окружения, установленных в контейнере
  • Docker-меток на ваших контейнерах приложений
  • Смонтированных файлов конфигурации

Правильные методы конфигурации Nginx

Метод 1: Переменные окружения (рекомендуется)

Самый надежный способ установить лимиты загрузки с помощью JWilder nginx-proxy — через переменные окружения. В вашем docker-compose.yml для сервиса прокси:

yaml
services:
  proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs:ro
    environment:
      CLIENT_MAX_BODY_SIZE: "500M"
      GLOBAL_MAX_BODY_SIZE: "500M"

Метод 2: Монтирование файла конфигурации

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

bash
# Создайте client_max_body_size.conf
echo "client_max_body_size 500M;" > client_max_body_size.conf

# Запустите контейнер со смонтированной конфигурацией
docker run -d \
  --name nginx-proxy \
  -v /var/run/docker.sock:/tmp/docker.sock \
  -v /path/to/client_max_body_size.conf:/etc/nginx/conf.d/client_max_body_size.conf:ro \
  -p 80:80 -p 443:443 \
  jwilder/nginx-proxy

Метод 3: Docker-метки

Установите метки на ваш контейнер приложения для настройки лимитов для каждого хоста:

yaml
services:
  myapp:
    image: myapp
    labels:
      - "client_max_body_size=500M"

Полное руководство по решению

Шаг 1: Проверьте лимиты Cloudflare

Проверьте лимиты вашего плана Cloudflare:

  • Бесплатный план: максимальный размер файла 100 МБ
  • Pro план: максимальный размер файла 100 МБ
  • Business план: максимальный размер файла 500 МБ
  • Enterprise план: настраиваемые лимиты

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

Шаг 2: Правильно настройте nginx-proxy

Измените конфигурацию nginx-proxy с помощью переменных окружения:

yaml
version: '3'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs:ro
    environment:
      CLIENT_MAX_BODY_SIZE: "500M"
      GLOBAL_MAX_BODY_SIZE: "500M"
      # Дополнительные рекомендуемые настройки
      PROXY_BUFFERING: "off"
      PROXY_REQUEST_BUFFERING: "off"

Шаг 3: Настройте лимиты для конкретных хостов

Если вам нужны разные лимиты для разных хостов, используйте Docker-метки:

yaml
services:
  myapp:
    image: myapp
    labels:
      - "VIRTUAL_HOST=mysite.io"
      - "VIRTUAL_PORT=8000"
      - "client_max_body_size=500M"

Шаг 4: Проверьте конфигурацию

После применения изменений:

  1. Перезапустите контейнер nginx-proxy: docker restart nginx-proxy
  2. Проверьте сгенерированную конфигурацию: docker exec nginx-proxy cat /etc/nginx/conf.d/default.conf
  3. Убедитесь, что настройка client_max_body_size присутствует

Альтернативные подходы

Обход Cloudflare для загрузок

Ваше решение по созданию поддомена, который обходит Cloudflare, является наиболее практичным для загрузки больших файлов. Настройте его следующим образом:

  1. Конфигурация DNS:

    • Создайте запись CNAME для upload.mysite.io, указывающую напрямую на IP-адрес вашего сервера
    • Удалите прокси Cloudflare (оранжевое облако) для этого поддомена
  2. Конфигурация nginx-proxy:

    yaml
    services:
      nginx-proxy:
        # ... существующая конфигурация
        environment:
          CLIENT_MAX_BODY_SIZE: "500M"
          GLOBAL_MAX_BODY_SIZE: "500M"
    
      upload-app:
        image: myapp
        labels:
          - "VIRTUAL_HOST=upload.mysite.io"
          - "VIRTUAL_PORT=8000"
          - "client_max_body_size=1G"  # Даже больший лимит для загрузок
    

Правила Cloudflare

Если вам нужно оставить Cloudflare для загрузок, но увеличить лимиты:

  1. Обновитесь до Business/Enterprise плана
  2. Пользовательские правила: настройте граничные правила для увеличения лимитов размера запросов
  3. Правила источника: настройте параметры размера запросов источника

Шаги проверки

Чтобы убедиться, что ваша конфигурация Nginx работает правильно:

  1. Проверьте логи nginx-proxy:

    bash
    docker logs nginx-proxy | grep "client_max_body_size"
    
  2. Проверьте сгенерированную конфигурацию:

    bash
    docker exec nginx-proxy nginx -T
    
  3. Протестируйте загрузку файла без Cloudflare:

    • Временно отключите прокси Cloudflare для вашего домена
    • Попробуйте загрузить файл
    • Если успешно, Cloudflare точно был проблемой
  4. Проверьте заголовки запросов:

    bash
    curl -I -X POST --data-binary "@large_file.zip" http://mysite.io/upload
    

Ключевой вывод заключается в том, что лимиты Cloudflare по умолчанию, скорее всего, являются основной причиной ваших ошибок 413. Хотя правильная настройка client_max_body_size в nginx-proxy важна, вам придется решить проблему ограничения Cloudflare либо через обход, обновление или пользовательские правила, чтобы успешно обрабатывать загрузку больших файлов.

Источники

  1. Nginx: 413 - Request Entity Too Large Error and Solution - nixCraft
  2. nginx - client_max_body_size has no effect - Stack Overflow
  3. How can I change the docker jwilder/nginx-proxy upload limits? - Stack Overflow
  4. docker-compose.yml and client_max_body_size · Issue #690 · nginx-proxy/nginx-proxy
  5. docker push error “413 Request Entity Too Large” - Stack Overflow
  6. Error: 413 “Request Entity Too Large” in Nginx with “client_max_body_size” - Medium

Заключение

  • Лимит Cloudflare в 100 МБ является основным барьером для ваших загрузок файлов, а не конфигурация Nginx
  • Используйте переменные окружения (CLIENT_MAX_BODY_SIZE, GLOBAL_MAX_BODY_SIZE) в вашей конфигурации nginx-proxy для надежных лимитов
  • Рассмотрите возможность обхода Cloudflare для специализированных поддоменов загрузки как наиболее практичное решение
  • Проверьте участие Cloudflare, проверив наличие заголовков cf-ray или временно отключив прокси Cloudflare
  • Регулярный мониторинг как логов Cloudflare, так и Nginx поможет диагностировать будущие проблемы с загрузкой

Наиболее эффективное долгосрочное решение, вероятно, представляет собой комбинацию правильной конфигурации nginx-proxy с переменными окружения и стратегического обхода Cloudflare для конечных точек загрузки, как вы уже обнаружили с вашим поддоменом upload.mysite.io.