Nginx代理到本地磁盘或S3上的文件

时间:2010-01-12 00:13:06

标签: proxy amazon-s3 nginx

所以我将我的网站从Apache移到了Nginx上,我遇到了这个场景的问题:

用户上传照片。此照片已调整大小,然后复制到S3。如果磁盘上有合适的空间(或者文件无法传输到S3),则会保留本地版本。

我希望对这些图像(例如http://www.mysite.com/p/1_1.jpg)的请求首先查看p /目录。如果不存在本地文件,我想将请求代理到S3并呈现图像(但不是重定向)。

在Apache中,我这样做了:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^p/([0-9]+_[0-9]+\.jpg)$ http://my_bucket.s3.amazonaws.com/$1 [P,L]

我尝试在Nginx中复制此行为是:

location /p/ {
    if (-e $request_filename) {
        break;
    }
    proxy_pass http://my_bucket.s3.amazonaws.com/;
}

每个请求都会尝试命中Amazon S3,即使该文件存在于磁盘上(如果它在亚马逊上不存在,我也会收到错误。)如果我删除了proxy_pass行,那么请求获取文件磁盘DO工作。

有关如何解决此问题的任何想法?

5 个答案:

答案 0 :(得分:33)

这不应该是使用try_files的一个例子吗?

location /p/ {
    try_files $uri @s3;
}

location @s3{ 
    proxy_pass http://my_bucket.s3.amazonaws.com;
}

确保S3网址上没有以下斜杠

答案 1 :(得分:12)

您可以像这样改进您的s3代理配置。改编自https://stackoverflow.com/a/44749584

location /p/ {
    try_files $uri @s3;
}

location @s3 {
  set $s3_bucket        'your_bucket.s3.amazonaws.com';
  set $url_full         '$1';

  proxy_http_version     1.1;
  proxy_set_header       Host $s3_bucket;
  proxy_set_header       Authorization '';
  proxy_hide_header      x-amz-id-2;
  proxy_hide_header      x-amz-request-id;
  proxy_hide_header      x-amz-meta-server-side-encryption;
  proxy_hide_header      x-amz-server-side-encryption;
  proxy_hide_header      Set-Cookie;
  proxy_ignore_headers   Set-Cookie;
  proxy_intercept_errors on;

  resolver               8.8.4.4 8.8.8.8 valid=300s;
  resolver_timeout       10s;
  proxy_pass             http://$s3_bucket$url_full;
}

答案 2 :(得分:3)

感谢保留我的coderwall帖子:)为了缓存目的,你可以稍微改进一下:

http {

  proxy_cache_path          /tmp/cache levels=1:2 keys_zone=S3_CACHE:10m inactive=24h max_size=500m;
  proxy_temp_path           /tmp/cache/temp;

  server {
    location ~* ^/cache/(.*) {
      proxy_buffering        on;
      proxy_hide_header      Set-Cookie;
      proxy_ignore_headers   Set-Cookie;
      ...
      proxy_cache            S3_CACHE;
      proxy_cache_valid      24h;
      proxy_pass             http://$s3_bucket/$url_full;
    }
  }

}

还有一个建议是将解析器缓存扩展到5分钟:

resolver                  8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout          10s;

答案 3 :(得分:0)

break并没有完全按照你的期望nginx做你最后要求的事情,如果你开始挖掘模块,这是有意义的......但基本上用来保护你的proxy_pass不存在版本

if (-f $request_filename) {
    break;
}
if(!-f $request_filename)
    proxy_pass  http://s3;
}

答案 4 :(得分:0)

我最终通过检查文件是否存在来解决这个问题,如果是,则重写该请求。然后我处理重写的请求并在那里执行proxy_pass,如下所示:

location /p/ {
  if (!-f $request_filename) {
    rewrite ^/p/(.*)$ /ps3/$1 last;
    break;
  }
}

location /ps3/ {
  proxy_pass http://my_bucket.s3.amazonaws.com/;
}