Linux
nginx + varnish + SSL中的重定向過多
我有一個集群基礎設施。我在清漆前使用 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);