上游从上游、客户端(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 问题。 POST content-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_sizefastcgi_buffer_size 必须设置为几乎相同的值,因为您的应用程序发送的 HTTP 标头仅在“途中”发送到客户端(从 nginx 到 Varnish,到“SSL nginx").【参考方案3】:

所以答案不是最好的,但它似乎已经解决了。

我绕过了 Varnish 并设置了 nginx 缓存。对页面速度几乎没有影响。

基本配置是正确的,没有 Varnish 错误就消失了。

不是最好的,但是,它有效。

【讨论】:

以上是关于上游从上游、客户端(nginx、varnish)读取响应头时发送了太大的头的主要内容,如果未能解决你的问题,请参考以下文章

如何在将请求传递给上游服务器之前删除 Nginx 中的客户端标头?

NGINX:从上游读取响应头时上游超时(110:连接超时)

AWS Nginx“从上游读取响应标头时上游过早关闭连接”

Nginx上游过早关闭连接,同时从上游读取响应标头,用于大型请求

NGINX *7060 上游超时(110:连接超时)

错误:从上游 [uWSGI/Django/NGINX] 读取响应标头时,上游过早关闭连接