Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

大容量ファイルのアップロードが失敗する:サイズ制限・UPLOAD_FILE_SIZE_LIMIT・Nginx設定・分割アップロードの実践

はじめに

ナレッジベース構築プロジェクトにおいて、「100MB超のPDFをアップロードしようとしたら失敗する」という問題は非常に頻繁に発生する。ファイルが大きいほど、問題は単なる「アップロードの失敗」にとどまらず、リバースプロキシの制限、バックエンドの設定制限、ストレージ書き込み、後続の解析・チャンク分割・インデックス処理にまで連鎖する。

本記事では、大容量ファイルのアップロード失敗を引き起こす複数のレイヤーを特定し、各レイヤーの設定変更から前処理パイプラインの構築まで、実践的な解決策を解説する。


症状

症状エラーメッセージ例失敗レイヤー
ブラウザ上でアップロードが途中で止まる(ネットワークエラー)ブラウザ / クライアント側
413 Request Entity Too Large413 Payload Too LargeNginx / リバースプロキシ
ファイルサイズ制限エラーFile size exceeds the limitDify バックエンド
アップロードは成功するが処理が終わらない(タイムアウト / ステータスが processing のまま)解析・インデックス処理
S3/MinIO への書き込みエラーPutObject failed / Connection resetオブジェクトストレージ

原因分析

大容量ファイルのアップロード失敗は、以下の5つのレイヤーのいずれか(または複数)で発生する。

flowchart TD
    A[ファイルアップロード] --> B[レイヤー1: ブラウザ/クライアント]
    B --> C[レイヤー2: リバースプロキシ Nginx/Ingress]
    C --> D[レイヤー3: Dify バックエンド]
    D --> E[レイヤー4: オブジェクトストレージ]
    E --> F[レイヤー5: 後続処理パイプライン]
    
    B -.->|タイムアウト| B1[接続切れ]
    C -.->|413エラー| C1[body size制限]
    D -.->|サイズ制限| D1[UPLOAD_FILE_SIZE_LIMIT]
    E -.->|書込失敗| E1[権限/容量]
    F -.->|処理超過| F1[解析タイムアウト]

レイヤー1:ブラウザ / クライアント側

  • ブラウザのメモリ制限(特に大量のタブを開いている場合)
  • ネットワーク接続の不安定さ
  • ブラウザのファイルアップロードタイムアウト

レイヤー2:リバースプロキシ(Nginx / Kubernetes Ingress)

これが最も頻度の高い失敗ポイントである。Dify のセルフホスト環境では、ほぼ必ず Nginx または Kubernetes Ingress がフロントに配置される。デフォルト設定では、リクエストボディのサイズ制限が 1MB〜10MB 程度であることが多い。

Nginx のデフォルト設定:

# デフォルト: client_max_body_size 1m;
# → 1MB を超えるファイルが 413 エラーで拒否される

レイヤー3:Dify バックエンドの設定

Dify 自体にもファイルサイズの上限が環境変数で設定されている。

環境変数デフォルト値説明
UPLOAD_FILE_SIZE_LIMIT15 (MB)単一ファイルの最大アップロードサイズ
UPLOAD_FILE_BATCH_LIMIT5一度にアップロードできるファイル数
UPLOAD_IMAGE_FILE_SIZE_LIMIT10 (MB)画像ファイルの最大サイズ
ETL_TYPEdifyドキュメント解析エンジン(dify / Unstructured)

レイヤー4:オブジェクトストレージ

Dify はファイルの保存先として以下をサポートしている:

  • ローカルファイルシステム
  • Amazon S3
  • Azure Blob Storage
  • Google Cloud Storage
  • Tencent Cloud COS
  • Huawei Cloud OBS
  • MinIO(S3互換)

各ストレージにはマルチパートアップロードの対応状況や単一アップロード上限(S3: 5GB、Azure Blob: 256MB等)が異なるため、事前に確認が必要である。

レイヤー5:後続処理パイプライン

ファイルのアップロード自体が成功しても、ナレッジベースへの登録には以下の後続処理が必要であり、それぞれにタイムアウトのリスクがある。

アップロード → テキスト抽出 → チャンク分割 → Embedding生成 → ベクトルDB書込

