EpicCDN
By:
EpicCDN

Nginx trowing error Error 400 Bad Request on Varnish

November 12, 2014 2.3k views

Hello, pretty weird thing is happening to one of my sites, I use Nginx 1.6.2 and everything works normal, but visitors who come from Varnish nodes (on another servers) receive some intermittent error 400 Bad Request.

If I modify my hosts file to point my domain directly to Nginx there is no error, if I pass trough Varnish as normal y get error 400 bad request (from Nginx) from time to time, so my guess is there is something wrong on Varnish.

Any Idea where to start?

Here my config:
Varnish default.vcl

vcl 4.0;

backend default {
    .host = "23.23.143.32";
    .port = "80";
    .probe = {
        .url = "/";
        .timeout = 1000ms;
        .interval = 5s;
        .window = 10;
        .threshold = 8;
    }
}

backend backup {
    .host = "23.23.143.32";
    .port = "80";
    .probe = {
        .url = "/";
        .timeout = 1000ms;
        .interval = 5s;
        .window = 10;
        .threshold = 8;
    }
}

backend espejo {
    .host = "54.163.206.168";
    .port = "80";
    .probe = {
        .url = "/";
        .timeout = 1000ms;
        .interval = 5s;
        .window = 10;
        .threshold = 8;
    }
}

import directors;    # load the directors
sub vcl_init {
    new cluster1 = directors.random(); #use .random() for weight, round_robin() for equal load balancing.
    cluster1.add_backend(default,10);  #use (default,weight); with .random() ie: (default,2); (backup,1); = 2/3 to default, 1/3 to backup backend.
    cluster1.add_backend(backup,0);
}

# Routine to identify and classify a device based on User-Agent
sub identify_device {

  # Default to classification as a PC
  set req.http.X-Device = "pc";

  if (req.http.User-Agent ~ "iPad" ) {
    # The User-Agent indicates it's a iPad - so classify as a tablet
    set req.http.X-Device = "mobile-tablet";
  }

  elsif (req.http.User-Agent ~ "iP(hone|od)" || req.http.User-Agent ~ "Android" || req.http.User-Agent ~ "Mobile.+Firefox") {
    # The User-Agent indicates it's a iPhone, iPod or Android - so let's classify as a touch/smart phone
    set req.http.X-Device = "mobile-smart";
  }

  elsif (req.http.User-Agent ~ "SymbianOS" || req.http.User-Agent ~ "^BlackBerry" || req.http.User-Agent ~ "^SonyEricsson" || req.http.User-Agent ~ "^Nokia" || req.http.User-Agent ~ "^SAMSUNG" || req.http.User-Agent ~ "^LG")        {
    # The User-Agent indicates that it is some other mobile devices, so let's classify it as such.
    set req.http.X-Device = "mobile-other";
  }
}

sub vcl_recv {
    call identify_device;

    # send all traffic to the cluster1 director:
    set req.backend_hint = cluster1.backend();

    if (req.http.host == "espejo.na.com") {
        set req.backend_hint = espejo;
    }

    if (req.method == "GET" || req.method == "HEAD") {
        return (hash);
    }

    if (req.http.User-Agent ~ "(?i)ipad") {
        return (hash);
    }

    # Add header for sending client ip to backend
    set    req.http.X-Forwarded-For = client.ip;

    # Remove has_js and CloudFlare/Google Analytics __* cookies.
    set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
    # Remove a ";" prefix, if present.
    set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");

    # Remove cookies and query string for real static files
    if (req.url ~ "^/[^?]+\.(gif|jpg|jpeg|swf|css|js|txt|flv|mp3|mp4|pdf|ico|png|gz|zip|lzma|bz2|tgz|tbz)(\?.*|)$") {
       unset req.http.cookie;
       set req.url = regsub(req.url, "\?.*$", "");
    }

    # Don't cache admin
#    if (req.url ~ "((wp-(login|admin|comments-post.php|cron.php))|login)" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php" || req.url ~ "on.gamemode.es/" || req.url ~ "phpMyAdmin" || req.url ~ "foro" || req.url ~ "contactform.php") {
#        return (pass);
#    } else {
#        unset req.http.cookie;
#    }

    #Blocks some urls
    if (req.url ~ "(wp-(login|admin))|login") {
        return (synth(405, "Su computador no esta dirigido al servidor correcto, contacte a TI por ayuda."));
    }

}

sub vcl_backend_response {
    # Dont cache admin
    if (bereq.url ~ "(wp-(login|admin|comments-post.php|cron.php))|login" || bereq.url ~ "preview=true" || bereq.url ~ "xmlrpc.php" || bereq.url ~ "on.gamemode.es/" || bereq.url ~ "phpMyAdmin" || bereq.url ~ "foro" || bereq.url ~ "contactform.php") {
        set beresp.uncacheable = true;
        set beresp.ttl = 120s;
        return (deliver);
    } else {
        if ( beresp.ttl > 0s ) {
            unset beresp.http.set-cookie;
        }
        # Our cache TTL
        set beresp.ttl = 10s;
        set beresp.grace = 24h; 
        return(deliver);
    }

    if (beresp.status == 404 || beresp.status >= 500) {
        set beresp.ttl   = 0s;
        set beresp.grace = 24h;
    }
}

sub vcl_hash {
# If the device has been classified as any sort of mobile device, include the User-Agent in the hash
# However, do not do this for any static assets as our web application returns the same ones for every device.
  if (!(req.url ~ ".(gif|jpg|jpeg|swf|flv|mp3|mp4|pdf|ico|png|gz|tgz|bz2)$")) {
    hash_data(req.http.X-Device);
  }
}

1 comment
  • So It happens to be a error caused by a pluggin on wordpress, funny thing is it only happens trough Varnish and not connected to Nginx directly as commented abode. While the problem is solved, I still wondering why such behavior.

1 Answer

Same problem here with nginx+varnis+ezpublish CMS.

Any idea?

  • I can't remember which plugin was, but it was caused by a WP plugin, in your case maybe is something similar from your CMS.

Have another answer? Share your knowledge.