nginx proxy cache 使用及常见问题
2019-04-24 22:17:41 阿炯

nginx的proxy_cache缓存用于反向代理时,对后端内容资源服务器进行缓存,缓存静态资源。nginx位于客户端和“原始服务器(origin server)”中间,它保留了所有可见内容的拷贝。如果一个客户端请求的内容在缓存中存储,则可以直接在缓存中获得该内容而不需要与服务器通信。这样一来,由于web缓存距离客户端“更近”,就可以提高响应性能,并更有效率的使用应用服务器,因为服务器不用每次请求都进行页面生成工作。

在浏览器和应用服务器之间,存在多种“潜在”缓存,如:客户端浏览器缓存、中间缓存、内容分发网络(CDN)和服务器上的负载平衡和反向代理。缓存,仅在反向代理和负载均衡的层面,就对性能提高有很大的帮助。

nginx从0.7.48版本开始,支持了类似Squid的缓存功能。这个缓存是把URL及相关组合当作Key,用md5编码哈希后保存在硬盘上,所以它可以支持任意URL链接,同时也支持404/301/302这样的非200状态码。虽然目前官方的nginxWeb缓存服务只能为指定URL或状态码设置过期时间,不支持类似Squid的PURGE指令,手动清除指定缓存页面,但是,通过一个第三方的nginx模块,可以清除指定URL的缓存。

nginx的Web缓存服务主要由proxy_cache相关指令集和fastcgi_cache相关指令集构成,前者用于反向代理时,对后端内容源服务器进行缓存,后者主要用于对FastCGI的动态程序进行缓存。两者的功能基本上一样。从 0.8.32版本,proxy_cache和fastcgi_cache已经比较完善,加上第三方的ngx_cache_purge模块(用于清除指定URL的缓存),已经可以完全取代Squid,速度不逊于 Squid。

在功能上,nginx已经具备Squid所拥有的Web缓存加速功能、清除指定URL缓存的功能。而在性能上,nginx对多核CPU的利用,胜过Squid不少。另外,在反向代理、负载均衡、健康检查、后端服务器故障转移、Rewrite重写、易用性上,nginx也比Squid强大得多。这使得一台nginx可以同时作为“负载均衡服务器”与“Web缓存服务器”来使用。

nginx的proxy_cache可以通过缓存首部Cache-Control和Expires进行代理缓存,但是有个参数proxy_cache_revalidate on;可以有效减少报文的传输。在说这个之前,先看下原理。在HTTP协议中If-Modified-Since和If-None-Match分别对应Last-Modified和ETag。结合Expires为缓存的方式实现减少传输报文的场景。按照RFC2616对HTTP协议的规定,在客户端第二次向服务器发出请求时,对于第一次访问请求的资源如果响应状态为200的资源,那么在这次请求中将会添加一个新的请求头:If-Modified-Since,故名思议,就是询问服务器从这个时间起,或者说是以这个时间为分割点,在这时间点之前有没有修改过这个文档,如果没有修改,那么返回的http状态代码是304;并且同时再次发回响应头Last-Modified,而且这两个头的时间完全相同的。

在计算Etag的时候,会产生CPU的耗费,所以也可以用时间戳,但这样直接使用Last-Modified即可。在同时使用Expires和Etag时,没有优先级,在满足两者时才会做出决定。在http的Response的首部中,有transfer-coding域值为chunked则无法使用304的原理。在tomcat中禁用的方法就是设置返回的缓存,只要返回数据小于这个缓存,则不会开启。


proxy_cache相关指令说明

1.proxy_cache指令
语法:proxy_cache zone_name;
默认值:none
使用配置段:http,server,location
该指令用于设置哪个缓存区将被使用,zone_name的值为proxy_cache_path指令创建的缓存区名称

2.proxy_cache_path指令
语法:proxy_cache_path  path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];
默认值:none
使用配置段:http
该指令用于设置缓存文件的存放路径

proxy_cache_path /usr/local/nginx-1.6/proxy_cache  levels=1:2  keys_zone=cache_one:100m inactive=2d  max_size=2g;

levels指定该缓存空间有两层hash目录,第一层目录为1个字母,第二层为2个字母

keys_zone参数设置这个缓存区的名称和内存缓存空间大小

inactive参数设置数据多长时间没有被访问将删除

max_size参数设置硬盘缓存空间大小

