nginx + varnish + SSL 中的错误重定向过多

nginx + varnish + SSL 中的错误重定向过多

我有一个集群基础架构。我在 varnish 前面使用 nginx 进行 SSL 终止。varnish 的后端是 apache web 服务器。我还有一个 haproxy 作为负载均衡器,它将 HTTPS 请求直接发送到 nginx,并将 HTTP 请求直接发送到 varnish 服务器。问题是,当我启动 nginx 时,一段时间内一切都正常,但之后,我在浏览 ssl 网站时在浏览器中收到 too_many_error_redirects!!我认为我的配置有问题,但我不知道哪些配置(nginx 或 varnish)是导致此错误的原因。当我将请求直接转发到 web 服务器时,一切都正常,所以可能是 varnish 配置有问题。以下是我的配置:
Nginx 配置:domain_name.conf

server {
        listen 443;

        server_name mydomain.com;
        ssl on;

        ssl_certificate /etc/nginx/ssl/domain_name_bundle.pem;
        ssl_certificate_key /etc/nginx/ssl/my_key.key;

        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 10m;

        ssl_prefer_server_ciphers       on;
        ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS +RC4 RC4";

        add_header Strict-Transport-Security "max-age=31536000";
        server_tokens off;
        proxy_pass_header Server;
location / {
            proxy_pass http://cache-servers;
            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 X-Forwarded-Port 443;
            proxy_redirect    off;
            proxy_set_header Host $host;
        }
}
upstream cache-servers
{
        ip_hash;
        #cache servers
        server 192.168.1.11:8080;
        server 192.168.1.12:8080;
}

清漆配置:

vcl 4.0;

import directors;

# Check backend health
probe backend_healthcheck {
   .url = "/";
   .timeout = 10s;
   .window = 5;
   .threshold = 3;
   .interval = 5s;
   .expected_response = 200;

}

backend web1 {
    .host = "192.168.1.105";
    .port = "8080";
    .probe = backend_healthcheck;
}
backend web2 {
    .host = "192.168.1.106";
    .port = "8080";
    .probe = backend_healthcheck;
}
sub vcl_init {
    new apache = directors.round_robin();
    apache.add_backend(web1);
    apache.add_backend(web2);
}
sub vcl_recv {

    set req.backend_hint = apache.backend();

set req.http.X-Forwarded-For = client.ip;

if (req.method == "GET" && (req.url ~ "^/?mylogout=")) {
     unset req.http.Cookie;
      return (pass);
  }
  #we should not cache any page for Prestashop backend
  if (req.method == "GET" && (req.url ~ "^/admin70")) {
      return (pass);
  }
  #we should not cache any page for customers
  if (req.method == "GET" && (req.url ~ "^/authentification" || req.url ~ "^/my-account")) {
      return (pass);
  }
  #we should not cache any page for customers
  if (req.method == "GET" && (req.url ~ "^/identity" || req.url ~ "^/my-account.php")) {
      return (pass);
  }
  #we should not cache any page for sales
  if (req.method == "GET" && (req.url ~ "^/cart.php" || req.url ~ "^/order.php")) {
      return (pass);
  }

#we should not cache any page for sales
  if (req.method == "GET" && (req.url ~ "^/addresses.php" || req.url ~ "^/order-detail.php")) {
      return (pass);
  }
  #we should not cache any page for sales
  if (req.method == "GET" && (req.url ~ "^/order-confirmation.php" || req.url ~ "^/order-return.php")) {
      return (pass);
  }
if (req.method != "GET" && req.method != "HEAD") {
      return (pass);
  }

#pass feeds
  if (req.url ~ "/feed")
  {
        return (pass);
  }

if (req.url ~ "/wp-(login|admin)" || (req.method == "GET" && req.url ~ "^/admin") || (req.method == "GET" && req.url ~ "^/user"))
  {
        #unset req.http.cookie;
        return (pass);
  }

  #cache everything left behind
  return(hash);
}

sub vcl_backend_response {

    if  (!(bereq.url ~ "(wp-(login|admin)|admin)"))  {
      unset beresp.http.set-cookie;
      set beresp.ttl = 10m;
     }
    set beresp.grace = 2h;

}

sub vcl_deliver {

    if (obj.hits > 0) {
           set resp.http.X-Cache = "HIT";
    } else {
           set resp.http.X-Cache = "MISS";
    }
 if (obj.hits > 0) {
           set resp.http.X-Cache-Lookup = "HIT";
    } else {
           set resp.http.X-Cache-Lookup = "MISS";
    }
 unset resp.http.X-Varnish;
 unset resp.http.Via;
 unset resp.http.Server;
 unset resp.http.X-Powered-By;
#return (deliver);

}

答案1

这里的问题非常常见:您在应用程序级别执行重定向 http -> https。

Apache/PHP 不知道它们已经在 SSL 中运行,因为 apache 在 http 中运行(然后传递给 varnish,然后传递给 nginx)。

解决方案很简单:您的 PHP 应用程序需要有 PHP ENV 变量$_SERVER['HTTPS'] = "on"

你可以用不同的方式来做:

  • 在 httpd.conf 中使用 apache SetEnv,
  • 在 .htaccess 中再次使用 SetEnv
  • 在你的 php 脚本中。

另外:我还将在 varnish 级别执行从 http 到 https 的重定向:添加自定义标头,例如X-Nginx = on当请求来自 nginx 时。在 varnish 中读取该标头,如果不存在,则将用户重定向到 https URL。

注意:如果您使用 wordpress(如在您的 vcl 文件中所示),请不要忘记添加此项:

define('FORCE_SSL_ADMIN', true);

相关内容