MAATRIX / Блог / Nextcloud не загружает большие файлы: причины и решение

Nextcloud не загружает большие файлы: причины и решение

Nextcloud не загружает большие файлы: причины и решение

MAATRIX

Мелочь синхронизируется мгновенно, а восьмигигабайтный архив падает: иногда сразу, иногда на 97 %, иногда «загрузился», но в папке его нет. client_max_body_size и upload_max_filesize вы уже подняли до 16G — не помогло. Значит, рвёт не тот лимит: в цепочке есть ещё сборка чанков, дисковый буфер nginx, request_terminate_timeout и, если вы за Cloudflare, потолок в 100 МБ, который вашим конфигом не настраивается.

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

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

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

Сначала выясните, кто именно оборвал загрузку

Nextcloud большие файлы теряет по шести разным причинам, и лечатся они в разных местах. Смотрите логи в момент падения:

tail -f /var/log/nginx/error.log /var/log/nginx/access.log /var/log/php8.3-fpm.log
sudo -u www-data tail -f /var/www/nextcloud/data/nextcloud.log | jq -r '[.time,.app,.message]|@tsv'

Дальше — по симптому:

Что видноКто оборвалКуда идти
413 сразу, а запроса в вашем access.log нетвнешний прокси или CDNсекция про Cloudflare
client intended to send too large body: 8589934592 bytesваш nginxclient_max_body_size
Прогресс дошёл до 100 %, потом ошибкасборка файла (MOVE)таймауты и место
expected filesize ... but read ... and wrote ... bytesтело запроса оборвалосьсеть или убитый воркер
507 Insufficient Storageквота или дискdf -h, квота пользователя
423 Locked при повтореостатки прошлой попыткитаблица oc_file_locks

Первая строка полезнее всех: нет записи о запросе в вашем access.log, а браузер получил 413 — файл до сервера не дошёл. Второй тест — залить его по WebDAV мимо веб-интерфейса, паролем приложения (Настройки → Безопасность), иначе двухфакторка не пустит.

fallocate -l 8G /tmp/test-8g.bin
curl -T /tmp/test-8g.bin -u 'ivan:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx' \
  -w '\nHTTP %{http_code}, отдано %{size_upload} байт за %{time_total} c\n' \
  https://cloud.example.com/remote.php/dav/files/ivan/test-8g.bin

Прошло по WebDAV, но падает в браузере — дело в чанках. Падает везде — виновата цепочка nginx → PHP-FPM → диск.

Веб грузит чанками, WebDAV — целиком: это две разные поломки

Веб-интерфейс и десктоп-клиент не отправляют большой файл одним запросом. С Nextcloud 15 работает chunked upload v2: клиент создаёт временный каталог, льёт туда части и одним MOVE просит сервер склеить их. Руками:

UP=https://cloud.example.com/remote.php/dav/uploads/ivan
AUTH='ivan:xxxxx-xxxxx-xxxxx-xxxxx-xxxxx'
curl -u "$AUTH" -X MKCOL "$UP/1770000000"
curl -u "$AUTH" -T part-00 "$UP/1770000000/00000000"
curl -u "$AUTH" -T part-01 "$UP/1770000000/00000001"
curl -u "$AUTH" -X MOVE -H "OC-Total-Length: 8589934592" \
  -H "Destination: https://cloud.example.com/remote.php/dav/files/ivan/big.bin" \
  "$UP/1770000000/.file"

Части сортируются лексикографически — нумеруйте с ведущими нулями, иначе 10 встанет между 1 и 2 и файл соберётся вперемешку.

Отсюда три вывода:

  • upload_max_filesize при загрузке из браузера почти не при чём. PHP видит не файл, а один чанк — по умолчанию 10 МБ. Значение 2M всё сломает, но поднимать его до 16G ради веба бессмысленно.
  • Запрос MOVE не несёт тела. client_max_body_size на него не влияет вообще, а fastcgi_read_timeout влияет напрямую: склейка 8 ГБ на NVMe с записью около 900 МБ/с занимает 9–12 секунд, на сетевом хранилище — минуты. Здесь и живёт «дошло до 100 % и упало».
  • Мелкий чанк на длинном маршруте дорог. 20 ГБ кусками по 10 МБ — 2048 запросов PUT; при RTT 48 мс одни round-trip'ы добавляют около 100 секунд.

Размер чанка для веба задаёт ключ max_chunk_size в байтах, разумный потолок — 50–100 МБ:

sudo -u www-data php occ config:system:set max_chunk_size --value 52428800

Оговорки честные: чанк обязан пролезать под client_max_body_size и post_max_size, а при обрыве сети заново поедет весь чанк; значение 0 отключает чанкование совсем. Десктоп-клиент подбирает размер сам, целясь в 60 секунд на часть, — переопределяется в ~/.config/Nextcloud/nextcloud.cfg ключами chunkSize, maxChunkSize, targetChunkUploadDuration.

Развернуть за пару минут

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

Развернуть Nextcloud

Cloudflare, Traefik и второй nginx: потолок, которого нет в вашем конфиге

