Linux

nginx + varnish + SSL中的重定向過多

  • June 27, 2017

我有一個集群基礎設施。我在清漆前使用 nginx 進行 SSL 終止。varnish 的後端是 apache web 伺服器。我還有一個 haproxy 作為負載均衡器,它直接將 HTTPS 請求發送到 nginx 並將 HTTP 請求直接發送到 varnish 伺服器。問題是當我啟動 nginx 一段時間後一切正常,但在那之後我在瀏覽 ssl 網站時在瀏覽器中得到了 too_many_error_redirects !!我認為我的配置有問題,但我不知道哪些配置(nginx 或 varnish)是導致此錯誤的原因。當我將請求直接轉發到網路伺服器時,一切正常,所以可能是清漆配置有問題。這是我的配置:

Nginx config: 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);

}

這裡的問題很常見:您在應用程序級別執行重定向 http -> https。

Apache/PHP 不知道它們已經在 SSL 中執行,因為 apache 在 http 中執行(然後傳遞給 varnish,然後傳遞給 nginx)。

解決方案很簡單:您的 PHP 應用程序需要有 PHP ENV 變數$_SERVER['HTTPS'] = "on"

您可以通過不同的方式進行操作:

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

另外:我還會在清漆級別從 http 重定向到 https:添加一個自定義標頭,例如X-Nginx = on當請求來自您的 nginx 時。在清漆中讀取該標頭,如果它不存在,則將使用者重定向到 https URL。

注意:如果您使用的是 wordpress(如您的 vcl 文件中所示),請不要忘記添加:

define('FORCE_SSL_ADMIN', true);

引用自:https://serverfault.com/questions/858203