Azure Web App容器Nginx代理大文件上传超时问题求助
问题描述
将包含Nginx服务器与RClone的容器部署到Azure Web App for Containers实例中,Nginx反向代理通过auth_request指令验证请求后,将请求proxy_pass至本地的RClone上游服务器。受网络延迟/带宽影响,耗时超约5分钟的大文件上传会被取消,日志显示连接被Azure中间件中断。
环境配置
Nginx超时配置(/etc/nginx/conf.d/timeout.conf)
client_header_timeout 1800; client_body_timeout 1800; proxy_connect_timeout 1800; proxy_send_timeout 1800; proxy_read_timeout 1800; send_timeout 1800;
Nginx主配置(/etc/nginx/nginx.conf)
pid /var/run/nginx/nginx.pid; load_module modules/ngx_http_js_module.so; worker_processes auto; events { worker_connections 1024; } http { resolver 127.0.0.11 ipv6=off; resolver_timeout 10s; default_type application/json; keepalive_timeout 65; client_max_body_size 0; upstream rclone { server localhost:5572; } upstream validator { server localhost:8079; } js_path "/etc/nginx/njs/"; js_import main from index.js; server { listen 8000; listen [::]:8000; server_name localhost; sendfile on; client_header_buffer_size 32k; location / { access_log off; return 200; } location /healthcheck { access_log off; return 200; } location ~* /operations/uploadfile { limit_except HEAD POST { deny all; } auth_request /_validate; proxy_set_header Content-Length $content_length; proxy_set_header Host $host; proxy_set_header Referer $http_referer; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; proxy_request_buffering off; proxy_intercept_errors off; proxy_pass http://rclone; } location = /_validate { internal; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Original-Method $request_method; proxy_pass_request_body off; proxy_intercept_errors off; proxy_pass http://validator/validate; } error_page 405 = @405; location @405 { return 405 '{"status":405,"code":"MethodNotAllowed","message":"Method Not Allowed"}\n'; } error_page 500 = @500; location @500 { return 500 '{"status":500,"code":"InternalServerError","message":"Internal Server Error"}\n'; } } server { listen 8079; listen [::]:8079; server_name localhost; client_header_buffer_size 32k; location /validate { js_content main.authorize; js_fetch_timeout 10; js_fetch_trusted_certificate /etc/ssl/certs/ca-certificates.crt; } } }
测试命令
Curl脚本
#!/bin/bash curl -v -X POST 'https://<redacted>.azurewebsites.net/operations/uploadfile?<rclone_query_params>' \ -H @token.txt \ -F file="../samples/test-500MB.file"
JavaScript上传脚本
const fs = require('fs'); const axios = require('axios'); const domain = 'https://<redacted>.azurewebsites.net'; const file = '../samples/test-500MB.file'; const fileStream = fs.createReadStream(file); const token = fs.readFileSync('./token.txt', 'utf8').split(':')[1].trim(); console.log(`Uploading file: ${file}`); console.log(`Token: ${token}`); axios({ method: 'post', url: `${domain}/operations/uploadfile?<rclone_query_params>`, headers: { 'Content-Type': 'application/octet-stream', 'Content-Length': fs.statSync(file).size, Expect: '100-continue', Connection: 'keep-alive', 'Transfer-Encoding': 'chunked', 'User-Agent': 'axios/0.21.4', Authorization: `${token}` }, data: fileStream, maxContentLength: Infinity, maxBodyLength: Infinity, onUploadProgress: (progressEvent) => { const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); console.log(`Upload progress: ${percentCompleted}%`); }, validateStatus: (status) => { return (status >= 200 && status < 300) || status === 308; }, maxRedirects: 0 }) .then((response) => { console.log(`Upload completed: ${response.status} ${response.statusText}`); }) .catch((error) => { console.error(`Upload failed: ${error.message}`); });
错误日志
Nginx日志
2023/05/13 13:01:34 [info] 18#18: *15 client prematurely closed connection while sending request to upstream, client: <redacted>, server: localhost, request: "POST /uploadfile?<rclone_query_param> HTTP/1.1", upstream: "http://127.0.0.1:5572/operations/uploadfile?<rclone_query_param>", host: "<redacted>.azurewebsites.net"
RClone日志
2023/05/13 13:01:34 ERROR : rc: "operations/uploadfile": error: multipart upload failed to upload part: context canceled
Azure中间件日志
Failed to forward request to http://<redacted>. Encountered a System.Threading.Tasks.TaskCanceledException exception after 299998.262ms with message: The request was canceled due to the configured HttpClient.Timeout of 300 seconds elapsing.. Check application logs to verify the application is properly handling HTTP traffic.
解决思路
调整Azure Web App请求超时限制
- Azure Web App默认300秒请求超时,需在门户的Web App配置中添加应用设置
WEBSITES_CONTAINER_START_TIME_LIMIT,设置为更大值(如1800秒);同时确认WEBSITES_PORT与容器暴露端口(8000)一致。 - 使用Azure CLI修改:
az webapp config appsettings set --name <your-webapp-name> --resource-group <your-resource-group> --settings WEBSITES_CONTAINER_START_TIME_LIMIT=1800
- Azure Web App默认300秒请求超时,需在门户的Web App配置中添加应用设置
优化Nginx长连接配置
- 在
/operations/uploadfile的location块中添加HTTP/1.1长连接支持:location ~* /operations/uploadfile { # 原有配置保留 proxy_http_version 1.1; proxy_set_header Connection ""; }
- 在
延长RClone RC服务超时
- 启动RClone时添加
--rc-timeout参数,确保服务不会提前断开:rclone rcd --rc-addr :5572 --rc-timeout 1800s <其他启动参数>
- 启动RClone时添加
客户端侧优化
- Curl命令添加
--no-buffer参数,避免数据缓冲导致超时:curl -v --no-buffer -X POST 'https://<redacted>.azurewebsites.net/operations/uploadfile?<rclone_query_params>' \ -H @token.txt \ -F file="../samples/test-500MB.file"
- Curl命令添加
启用ARR Affinity(多实例场景)
- 在Azure门户Web App配置中开启"ARR Affinity",确保长请求始终路由到同一实例,避免实例切换导致连接中断。
内容的提问来源于stack exchange,提问作者chauvd
相关产品推荐
相关产品推荐

