# Fastcgi\_cache\_bypass and 502 Bad Gateway

**URL:** <https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006>\
**Category:** NGINX\
**Created:** [February 10, 2011, 1:10pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006 "2011-02-10T13:10:22Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [February 10, 2011, 1:10pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/1 "2011-02-10T13:10:22Z")

</div>

Using Nginx 0.8.54.

I’m trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to  
request a new response from the backend and cache it.

```auto
if ($http_cookie ~*
"comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
  set $donot_cache 1;
}

fastcgi_cache cachetitle;
fastcgi_cache_key $scheme$host$request_uri;
fastcgi_no_cache $donot_cache; # do no cache at all
fastcgi_cache_bypass $http_cache_bypass; # bypass cache and cache the
new response
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_cache_min_uses 1;
```

It does seem to work – I see a fresh page returned from the backend,  
but on the second request without the header I get a 502 Bad Gateway  
response.

I also noticed that on Nginx wiki page there is no reference to  
fastcgi\_cache\_bypass, although I saw it there just a few days ago.

Is this feature being removed or postponed for later? Is it available in  
the latest dev version?

Kaspars

> **[I build websites, software products and electronic devices.](https://kaspars.net/)**
>
> Read my blog, check out my projects and follow me on Youtube, Twitter, Instagram and GitHub....

Posted at Nginx Forum:

> **[fastcgi\_cache\_bypass and 502 Bad Gateway](https://forum.nginx.org/read.php?2,173795,173795#msg-173795)**
>
> Using Nginx 0.8.54. I'm trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to request a new response from the backend and cache it. \[code\] if ($http\_cookie ~\* "comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_" ) { set...

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 2:26pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/2 "2011-02-11T14:26:21Z")

</div>

Anyone using fastcgi\_cache\_bypass with success?

I have looked through the changelogs and have not seen it being removed  
as a feature. The documentation in russian still contains it, while the  
english wiki does not.

Kaspars

Posted at Nginx Forum:

> **[Re: fastcgi\_cache\_bypass and 502 Bad Gateway](https://forum.nginx.org/read.php?2,173795,174131#msg-174131)**
>
> Using Nginx 0.8.54. I'm trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to request a new response from the backend and cache it. \[code\] if ($http\_cookie ~\* "comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_" ) { set...

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 4:18pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/3 "2011-02-11T16:18:04Z")

</div>

## kaspars Wrote:

> if ($http\_cookie ~\*  
> “comment\_author\_|wordpress\_(?!test\_cookie)|wp-post  
> pass\_” ) {  
> set $donot\_cache 1;  
> }

AFAIK, the '$donot\_cache ’ you set here will not contain anything  
outside the if block. and therefore your no\_cache test will always be  
done on an empty variable.

Variable scopes are not documented and only trial and error and fumbling  
in the dark reveals stuff.

Would be great if they just had global scopes so that once it is set, it  
is there to be used everywhere. However, I think I read something  
negative once on this from Maxim D. (who seems to be one of the  
devs) so I think no matter how much we might want this sort of thing, it  
will not happen.

A bit of a pain but that is how it is and most of us don’t know enough  
to fill in the gaps in the documentation.

I had a similar problem and had to use the 3rd party lua module to run  
the test in a way that the variable set was available after:  
[http://forum.nginx.org/read.php?2,161969,168394#msg-168394](http://forum.nginx.org/read.php?2,161969,168394#msg-168394)

In your case, why not just use ‘fastcgi\_no\_cache  
$cookie\_COOKIE-1$cookie\_COOKIE-2$cookie\_COOKIE-3’ and skip the whole  
‘if’ test?

The advice is to avoid using ‘if’ unless absolutely required. See:

> **[GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki...](https://github.com/nginxinc/nginx-wiki)**
>
> ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,173795,174161#msg-174161](http://forum.nginx.org/read.php?2,173795,174161#msg-174161)

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 5:33pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/4 "2011-02-11T17:33:15Z")

</div>

> AFAIK, the '$donot\_cache ’ you set here  
> will not contain anything outside the if block.

You are right, I forgot to put “set $donot\_cache = 0;” right before the  
if block, but it doesn’t seem to be the problem.

Everything is fine regarding the availability of those variables, and I  
verified it by adding them as an HTTP header to all responses.

> In your case, why not just use ‘fastcgi\_no\_cache  
> $cookie\_COOKIE-1$cookie\_COOKIE-2$cookie\_COOKIE-3’  
> and skip the whole ‘if’ test?

Because those cookie names change – they have random numbers appended  
to them, so I need to do a regex check for their prefixes.

I’ll be sure to post an update if I find something.

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,173795,174184#msg-174184](http://forum.nginx.org/read.php?2,173795,174184#msg-174184)

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 6:09pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/5 "2011-02-11T18:09:36Z")

</div>

[quote]$test will always be equal to 0 as any variable set within the  
‘if’ block is not exposed outside the block AFAIK.[/quote]

No. I am already using this check successfully for the fastcgi\_no\_cache  
rule.

The real problem is with the _fastcgi\_cache\_bypass_. My understanding is  
that if “fastcgi\_cache\_bypass 1”, then Nginx will request a fresh  
response from the backend and cache that response for further use where  
“fastcgi\_cache\_bypass 0”.

Is that how fastcgi\_cache\_bypass should work?

Posted at Nginx Forum:

> **[Re: fastcgi\_cache\_bypass and 502 Bad Gateway](https://forum.nginx.org/read.php?2,173795,174194#msg-174194)**
>
> Using Nginx 0.8.54. I'm trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to request a new response from the backend and cache it. \[code\] if ($http\_cookie ~\* "comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_" ) { set...

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 5:59pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/6 "2011-02-11T17:59:33Z")

</div>

The point I was trying to make is that in this case for instance, …

```auto
set $donot_cache 0;
if ($http_cookie ~*
"comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
  set $donot_cache 1;
}
set $test $donot_cache;
```

… $test will always be equal to 0 as any variable set within the ‘if’  
block is not exposed outside the block AFAIK.

So when you run …

```auto
set $donot_cache 0;
if ($http_cookie ~*
"comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
  set $donot_cache 1;
}
...
fastcgi_no_cache $donot_cache;
```

… ‘$donot\_cache’ will always resolve to null.

Again, this is AFAIK based on stuff I have read here and there.

See here for instance:

> **[Module vars set inside if's are not set](https://forum.nginx.org/read.php?2,25197,25197#msg-25197)**
>
> Variables that are used by modules and are set inside 'if' blocks in the nginx.conf file are not being set correctly. My nginx version (-V output) is: nginx version: nginx/0.7.64 built by gcc 4.3.3 (Ubuntu 4.3.3-5ubuntu4) TLS SNI support enabled...

Posted at Nginx Forum:

> **[Re: fastcgi\_cache\_bypass and 502 Bad Gateway](https://forum.nginx.org/read.php?2,173795,174192#msg-174192)**
>
> Using Nginx 0.8.54. I'm trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to request a new response from the backend and cache it. \[code\] if ($http\_cookie ~\* "comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_" ) { set...

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 6:53pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/7 "2011-02-11T18:53:30Z")

</div>

## kaspars Wrote:

> My understanding is that  
> if “fastcgi\_cache\_bypass 1”, then Nginx will  
> request a fresh response from the backend and  
> cache that response for further use where  
> “fastcgi\_cache\_bypass 0”.
> 
> Is that how fastcgi\_cache\_bypass should work?

No idea as it is not documented in the English docs and I can’t read  
Russian.

Assuming it works like the proxy version though (and the English  
documentation for that is really unclear as it seems to suggest to just  
use the ‘cache\_bypass’ version and forget about the ‘no\_cache’ version),  
then my understanding is:

1. ?\_no\_cache = get from backend but cache response
2. ?\_cache\_bypass = do not cache response

So if you want to bypass the cache and also not cache that response,  
then you should be using the two together.

Note though that as said, the English documentation does not state this  
but again I think I have read Igor posting this somewhere.

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,173795,174207#msg-174207](http://forum.nginx.org/read.php?2,173795,174207#msg-174207)

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 10:21pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/8 "2011-02-11T22:21:33Z")

</div>

> This is known issue and I believe Igor worked on patching this.  
> Avoid using different _\_cache\_bypass/_\_no\_cache until this is  
> fixed.

Thanks, Maxim! That’s good to know.

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,173795,174250#msg-174250](http://forum.nginx.org/read.php?2,173795,174250#msg-174250)

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 10:56pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/9 "2011-02-11T22:56:37Z")

</div>

On 11 Fev 2011 16h57 WET, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> [/code]  
> set $donot\_cache 1;  
> }