3.proxy_cache_methods指令
语法:proxy_cache_methods  [GET HEAD POST];
默认值:proxy_cache_methods  GET HEAD POST;
使用配置段:http,server,location
该指令用于设置缓存哪些HTTP方法

4.proxy_cache_min_uses指令
语法:proxy_cache_min_uses number;
默认值:proxy_cache_min_uses 1;
使用配置段:http,server,location
该指令用于设置缓存的最小使用次数

5.proxy_cache_valid指令
语法:proxy_cache_valid
默认值:none
使用配置段:http,server,location
该指令用于对不同返回状态码的URL设置不同的缓存时间

例如,设置200、302状态的URL缓存10分钟,404状态的URL缓存1分钟,不指定状态码表示200、301、302

proxy_cache_valid  200  302   10m;
proxy_cache_valid  404    1m;
proxy_cache_valid  5m;
proxy_cache_valid  any  1m;  其余没有定义的状态码,

6.proxy_cache_key指令
语法:proxy_cache_key  line;
默认值:none
使用配置段:http,server,location
该指令用来设置web缓存的key值,nginx根据key值MD5哈希存储缓存,根据域名、请求路径等变量

proxy_cache_key  $host$uri$is_args$args;


我们只需要两个命令就可以启用基础缓存: proxy_cache_path和proxy_cache,proxy_cache_path用来设置缓存的路径和配置,proxy_cache用来启用缓存。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
use_temp_path=off;

proxy_cache_path命令中的参数及对应配置说明如下:

1.用于缓存的本地磁盘目录是/path/to/cache/

2.levels在/path/to/cache/设置了一个两级层次结构的目录。将大量的文件放置在单个目录中会导致文件访问缓慢,所以针对大多数部署,我们推荐使用两级目录层次结构。如果levels参数没有配置,则nginx会将所有的文件放到同一个目录中。

3.keys_zone设置一个共享内存区,该内存区用于存储缓存键和元数据,有些类似计时器的用途。将键的拷贝放入内存可以使nginx在不检索磁盘的情况下快速决定一个请求是HIT还是MISS,这样大大提高了检索速度。一个1MB的内存空间可以存储大约8000个key,那么上面配置的10MB内存空间可以存储差不多80000个key。

4.max_size设置了缓存的上限(在上面的例子中是10G)。这是一个可选项;如果不指定具体值,那就是允许缓存不断增长,占用所有可用的磁盘空间。当缓存达到这个上线,处理器便调用cache manager来移除最近最少被使用的文件,这样把缓存的空间降低至这个限制之下。

5.inactive指定了项目在不被访问的情况下能够在内存中保持的时间。在上面的例子中,如果一个文件在60分钟之内没有被请求,则缓存管理将会自动将其在内存中删除,不管该文件是否过期。该参数默认值为10分钟(10m)。注意,非活动内容有别于过期内容。nginx不会自动删除由缓存控制头部指定的过期内容(本例中Cache-Control:max-age=120)。过期内容只有在inactive指定时间内没有被访问的情况下才会被删除。如果过期内容被访问了,那么nginx就会将其从原服务器上刷新,并更新对应的inactive计时器。

6.nginx最初会将注定写入缓存的文件先放入一个临时存储区域, use_temp_path=off命令指示nginx将在缓存这些文件时将它们写入同一个目录下。我们强烈建议你将参数设置为off来避免在文件系统中不必要的数据拷贝。use_temp_path在nginx1.7版本和nginxPlus R6中有所介绍。

最终, proxy_cache命令启动缓存那些URL与location部分匹配的内容。你同样可以将proxy_cache命令添加到server部分,这将会将缓存应用到所有的那些location中未指定自己的proxy_cache命令的服务中。


旧缓存总比没有好

nginx内容缓存的一个非常强大的特性是:当无法从原始服务器获取最新的内容时,nginx可以分发缓存中的陈旧(stale,编者注:即过期内容)内容。这种情况一般发生在关联缓存内容的原始服务器宕机或者繁忙时。比起对客户端传达错误信息,nginx可发送在其内存中的陈旧的文件。nginx的这种代理方式,为服务器提供额外级别的容错能力,并确保了在服务器故障或流量峰值的情况下的正常运行。为了开启该功能,只需要添加proxy_cache_use_stale命令即可:
location / {
...
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
}

按照上面例子中的配置,当nginx收到服务器返回的error,timeout或者其他指定的5xx错误,并且在其缓存中有请求文件的陈旧版本,则会将这些陈旧版本的文件而不是错误信息发送给客户端。