Конфиг идеален, а 413 приходит всё равно — значит, перед Nextcloud стоит ещё один слой.

Cloudflare в режиме прокси (оранжевое облако) режет тело запроса на 100 МБ для Free и Pro и на 200 МБ для Business. Вашими настройками это не обходится. Диагностика однозначная: curl -sI https://cloud.example.com/ | grep -i cf-ray что-то возвращает, а в вашем access.log неудачного запроса нет.

Вариантов два: увести домен из-под прокси («DNS only», серое облако) либо завести поддомен dav.example.com мимо прокси. Первый проще, но теряется скрытие origin-IP и защита от DDoS; второй сохраняет защиту веб-интерфейса, но раскрывает адрес сервера в DNS. Traefik и внешний nginx режут так же тихо: у первого лимит задаёт middleware buffering с maxRequestBodyBytes, второму нужен свой client_max_body_size.

Отдельная история — куда nginx кладёт тело запроса. По умолчанию он принимает весь запрос на диск и только потом отдаёт PHP-FPM:

[warn] 812#812: *45 a client request body is buffered to a temporary file
/var/lib/nginx/body/0000000003, client: 10.0.0.5, request: "PUT /remote.php/dav/... HTTP/2.0"

Каталог /var/lib/nginx/body живёт на корневом разделе: заливаете 30 ГБ, а под / осталось 12 — загрузка умрёт, и Nextcloud тут ни при чём. Лечится переносом буфера или потоковой передачей:

client_body_temp_path /srv/nginx-body 1 2;
fastcgi_request_buffering off;

Минус второго варианта: без буферизации nginx не может повторить запрос к бэкенду, а медленный клиент занимает воркер PHP-FPM всё время передачи.

Место: файл существует в трёх копиях одновременно

Ошибка планирования — считать, что под файл в 30 ГБ нужно 30 ГБ. В пике на диске лежит до трёх копий: буфер тела в /var/lib/nginx/body, чанки в data/<user>/uploads/<uploadid>/ и собираемый файл в data/<user>/files/.

du -sh /var/www/nextcloud/data/*/uploads/ 2>/dev/null
df -h /var/www/nextcloud/data /var /tmp
df -i /var/www/nextcloud/data

df -i не пропускайте: 20 ГБ кусками по 10 МБ — 2048 inode за загрузку, и на скромном разделе они кончатся раньше байтов. Ошибка невнятная: No space left on device при живых 40 % свободного места. Мусор от оборванных попыток сам не исчезает:

find /var/www/nextcloud/data/*/uploads/ -mindepth 1 -maxdepth 1 -type d -mtime +1 -exec rm -rf {} +

Второе узкое место — временный каталог. Во многих сборках /tmp смонтирован как tmpfs в половину ОЗУ: на сервере с 4 ГБ это 2 ГБ, и запись туда съедает оперативку. Увидели tmpfs в df -h /tmp — уводите временные файлы на диск, и в PHP, и в Nextcloud:

upload_tmp_dir = /var/nc-tmp
sys_temp_dir = /var/nc-tmp
output_buffering = 0
install -d -o www-data -g www-data -m 750 /var/nc-tmp
sudo -u www-data php occ config:system:set tempdirectory --value /var/nc-tmp

output_buffering = 0 не случайно: с буферизацией вывода PHP держит в памяти то, что должен отдавать потоком, и упирается в memory_limit.

Таймауты: max_execution_time вас не спасёт, request_terminate_timeout убьёт

max_execution_time считает время работы скрипта и не учитывает время в системных вызовах — а чтение тела запроса и запись файла это именно они. Поднятие до 3600 на долгую загрузку часто не влияет никак: она под него и не попадала.

Реально обрывает request_terminate_timeout в пуле PHP-FPM: он считает астрономическое время и убивает воркер.

WARNING: [pool nextcloud] child 2841, script '/var/www/nextcloud/remote.php'
(request: "MOVE /remote.php/dav/uploads/ivan/1770000000/.file") execution timed out
(305.418712 sec), terminating

Клиент получит 502 или ту самую строку expected filesize ... but read ... and wrote ... bytes: соединение закрылось раньше, чем приехали все байты. По умолчанию параметр выключен (0), но панели и готовые сборки часто ставят 300 секунд. Правьте /etc/php/8.3/fpm/pool.d/nextcloud.conf:

request_terminate_timeout = 3600
pm = dynamic
pm.max_children = 20

И согласуйте с веб-сервером: fastcgi_read_timeout 3600; в location Nextcloud, иначе оборвёт он. Второй эффект — голодание пула: воркер занят всё время передачи, и при pm.max_children = 5 пять параллельных заливок вешают весь Nextcloud вместе с логином, а в лог падает server reached pm.max_children setting (5), consider raising it. Считайте просто: один процесс PHP-FPM с Nextcloud занимает 90–140 МБ RSS. На 4 ГБ ОЗУ с MariaDB и Redis рядом реалистичный потолок — 12–16 детей. Ставить 50 «с запасом» нельзя: при всплеске сервер уйдёт в OOM, и journalctl -k | grep -i oom покажет убитый php-fpm8.3.