100MB超のPDFの場合:

  • テキスト抽出に数分〜数十分
  • 数千チャンクの Embedding 生成に大量のAPIコール
  • ベクトルDB への大量書き込み

解決策

解決策1:Nginx / リバースプロキシの設定変更

Nginx の場合:

# /etc/nginx/nginx.conf または /etc/nginx/conf.d/default.conf

http {
    # リクエストボディの最大サイズを 200MB に拡大
    client_max_body_size 200m;
    
    # アップロードタイムアウトの延長
    client_body_timeout 300s;
    
    # プロキシタイムアウトの延長
    proxy_connect_timeout 300s;
    proxy_send_timeout 300s;
    proxy_read_timeout 300s;
    
    # 大容量リクエストのバッファ設定
    client_body_buffer_size 10m;
    client_body_temp_path /tmp/nginx_upload;
}

Kubernetes Ingress(Nginx Ingress Controller)の場合:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dify-ingress
  annotations:
    # リクエストボディの最大サイズ
    nginx.ingress.kubernetes.io/proxy-body-size: "200m"
    # タイムアウト設定
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
spec:
  rules:
    - host: dify.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: dify-web
                port:
                  number: 80

Docker Compose 同梱の Nginx の場合: docker/nginx/conf.d/default.conf を編集し、同様に client_max_body_size 200m; とプロキシタイムアウトを設定する。

解決策2:Dify 環境変数の調整

.env ファイルまたは docker-compose.yml で以下を設定する:

# ファイルアップロード制限の拡大
UPLOAD_FILE_SIZE_LIMIT=200          # 200MB に変更
UPLOAD_FILE_BATCH_LIMIT=10          # バッチ上限を10ファイルに

# ドキュメント解析エンジンの変更(大容量PDF対応)
ETL_TYPE=Unstructured               # Unstructured.io を使用
UNSTRUCTURED_API_URL=http://unstructured:8000/general/v0/general

# ワーカー設定の調整
CELERY_WORKER_AMOUNT=4              # バックグラウンドワーカー数

設定変更後の反映:

# Docker Compose 環境の場合
cd /path/to/dify/docker
docker compose down
docker compose up -d

# 設定が反映されたことを確認
docker compose exec api env | grep UPLOAD

解決策3:オブジェクトストレージの設定

Amazon S3 の場合:

# .env ファイル
STORAGE_TYPE=s3
S3_ENDPOINT=https://s3.ap-northeast-1.amazonaws.com
S3_BUCKET_NAME=dify-storage
S3_ACCESS_KEY=YOUR_ACCESS_KEY
S3_SECRET_KEY=YOUR_SECRET_KEY
S3_REGION=ap-northeast-1

MinIO(ローカルS3互換)の場合:

# .env ファイル
STORAGE_TYPE=s3
S3_ENDPOINT=http://minio:9000
S3_BUCKET_NAME=dify-storage
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_REGION=us-east-1
S3_USE_AWS_MANAGED_IAM=false

解決策4:ファイル前処理パイプライン

100MB超のPDFをそのままアップロードするのではなく、事前に前処理を行うことを強く推奨する。

Python による PDF 前処理スクリプト(PyPDF2使用):

from PyPDF2 import PdfReader, PdfWriter
import os

def split_pdf(input_path: str, output_dir: str, max_pages: int = 50):
    """大容量PDFをページ数で分割する"""
    reader = PdfReader(input_path)
    os.makedirs(output_dir, exist_ok=True)
    for start in range(0, len(reader.pages), max_pages):
        writer = PdfWriter()
        for p in range(start, min(start + max_pages, len(reader.pages))):
            writer.add_page(reader.pages[p])
        out = os.path.join(output_dir, f"part{start//max_pages+1}.pdf")
        with open(out, "wb") as f:
            writer.write(f)

# 使用例: split_pdf("/path/to/large.pdf", "/path/to/output/", max_pages=30)

OCR 前処理(スキャンPDFの場合):

# OCRmyPDF で日本語OCR処理
pip install ocrmypdf
ocrmypdf --language jpn --deskew --clean input_scan.pdf output_ocr.pdf