缓存微调

nginx提供了丰富的可选项配置用于缓存性能的微调。下面是使用了几个配置的例子:
proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m
use_temp_path=off;
server {
    ...
location / {
    proxy_cache my_cache;
    proxy_cache_revalidate on;
    proxy_cache_min_uses 3;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_lock on;
    proxy_pass http://my_upstream;

}

配置解释如下:

proxy_cache_revalidate指示nginx在刷新来自服务器的内容时使用GET请求。如果客户端的请求项已经被缓存过了,但是在缓存控制头部中定义为过期,那么nginx就会在GET请求中包含If-Modified-Since字段,发送至服务器端。这项配置可以节约带宽,因为对于nginx已经缓存过的文件,服务器只会在该文件请求头中Last-Modified记录的时间内被修改时才将全部文件一起发送。在proxy_cache_revalidate设置为on的情况下:如果代理的缓存没有过期,则代理缓存可以直接返回304状态码,没有body如果代理缓存过期,则会向后端应用服务器验证,如果后端服务器返回304,则代理缓存继续使用。另外在proxy_cache中,当启用proxy_cache_min_uses最后一次缓存出发的时候,nginx服务器不会把304透传给应用服务器,而是直接获取最新的数据进行缓存,应用服务器返回200状态码。

proxy_cache_min_uses设置了在nginx缓存前,客户端请求一个条目的最短时间。当缓存不断被填满时,这项设置便十分有用,因为这确保了只有那些被经常访问的内容才会被添加到缓存中,该项默认值为1。

proxy_cache_use_stale中的updating参数告知nginx在客户端请求的项目的更新正在原服务器中下载时发送旧内容,而不是向服务器转发重复的请求。第一个请求陈旧文件的用户不得不等待文件在原服务器中更新完毕。陈旧的文件会返回给随后的请求直到更新后的文件被全部下载。

当proxy_cache_lock被启用时,当多个客户端请求一个缓存中不存在的文件(或称之为一个MISS),只有这些请求中的第一个被允许发送至服务器。其他请求在第一个请求得到满意结果之后在缓存中得到文件。如果不启用proxy_cache_lock,则所有在缓存中找不到文件的请求都会直接与服务器通信。


如何决定是否缓存

默认情况下,nginx需要考虑从原始服务器得到的Cache-Control标头。当在响应头部中Cache-Control被配置为Private,No-Cache,No-Store或者Set-Cookie,nginx不进行缓存。nginx仅仅缓存GET和HEAD客户端请求。可以参照下面的解答覆盖这些默认值。

1、Cache-Control头部可否被忽略?
可以,使用proxy_ignore_headers命令。如下列配置:
 
location /images/ {
    proxy_cache my_cache;
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30m;
    ...
}

nginx会忽略所有/images/下的Cache-Control头。proxy_cache_valid命令强制规定缓存数据的过期时间,如果忽略Cache-Control头,则该命令是十分必要的。nginx不会缓存没有过期时间的文件。

2、nginx能否缓存POST 请求?
可以,使用proxy_cache_methods命令:
proxy_cache_methods GET HEAD POST;

3、nginx可以缓存动态内容吗?
可以,提供的Cache-Control头部可以做到。缓存动态内容,甚至短时间内的内容可以减少在原始数据库和服务器中加载,可以提高第一个字节的到达时间,因为页面不需要对每个请求都生成一次。

4、可以使用Cookie作为缓存键的一部分吗?
可以,缓存键可以配置为任意值,如:
proxy_cache_key $proxy_host$request_uri$cookie_jessionid;

5、nginx如何处理字节范围请求?
如果缓存中的文件是最新的,nginx会对客户端提出的字节范围请求传递指定的字节。如果文件并没有被提前缓存,或者是陈旧的,那么nginx会从服务器上下载完整文件。如果请求了单字节范围,nginx会尽快的将该字节发送给客户端,如果在下载的数据流中刚好有这个字节。如果请求指定了同一个文件中的多个字节范围,nginx则会在文件下载完毕时将整个文件发送给客户端。一旦文件下载完毕,nginx将整个数据移动到缓存中,这样一来,无论将来的字节范围请求是单字节还是多字节范围,nginx都可以在缓存中找到指定的内容立即响应。


配置及清理proxy缓存

在nginx主配置文件nginx.conf中的http段添加如下两行

proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=cache_one:100m inactive=1d max_size=1g;

在/usr/local/nginx/conf目录下编辑web.conf配置文件

location / {
    root   html;
    index index.html index.htm;
    proxy_set_header Host   $host:$server_port;
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_pass  http://hnr.test.com;
}

location ~ /purge(/.*) {
    allow  127.0.0.1;
    allow  192.168.115.0/24;
    allow  192.168.1.0/24;
    deny all;
    proxy_cache_purge  cache_one $host$1$is_args$args;
    #error_page 405 =200 /purge$1;
}

####注意 location ~ /purge(/.*)需要定义在静态缓存配置上面否则清除缓存时会报404错误
location ~ .*\.(gif|jpg|png|html|css|js|ico|swf|pdf)(.*) {
    proxy_pass  http://hnr.test.com;
    proxy_cache cache_one;
    add_header nginx-Cache $upstream_cache_status;
    proxy_cache_valid  200 304 301 302 2h;
    proxy_cache_valid 404 1m;
    proxy_cache_valid  any 2d;
    proxy_cache_key $host$uri$is_args$args;
    expires 30d;
}

编辑/usr/local/nginx/conf目录下upstream.conf文件指定后端tomcat服务器。

pstream  hnr.test.com{
    server 192.168.115.23:8080;
}

测试配置文件没问题重新载入配置文件
sbin/nginx-t
sbin/nginx-s reload


平滑升级nginx

1.编译nginx
# ./configure  ...
# make

这里不执行install,直接复制编译好的二进制文件替换原有的二进制文件,注意需要备份文件。

平滑升级nginx

# mv /usr/local/nginx/sbin/nginx/usr/local/nginx/sbin/nginx.old
# cp -p /root/soft/nginx/nginx-Ver/objs/nginx/usr/local/nginx/sbin/

执行以下命令,nginx新旧进程一起工作

# kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`

关闭旧的工作进程,此时旧的主进程还存在,可以选择使用新版本是恢复到旧版本

# kill -WINCH `cat /usr/local/nginx/logs/nginx.pid.oldbin`

如果想恢复到旧版本,执行以下命令,将重新生成旧的工作进程

# kill -HUP `cat /usr/local/nginx/logs/nginx.pid.oldbin`

使用新版本,就关闭旧版本的主进程

# kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`

至此nginx升级成功。

收集盘点的他人在nginx cache过程中的一些问题集(中外)

-------------------------------
nginx缓存之MISS

计划配置nginx作为反向代理和负载均衡,同时利用其缓存功能,将静态页面在nginx缓存,以达到降低后端服务器连接数的目的。

关键配置点:
http{
.........
proxy_cache_path /usr/local/nginx/nginx_cache levels=1:2 keys_zone=cache_one:256m inactive=30m max_size=8G;
log_format access '$remote_addr - $remote_user [$time_local] "$request"'
'$status $body_bytes_sent "$http_referer"'
'"$http_user_agent" $http_x_forwarded_for'
'"$upstream_cache_status"';
.........
}

server{
    proxy_cache_key $host$uri$is_args$args;
}

但在我的应用场景中,nginx upstrem后端的ip不是具体服务器的地址,而是netscaler的VTP,且后端对应多台服务器,关键是为了persistence功能,配置了cookie insert,所以nginx去源站取回的所有页面,在header里面,都内插入了cookie信息。但nginx默认会不缓存带cookie的页面,所以才导致nginx缓存都是MISS。

解决办法:  
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;

根据具体需求将配置加入http、server、或者location段

详细见:
http://nginx.org/cn/docs/http/ngx_http_proxy_module.html#proxy_hide_header
http://nginx.org/cn/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers

附一:缓存状态判断:利用 "$upstream_cache_status",再日志里面输出,或者用浏览器端的工具,如:"live http headers"

附二:nginx缓存优先级(缓存问题者必看)


附三:varnish缓存也会遇到相同的问题,解决如下:
## 静态资源需要去除cookie信息
if (req.request == "GET" && req.url ~ "\.(css|js|bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flvi|html|shtml)($|\?)") {
    unset req.http.cookie;
    return (lookup);
}

https://www.varnish-cache.org/docs/3.0/tutorial/cookies.html

http://eneplace.com/2011/01/varnish-cookies-querystrings.html

总结:使用缓存时,cookie问题很重要。


-------------------------------
Nginx内容缓存常见问题(FAQ)


本节回答有关Nginx内容缓存的一些常见问题。

Nginx缓存可以进行检测吗?

是的,与add_header指令:
add_header X-Cache-Status $upstream_cache_status;

本示例X-Cache-Status在响应客户端时添加HTTP标头。以下是可能的值$upstream_cache_status:
MISS - 在缓存中未找到响应,因此从原始服务器获取响应。该响应可能已被缓存。
BYPASS- 响应是从原始服务器获取的,而不是从缓存中提供,因为请求与proxy_cache_bypass指令匹配(请参阅下面的“我可以通过我的缓存打孔”)。然后可能会缓存响应。
EXPIRED - 缓存中的条目已过期。该响应包含来自原始服务器的新内容。
STALE- 内容陈旧,因为原始服务器没有正确响应,并且proxy_cache_use_stale已配置。
UPDATING- 内容陈旧,因为该条目当前正在更新以响应先前的请求并proxy_cache_use_stale updating进行配置。
REVALIDATED- proxy_cache_revalidate指令已启用,Nginx验证当前缓存内容仍然有效(If-Modified-Since或If-None-Match)。
HIT - 响应包含直接来自缓存的有效新鲜内容。

Nginx如何确定是否缓存某些内容?

默认情况下,Nginx尊守Cache-Control来自原始服务器的标题。它不缓存响应Cache-Control设置为Private,No-Cache或No-Store或Set-Cookie在响应头。Nginx只缓存GET和HEAD客户端请求。可以覆盖这些默认值,如下面的答案中所述。

如果proxy_buffering设置为Nginx不会缓存响应off,这是on默认的。

Cache-Control头能视而不见吗?

是的,与proxy_ignore_headers指令,使用此配置:
location /images/ {
proxy_cache my_cache;
proxy_ignore_headers Cache-Control;
proxy_cache_valid any 30m;
# ...
}

Nginx忽略/ images /Cache-Control下所有内容的标题。该指令强制缓存数据到期,如果忽略标题,则是必需的。NGINX不会缓存没有到期的文件。proxy_cache_valid Cache-Control。

Nginx缓存POST请求可以吗?

是的,与proxy_cache_methods指令:
proxy_cache_methods GET HEAD POST;

Nginx可以缓存动态内容吗?

是的,只要Cache-Control标题允许。在短时间内缓存动态内容可以减少原始服务器和数据库的负载,这可以缩短第一个字节的时间,因为不必为每个请求重新生成页面。

我可以通过缓存打洞吗?

是的,与proxy_cache_bypass指令配合:
location / {
proxy_cache_bypass $cookie_nocache $arg_nocache;
# ...
}

该指令定义Nginx立即从源服务器请求内容的请求类型,而不是先尝试在缓存中找到它。这有时被称为通过缓存“打孔”。在这个例子中,例如,Nginx为具有nocachecookie或参数的请求执行此操作http://www.example.com/?nocache=true。Nginx仍然可以为将来未被绕过的请求缓存响应结果。

Nginx使用什么缓存键?

Nginx生成密钥的缺省形式是类似于以下的MD5哈希Nginx变量:$scheme$proxy_host$request_uri; 实际使用的算法稍微复杂一些。

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
location / {
proxy_cache my_cache;
proxy_pass http://my_upstream;
}
}

