nginx: How can I set proxy_* directives only for matching URIs?

Posted by Artem Russakovskii on Server Fault See other posts from Server Fault or by Artem Russakovskii
Published on 2012-03-26T00:53:08Z Indexed on 2012/03/26 5:31 UTC
Read the original article Hit count: 669

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

© Server Fault or respective owner

Related posts about nginx

Related posts about proxy