最後更新: 2019-04-09
目錄
- Simple Load Balancing
- Reverse Proxy with Caching (proxy_cache_)
- proxy_redirect
- Nginx 與 Apache 的 proxy 對應設定
- proxy_set_header
- 進階的 proxy 設定
- Stale Cache
- Backend Server Setting (Apache)
- SSL-Offloader
- Maintenance Page
- Route by IP
- proxy_store
- proxy_cache 與 proxy_store 比較
- Custom Log Format
- proxy_cache_purge
- Useful Settings
- Troubleshoot
- Doc
Simple Load Balancing
Diagram
/--> apache1 (1.11) (wan ip)nginx(1.1) ---> apache2 (1.12) \--> apache3 (1.13)
Simple Load Balancing
http { include backend.conf; include website.conf; }
backend.conf
# ngx_http_upstream_module # 定義一個叫 myproject 既 Backend Group upstream myproject { # Load Balancing Method # Default 係用 "weighted round-robin" 去分配 request 到 backend 的 # least_conn; # 連去 connection 最小的 backend ( 一般來說它負載最小 ) ip_hash; # The key for the hash is the class-C network address (佢有 sticky 的效果) # server address [parameters]; # 相當於 "server n.n.n.n:80 weight=1 max_fails=1 fail_timeout=10;" # 意思是 10 秒內有 1 次沒反應就當 Server 死了, 其後 10 秒不 forward request 到去 # max_fails=0 <= disables the accounting of attempts server 192.168.1.11:80; # It will be passed requests when the primary servers are down. server 192.168.1.12:80 backup; # max_conns: limits the maximum number of simultaneous active connections to the proxied server (1.11.5) # If the server group does not reside in the shared memory, the limitation works per each worker process # Shared memory syntax: zone name [size]; # Default: 0 (no limit) server 192.168.1.13:80 max_conns=50; # marks server as permanently offline server 192.168.1.14:80 down; # commercial subscription only # 判斷 Server 的 healthy # Module: ngx_http_upstream_module health_check interval=3 fails=3 passes=3; # keepalive settings keepalive 16; }
website.conf
# 定義一個 proxy server { listen 80; server_name domain.com www.domain.com; location / { include /etc/nginx/proxy_params; proxy_pass http://myproject; proxy_bind 192.168.1.1; # 設定 outgoing 去 upstream 的 interface/address } }
health_check
# default, 5 seconds;
# fails: 連續多少次連不到 uri 就認為 Server unhealthy, default, 1;
# passes: 連續多少次連到才認為 healthy
# uri: default, "/"
# match: by default, the response should have status code 2xx or 3xx.
health_check [interval=time] [fails=number] [passes=number] [uri=uri] [match=name];
http { server { ... location / { proxy_pass http://backend; health_check match=welcome; } } match welcome { status 200; header Content-Type = text/html; body ~ "Welcome to nginx!"; } }
# maximum number of idle keepalive connections to upstream servers that are preserved in the cache.
# When this number is exceeded, the least recently used connections are closed.
# keepalive directive does not limit the total number of connections to upstream servers
# => parameter should be set to a number small enough to let upstream servers process new incoming connections
keepalive 16;
P.S. Setting for Client (Browser)
Context: http, server, location # 不是在 upstream 的
keepalive_time 1h; keepalive_timeout 60s; # Default: 60s keepalive_requests 100; # Ver < 1.19.10, Default: 100
* reached => closed following the subsequent request processing
keepalive_time
Limits the maximum time during which requests can be processed through one keepalive connection.
keepalive_timeout
Sets a timeout during which an idle keepalive connection to an upstream server will stay open.
keepalive_requests
# Sets the maximum number of requests that can be served through one keepalive connection.
gzip to backend
nginx is not using gzip to talk to backend servers
Nginx is a HTTP/1.0 reverse proxy, gzip compression was not in the HTTP specification until HTTP/1.1
/etc/nginx/proxy_params 的內容
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
P.S.
# 在 Nginx 後面的 Apache 會獲得 HTTP_X_FORWARDED_PROTO
$proxy_add_x_forwarded_for
the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma.
If the “X-Forwarded-For” field is not present in the client request header,
the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.
應用:
能用在 .htaccess
RewriteEngine on
# Rewrite to SSL for anything coming off of a proxy.
RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
RewriteRule ^(.*) https://%{SERVER_NAME}/$1 [L,R=301]
%{HTTP:header} 係一個 mod_rewrite 的 variable 來
php code:
$_SERVER["HTTPS"] returns "on" when it's https:// 在 https offload proxy 時用不到.
$_SERVER['HTTP_X_FORWARDED_PROTO'];
Reverse Proxy with Caching
Setting
http { # 建立用來存放 Cache 的 Folder # mkdir -p /var/cache/nginx/tmp /var/cache/nginx/cache # chown nginx. /var/cache/nginx -R # chmod 770 /var/cache/nginx -R # A directory for storing temporary files with data received from proxied servers proxy_temp_path /var/cache/nginx/tmp 1 2 # level: 設定 subdirectory 的層數, 格式是 1, 1:1, 1:2:3 # keys_zone: 建立一個名叫 STATIC 的 cache, 並且有 64 Mbyte Ram # inactive: 多久沒有人 access 就 Delete 了 cache 了的檔案 # max_size: 那 cache folder 的 Total size # proxy_cache_path and proxy_temp_path 一定要在同一個 filesystem proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=MyCache:10m inactive=24h max_size=1g; server { location / { include /etc/nginx/proxy_params; proxy_pass http://BACKEND_IP; # proxy_cache zone | off (default); # off => disables caching proxy_cache MyCache; # 在 response 加入了 X-Cache-Status: MISS
|HIT |
|
BYPASS (中左 proxy_cache_bypass) add_header X-Cache-Status $upstream_cache_status; proxy_cache_valid 200 1d; proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; } } }
proxy_cache_valid: (這設定是必須的, 否則 nginx 就不會 cache 東西)
Usage: proxy_cache_valid [code ...] time;
# Default 只有 200, 301 and 302 才會 cache
proxy_cache_valid 1d;
Unit: m, h, d
# 設定不同 return code 有不同的 cache time
proxy_cache_valid 404 1m;
# 其餘 code 用 any
proxy_cache_valid any 1m;
* Upstream cache-related directives have priority over proxy_cache_valid value
proxy_ignore_headers: Disables processing of certain response header fields from the proxied server.
Override Upstream:
proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
proxied server 的不同 cache header 的 priority:
-
X-Accel-Expires
n => seconds
0 => disables caching for a response
@X => absolute time(seconds since Epoch) - Expires/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
- proxy_cache_valid
P.S.
nginx 不會 cache 有 Set-Cookie header 的東西 !
亦不會 cache Cache-Control 的值是 "no-cache", "no-store", "private", "max-age=0"
proxy_cache_use_stale:
# 當什麼時候照用 stale cache
# Default: off # 還有設定 http_404 proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_key
Default:
proxy_cache_key $scheme$proxy_host$request_uri;
$proxy_host
The name and port of the upstream server that handled the request.
proxy_cache_lock
# only one request at a time will be allowed to populate a new cache element passing to a proxied server
# identified according to the proxy_cache_key directive
# Other requests of the same cache element will either
# wait for a response to appear in the cache or
# the cache lock for this element to be released (proxy_cache_lock_timeout=5s;)
proxy_cache_lock on;
Cache Control
什麼情況不 cache
-
proxy_cache_bypass string
string not empty and is not equal to “0” then the response will not be taken from the cache -
proxy_no_cache
which the response will not be saved to a cache
proxy_cache_bypass $http_cache_control; proxy_cache_bypass $http_secret_header; proxy_no_cache $http_cache_control;
proxy_ignore_headers
proxy_ignore_headers Set-Cookie; proxy_ignore_headers Cache-Control;
proxy_ignore_headers
Disables processing of certain response header fields from the proxied server
設定某目錄在 browser 的 cache ttl
location / { # ... location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires 1y; log_not_found off; } }
設定某類 file 在 browser 的 cache ttl
if ($request_uri ~ \.css$) { expires max; }
Bownser 的 refresh 情況
Request headers:
按 Enter -> 沒有 "Cache-Control"
按F5 -> Cache-Control:max-age=0
按 Ctrl + F5 -> Cache-Control:no-cache
針對 Request headers 的 cache control
HTTP_CACHE_CONTROL is the value of the Cache-Control header received from the client.
It's not something configured on your server, it's based on what the client sends.
# 當 Request headers 內的 Cache-Control 是 no-cache 時,
# 就會把 $clearcache 設定成 1
Context: http
map $http_cache_control $clearcache { default ""; "no-cache" 1; }
# Cache setting
Context: http, server, location
proxy_cache_bypass $clearcache;
不安全的做法 (直食 Request headers)
# $http_X 是 http header 來
proxy_cache_bypass $http_bypass_cache;
# $http_bypass_cache 相當於 bypass-cache
curl http://mydomain/mypage.html -s -I -H "bypass-cache" # 無效
curl http://mydomain/mypage.html -s -I -H "bypass-cache:1" # 有效
curl http://mydomain/mypage.html -s -I -H "bypass-cache:true" # 有效
Browser
RFC 2616
"00:00:00 UTC, January 1, 1970"
If a "Cache-control: max-age=N" header is specified, then the freshness lifetime is equal to N.
strong validator.
If the "ETag" header is present in a response, then the client can issue an "If-None-Match" request header to validate the cached document.
weak validator
"Last-Modified" response header
# forces the browser to request a fresh version of them every time
# Therefore they are not retrieved from the browsers cache.
But don't you end up serving stale content?
Nope, each document stored in the mozilla cache is given an expiration time. If mozilla tries to load the document for normal viewing, this expiration time is honored. A cached document will be validated with the server if necessary before being shown to the user.
Firefox view cache
about:cache
只 Cache 部份 File
include /etc/nginx/proxy_params; location ~* \.(bmp|jpg|jpeg|png|svg|ico|gif|mp4|css|js|html|txt|zip|rar)$ { add_header X-Cache-Status $upstream_cache_status; proxy_pass http://MyBackend; proxy_bind 192.168.123.14; log_not_found off; access_log off; proxy_cache cache-www; proxy_buffering on; proxy_cache_valid 200 30d; proxy_cache_valid 301 302 10m; proxy_cache_valid 404 1m; proxy_cache_min_uses 3; proxy_cache_key $host$uri$is_args$args; proxy_cache_use_stale error timeout updating; proxy_cache_lock on; #proxy_cache_purge $purge_method; } location / { ... }
再談 proxy_cache_key
以下兩 link 不是同一份 Cache 的
Setting
set $cache_key $host$uri$is_args$args;
proxy_cache_key $cache_key;
add_header X-Cache-Status $upstream_cache_status;
add_header X-CACHE-KEY $cache_key;
Test Code
<? print_r($_GET); ?>
Test
curl -I 'https://example.com/?a=1&b=2'
curl -I 'https://example.com/?b=2&a=1'
令它們同一份 Cache 的方案
[1] using normalized URI
set $cache_key $host$uri${is_args}a=${arg_a}&b=$arg_b;
[2] use map
a)
map $args $my_args { default $args; ~^a=(.*)&b=(.*)$ a=${1}b=${2}; ~^b=(.*)&a=(.*)$ a=${2}b=${1}; }
b)
set $cache_key $host$uri${is_args}$my_args;
[2] use if
if ($args ~ ... { set $args ...; } if ($args ~ ... { set $args ...; }
Remark
$is_args is an empty string if there are no arguments, or a ? to signify the start of the query string.
$args then adds the arguments ($query_string could also be used with the same result).
$request_uri 近似于 $uri$is_args$args
$request_uri : full original request URI (with arguments)
$request_uri vs $uri
$uri
The $uri variable is set to the URI that nginx is currently processing,
but it is also subject to normalisation, including:
- Removal of the ? and query string
- Consecutive / characters are replace by a single /
- URL encoded characters are decoded
$request_uri
The value of $request_uri is always the original URI and is not subject to any of the above normalisations.
Most of the time you would use $uri, because it is normalised.
Using $request_uri in the wrong place can cause URL encoded characters to become doubly encoded.
proxy_redirect
Replaceable "Location" and "Refresh" in proxied server response-header
Syntax:
- proxy_redirect default; # Default
- proxy_redirect off;
- proxy_redirect redirect replacement;
設定:
假設有設定
proxy_redirect http://localhost:8000/two/ http://frontend/one/;
Remark: 可以縮寫成
proxy_redirect http://localhost:8000/two/ /;
Suppose a proxied server returned the header field
Location: http://localhost:8000/two/some/uri/
Will rewrite this string to
Location: http://frontend/one/some/uri/
proxy_redirect default
location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect default;
相當於
location /one/ { proxy_pass http://upstream:port/two/; proxy_redirect http://upstream:port/two/ /one/;
e.g.
[1]
# port & servername re-write proxy_redirect http://localhost:8000/two/ http://frontend/one/; # SSL Offload for OWA proxy_redirect http://MyDomain/owa https://MyDomain:8443/owa;
[2]
# The off parameter cancels the effect of all proxy_redirect directives on the current level: # There could be several proxy_redirect directives: proxy_redirect off; proxy_redirect default; proxy_redirect http://localhost:8000/ /; proxy_redirect http://www.example.com/ /;
[3]
A redirect can also contain (1.1.11) variables:
proxy_redirect http://$proxy_host:8000/ /;
Nginx 與 Apache 的 proxy 對應設定
apache:
<VirtualHost myhost:80>
ServerName myhost
DocumentRoot /path/to/myapp/public
ProxyPass / http://myapp:8080/
ProxyPassReverse / http://myapp:8080/
</VirtualHost>
ngnix:
server {
listen myhost:80;
server_name myhost;
location / {
root /path/to/myapp/public;
proxy_pass http://myapp:8080;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
}
** 沒有 server_name 時, nginx 是不會開始 listen port 的 !!
proxy_set_header
Syntax:
proxy_set_header field value;
The value can contain text, variables, and their combinations.
These directives are inherited from the previous level
if and only if there are no proxy_set_header directives defined on the current level.
By default:
proxy_set_header Host $proxy_host; proxy_set_header Connection close;
X-Forwarded-X (de-facto standard header)
X-Forwarded-For (XFF)
for identifying the originating IP address of a client connecting to a web server through an HTTP proxy
X-Forwarded-Host (XFH)
for identifying the original host requested by the client in the Host HTTP request header.
X-Forwarded-Proto (XFP)
protocol (HTTP or HTTPS) that a client used to connect to your proxy
X-Forwarded-Port
for identifying the port that the client used to connect to the load balancer
$proxy_X
$proxy_add_x_forwarded_for
If the "X-Forwarded-For" field is not present in the client request header,
the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.
$proxy_host
name and port of a proxied server as specified in the proxy_pass directive;
$proxy_port
port of a proxied server as specified in the proxy_pass directive
MySetting
proxy_set_header Host $host:$server_port; proxy_set_header X-Forwarded-Host $host:$server_port;
進階的 proxy 設定
server{ ... access_log off; error_log off; # 不用 log 常見的 file location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } # 直接在 proxy 上 deny 了 location ~ /\. { deny all; } #location ~ /\.ht { # deny all; # access_log off; # # files not found on disk # log_not_found off; #} #################################################### local error page error_page 500 502 503 504 /50x.html; error_page 404 /404.html location = /404.html { root /usr/share/nginx/html; } location = /50x.html { root /usr/share/nginx/html; } #################################################### 主要 setting location / { include /etc/nginx/proxy_params; proxy_pass http://MyBackend; } location ~* \.(bmp|jpg|jpeg|png|swf|ico|gif|mp4|css|js|html|txt|zip|rar|gz)$ { include /etc/nginx/proxy_params; proxy_pass http://MyBackend; # buffer size for reading client request body (POST) # Default: 32b=>8K, 64bit=>16K # over => written to a temporary file (client_body_temp_path) client_body_buffer_size 128k; # mkdir /var/lib/nginx/client_temp -p # chown www-data. /var/lib/nginx/client_temp # chmod 770 /var/lib/nginx/client_temp # 必須設定它, 否則當 POST over 了 client_body_buffer_size 時就會失敗 # (過 proxy_read_timeout 就會出 504) client_body_temp_path /var/lib/nginx/client_temp 1 2; # request header field:“Content-Length” # exceeds => 413 (Request Entity Too Large) error # 0 => disables checking of client request body size. client_max_body_size 10m; # 初始為 connect 的 timeout (Client 第一次 connect 上來) # Default: 60s proxy_connect_timeout 10; # Between two write successive operations(not on entire transfer of request) # timeout with the transfer of request to the upstream server proxy_send_timeout 10; # read timeout for the response of the proxied server proxy_read_timeout 10; # 當 buffer 是 off 時, cache 及 rate limiting 都會唔 work !! (Default: on) # If the whole response does not fit into memory(proxy_buffer_size), # a part of it can be saved to a temporary file on the disk(proxy_max_temp_file_size) proxy_buffering on; # read the first part of the response, obtained from the proxied server # By default, the buffer size is equal to one memory page(4k | 8k) # usually contains a small response header proxy_buffer_size 4k; # for reading a response from the proxied server (for a single connection) # number and the size of buffers(read the answer obtained from the proxied server) proxy_buffers 4 32k; # If file is larger than this size, # it will be served synchronously from upstream server rather than buffered to disk. # 0: temporary files usage will be disabled proxy_max_temp_file_size 1m; # flushed to the proxy_temp_path when writing proxy_temp_file_write_size 128k; # Enabled: the entire request body is read from the client before sending the request to a proxied server. # Disabled: the request body is sent to the proxied server immediately as it is received. # When HTTP/1.1 chunked transfer encoding is used to send the original request body, # the request body will be buffered regardless of the directive value unless HTTP/1.1 is enabled for proxying. proxy_request_buffering on } location /software/ { proxy_pass http://192.168.3.106:8080; proxy_redirect http://192.168.3.106:8080 http://datahunter.org/software/; } }
proxy_no_cache
Specifies in what cases a response will not be cached
e.g.
# the response will never be cached if the cookie "nocache" is set in the request.
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass
Answer will not be taken from the cache.
當 string variable 不是 empty 或 0 時, 就不用 cache
e.g.
假設 client request 的 header 有 "My-Secret-Header: 1" 時, 那就會 bypass
proxy_cache_bypass $http_my_secret_header;
proxy_cache_lock
# Default: off
proxy_cache_lock on; proxy_cache_lock_timeout 5;
proxy_cache_min_uses
# 某 file 被 client 存取幾多次後才開始被 cache. Default 1 <-- 亦即是不用改
proxy_cache_min_uses 3;
# Catch the wordpress cookies.
# Must be set to blank first for when they don't exist. set $wordpress_auth ""; if ($http_cookie ~* "wordpress_logged_in_[^=]*=([^%]+)%7C") { set $wordpress_auth wordpress_logged_in_$1; }
# 2 rules to dedicate the no caching rule for logged in users.
proxy_cache_bypass $wordpress_auth; # Do not cache the response. proxy_no_cache $wordpress_auth; # Do not serve response from cache.
Stale Cache
作用
解決 "Cache stampede" 問題
reduce requests that has to come through upstream(Backend)
Usage
This serves out of date elements from cache, and issuing updates from backend.
So when your backend servers a page after 2 seconds, the client already got the old ressource from cache.
The second locks one element from cache, while already a update-cache request to backend is running,
so there are no paralell requests for one cache-item.
proxy_cache_lock on; proxy_cache_use_stale error timeout updating; proxy_cache_background_update on;
proxy_cache_lock
Default: off
only one request at a time will be allowed to populate a new cache element identified according to the proxy_cache_key directive by passing a request to a proxied server.
up to the time set by the "proxy_cache_lock_timeout 5s;" (Default)
proxy_cache_use_stale
Default: off
Determines in which cases a stale cached response can be used
Syntax:
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off (Default);
error: using a stale cached response if a proxied server to process a request cannot be selected
updating: permits using a stale cached response if it is currently being updated
proxy_cache_background_update
Default 都是 off
Allows starting a background subrequest to update an expired cache item,
while a stale cached response is returned to the client.
Backend Server Setting (Apache)
.htaccess
<Files ~ "\.(htaccess|htpasswd|ini|bak|old|log|sh|sql)$">
deny from all
</Files>
RewriteEngine On
# all to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
# single enter point
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !\.(jpg|png|css|gif|js|ico)$
RewriteRule ^(.*)$ index.php [L,QSA]
log setting
<IfModule log_config_module> # The following directives define some format nicknames for use with a CustomLog directive #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined #LogFormat "%h %l %u %t \"%r\" %>s %b" common LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%a %l %u %t \"%r\" %>s %b" common <IfModule logio_module> # You need to enable mod_logio.c to use %I and %O LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio </IfModule> .... </IfModule>
* 將 %h 改成 %a
%h Remote hostname. Will log the IP address if HostnameLookups is set to Off (Default: Off)
%a Client IP address of the request (see the mod_remoteip module)
More info.
https://datahunter.org/apache24_module#mod_remoteip
SSL-Offloader
nginx.conf
server { listen 443; server_name datahunter.org; # SSL Setting ssl on; #Default: off ssi on; # Default: off ssi_silent_errors on; ssl_certificate /etc/nginx/ssl/server.pem; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_protocols TLSv1.2; ssl_session_timeout 30m; ssl_session_cache shared:SSL:10m; location / { include /etc/nginx/proxy_params; proxy_pass http://MyBackend; proxy_cache_min_uses 3; proxy_cache_key $host$uri$is_args$args; # re-write redirects to http as to https, example: /home proxy_redirect http:// https://; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } location ~ /\. { deny all; } access_log /var/log/nginx/ssl.log; access_log /var/log/nginx/ssl-cache.log cache_status; }
Doc: http://wiki.nginx.org/SSL-Offloader
Maintenance Page
假設 index.html 係 maintenance page 的內容
Setting - 1
# maintenance page server { listen 80; # 不 log access_log off; error_log /dev/null; root /home/vhosts/maintenance/web; location / { # 留 cache expires 60s; index index.html; # 找不到的 URL 都去/index.html try_files $uri $uri/ /index.html; } }
Setting - 2
server { ... location / { # ACL deny 1.1.1.1; deny 123.123.123.123; # maintenance try_files /maintenance.htm @proxy; # Limit req limit_req zone=qps2 burst=10 nodelay; } location @proxy { # Proxy Setting include /etc/nginx/proxy_params; proxy_pass http://MyBackend; } }
Route by IP
簡單版(if)
server { # Route by IP if ( $remote_addr ~* ip-address-here ) { proxy_pass http://Anoter_Backend; } listen 80; proxy_pass http://Default_Backend; }
進階版(map)
# Backend setting upstream staging1 { server 10.0.0.11:80; } upstream staging2 { server 10.0.0.12:80; } # Route by IP map $remote_addr $upstream { 4.5.6.7 staging2; default staging1; } # Website server { listen 80; proxy_pass http://$upstream; }
proxy_store
This directive can be used to create local copies of static unchangeable files
直接 cache 文件到 local 同樣結構的目錄(像 mirror 一樣)
(proxy_store會按照實際請求的url地址建立相應的目錄結構)
但無法通過程序控制 "cache" 何時過期, 需要定期刪除緩存目錄中的內容
* The modification time of files is set according to the received “Last-Modified” response header field.
* proxy_temp_path -> root | alias
proxy_store
# Enables saving of files to a disk. Default: off
# on: saves files with paths corresponding to the directives alias or root
# string: the file name can be set explicitly using the string with variables
Syntax: proxy_store on | off | string;
i.e.
proxy_store /data/www$original_uri;
* The response is first written to a temporary file(proxy_temp_path), and then the file is renamed( 移去 proxy_store 位置 ).
proxy_store_access
# Sets access permissions for newly created files and directories
proxy_store_access user:rw group:rw all:r;
Usage Example
[Example 1]
location /images/ { root /data/www; error_page 404 = @fetch; } location @fetch { internal; proxy_pass http://backend; proxy_store on; proxy_store_access user:rw group:rw all:r; # 一定要用同一個 FileSystem proxy_temp_path /data/temp; root /data/www; }
"@"
The “@” prefix defines a named location
Such a location is not used for a regular request processing, but instead used for request redirection
They cannot be nested, and cannot contain nested locations
[Example 2]
location ~ .*\.(js|css|jpg|png|mp4|doc|docx|ppt)$ { expires 120h; proxy_store on; proxy_store_access user:rw group:rw all:rw; root /data/cache/a; proxy_temp_path /data/cache/b; include /etc/nginx/proxy_params; if ( !-e $request_filename) { proxy_pass http://127.0.0.1:8080; } }
[Example 3]
準備
mkdir -p /home/vhosts/datahunter.org cd /home/vhosts/datahunter.org/ mkdir web temp chown www-data. web temp chmod 750 web temp
設定
upstream MyBackend{ server 192.168.123.11:80; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|html|htm|css)$ { expires 7d; proxy_store on; proxy_store_access user:rw group:r ; root /home/vhosts/datahunter.org/web; proxy_temp_path /home/vhosts/datahunter.org/temp; log_not_found off; access_log off; include /etc/nginx/proxy_params; proxy_set_header Accept-Encoding ''; if ( !-e $request_filename) { proxy_pass http://MyBackend; } }
Remark
如果沒有 "proxy_set_header Accept-Encoding '';" 如果 MyBackend 傳回的資料是 gzip 了,
那 local 會把 gzip 的內容保存為原來名稱
i.e.
file css_c06a06487539ab1845387427cebdb4e0.css
css_c06a06487539ab1845387427cebdb4e0.css: gzip compressed data, from Unix
proxy_cache 與 proxy_store 比較
proxy_cache 比 proxy_store 有較高效能
1. 以 gzip 保留了 file, 不用二次壓縮
file 5677d21b6492fb95723795f3bd4a69bd
5677d21b6492fb95723795f3bd4a69bd: data
2. 保留了 Backend 回應的資訊
ETag, Last-Modified, Content-Length, Content-Type
client_body_in_?
client_body_in_file_only
save the entire client request body into a file (for debugging)
- off (Default)
- on: temporary files are not removed after request processing
- clean: will cause the temporary files left after request processing to be removed
i.e.
client_body_in_file_only on;
client_body_in_single_buffer
client_body_in_file_only 的相反
Default: off
proxy_cache_purge
* This functionality is available as part of our commercial subscription.
Usage:
Defines conditions under which the request will be considered a cache purge request.
not empty and is not equal to 0 then the cache entry with a corresponding cache key is removed.
proxy_cache_purge string
If the cache key of a purge request ends with an "*" , all cache entries matching the wildcard key will be removed from the cache.
entries will remain on the disk until they are deleted for either inactivity, or processed by the cache purger
proxy_cache_key
Defines a key for caching
Default: proxy_cache_key $scheme$proxy_host$request_uri;
$proxy_host
name and port of a proxied server as specified in the proxy_pass directive;
Example
http { ... geo $purge_allowed { default 0; # deny from other 127.0.0.1 1; # allow from localhost 192.168.0.0/24 1; # allow from localnet } map $request_method $purge_method { PURGE $purge_allowed; default 0; } } server { listen 80; server_name www.example.com; location / { proxy_pass https://localhost:8002; proxy_cache mycache; proxy_cache_purge $purge_method; } }
curl send PURGE Command
curl -X PURGE -D – "https://www.example.com/*"
purger
purger=on|off(Default)
Instructs whether cache entries that match a "wildcard key" will be removed from the disk by the cache purger (1.7.12).
on: activate the "cache purger" process that permanently iterates through all cache entries and
deletes the entries that match the wildcard key.
purger_files=number # Default: 10
Sets the number of items that will be scanned during one iteration
purger_threshold=number (Default: 50ms)
Sets the duration of one iteration
Example
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on;
proxy_cache_path
# V1.7.10
# The directory for temporary files is set based on the "use_temp_path" parameter
# off, temporary files will be put directly in the cache directory.
# on, use the directory set by the proxy_temp_path directive
proxy_cache_path ... use_temp_path=no
proxy_cache_revalidate
proxy_cache_revalidate yes;
Enables revalidation of expired cache items using conditional requests with
the “If-Modified-Since” and “If-None-Match” header fields.
Useful Settings
# 對於 Backend, Origin 及 Referer 都沒有用
proxy_set_header Origin ''; proxy_set_header Referer '';
# Handle WebSocket upgrades if your application uses WebSockets
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
Troubleshoot
[Case 1]
Error
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block.
Config
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 4w;
proxy_pass http://127.0.0.1:8081/;
}
原因
如果 location 包含了 regex, 則 proxy_pass 不能包含 URI part
=> proxy_pass的值後面不要有斜槓"/"
Doc
http://wiki.nginx.org/HttpProxyModule