对于此示例配置,缓存密钥for http://www.example.org/my_image.jpg计算为md5('http://my_upstream:80/my_image.jpg')。

请注意,$proxy_host变量用于哈希值而不是实际的主机名(www.example.com),$proxy_host被定义为proxy_pass指令中指定的代理服务器的名称和端口。

要更改用作键的变量(或其他),请使用该 proxy_cache_key 指令。

我可以使用Cookie作为我的缓存键的一部分吗?

是的,缓存密钥可以配置为任意值,例如:
proxy_cache_key $proxy_host$request_uri$cookie_jessionid;

本示例将JSESSIONID Cookie的值合并到缓存键中,具有相同URI但具有不同JSESSIONID值的项目将分别缓存为唯一项目。

Nginx是否使用ETag标题?

在Nginx 1.7.3和Nginx Plus R5及更高版本中,ETag头文件完全受支持If-None-Match。

Nginx如何处理字节范围请求?

如果该文件在缓存中是最新的,那么Nginx将确认一个字节范围请求,并仅将该项目的指定字节提供给客户端。如果文件没有被缓存,或者文件已经失效,Nginx从原始服务器下载整个文件。如果请求是针对单个字节范围的,Nginx一旦在下载流中遇到该范围,就将该范围发送给客户端。如果请求在同一文件中指定了多个字节范围,则在下载完成时,Nginx会将整个文件传送到客户端。

