我有一个集群基础架构。我在 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);