Nginx+PHP-FPM上传大文件报400错误,求配置排查方案
问题
使用PHP-FPM7.1与Nginx的Docker镜像部署服务,需要支持上传50MB以上的MP4文件,但上传超过1.5MB的文件时会返回400 Bad Request错误。以下是当前的Nginx配置和php.ini配置,求排查配置中的问题:
Nginx配置
user root; worker_processes 2; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; real_ip_header X-Forwarded-For; set_real_ip_from 0.0.0.0/0; log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; ## Cache ##open_file_cache max=1000 inactive=24h; ##open_file_cache_valid 24h; ##open_file_cache_min_uses 2; ##open_file_cache_errors on; ## Timeouts client_header_timeout 15; client_body_timeout 15; send_timeout 15; keepalive_timeout 0; ## Size limits # client_max_body_size 100M; client_header_buffer_size 32k; client_body_buffer_size 128k; large_client_header_buffers 64 8k; ## General types_hash_max_size 2048; server_names_hash_bucket_size 64; ignore_invalid_headers on; limit_conn_zone $binary_remote_addr zone=addr:10m; recursive_error_pages on; reset_timedout_connection on; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; server_name_in_redirect off; keepalive_requests 0; client_max_body_size 1024m; ## Compression gzip on; gzip_static on; gzip_comp_level 6; gzip_disable "msie6"; gzip_buffers 16 8k; gzip_vary on; gzip_proxied any; gzip_min_length 256; gzip_http_version 1.1; gzip_types text/css text/javascript text/xml text/plain application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml; output_buffers 10 128k; postpone_output 1500; ## Fastcgi Caching #fastcgi_cache_path /var/cache/nginx/fastcgi_tmp levels=1:2 #keys_zone=CZONE:15m inactive=60m; #fastcgi_cache_key "$scheme$request_method$host$request_uri"; #fastcgi_cache_use_stale error timeout invalid_header http_500; server { listen 80; root /app/src/public; index index.html index.htm index.php; error_page 500 501 502 503 504 505 506 507 508 509 510 511 /error/bad_request; error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 420 422 423 424 426 428 429 431 444 449 450 451 /error/not_found; ## Rewrite rules location / { try_files $uri $uri/ /index.php?$args; } location ^~ /relay { allow 50.17.201.90; allow 52.77.175.201; deny all; try_files $uri $uri/ /index.php?$args; error_page 403 = @kick_out; } location @kick_out { rewrite ^(.*) https://$server_name/error/not_found; } ## Deny access to hidden files location ~ /\. { deny all; } ## No log for known files location ~* ^.+\.(js|css|swf|xml|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|mid|midi|wav|bmp)$ { access_log off; log_not_found off; expires 30d; } location = /favicon.ico { access_log off; log_not_found off; expires 30d; } location = /robots.txt { allow all; access_log off; log_not_found off; expires 30d; } location = /health { return 200; access_log off; log_not_found off; expires 30d; } ## Pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 location ~ \.php$ { try_files $uri = 404; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_connect_timeout 60; fastcgi_send_timeout 90; fastcgi_read_timeout 90; fastcgi_buffer_size 512k; fastcgi_buffers 64 512k; fastcgi_cache_valid any 1h; include fastcgi_params; } } }
php.ini配置
[www] user = root group = root listen = 127.0.0.1:9000 listen.allowed_clients = 127.0.0.1 pm = dynamic pm.max_children = 100 pm.start_servers = 10 pm.min_spare_servers = 10 pm.max_spare_servers = 20 request_terminate_timeout = 120 slowlog = /var/log/nginx/error.log expose_php = Off error_reporting = E_ALL & ~E_NOTICE display_errors = 1 upload_max_filesize = 100M post_max_size = 100M memory_limit = 512M
上传1.5MB以内的文件正常,超过则返回400 Bad Request错误。
分析与解决
1. Nginx请求体超时过短
当前Nginx的client_body_timeout设置为15秒,上传50MB级别的文件时,网络传输耗时很容易超过这个阈值,导致Nginx提前中断连接,返回400错误。
修改方案:
将client_body_timeout调整为更长时间,比如60秒:
client_body_timeout 60;
2. 补充Nginx请求体缓冲区配置
当前client_body_buffer_size为128k,当文件大小超过缓冲区时,Nginx会将文件写入临时目录。如果临时目录权限不足或磁盘空间不足,也会触发400错误。可以适当调大缓冲区,同时确保容器内/var/lib/nginx/tmp目录权限正常:
client_body_buffer_size 256k;
3. 确保client_max_body_size层级覆盖正确
虽然在http块设置了client_max_body_size 1024m;,但建议在server块也添加该配置,避免层级覆盖问题:
server { listen 80; root /app/src/public; index index.html index.htm index.php; client_max_body_size 1024m; # 添加到server块 # ... 其他配置 }
4. 检查Nginx错误日志定位具体原因
查看/var/log/nginx/error.log的详细内容,确认400错误的具体触发点,比如是否是临时目录写入失败、请求头过大等问题,针对性解决。
5. 验证PHP临时目录权限
PHP上传文件依赖临时目录(默认/tmp),确保Docker容器内该目录有root用户的读写权限,避免因权限不足导致上传失败,被Nginx返回400错误。
内容的提问来源于stack exchange,提问作者Hassan Raza
相关产品推荐
相关产品推荐