下载完成后,Nginx将整个资源移入缓存中,以便所有将来的字节范围请求(无论是单个范围还是多个范围)都立即从缓存中满足。

请注意,upstream服务器必须支持Nginx的字节范围请求,以响应到该upstream服务器的字节范围请求。

Nginx是否支持缓存清除?

Nginx Plus支持选择性清除缓存文件。如果文件已在源服务器上更新但在Nginx Plus缓存Cache-Control:max-age中仍然有效(该文件仍然有效,并且指令inactive参数设置的超时proxy_cache_path未过期),此功能很有用。借助Nginx Plus的缓存清除功能,该文件可以轻松删除。

Nginx如何处理Pragma标题?

在Pragma:no-cache报头由客户加入到绕过所有中间缓存,直接进入到源服务器的请求的内容。Nginx在Pragma默认情况下不支持标题,但您可以使用以下proxy_cache_bypass指令配置该功能:
location /images/ {
proxy_cache my_cache;
proxy_cache_bypass $http_pragma;
# ...
}

Nginx是否支持头文件stale-while-revalidate和stale-if-error扩展Cache-Control?

是的,在Nginx Plus R12和Nginx 1.11.10及更高版本中。这些扩展可以做什么:
HTTP头的stale-while-revalidate扩展Cache-Control允许使用陈旧的缓存响应,如果它正在更新。
HTTP头的stale-if-error扩展Cache-Control允许在发生错误时使用陈旧的缓存响应。