Тихие блокировщики: антивирус, квота, блокировки и S3

Эти причины не дают внятной ошибки — файл просто не появляется.

ClamAV через files_antivirus. Дистрибутивные значения в /etc/clamav/clamd.confStreamMaxLength 25M, MaxFileSize 100M, MaxScanSize 100M. Всё, что больше StreamMaxLength, clamd не принимает: Nextcloud получает ошибку сканирования вместо вердикта, и файл либо блокируется, либо помечается непроверенным. Поднимите до StreamMaxLength 2G и сделайте systemctl restart clamav-daemon. Честно: потоковое сканирование забирает память и время, крупные архивы разумнее из проверки исключить.

Квота пользователя. 507 Insufficient Storage часто вызван не диском. На квоту влияют корзина и версии: удалённый вчера архив занимает место, пока лежит в Deleted files.

sudo -u www-data php occ user:info ivan
sudo -u www-data php occ user:setting ivan files quota 500GB

Блокировки. Оборванная загрузка оставляет запись в oc_file_locks, и повтор получает 423 Locked (Sabre\DAV\Exception\Locked). Штатно — подождать, пока протухнет; быстро:

sudo -u www-data php occ maintenance:mode --on
mysql -u nextcloud -p nextcloud -e "DELETE FROM oc_file_locks WHERE 1;"
sudo -u www-data php occ maintenance:mode --off

Если блокировки живут в Redis, достаточно перезапустить redis-server.

S3 как primary storage. Файл сначала целиком собирается локально и лишь потом уходит в бакет частями (uploadPartSize в objectstore.arguments) — локальное место нужно всё равно.

И проверьте разрядность: php -r 'echo PHP_INT_SIZE;' должен вернуть 8. На 32-битной сборке файлы больше 4 ГБ не обрабатываются в принципе.

Какой сервер под Nextcloud с большими файлами брать в MAATRIX

Заливка гигабайтов — задача про диск и канал, а не про процессор: ядра нужны PHP-FPM лишь для параллельных соединений, TLS на потоке в 200 Мбит/с стоит vCPU единицы процентов.

Минимум: 2 vCPU, 4 ГБ RAM, 80 ГБ NVMe. Двое-трое пользователей, файлы до 5–10 ГБ. Ограничения честные: 4 ГБ — это 12–16 процессов PHP-FPM вместе с MariaDB и Redis, то есть 3–4 одновременные заливки, дальше очередь. А 80 ГБ под правило трёх копий дают реальный потолок файла около 25 ГБ, а не 80.

Комфортный вариант: 4 vCPU, 8 ГБ RAM, 200–500 ГБ NVMe. Отдел на 15–30 человек, видео и образы дисков, спокойные pm.max_children = 24, место под /var/nc-tmp и буфер nginx на отдельном разделе. Файлы на сотни гигабайт разумнее держать на отдельном дисковом томе, а не наращивать системный.

Локация — Великобритания (Лондон). Каждый чанк — отдельный round-trip, и на 2000 частей разница в 40 мс превращается в полторы минуты. RTT Москва — Лондон 45–55 мс против 120–140 мс до восточного побережья США, а сотрудникам в ЕС Лондон даёт единицы миллисекунд; плюс европейская юрисдикция и GDPR-соседство. Если аудитория целиком российская и в договоре есть персональные данные — берите RU: 152-ФЗ и минимальный пинг перевесят.

Nextcloud из каталога apps.maatrix.io разворачивается на сервер автоматически при заказе: руками ничего вставлять не нужно, автоустановка работает на Ubuntu и Debian, доступы появляются в личном кабинете в разделе «Доступ». Оговорка честная: базовая установка настроена под типовой сценарий, а лимиты под 30-гигабайтные файлы (request_terminate_timeout, client_body_temp_path, tempdirectory) вы правите под себя. Оплата — картой российского банка, по СБП или криптовалютой.

Развернуть за пару минут

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

Развернуть Nextcloud

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

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

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

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

Поднял client_max_body_size и upload_max_filesize до 16G, а из браузера файлы рвутся. Почему?

Веб-интерфейс грузит чанками по 10 МБ, и эти лимиты для него почти не работают. Смотрите на запрос MOVE, который склеивает части: он упирается в fastcgi_read_timeout и request_terminate_timeout, а не в размер тела.

Файл 100 МБ проходит, а 101 МБ — нет, и в логах nginx пусто. Что это?

Почти наверняка Cloudflare в режиме прокси: на Free и Pro тело запроса ограничено 100 МБ. Проверьте cf-ray в ответе и либо уведите домен из-под прокси, либо заведите отдельный поддомен для WebDAV.

Сколько свободного места нужно под файл на 30 ГБ?

Считайте до трёх копий: буфер nginx, каталог uploads с чанками и итоговый файл — около 90 ГБ в пике, если буферизация включена и каталоги на одном разделе.

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

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