解決策5:Dify API によるプログラマティックアップロード

大容量ファイルのアップロードをブラウザUIではなく、APIから行うことで、タイムアウトの制御がしやすくなる。

import requests, os

def upload_document(api_base, api_key, dataset_id, file_path):
    url = f"{api_base}/datasets/{dataset_id}/document/create_by_file"
    with open(file_path, "rb") as f:
        resp = requests.post(url,
            headers={"Authorization": f"Bearer {api_key}"},
            files={"file": (os.path.basename(file_path), f, "application/pdf")},
            data={"data": '{"indexing_technique":"high_quality","process_rule":{"mode":"automatic"}}'},
            timeout=600)
    return resp.json() if resp.status_code == 200 else None

# 分割済みPDFを順次アップロード
for pdf in sorted(os.listdir("/path/to/split_pdfs/")):
    if pdf.endswith(".pdf"):
        upload_document("https://dify.example.com/v1", "YOUR_KEY", "DATASET_ID",
                       f"/path/to/split_pdfs/{pdf}")

解決策6:テーマ別ナレッジベース分割

大容量のドキュメントを1つのナレッジベースに詰め込むのではなく、テーマ別に分割する。

Before:
  ナレッジベース「全社マニュアル」 ← 500MB分のPDF

After:
  ナレッジベース「人事規程」      ← 就業規則、福利厚生、評価制度
  ナレッジベース「IT手順書」      ← VPN、メール、セキュリティ
  ナレッジベース「経理マニュアル」  ← 経費精算、請求、税務
  ナレッジベース「製品仕様書」    ← 製品A仕様、製品B仕様

メリット:

  • 個別のドキュメント更新が容易
  • 検索精度の向上(ドメインが絞られるため)
  • アップロード失敗時の影響範囲が限定される

予防策

1. アップロード前チェックリスト

ファイルをアップロードする前に、以下を確認する:

  • ファイルサイズが UPLOAD_FILE_SIZE_LIMIT 以下か
  • Nginx / Ingress の client_max_body_size が十分か
  • 不要なページ(空白、表紙、目次、索引)を除去したか
  • スキャンPDFの場合、OCR処理済みか
  • ファイルが破損していないか(PDFリーダーで開けるか確認)

2. 設定値の整合性チェック

各レイヤーの制限値が矛盾していないことを確認する。

Nginx client_max_body_size  >=  UPLOAD_FILE_SIZE_LIMIT  >=  実際のファイルサイズ

よくある矛盾の例:

NginxDify結果
1m (デフォルト)15MBNginx で 413 エラー
200m15MB (デフォルト)Dify バックエンドでサイズエラー
200m200MBOK(ただし後続処理のタイムアウトに注意)

3. 大容量ファイル運用フローの標準化

flowchart TD
    A[原本PDF] --> B{サイズ > 15MB?}
    B -->|No| C[そのままアップロード]
    B -->|Yes| D[前処理パイプライン]
    D --> E[空白ページ除去]
    E --> F[OCR処理 if スキャンPDF]
    F --> G{サイズ > 15MB?}
    G -->|No| C
    G -->|Yes| H[チャプター/ページ分割]
    H --> I[分割ファイルを順次アップロード]
    C --> J[インデックス処理完了を確認]
    I --> J
    J --> K[検索品質テスト]

4. モニタリング

API 経由で GET /datasets/{dataset_id}/documents を定期的に呼び出し、各ドキュメントの indexing_statuscompleted になっていることを確認する。processing のまま長時間停滞している場合は、後続パイプラインでのタイムアウトを疑う。


まとめ

100MB超のPDFアップロード失敗は、単一の設定変更では解決しないことが多い。Nginx のリクエストボディサイズ制限、Dify の UPLOAD_FILE_SIZE_LIMIT、オブジェクトストレージの設定、そして後続の解析パイプラインのタイムアウトが、すべて連鎖的に影響する。

最も効果的なアプローチは、アップロードの制限値を調整するだけでなく、ファイルの前処理パイプラインを構築し、大容量ファイルを適切なサイズに分割・最適化してからアップロードすることである。これはアップロードの成功率を上げるだけでなく、ナレッジベースの検索品質も向上させる。


参考資料