这些头具有比较低的优先级。

Nginx是否支持Vary标题?

是的,在Nginx Plus R5和Nginx 1.7.7及更高版本中。


-------------------------------
nginx as cache proxy not caching anything

nginx.conf cache part:

** nginx.conf **
proxy_cache_path /usr/share/nginx/www/cache levels=1:2 keys_zone=static$
proxy_temp_path /usr/share/nginx/www/tmp;
proxy_read_timeout 300s;

Heres the default virtual server.

**sites-available/default**
server {
    listen   80;
    root /usr/share/nginx/www;
    server_name myserver;
    access_log /var/log/nginx/myserver.log main;
    error_log /var/log/nginx/error.log;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location ~* ^/(thumbs|images|css|js|pubimg)/(.*)$ {
    proxy_pass http://backend;
    proxy_cache static;
    proxy_cache_min_uses 1;
    proxy_cache_valid 200 301 302 120m;
    proxy_cache_valid 404 1m;
    expires max;
    }

    location / {
    proxy_pass http://backend;
    }
}

Make sure your backend does not return Set-Cookie header. If Nginx sees it, it disables caching.

If this is your case, the best option is to fix your backend. When fixing the backend is not an option, it's possible to instruct Nginx to ignore Set-Cookie header:
proxy_ignore_headers "Set-Cookie";
proxy_hide_header "Set-Cookie";

See the documentation

proxy_ignore_header will ensure that the caching takes place. proxy_hide_header will ensure the Cookie payload is not included in the cached payload. This is important to avoid leaking cookies via the NGINX cache.

I would like to add that multiple configuration options and combinations can disable proxy caching in Nginx. Unfortunately this is poorly documented.In my configuration I set proxy_buffering on and it enabled caching as expected.

10m = 10mb key cache, max_size to 2GB, inactive=120m (refresh from source after 120minutes of inactive), use_temp_path=off (to reduce io)

proxy_cache_valid - cache status of 200 and 302 for 60minutes

proxy_cache_path /tmp/cache levels=1:2 keys_zone=default_cache:10m max_size=2g inactive=120m use_temp_path=off;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 60m;

server {
    listen       80;
    server_name  example.com;

    location / {
        proxy_cache default_cache;
        proxy_buffering on;
        proxy_ignore_headers Expires;
        proxy_ignore_headers X-Accel-Expires;
        proxy_ignore_headers Cache-Control;
        proxy_ignore_headers Set-Cookie;

        proxy_hide_header X-Accel-Expires;
        proxy_hide_header Expires;
        proxy_hide_header Cache-Control;
        proxy_hide_header Pragma;

        add_header X-Proxy-Cache $upstream_cache_status;
        proxy_pass http://ip-of-host:80;

        #set $memcached_key "$uri?$args";
        #memcached_pass 127.0.0.1:11211;
        # error_page     404 502 504 = @fallback;
    }
}

