Ngnix實現一個快取和縮略處理的反向代理伺服器

2016-03-12    分類:作業系統、程式設計開發、首頁精華2人評論發表於2016-03-12

本文由碼農網 – 邱康原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

一兩個月前,我決定從我的站點中移除Varnish ,並用Nginx內建的快取系統替代它。我本來已經在我的python站點上用了nginx來反向代理,所以擺脫Varnish意味著少了一個麻煩。我花了好幾天時間閱讀怎樣配置nginx的快取,翻遍了我的python站點的不同的配置檔案(是的,很諷刺)。在閱讀過程中我標記了一些有趣的nginx的模組,這中間就有 Image Filter module(影像過濾處理模組)。

我覺得結合nginx的反向代理,快取和影像過濾處理三大模組來為我託管在S3上的圖片來建立一個縮圖伺服器會很優雅。如果你仔細的檢視下面的(甚至整個站點的)<img>標籤,你就可以看到nginx實戰了。

在本文中,我將描述我是怎樣配置nginx來有效安全的為S3上的圖片產生縮圖。作為額外獎勵,我也會描述我是怎樣使用 Secure Links module (安全連結模組)來防止人們惡意使用該伺服器產生縮圖。

準備開始

為了讓不同部分能協同工作,你的nginx需要編譯進影像濾波,代理和安全連結三個模組。你可以通過nginx –V 來檢查你所具有的模組。如果你使用的Ubuntu(Debian也行),你可以很輕易的安裝其它任意的nginx模組(apt-get install 命令)。

一旦nginx準備好了,我們可以開始配置nginx了。

配置

首先需要申明的是我們的代理快取。這個申明位於nginx.conf檔案的http部分並且描述了基於檔案的快取所在,該快取將會儲存我們產生的縮圖。因為一次快取未命中即意味著要從S3伺服器上獲取完整的圖並且改變它的大小,我們希望配置快取足夠大以使其能包含我們大部分的縮圖。對於我的站點,我估計200MB足夠了。

為了確定你的快取,把下面的程式碼新增到nginx配置檔案的http部分的某個地方:

# Nginx will create a cache capable of storing 16MB of keys and 200MB of data.
proxy_cache_path /tmp/nginx-thumbnails levels=1:2 keys_zone=thumbnail_cache:16M inactive=60d max_size=200M;

現在我們需要說明兩個伺服器定義:一個快取伺服器和一個調整大小伺服器。後者將作為S3的反向代理,產生並提供調整大小後的影像。快取伺服器位於調整大小伺服器的前面,快取並提供調整大小後的影像。雖然我不認為必須要兩個伺服器,因為我的站點訪問量並不是特別大,但在谷歌了一下後,我看見的一些文章表明,就是應該這樣。

快取伺服器

快取伺服器會暴露給公共訪問(我的位於m.charlesleifer.com)。因為該伺服器的唯一任務就是快取從調整大小伺服器獲得的響應,所以配置相當簡單。下面是我的配置:

server {
  listen 80;
  server_name m.charlesleifer.com;

  location / {
    proxy_pass http://localhost:10199;
    proxy_cache thumbnail_cache;
    proxy_cache_key "$host$document_uri$is_args$arg_key";
    proxy_cache_lock on;
    proxy_cache_valid 30d;  # Cache valid thumbnails for 30 days.
    proxy_cache_valid any 15s;  # Everything else gets 15s.
    proxy_cache_use_stale error timeout invalid_header updating;
    proxy_http_version 1.1;
    expires 30d;
  }
}

無論何時快取伺服器得到一個請求,“thumbnail_cache”將首先被檢測。如果沒找到匹配項,那就將請求轉發至調整大小伺服器(執行在本地localhost)。它返回有效的響應,快取伺服器將快取該響應30天,其它任何東西都只快取15秒。

調整大小的伺服器

所有有趣的事情都在調整大小伺服器。它的任務是從S3上獲得圖片並基於URL上的引數實時調整圖片大小。另外,該伺服器會檢查每個請求的安全祕鑰以防止其他人隨意產生縮圖。

因為該伺服器配置有幾個不同的部分,所以讓我們從我們已經見過的部分開始:代理

server {
  listen 10199;
  server_name localhost;

  set $backend 'your.s3.bucket_name.s3.amazonaws.com';

  resolver 8.8.8.8;  # Use Google for DNS.
  resolver_timeout 5s;

  proxy_buffering off;
  proxy_http_version 1.1;
  proxy_pass_request_body off;  # Not needed by AWS.
  proxy_pass_request_headers off;

  # Clean up the headers going to and from S3.
  proxy_hide_header "x-amz-id-2";
  proxy_hide_header "x-amz-request-id";
  proxy_hide_header "x-amz-storage-class";
  proxy_hide_header "Set-Cookie";
  proxy_ignore_headers "Set-Cookie";
  proxy_set_header Host $backend;
  proxy_method GET;
}

這裡除了告訴我們該伺服器如何與S3通訊外並沒有多餘的其他內容,所以我們繼續看下一部分。接下來要配置的是nginx的影像濾波模組。只需要幾個指令,其中一些我們會定義到伺服器級別。

下面是代理設定,新增如下的影像濾波模組:

server {
  # ...

  image_filter_jpeg_quality 85;  # Adjust to your preferences.
  image_filter_buffer 12M;
  image_filter_interlace on;
}

最後,我們定義一個程式碼塊,完成如下功能:

1.檢查形式合法的URL

2.校驗請求的簽名

3.從URL中提取圖片大小引數

4.從S3獲得影像並把它載入 image_filter_buffer

5.調整圖片大小並響應

第二項相當有趣。一篇類似的文章的作者使用Lua來校驗請求的簽名,但那樣好像步驟比較繁瑣。 Nginx的 secure_link 擴充套件相當容易使用。

secure_link模組原理是:用被請求的圖片的URL和只有你的app知道的金鑰串連線起來的串來產生一個雜湊(hash)。由於hash長度擴充套件,我們最後附加我們的金鑰而不是預先考慮它。因為你知道祕鑰,所以無論何時你想在你的應用中展示圖片縮圖時你都可以產生有效的hash。

下面是配置的最後一部分:

server {
  # ...
  error_page 404 =404 /empty.gif;

  location ~ ^/t/([\d-]+)x([\d-]+)/(.*) {
    secure_link $arg_key;  # The hash is stored in the `key` querystring arg.
    secure_link_md5 "$uri my-secret-key";
    if ($secure_link = "") {
      # The security check failed, invalid key!
      return 404;
    }
    set $image_path '$3';
    image_filter resize $1 $2;

    proxy_pass http://$backend/$3;
  }
}

這就是所有的。

產生hash

如果你使用python,下面是我寫的程式碼用以在特定URI下產生hash:

import base64
import hashlib

def thumbnail_url(filename, width, height='-'):
    uri = '/t/%sx%s/%s' % (width, height, filename)
    md5_digest = hashlib.md5(uri + ' my-secret-key').digest()
    key = base64.b64encode(md5_digest)
    # Make the key look like Nginx expects.
    key = key.replace('+', '-').replace('/', '_').rstrip('=')

    return 'http://m.charlesleifer.com%s?key=%s' % (uri, key)

感謝閱讀

感謝你花時間閱讀這篇文章,我希望你找到了樂趣。請留下評論,我會盡力回答。如果你發現了我上面的說明有什麼錯誤也請讓我知道,我會更新本文。

譯文連結:http://www.codeceo.com/article/nginx-cache-image-filter-server.html
英文原文:Nginx: a caching, thumbnailing, reverse proxying image server
翻譯作者:碼農網 – 邱康
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章