我已将 nginx 设置为终止 SSL 连接并将请求转发到 http 后端。客户端发出许多后台请求,其中一个请求400 Bad Reqest
在尝试协商 SSL 连接时失败。如果它不需要协商连接 - 例如,如果另一个后台请求刚刚成功发布,则请求成功。检查 Chrome 网络选项卡显示成功请求和失败请求之间没有相关差异。我的旅程发布在这里此错误报告,但以下是我目前能够提炼出来的内容:
SSL 连接
当问题请求成功时,我可以通过查看网络请求的“时间”选项卡(在 Chrome 中)来判断它不需要协商 SSL 连接:时间 - 请求成功
另一方面,每当请求失败时,我都会看到它已尝试协商 SSL 连接,如下图所示:时间安排 - 请求失败
Nginx 处理
通过检查应用程序访问日志,我确定是 nginx 返回了错误400 Bad Request
,而不是 HTTP 应用程序。当请求失败时,所有 nginx 日志都是 POST 主体而不是通常的 HTTP 方法和 URL(我没有自定义 nginx 日志格式)。
我在 nginx 错误日志中打开了调试功能(使用 行error_log /var/log/nginx/error.log debug;
)。这样我就可以看到 SSL 协商期间发生了什么(尽管我不明白)。
正如我上面简要提到的,还有其他后台请求确实会成功,尽管它们运行的频率较低。任何请求成功后,所有请求都会在一段时间内成功(直到它们需要协商 SSL 连接)。
此外,如果我使用Copy as cURL
Chrome 的功能并将请求作为 cURL 请求运行,它总是会成功。我观察到它唯一一次失败是在浏览器发出请求时。
Nginx 调试日志
以下是日志中成功的 SSL 请求的相关内容:
2021/10/22 20:37:59 [debug] 1858722#1858722: *441 free: 0000562A9F69F340
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 http upstream request: "/api/method/frappe.core.doctype.log_settings.log_settings.has_unseen_error_log?"
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 http upstream process header
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 malloc: 0000562A9F712CB0:131072
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 recv: eof:0, avail:-1
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 recv: fd:9 678 of 131072
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 http proxy status 200 "200 OK"
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 http proxy header: "Server: gunicorn"
... more http proxy headers ...
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 http proxy header done
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 xslt filter header
2021/10/22 20:37:59 [debug] 1858722#1858722: *438 HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
... HTTP response
失败的谈判如下:
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 free: 0000562A9F69F340
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 http wait request handler
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 malloc: 0000562A9F69F340:1024
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 SSL_read: 812
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 SSL_read: -1
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 SSL_get_error: 2
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 reusable connection: 0
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 posix_memalign: 0000562A9F70CEB0:4096 @16
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 http process request line
2021/10/22 20:39:00 [info] 1858722#1858722: *446 client sent invalid method while reading client request line, client: 107.185.20.83, server: atlas-dev.ebs.llc, request: "doctype=Error+Log&fields=%5B%22%60tabError+Log%60.%60name%60%22%2C%22%60tabError+Log%60.%60owner%60%22%2C%22%60tabError+Log%60.%60creation%60%22%2C%22%60tabError+Log%60.%60modified%60%22%2C%22%60tabError+Log%60.%60modified_by%60%22%2C%22%60tabError+Log%60.%60_user_tags%60%22%2C%22%60tabError+Log%60.%60_comments%60%22%2C%22%60tabError+Log%60.%60_assign%60%22%2C%22%60tabError+Log%60.%60_liked_by%60%22%2C%22%60tabError+Log%60.%60docstatus%60%22%2C%22%60tabError+Log%60.%60parent%60%22%2C%22%60tabError+Log%60.%60parenttype%60%22%2C%22%60tabError+Log%60.%60parentfield%60%22%2C%22%60tabError+Log%60.%60idx%60%22%2C%22%60tabError+Log%60.%60method%60%22%2C%22%60tabError+Log%60.%60seen%60%22%5D&filters=%5B%5D&order_by=%60tabError+Log%60.%60modified%60+desc&start=0&page_length=20&view=List&with_comment_count=true"
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 http finalize request: 400, "?" a:1, c:1
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 event timer del: 9: 337737968
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 http special response: 400, "?"
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 http set discard body
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 xslt filter header
2021/10/22 20:39:00 [debug] 1858722#1858722: *446 HTTP/1.1 400 Bad Request
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 22 Oct 2021 20:39:00 GMT
Content-Type: text/html
Content-Length: 166
Connection: close
根据我对 nginx 调试日志的了解(即没有),在我看来,nginx 在协商过程中将 HTTP 方法和 URL 替换为主体。当它查找 HTTP 方法时,该方法不再存在,并且会阻塞。
Nginx SSL 配置
版本信息:nginx/1.18.0 (Ubuntu)
,Ubuntu 20.04 LTS
我使用默认的nginx.conf
。服务器配置文件的 SSL 部分如下所示:
listen 443 ssl;
server_name [HOST];
root /opt/erpnext/bench/sites;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
ssl_certificate /etc/letsencrypt/live/[HOST]/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/[HOST]/privkey.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;
文件底部有一个 SSL 重定向,并且 nginx 被设置为从另一个配置在端口 8080 上提供基于平面文件的 HTTP 网络服务器。
我如何确定问题的原因?我知道请求格式正确,因为相同的请求成功了……直到它需要协商 SSL 连接。帮帮忙?