0

I have a clustered infrastructure. I use nginx for SSL termination in front of varnish. The backends of varnish are apache web servers.and I also have a haproxy as a load balancer which sends HTTPS requests directly to nginx and sends HTTP requests directly to varnish servers. The problem is that when I start nginx everything is OK for some while, but after that I get the too_many_error_redirects in browsers when browsing ssl websites!! I think there is something wrong with my configurations, but I don't know which configurations (nginx or varnish) are the cause of this error. When I forward requests directly to the webservers everything is OK, so may be the varnish config has problem. here are my configurations:
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;
}

Varnish config:

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

}
  • Ask yourself, where in your stack did you configure redirects from HTTP to HTTPS? :) Based on the given configuration the redirects happen at application level. So you should forward info from Nginx (SSL level) and drill it down to app level and not do any redirects when SSL flag is set. – Danila Vershinin Jun 27 '17 at 19:27
0

The problem here is very common: you're doing redirect http -> https at application level.

Apache/PHP don't know they are already running in SSL, as apache is running in http (then passing to varnish, then passing to nginx).

The solution is simple: your PHP Application needs to have the PHP ENV variable $_SERVER['HTTPS'] = "on".

You can do in different ways:

  • in httpd.conf using apache SetEnv,
  • in .htaccess using again SetEnv
  • in your php scripts.

Plus: I would also do a redirect from http to https at varnish level: add a custom header like X-Nginx = on when request come from your nginx. In varnish read that header, if it doesn't exist, then redirect the user to https URL.

NOTE: If you're using wordpress (as it seems in your vcl file) don't forget to add this:

define('FORCE_SSL_ADMIN', true);
  • Thank you @Giorgio Marziani. I have added the php ENV variable to the apache configuration file by adding the line "SetEnvIf X-Forwarded-Proto "^https$" HTTPS=on" to all backends. For the next part, I don't know how to do that. May you please tell me how to define a custom header and the requreid codes in varnish? Thanks in advanced. – Sinai Jun 28 '17 at 13:25
  • The next part is not required, are you still experiencing the issue? – Giorgio Marziani de Paolis Jun 28 '17 at 13:28
  • Yes. I have added the SetENVIf line before I ask the question here. As I said, when I forward requests directly to web servers everything is OK (which is running at the moment). The problem occurs when I forwards https requests to varnish! – Sinai Jun 28 '17 at 13:53
  • did you flush your varnish cache after the fix of setenv? – Giorgio Marziani de Paolis Jun 28 '17 at 14:02
  • No I did'nt. Should I restart varnish? – Sinai Jun 28 '17 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.