This is because as Maxim, and agentzh have explained before: an if is  
an _implicit location_. So what you’re requesting above is for a  
variable with a value changed at a lower level (implicit location) be  
visible at an upper level (containing location).

My understanding of Nginx scoping is that it works in one direction,  
i.e., you can only be sure that this works global → http → server →   
location → if in location.

There’s no reverse path for inheriting variables set at a lower level  
on a higher level.

Can someone more knowledgeable than I concur and straighten me if I’m  
incorrect?

Thanks,  
— appa

…

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 12, 2011, 1:07am UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/10 "2011-02-12T01:07:59Z")

</div>

Hello!

On Fri, Feb 11, 2011 at 09:49:54PM +0000, António P. P. Almeida wrote:

> > }  
> > if ($http\_cookie ~\*  
> > My understanding of Nginx scoping is that it works in one direction,  
> > i.e., you can only be sure that this works global → http → server →   
> > location → if in location.
> 
> There’s no reverse path for inheriting variables set at a lower level  
> on a higher level.
> 
> Can someone more knowledgeable than I concur and straighten me if I’m  
> incorrect?

You are incorrect. Variables are property of request. They are  
either set during request processing or not, and if set - they are  
visible to all operations with request.

Maxim D.

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 11, 2011, 7:07pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/11 "2011-02-11T19:07:17Z")

