Sửa Lỗi Nginx 413 Request Entity Too Large

beginner Nginx2026-03-18| Nginx 1.x trên Ubuntu/Debian/CentOS, thường xảy ra trong các thiết lập reverse proxy với PHP-FPM, Node.js, hoặc các endpoint upload file

Error Message

413 Request Entity Too Large
#nginx#upload#client_max_body_size

Tình Huống

2 giờ sáng. Một người dùng báo không thể upload gì — chỉ thấy trang trắng hoặc lỗi mơ hồ trên trình duyệt. Bạn kiểm tra /var/log/nginx/error.log:

2025/03/16 02:13:44 [error] 1234#1234: *42 client intended to send too large body: 12582912 bytes, client: 203.0.113.55, server: example.com, request: "POST /upload HTTP/1.1", host: "example.com"

12.582.912 bytes — tức là 12MB. Trình duyệt hiển thị gọn gàng:

413 Request Entity Too Large

Nginx đã chặn request trước khi chạm tới ứng dụng của bạn. Có hai lớp cần sửa — bỏ sót lớp thứ hai là lỗi quay lại ngay.

Nguyên Nhân

Nginx áp đặt giới hạn cứng trên kích thước body của request đến. Mặc định là 1MB (client_max_body_size 1m). Bất kỳ request POST nào — upload file, JSON payload, form submission — vượt quá giới hạn này đều bị từ chối ngay với lỗi 413.

Đây là cổng kiểm soát ở tầng Nginx, hoàn toàn tách biệt với giới hạn upload của ứng dụng. upload_max_filesize của PHP, cấu hình body parser của Node.js, config presigned URL của S3 — tất cả đều vô nghĩa nếu Nginx chặn request từ đầu. Dù ứng dụng của bạn chấp nhận file 100MB, Nginx vẫn giết mọi thứ vượt quá 1MB trừ khi bạn chỉ định rõ ràng.

Sửa Nhanh (Server Đang Chạy)

Trước tiên, kiểm tra cấu hình đang thực sự hoạt động:

# Kiểm tra config nào đang active
nginx -T | grep -n client_max_body_size

# Hoặc tìm tất cả file config của nginx
grep -r client_max_body_size /etc/nginx/

Không có output nghĩa là đang dùng mặc định (1MB) — directive chưa bao giờ được set. Thêm hoặc cập nhật trong server block của bạn:

sudo nano /etc/nginx/sites-available/your-site.conf

Thêm vào trong server {} hoặc block location {} cụ thể:

server {
    listen 80;
    server_name example.com;

    # Cho phép upload tối đa 20MB
    client_max_body_size 20m;

    location / {
        proxy_pass http://localhost:3000;
    }
}

Kiểm tra và reload — không cần downtime:

sudo nginx -t && sudo systemctl reload nginx

Sửa Vĩnh Viễn — Đặt Đúng Phạm Vi

Vị trí đặt client_max_body_size rất quan trọng. Nginx áp dụng block khớp trong cùng nhất, nên bạn có thể chi tiết đến từng endpoint:

Tùy chọn 1: Toàn cục (tất cả virtual host)

Trong /etc/nginx/nginx.conf, bên trong block http {}:

http {
    client_max_body_size 20m;
    ...
}

Tùy chọn 2: Theo từng virtual host

Bên trong block server {} cụ thể — ghi đè giá trị toàn cục:

server {
    server_name api.example.com;
    client_max_body_size 50m;
    ...
}

Tùy chọn 3: Theo từng location (chính xác nhất)

Khi chỉ một endpoint cần giới hạn cao hơn, hãy đặt ở đó. Mọi thứ còn lại vẫn giữ mặc định:

server {
    server_name example.com;
    client_max_body_size 1m;  # mặc định cho tất cả

    location /api/upload {
        client_max_body_size 100m;  # chỉ riêng endpoint này
        proxy_pass http://localhost:3000;
    }
}

