症状
Nextcloud iOS アプリで写真等をまとめてアップロードすると、一定割合で失敗する。
-
サーバ側:Nextcloudのログに「
エラー / no app in cotext / Nextcloudクライアントからの想定ファイルサイズは、XXXXXXX bytes ですが、Nextcloudストレージへの書き込みファイルサイズは 0 bytes でした。送信側のネットワークの問題またはサーバー側のストレージへの書き込みに問題がある可能性があります。」が出る。

Apacheのアクセスログでは、PUT /remote.php/dav/files/... が 400 になっている。
原因
原因は Nextcloud 本体ではなく、Nextcloudコンテナ内で動いている Apache の mod_reqtimeout(RequestReadTimeout)。
多量アップロード(並列アップロード)時は、各リクエストの実効転送速度が落ちたり、開始が遅れたりして、Apache側が「遅い接続」と判断して リクエストボディの受信を中断してしまう。
その結果、Nextcloud から見ると「期待したサイズのファイルが来ていない(0 bytes)」になり、400を返している。
今回の環境では、以下のデフォルト設定が厳しすぎた。体感として「1件だけだと成功するが、同一秒に多数アップロードすると失敗率が上がる」挙動。
-
RequestReadTimeout body=10,minrate=500- リクエストボディーの受信開始から完了までのタイムアウト時間が10秒。
- 最低転送レート 500 Byte/sec を下回ったらタイムアウト。
筆者の構成
今回の構成は以下。
クライアント(iOS Nextcloud) → リバースプロキシ(Caddy) → Nextcloudコンテナ(Apache) → Nextcloud(PHP)
タイムアウトに該当しているか切り分け
次のコマンドで Apache の a2dismod reqtimeout で、一旦無効化してみる。
app の dockerコンテナの場合は、以下になる。
docker compose exec -T --user root app a2dismod reqtimeout
docker compose restart app
これで大量アップロードを再テストして 400が消えればタイムアウトで原因が確定。
戻すときは a2enmod reqtimeout で app の dockerコンテナの場合は、以下になる。
docker compose exec -T --user root app a2enmod reqtimeout
docker compose restart app
恒久対処:タイムアウトは残して、タイムアウト値を緩和する
DoS対策等で reqtimeout は残しておくとよいので、無効化ではなく bodyの条件だけ緩める。
今回、以下でテストしたところ エラーがなくなった。
-
body=600,minrate=100- リクエストボディーの受信開始から完了までのタイムアウト時間が10→600秒(10分)に引き上げ緩和
- 最低転送レート 500 → 100 Byte/sec を下回ったらタイムアウトに引き下げ緩和
設定例:
<IfModule reqtimeout_module>
RequestReadTimeout header=20-40,minrate=500
RequestReadTimeout body=600,minrate=100
</IfModule>
参考(公式)
Nextcloud 管理者マニュアルの Big file upload configuration にも、mod_reqtimeout がアップロードを完了させない場合があり、無効化または RequestReadTimeout の調整を推奨する旨が書かれている。