Nginx not caching data

This must be specified with proxy_cache_valid directive.

proxy_cache one;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 10m;

But, this won't work for POST requests because you have no cache key that differs from a POST request to another on the same URL if they don't have same content.

So you will need to adjust the cache key to $host$request_uri|$request_body. You will have to monitor the cache size (proxy_cache_path parameter max_size) and proxy response buffer proxy_buffer_size so it suits your needs.

Syntax: proxy_cache_valid [code ...] time;

Parameters of caching can also be set directly in the response header. This has higher priority than setting of caching time using the directive.

The “X-Accel-Expires” header field sets caching time of a response in seconds. The zero value disables caching for a response. If the value starts with the @ prefix, it sets an absolute time in seconds since Epoch, up to which the response may be cached.

If the header does not include the “X-Accel-Expires” field, parameters of caching may be set in the header fields “Expires” or“Cache-Control”.

If the header includes the “Set-Cookie” field, such a response will not be cached.

If the header includes the “Vary” field with the special value “*”, such a response will not be cached (1.7.7). If the header includes the “Vary” field with another value, such a response will be cached taking into account the corresponding request header fields (1.7.7).

Processing of one or more of these response header fields can be disabled using the proxy_ignore_headers directive.Most web apps set Set-Cookie header, so a response will not be cached. To fix that, use this directive:
proxy_ignore_headers Set-Cookie;

-------------------------------
proxy_pass not caching content

## Proxy Server Setting
server {
    listen *:8181;

    proxy_cache     STATIC;
    proxy_cache_key "$request_uri";
    proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;

    location ~ ^/(.*) {
    set $dropbox_api 'api-content.dropbox.com';
    set $url    '$1';

    proxy_set_header  Host  $dropbox_api;

    proxy_cache  STATIC;
    proxy_cache_key "$request_uri";
    proxy_cache_use_stale   error timeout invalid_header updating http_500 http_502 http_503 http_504;

    add_header X-Cache $upstream_cache_status;

    proxy_pass https://$dropbox_api/$url$is_args$args;
    }

    ##Error Handling
    error_page 500 502 503 504 404 /error/;  
    location = /error/ {
    default_type text/html;
    }
}

Turns out that thumbnail requests returned from Dropbox include the header:
Cache-Control: no-cache

and Nginx will adhere to these headers unless they are explicitly ignored which can be done by simply using the following config line that will ignore any caching control.

proxy_ignore_headers X-Accel-Expires Expires Cache-Control;

We also had issues placing the "proxy_ignore_headers" option in different areas within the nginx.conf file. Finally after much playing around we got it to work by explicitly setting it in the "location" block. The full snippet of the config file can be found below

## Proxy Server Caching
proxy_cache_path  /data/nginx/cache  levels=1:2 keys_zone=STATIC:50m inactive=2h max_size=2g;

## Proxy Server Setting
server {
    listen *:8181;

    location ~ ^/(.*) {
    set $dropbox_api 'api-content.dropbox.com';
    set $url    '$1';

    proxy_set_header    Host    $dropbox_api;
    proxy_hide_header   x-dropbox-thumbcachehit;
    proxy_hide_header   x-dropbox-metadata;
    proxy_hide_header   x-server-response-time;
    proxy_hide_header   x-dropbox-request-id;

    proxy_hide_header cache-control;
    proxy_hide_header expires;

    add_header cache-control "private";
    add_header x-cache $upstream_cache_status; # HIT / MISS / BYPASS / EXPIRED

    proxy_cache     STATIC;
    proxy_cache_valid       200  1d;
    proxy_cache_use_stale   error timeout invalid_header updating
         http_500 http_502 http_503 http_504;
    proxy_ignore_headers    X-Accel-Expires Expires Cache-Control;

    proxy_pass https://$dropbox_api/$url$is_args$args;
    }
}

In order to cache the proxy response the request between Nginx and origin should be cookie-less:
proxy_hide_header    Set-Cookie;
proxy_ignore_headers    Set-Cookie;

See full configuration with invalidation methods: https://gist.github.com/mikhailov/9639593

-------------------------------