Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I've been at this for hours and I can't figure out a clean solution.

Basically, I have an nginx proxy setup, which works really well, but I'd like to handle a few urls more manually. Specifically, there are 2-3 locations for which I'd like to set proxy_ignore_headers to Set-Cookie to force nginx to cache them (nginx doesn't cache responses with Set-Cookie as per http://wiki.nginx.org/HttpProxyModule#proxy_ignore_headers).

So for these locations, all I'd like to do is set proxy_ignore_headers Set-Cookie;

I've tried everything I could think of outside of setting up and duplicating every config value, but nothing works.

I tried:

  • Nesting location directives, hoping the inner location which matches on my files would just set this value and inherit the rest, but that wasn't the case - it seemed to ignore anything set in the outer location, most notably proxy_pass and I end up with a 404).
  • Specifying the proxy_cache_valid directive in an if block that matches on $request_uri, but nginx complains that it's not allowed ("proxy_cache_valid" directive is not allowed here).
  • Specifying a variable equal to "Set-Cookie" in an if block, and then trying to set proxy_cache_valid to that variable later, but nginx isn't allowing variables for this case and throws up.

It should be so simple - modifying/appending a single directive for some requests, and yet I haven't been able to make nginx do that.

What am I missing here?

Is there at least a way to wrap common directives in a reusable block and have multiple location blocks refer to it, after adding their own unique bits?

Thank you.

Just for reference, the main location / block is included below, together with my failed proxy_ignore_headers directive for a specific URI.

location / {
  # Setup var defaults
  set $no_cache "";

  # If non GET/HEAD, don't cache & mark user as uncacheable for 1 second via cookie
  if ($request_method !~ ^(GET|HEAD)$) {
    set $no_cache "1";
  }

  if ($http_user_agent ~* '(iphone|ipod|ipad|aspen|incognito|webmate|android|dream|cupcake|froyo|blackberry|webos|s8000|bada)') {
    set $mobile_request '1';
    set $no_cache "1";
  }

  # feed crawlers, don't want these to get stuck with a cached version, especially if it caches a 302 back to themselves (infinite loop)
  if ($http_user_agent ~* '(FeedBurner|FeedValidator|MediafedMetrics)') {
    set $no_cache "1";
  }

  # Drop no cache cookie if need be
  # (for some reason, add_header fails if included in prior if-block)
  if ($no_cache = "1") {
    add_header Set-Cookie "_mcnc=1; Max-Age=17; Path=/";
    add_header X-Microcachable "0";
  }

  # Bypass cache if no-cache cookie is set, these are absolutely critical for Wordpress installations that don't use JS comments
  if ($http_cookie ~* "(_mcnc|comment_author_|wordpress_(?!test_cookie)|wp-postpass_)") {
    set $no_cache "1";
  }

  if ($request_uri ~* wpsf-(img|js)\.php) {
    proxy_ignore_headers Set-Cookie;
  }

  # Bypass cache if flag is set
  proxy_no_cache $no_cache;
  proxy_cache_bypass $no_cache;

  # under no circumstances should there ever be a retry of a POST request, or any other request for that matter
  proxy_next_upstream off;
  proxy_read_timeout 86400s;

  # Point nginx to the real app/web server
  proxy_pass http://localhost;

  # Set cache zone
  proxy_cache microcache;

  # Set cache key to include identifying components
  proxy_cache_key $scheme$host$request_method$request_uri$mobile_request;

  # Only cache valid HTTP 200 responses for this long
  proxy_cache_valid 200 15s;

  #proxy_cache_min_uses 3;

  # Serve from cache if currently refreshing
  proxy_cache_use_stale updating timeout;

  # Send appropriate headers through
  proxy_set_header Host $host;
  # no need for this proxy_set_header X-Real-IP $remote_addr;
  # no need for this proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  # Set files larger than 1M to stream rather than cache
  proxy_max_temp_file_size 1M;

  access_log /var/log/nginx/androidpolice-microcache.log custom;
}
share|improve this question
    
The comment for proxy_max_temp_file_size in your config file is incorrect -- that directive won't prevent a file from being cached.... –  user134155 Aug 30 '12 at 20:47

1 Answer 1

After trying literally 10 different things and consulting with Fenn Bailey of http://fennb.com, I have to resort to the include solution, which seems to be the only thing that avoids code duplication and actually works.

I moved all directives from location / {} into their own file and did this:

location / {
  include /etc/nginx/vhosts/androidpolice-root.conf;
}

location ~* wpsf-(img|js)\.php {
  include /etc/nginx/vhosts/androidpolice-root.conf;
  proxy_ignore_headers "Set-Cookie" "Cache-Control";
}

At this point I'm quite shocked by nginx's inflexibility when it comes to ifs and conditionals - these things should be so trivial, yet they're not.

By the way, I'm on the latest nginx 1.1.17.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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