Tắt giới hạn hoàn toàn (không khuyến nghị)

Đặt thành 0 sẽ bỏ hoàn toàn việc kiểm tra. Chỉ dùng trên mạng nội bộ hoặc mạng tin cậy:

client_max_body_size 0;

Nếu Bạn Đang Dùng PHP-FPM

Nginx sẽ chuyển request qua rồi — nhưng PHP vẫn có thể từ chối. Kiểm tra hai thiết lập này:

# Tìm file php.ini của bạn
php --ini | grep "Loaded Configuration"

# Chỉnh sửa nó
sudo nano /etc/php/8.1/fpm/php.ini

Cả hai giá trị cần khớp hoặc vượt quá giới hạn Nginx của bạn:

upload_max_filesize = 20M
post_max_size = 25M

post_max_size phải lớn hơn upload_max_filesize. Nó bao phủ toàn bộ POST body — một file 20MB trong một form submission sẽ chiếm hơn 20MB khi tính thêm dữ liệu các field.

Khởi động lại PHP-FPM để áp dụng:

sudo systemctl restart php8.1-fpm

Nếu Bạn Đứng Sau Proxy Khác (AWS ALB, Cloudflare, v.v.)

Khi Nginx nằm sau load balancer hoặc CDN, lớp ngoài đó có thể áp đặt giới hạn kích thước riêng:

  • AWS ALB: Không có giới hạn thực tế với EC2/container target — thường không phải thủ phạm ở đây
  • Cloudflare Free/Pro: Giới hạn upload 100MB theo mặc định
  • AWS API Gateway: Giới hạn cứng 10MB — không thể tăng lên

Phân biệt sự khác nhau: nếu lỗi 413 hiển thị trang lỗi có thương hiệu Cloudflare thay vì response text thuần của Nginx, thì việc chặn đang xảy ra ở phía họ. Không có thay đổi nào trong nginx.conf sẽ sửa được điều đó.

Xác Nhận Đã Sửa Xong

Dùng curl để kiểm tra với file thực tế có kích thước biết trước:

# Tạo file test 15MB
dd if=/dev/urandom of=/tmp/testfile bs=1M count=15

# Thử upload nó
curl -v -X POST https://example.com/api/upload \
  -F "file=@/tmp/testfile" 2>&1 | grep -E "< HTTP|413|200"

Sau khi sửa thành công:

< HTTP/1.1 200 OK

Vẫn thấy 413? Xác nhận việc reload đã thực sự có hiệu lực:

# Xác nhận config đang active đã được reload
nginx -T | grep client_max_body_size

# Kiểm tra Nginx đang chạy với config bạn nghĩ
sudo nginx -t

Theo dõi error log trong khi gửi lại request — nó sẽ cho biết chính xác điều gì vẫn đang chặn:

sudo tail -f /var/log/nginx/error.log

Khuyến Nghị Về Kích Thước

  • API endpoint (chỉ JSON): Giữ ở 1–4MB. Payload JSON 50MB là vấn đề thiết kế, không phải vấn đề giới hạn kích thước.
  • Upload ảnh: 10–20MB đủ cho hầu hết trường hợp, kể cả ảnh RAW từ máy ảnh hiện đại.
  • Upload video/tài liệu: 50–200MB tùy use case. Với bất kỳ thứ gì trên 50MB, hãy cân nhắc chunked upload — chúng đáng tin cậy hơn trên kết nối kém ổn định.
  • Công cụ quản trị nội bộ: Có thể đặt cao hơn vì bạn kiểm soát chính xác ai có quyền truy cập.

Đừng đặt client_max_body_size cao hơn mức cần thiết trên các endpoint công khai. Một loạt request quá kích thước sẽ nhanh chóng làm tắc nghẽn backend worker — đây là vector tấn công DoS dễ khai thác. Hãy đặt giới hạn chặt chẽ nhất mà tính năng cho phép.

Related Error Notes