Search code examples
varnishvarnish-vcl

Varnish round-robin load balancing with Named Vhosts


Actually my set up looks like this.

cluster.com - 192.168.0.200 (varnish/port 80)
example.com - 192.168.0.100  (apache,namebased vhost/8080 - backendname - website)
yyy.com - 192.168.0.100  (apache,namebased vhost/8080 -backendname - api)

cluster.com is the varnish server and front-end connections coming to this and rewrite to other defined back-ends (round-robin based balancing)

    backend website     {
    .host = "example.com";
    .port = "8080";

         }
    backend api     {
       .host = "yyy.com";
        .port = "8080";

      }

     director clust round-robin     {
          { .backend = api;  }
          { .backend = website;  }

          }

        sub vcl_recv    {
        set req.backend = clust;
        if (req.request)
         {
         return(pass);
         }

         }


when i hit the cluster.com , it is always going to example.com, but what i need to do is first request go to example.com second request yyy.com and so on...when i add another server (different host/different IP say 192.168.0.111/zzz.com, and a different backend) , it goes like this

first request - example.com
second request - examplee.com
third request - zzz.com


but i can change the default behavior by setting up set req.host = yyy.com and then it will      goes to
first request - yyy.com
  second request - yyy.com
   third request - zzz.com

this is something to do with the host-header forwarding to the correct back-end. how should i add that functionality to the vcl_recv ? appreciate your help on this, this is working perfectly with other servers (different servers, not with namebased vhosts)


Solution

  • You don't need to worry about Host headers, since varnish backend selection doesn't use it.

    So, you only need a backend declaration for 192.168.0.100:8080 (since Apache will take care of named virtual hosts). NOTE: The host header in request should contain a defined Apache ServerName/ServerAlias

    So if 192.168.0.111 can resolve both example.com and yyy.com but 192.168.0.100 can't resolve zzz.com , you only need to deal with backend choosing:

    # As both your defined backends resolve to the same IP and port,
    #you only need to define ONE backend instead of two
    backend website_and_api {
      # Which resolves both example.com and yyy.com
      .host = "192.168.0.100";
      .port = "8080";
    }
    # The server you add later on
    backend third {
      # Which resolves all example.com, yyy.com and zzz.com
      .host = "192.168.0.111";
      .port = "8080";
    }
    
    director clust round-robin {
      #Backends that resolve both example.com and yyy.com
      { .backend = website_and_api; }
      { .backend = third; }
    }
    
    sub vcl_rec {
      # Set the default backend, I'll choose two since it resolves most domains
      set req.backend = third;
      # Choose clust if the domain is appropiate
      if ( req.http.host ~ "example.com"
        || req.http.host ~ "yyy.com") {
        set req.backend = clust;
      }
      # Any return must be done below here
      # ...
    }
    

    PS: VCL edited and expanded trying to clarify a bit

    This will work fine given:

    1. The client pass the correct Host header in the request (example.com|yyy.com|zzz.com)
    2. Server 192.168.0.100 is correctly set up to handle Named virtual hosting:
      • Apache resolves example.com:8080
      • Apache resolves yyy.com:8080
      • Apache gives a sensible default for 192.168.0.100:8080
    3. Server 192.168.0.111 is correctly set up to handle Named virtual hosting:
      • Apache resolves example.com:8080
      • Apache resolves yyy.com:8080
      • Apache resolves zzz.com:8080
      • Apache gives a sensible default for 192.168.0.100:8080
    4. Your VCL code don't mess received Host header (don't set it to another thing)