上游从上游、客户端(nginx、varnish)读取响应头时发送了太大的头
Posted
技术标签:
【中文标题】上游从上游、客户端(nginx、varnish)读取响应头时发送了太大的头【英文标题】:upstream sent too big header while reading response header from upstream, client (nginx, varnish) 【发布时间】:2018-12-14 13:34:56 【问题描述】:我的 nginx 日志中一直收到“从上游读取响应标头时上游发送的标头太大”错误。
首先,这是我的架构:
此错误由运行在端口 8080 上的 nginx 服务器记录。
2018/07/06 11:17:29 [错误] 18857#18857: *39687 上游发送太大 从上游读取响应标头时标头,客户端:127.0.0.1, 服务器:amr.com.au,请求:“POST /wp-admin/admin-ajax.php HTTP/1.1”, 上游:“fastcgi://unix:/var/run/php/php7.1-fpm.sock:”,主机: “amr.com.au”,推荐人:“https://amr.com.au/wp-admin/”
我试过这个Upstream too big - nginx + codeigniter,但无济于事。
我会把我的 php、nginx 和 varnish 配置放在这里以供参考。
清漆:
vcl 4.0;
backend default
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 600s;
.first_byte_timeout = 600s;
.between_bytes_timeout = 600s;
.max_connections = 800;
acl purger
"localhost";
"127.0.0.1";
sub vcl_recv
# Forward client's IP to the backend
if (req.restarts == 0)
if (req.http.X-Real-IP)
set req.http.X-Forwarded-For = req.http.X-Real-IP;
else if (req.http.X-Forwarded-For)
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
else
set req.http.X-Forwarded-For = client.ip;
# pipe on weird http methods
if (req.method !~ "^GET|HEAD|PUT|POST|TRACE|OPTIONS|DELETE$")
return(pipe);
if (req.method != "GET" && req.method != "HEAD")
return(pass);
if (req.http.X-Requested-With == "XMLHttpRequest")
return (pass);
if (client.ip != "127.0.0.1" && req.http.host ~ "amr.com.au")
set req.http.x-redir = "https://amr.com.au" + req.url;
return(synth(850, ""));
if (req.method == "PURGE")
if (!client.ip ~ purger)
return(synth(405, "This IP is not allowed to send PURGE requests."));
return (purge);
# Pass through the WooCommerce dynamic pages
if (req.url ~ "^/(cart|my-account/*|checkout|wc-api/*|addons|logout|lost-password|product/*)")
return (pass);
# Pass through the WooCommerce add to cart
if (req.url ~ "\?add-to-cart=" )
return (pass);
# Pass through the WooCommerce API
if (req.url ~ "\?wc-api=" )
return (pass);
sub vcl_synth
if (resp.status == 850)
set resp.http.Location = req.http.x-redir;
set resp.status = 302;
return (deliver);
sub vcl_purge
set req.method = "GET";
set req.http.X-Purger = "Purged";
return (restart);
sub vcl_backend_response
if (beresp.status >= 300)
if (beresp.status == 500)
return (retry);
set beresp.uncacheable = true;
set beresp.ttl = 2s;
else
set beresp.ttl = 24h;
set beresp.grace = 1h;
if (bereq.url !~ "wp-admin|wp-login|product|cart|checkout|my-account|/?remove_item=|/?wc-ajax=")
unset beresp.http.set-cookie;
sub vcl_deliver
if (req.http.X-Purger)
set resp.http.X-Purger = req.http.X-Purger;
sub vcl_pipe
return (pipe);
sub vcl_pass
return (fetch);
nginx.conf
user admin;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
worker_rlimit_nofile 50000;
events
use epoll;
worker_connections 100000;
multi_accept on;
http
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65s;
reset_timedout_connection on;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Gzip Settings
##
gzip on;
gzip_min_length 1000;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_disable "msie6";
open_file_cache max=50000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
client_max_body_size 512m;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
nginx 站点可用
server
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name amr.com.au;
port_in_redirect off;
server_tokens off;
more_clear_headers Server;
ssl on;
ssl_certificate_key /etc/letsencrypt/keys/0001_key-certbot.pem;
ssl_certificate /etc/letsencrypt/live/amr.com.au/fullchain.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 60m;
ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
add_header Strict-Transport-Security "max-age=31536000";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
# enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner)
# http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
resolver 8.8.8.8 8.8.4.4;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/amr.com.au/fullchain.pem;
location = /favicon.ico
log_not_found off;
access_log off;
location = /robots.txt
allow all;
log_not_found off;
access_log off;
location /
proxy_pass http://127.0.0.1:80;
proxy_http_version 1.1;
# proxy_connect_timeout 300s;
# proxy_send_timeout 300s;
# proxy_read_timeout 300s;
# send_timeout 300s;
# proxy_set_header Connection "";
# proxy_set_header Host $http_host;
# proxy_set_header X-Forwarded-Host $http_host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto https;
# proxy_set_header HTTPS "on";
# time out settings
proxy_connect_timeout 159s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
# proxy_buffer_size 256k;
# proxy_buffers 32 256k;
# proxy_busy_buffers_size 256k;
# proxy_temp_file_write_size 256k;
proxy_pass_header Set-Cookie;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_ignore_headers Cache-Control Expires;
proxy_set_header Referer $http_referer;
proxy_set_header Host $host;
proxy_set_header Cookie $http_cookie;
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;
access_log /var/www/logs/ssl-access.log;
error_log /var/www/logs/ssl-error.log error;
server
listen 8080;
listen [::]:8080;
server_name amr.com.au;
root /var/www/amr-prod;
index index.php;
port_in_redirect off;
client_header_buffer_size 2M;
large_client_header_buffers 16 2M;
client_body_buffer_size 100M;
client_max_body_size 100M;
fastcgi_buffers 256 200k;
access_log /var/www/logs/backend-access.log;
error_log /var/www/logs/backend-error.log warn;
rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml$ "/index.php?xml_sitemap=params=$2" last;
rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml\.gz$ "/index.php?xml_sitemap=params=$2;zip=true" last;
rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html$ "/index.php?xml_sitemap=params=$2;html=true" last;
rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html.gz$ "/index.php?xml_sitemap=params=$2;html=true;zip=true" last;
location /
try_files $uri $uri/ /index.php?$args;
location ~ \.php$
try_files $uri $document_root$fastcgi_script_name =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_read_timeout 240s;
也供参考:
awk '($9 ~ /200/) i++;sum+=$10;max=$10>max?$10:max; END printf("Maximum: %d\nAverage: %d\n",max,i?sum/i:0); ' access.log
最大值:62833994 平均:68531
有人可以帮我弄清楚为什么我会收到这个错误吗?这对我来说似乎没有任何意义??看来我的配置是正确的。
提前致谢,
迈克
编辑:
所以,我创建了一个副本服务器,然后关闭了 Varnish,嘿,很快,它就可以工作了。所以 Varnish 中发生了一些事情。我还没有时间调查它,但我会在这周尝试更新,如果我能解决的话。
【问题讨论】:
您是否修复了您的 Wordpress 安装中出现的所有错误?到目前为止,您的 PHP 日志将为您提供最丰富的信息。您的所有插件都对 PHP 7.1 友好吗?我上周告诉过你为什么会出现这个错误,PHP 向 STDERR 输出的内容太多以至于 Nginx 标头缓冲区溢出并导致它返回 502。修复你的 Wordpress,你就会解决你的问题。 【参考方案1】:您是否在出现 nginx 错误的同时梳理了您的 PHP 错误日志? nginx 错误upstream sent too big header while reading response header from upstream
是一条非常通用的消息,可能与许多问题有关。一个可能的罪魁祸首是有缺陷的 PHP 脚本。其他可能性包括线程崩溃或任何其他数字标题问题。
查看answer 33878041 以了解在调试此上游错误时需要调查的其他要点。这包括验证 Content-Length 不超过 POST 事务的实际内容长度。
【讨论】:
我有.. php 在它发生时附近没有记录任何错误。 也许是愚蠢的问题,但是是否设置了 error_reporting 和 display_errors ?您是否能够记录每个请求的所有标头并确保它们是洁净的(链接答案中的#2)?最后,您确定您的线程正在到达正确的退出点(链接答案中的#1)吗? 早上喝完饮料后,我找不到您的任何 PHP 错误报告配置。您是否启用了 PHP 错误日志记录?请考虑以下链接以启用 PHP 错误记录:serverfault.com/questions/831249/… 所以,我编辑了帖子,但它似乎是 Varnish 问题。 POSTcontent-length
是否有可能在 nginx 将其传递给清漆和清漆到 nginx 的 8080 实例之间的某个地方被破坏?测试这一点的一种方法是在 HTTP 请求的所有三个跃点上打开标头日志记录。将 443 nginx 标头日志条目与 varnish 的日志条目进行比较,最后它如何到达 8080 nginx 可能会产生信息性结果。【参考方案2】:
您可能想取消注释:
proxy_buffer_size 256k;
proxy_buffers 32 256k;
如果在此之后仍然无法正常工作,请使用 fastcgi_buffer*
和 proxy_buffer*
值集。 (可能必须增加)。
nginx 必须能够在内存中容纳 HTTP 标头,并且显然您的应用设置了太长的标头(Set-Cookie
等)。
长篇大论here 解释了如何为proxy_buffer_size
找到合适的价值。
【讨论】:
您能否更详细地解释一下您所说的“nginx 必须能够在内存中容纳 HTTP 标头,并且显然您的应用程序设置了太长的标头(Set-Cookie 等)。 " ...我将如何更改 nginx 设置? 查看我的答案的补充。 Nginx 总是缓冲响应头。因此,如果您的应用发送的标头过多/过长,则可能会超过默认的 4k|8k。请注意,proxy_buffer_size
和 fastcgi_buffer_size
必须设置为几乎相同的值,因为您的应用程序发送的 HTTP 标头仅在“途中”发送到客户端(从 nginx 到 Varnish,到“SSL nginx").【参考方案3】:
所以答案不是最好的,但它似乎已经解决了。
我绕过了 Varnish 并设置了 nginx 缓存。对页面速度几乎没有影响。
基本配置是正确的,没有 Varnish 错误就消失了。
不是最好的,但是,它有效。
【讨论】:
以上是关于上游从上游、客户端(nginx、varnish)读取响应头时发送了太大的头的主要内容,如果未能解决你的问题,请参考以下文章
如何在将请求传递给上游服务器之前删除 Nginx 中的客户端标头?