</div>

Hello!

On Fri, Feb 11, 2011 at 12:07:52PM -0500, kaspars wrote:

> Is that how fastcgi\_cache\_bypass should work?

Yes, it’s how it should work. But this isn’t really how it works  
now - due to bug behaviour is undefined if fastcgi\_cache\_bypass  
isn’t the same as fastcgi\_no\_cache (and the same applies to  
proxy\_cache\_bypass/proxy\_no\_cache and so on).

This is known issue and I believe Igor worked on patching this.  
Avoid using different _\_cache\_bypass/_\_no\_cache until this is  
fixed.

Maxim D.

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 12, 2011, 1:28am UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/12 "2011-02-12T01:28:27Z")

</div>

On 12 Fev 2011 00h06 WET, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hello!

> You are incorrect. Variables are property of request. They are  
> either set during request processing or not, and if set - they are  
> visible to all operations with request.

So there’s no concept of scope in the usual programming language  
sense. It just depends on the request. If the request visits all  
locations where variables are set, then the values are set  
independently of the context level at which the assignment  
instructions exist.

Is this correct?

Thanks,  
— appa

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 12, 2011, 10:17am UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/13 "2011-02-12T10:17:19Z")

</div>

## António P. P. Almeida Wrote:

> Is this correct?  
> I think this is correct but this to me essentially create a variable  
> scope since as Maxim has explained elsewhere, the if block creates a  
> nested location block and since only one location block is processed in  
> the request flow, things set in there may not be visible, to the rest of  
> the flow.

The problem is know what exactly is visible after and what is not.

So far, according to the ifisevil page, it seems ‘return’, and rewrite  
commands are safe but anything else may result in errors.

It may be the case that ‘set’ is safe too and a list of what is and  
isn’t would be really great.

For me, I just use the two listed stuff on the ifisevil page (return and  
rewrites) and agetnzh’s lua module to do other if tests.

To the OP, perhaps try using the same variable on both fastcgi params  
which from Maxim’s explanation, is not susceptible to the bug.

fastcgi\_no\_cache $http\_cache\_bypass; # do no cache at all  
fastcgi\_cache\_bypass $http\_cache\_bypass; # bypass cache \<— Not sure  
how you get the user’s browser to send this header

At a suitable point in your application, you could also do something  
like  
EQUIVALENT-OF if ($http\_cookie ~\*  
“comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_” ) {  
header(Cache-Control: private, no-store, no-cache);  
}  
so that nginx will not cache the response.

