从上游、客户端(nginx、varnish)读取响应头时,上游发送了太大的头

upstream sent too big header while reading response header from upstream, client (nginx, varnish)

我的 nginx 日志中一直出现 "upstream sent too big header while reading response header from upstream" 错误。

首先,这是我的架构:

此错误由 nginx 服务器 运行 在端口 8080 上记录。

2018/07/06 11:17:29 [error] 18857#18857: *39687 upstream sent too big header while reading response header from upstream, client: 127.0.0.1, server: amr.com.au, request: "POST /wp-admin/admin-ajax.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.1-fpm.sock:", host: "amr.com.au", referrer: "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=" last;
   rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml\.gz$ "/index.php?xml_sitemap=params=;zip=true" last;
   rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html$ "/index.php?xml_sitemap=params=;html=true" last;
   rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html.gz$ "/index.php?xml_sitemap=params=;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 '( ~ /200/) { i++;sum+=;max=>max?:max; } END { printf("Maximum: %d\nAverage: %d\n",max,i?sum/i:0); }' access.log

最大:62833994 平均:68531

谁能帮我弄清楚为什么我会收到这个错误?对我来说似乎没有任何意义??看来我配置正确了。

提前致谢,

麦克

编辑:

所以,我制作了一个副本服务器,并关闭了 Varnish,嘿,转眼间,它起作用了。所以 Varnish 中发生了一些事情。我还没有时间调查它,但我会在本周尝试并更新是否可以解决。

您是否在 nginx 错误的同时梳理了您的 PHP 错误日志? nginx 错误 upstream sent too big header while reading response header from upstream 是一个非常通用的消息,可能与任何数量的错误相关。一个可能的罪魁祸首是有问题的 PHP 脚本。其他可能性包括线程崩溃或任何其他 header 问题。

查看 answer 33878041 以了解调试此上游错误时需要调查的其他要点。这包括验证 Content-Length 不超过 POST 事务的实际内容长度。

您可能想要取消评论:

proxy_buffer_size    256k;
proxy_buffers     32 256k;

并尝试使用 fastcgi_buffer*proxy_buffer* 值集,如果之后仍然无法正常工作。 (可能必须增加)。

nginx 必须能够在内存中容纳 HTTP headers,显然您的应用程序设置太长了(Set-Cookie,等等)。

长话短说 here 解释了如何找到 proxy_buffer_size 的正确值。

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

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

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

不是最好的,但是很管用。