在nginx + varnish + SSL中错误太多的redirect

我有一个集群基础结构。 我使用nginx在清漆前面进行SSL终止。 varnish的后端是apache web服务器。我也有一个haproxy作为负载平衡器,它直接发送HTTPS请求到nginx,并直接发送HTTP请求到清漆服务器。 问题是,当我启动nginx时,一切都可以,但是在浏览ssl网站的浏览器中,我得到了too_many_error_redirects! 我认为我的configuration有问题,但我不知道哪个configuration(nginx或varnish)是这个错误的原因。 当我直接向Web服务器转发请求时,一切正常,因此可能是清漆configuration有问题。 这里是我的configuration:
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; } 

清漆configuration:

 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); } 

这里的问题非常普遍:你在应用程序级别上redirecthttp – > https。

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

解决scheme很简单:您的PHP应用程序需要PHP ENVvariables$_SERVER['HTTPS'] = "on"

你可以用不同的方式做:

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

另外:我也会做一个从http到https的清晰度级别的redirect:当请求来自你的nginx时,添加一个像X-Nginx = on的自定义标题。 在清漆读取头,如果它不存在,然后redirect到https URL的用户。

注意:如果你使用wordpress(就像在你的vcl文件中),不要忘记添加这个:

 define('FORCE_SSL_ADMIN', true);