Basically, try to share the load between the application and nginx.

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,173795,174371#msg-174371](http://forum.nginx.org/read.php?2,173795,174371#msg-174371)

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 13, 2011, 3:20pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/14 "2011-02-13T15:20:03Z")

</div>

[quote]fastcgi\_no\_cache $http\_cache\_bypass; # do no cache at all  
fastcgi\_cache\_bypass $http\_cache\_bypass; # bypass cache \<— Not sure  
how you get the user’s browser to send this header[/quote]

On each page I would have an AJAX call to a very small PHP script that  
checks for the cache version number and makes a GET (or HEAD) request  
with Cache-Bypass header if the page needs to be regenerated.

The idea is similar to the one described here:  
[http://konstruktors.com/blog/wordpress/2521-ajax-cache-purge-cookie-plugin/](http://konstruktors.com/blog/wordpress/2521-ajax-cache-purge-cookie-plugin/)

But instead of using a version number for cache key (set by a cookie), I  
would use it for cache invalidation.

Posted at Nginx Forum:

> **[Re: fastcgi\_cache\_bypass and 502 Bad Gateway](https://forum.nginx.org/read.php?2,173795,174729#msg-174729)**
>
> Using Nginx 0.8.54. I'm trying to use fastcgi\_cache\_bypass with an HTTP header for Nginx to request a new response from the backend and cache it. \[code\] if ($http\_cookie ~\* "comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_" ) { set...

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 14, 2011, 5:41am UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/15 "2011-02-14T05:41:19Z")

</div>

On Sat, Feb 12, 2011 at 8:21 AM, Antnio P. P. Almeida [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> So there’s no concept of scope in the usual programming language  
> sense. It just depends on the request. If the request visits all  
> locations where variables are set, then the values are set  
> independently of the context level at which the assignment  
> instructions exist.
> 
> Is this correct?

Correct as long as the “request” in your context is an _atomic_  
request, that is, excluding any subrequests that it issues directly or  
indirectly.

Even though by default, nginx subrequests also _share_ all the  
variables of the parent requests (as well as all of its siblings), and  
ngx\_auth\_request, ngx\_eval, ngx\_addition, and ngx\_ssi all follow this  
default behavior, some notable exceptions, however, exist in the wild.

Almost all of _our_ nginx modules, for example, disable the sharing  
because of potential bad effects similar to use of global variables in  
a general-purpose programming language. Our ngx\_echo, ngx\_srcache, and  
ngx\_lua modules fall into this category, just to name a few 🙂

Cheers,  
-agentzh

---

<div class="post-metadata">

**Author:** ![kaspars](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/57b2e6/32.png) [@kaspars](https://www.ruby-forum.com/u/kaspars)\
**Post date:** [February 12, 2011, 1:49pm UTC](https://www.ruby-forum.com/t/fastcgi-cache-bypass-and-502-bad-gateway/203006/16 "2011-02-12T13:49:33Z")

</div>

On 12 Fev 2011 09h15 WET, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > instructions exist.  
> > So far, according to the ifisevil page, it seems ‘return’, and  
> > bug.
> 
> fastcgi\_no\_cache $http\_cache\_bypass; # do no cache at all  
> fastcgi\_cache\_bypass $http\_cache\_bypass; # bypass cache \<— Not  
> sure how you get the user’s browser to send this header

Hmm, IIRC I’ve read somewhere that (some?) fastcgi directives do  
behave like a “standard” programming language thing in the sense  
there’s a scope and the usual rules apply. But I may be wrong. It  
would be great if Igor, Maxim or agentzh could elaborate further and  
help put this issue to rest, at least make it clear what’s a hack, and  
what’s not hack, i.e., behaves much more in the declarative language  
sense than in the imperative programming sense.

> At a suitable point in your application, you could also do something  
> like  
> EQUIVALENT-OF if ($http\_cookie ~\*  
> “comment\_author\_|wordpress\_(?!test\_cookie)|wp-postpass\_” ) {  
> header(Cache-Control: private, no-store, no-cache);  
> }  
> so that nginx will not cache the response.

Or send the ‘X-Accel-Expire: 0’ header.

— appa
