直接查閱 nginx doc 是一個最簡單的途徑(Alphabetical index of directives,Alphabetical index of variables);你可以查看每個 Module 的詳盡解釋,很好。
location 命令
- Understanding Nginx Server and Location Block Selection Algorithms;
- regex101,一個很好的在線正則表達式調試網站;
- add_header;
-
~
:Regular expressions ( for case-sensitive matching); -
~*
:Regular expressions (for case-insensitive matching); - The
@
prefix defines a named location. Such a location is not used for a regular request processing, but instead used for request redirection(內部重定向).
location priority 一般優先級
- Directives with the "=" prefix that match the query exactly. If found, searching stops.
- All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
- Regular expressions, in the order they are defined in the configuration file.
- If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
rewrite
- 一般形式:
rewrite regex replacement [flag];
- rewrite 針對的是處理 path,不處理 query string;
要獲得 query string,請使用$query_string
變量; -
關于 URI;
nginx 內部通常使用$uri
(沒有 query string,且歸一化了),區別于$request_uri
(full original request URI (with arguments),即有 query string); - 通常:
rewrite /grab-new/index.html$ /demand.html;
這里只需指定新的 path;其他部分,包括原有的 query_string 會自動添加上,從而形成新的 url; -
rewrite /grab-new/index.html$ /demand.html permanent;
permanent 返回 301,永久重定向;redirect 返回 302,臨時重定向;不指定 permanent 或者 redirect,就是 nginx 內部重定向(internal redirect,對用戶是透明的,即用戶并不知曉改變);permanent 或 redirect 會改變瀏覽器地址欄; -
rewrite /grab-new/index.html$ /demand.html?a=2? permanent;
使用新的 query_string: a=2,如果沒有最后的?
,則原有的 query_string 會自動添加上;
replacement:/demand.html?$query_string?
等同于/demand.html
; - 如果要跳轉到新域名,replacement 請使用 http:// 或 https:// 開頭的完整 url,這時不指定 flag 的話,默認 302 redirect;
方法1
下面代碼中,listen 指令表明 server 塊同時用于 HTTP流量。
server_name 指令匹配包含域名 www.old-name.com 的請求。
return 指令告訴 Nginx 停止處理請求,直接返回 301 (Moved Permanently) 代碼和指定的重寫過的URL到客戶端。
$scheme 是協議(HTTP 或 HTTPS),$request_uri是包含參數的完整的 URI。
server{
listen 80;
server_name www.old-name.com;
# return 指令的第一個參數是響應碼。第二個參數可選,可以是重定向的 URL
# location 和 server 上下文中都可以使用 return 指令。
return 301 $scheme://www.new-name.com$request_uri;
}
方法2
server {
listen 80;
server_name old.example.cn;
rewrite ^(.*)$ http://$newhost$1 permanent;
}
常用指令
- server_name,more about server names;
- index
- listen
- root
-
expires time;Excellent Caching Tutorial;
該設置用于生成 HTTP Response Header:Expires,Cache-Control; - try_files
-
access_log
log_format,有時日志暫時不需要,可以關閉:access_log off;
-
error_log
有時日志暫時不需要,可以關閉:error_log off;
- return
- 簡單認證 auth_basic
auth_basic "Git authentication required";
auth_basic_user_file htpasswd/pages.example.com;
使用openssl passwd
來將明文轉為密碼;printf "USER:$(openssl passwd -crypt PASSWORD)\n" >> <passwdfilename>
,printf 類似 echo; - error_page
- rewrite,if 是 rewrite 模塊的一個指令;
-
client_body_in_file_only;
可用來查看調試 request body 內容,在 log_format 中使用$request_body_file
記錄文件名,文件路徑為$nginx/client_body_temp
; - 記錄請求頭和響應頭;
記錄請求頭(request headers),則需要在 log_format 中使用 $http_name 分別指定,記錄響應頭(response headers)則形如:$sent_http_name,自定義的 header 也沒問題;比如:$sent_http_content_type(Content-Type);(Header lines sent to a client have the prefix “sent_http_”, for example, $sent_http_content_range.) -
add_header
其中偶遇的 map 功能挺有意思:根據返回的 Content-Type 來決定 expires;
map $sent_http_content_type $expires {
default off;
application/pdf 42d;
~image/ max;
}
expires $expires;
Embedded Variables
- Alphabetical index of variables;
- $http_name
arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores.
請求頭中字段名轉為小寫,連字符改為下劃線;比如:User-Agent => $http_user_agent;X-Abc-Xyz => $http_x_abc_xyz; - $server_name
示例解析 nginx.conf 片段
example.com 301 便利 SEO 收錄和統計
server {
listen 80;
server_name example.com;
return 301 $scheme://www.example.com$request_uri;
}
subdomain 和 path-component 共存
default_server
server {
listen 80 default_server;
location / {
root html;
index index.html;
}
# return 200;
}
- root html 指的是 $NGINX_HOME/html,和 conf/ 目錄同級;
html/index.html 這個文件可以很好的作為測試使用; - 通過
include zwph/*.conf;
引入的配置片段,root html 中的 html 路徑是一樣的; - 運行時,請打開 return 200;
log_not_found
假如 favicon.ico 和 robots.txt 兩個文件都沒有定義,可以如下設置:
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
- log_not_found
- 但是如果同時定義了 error_page 404,則 請不要設置以上內容,因為設置了也沒有用,反而應當 touch 兩個文件更簡單或者設置
return 204;
location = /favicon.ico {
log_not_found off;
access_log off;
return 204;
}
Requests are logged in context of a location where request execution ends up. As you have error_page 404 defined, and no favicon.ico file - error 404 is generated and redirected to /errors/404.html. As a result request is logged in context of "location /errors/" where you have access log enabled.
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
}
access_log /logs/wph/www/access-$year$month$day$hour.log;
- 注意 if 后面的空格;
location /hour24/screen-detail/ {
if (!-f $request_filename) {
rewrite ^/hour24/screen-detail/(.*)\.html$ /hour24/screen-detail.html?id=$1 last;
}
}
按版本部署 api
root /home/app/8ni/api.m/;
location ~ "^(/v[0-9]{1,2}\.[0-9]{1,2}/)(.*)\.php$" {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/app/8ni/api.m/$1/web/$2.php;
include fastcgi_params;
}
- 注意正則表達式的雙引號,否則會報告錯誤:
pcre_compile() failed: missing ) in "^(/v[0-9]"
,因為把緊跟其后面的那個 { 認為是 location {} 的那個 {。
fonts 設置 cors
location ~* ^.*?\.(eot|ttf|woff)$ {
expires 1M;
access_log off;
add_header Access-Control-Allow-Origin *;
}
- svg? woff2?
按版本部署 www
root /home/app/example/wph.pages/;
index index.html;
location ~ "^(?!(\/s[0-9]{1,2}\.[0-9]{1,2}[a-z]))(.*)" {
root /home/app/example/wph.pages/s0.6e/;
}
- 上述配置含義:只要不是
s0.6e
形式的訪問,直接到 s0.6e 目錄下(最新版本的目錄);不需要其他方式 location; - regex101: Online regex tester and debugger: JavaScript, Python, PHP, and PCRE;
- nginx 使用的是 PCRE 語法;
- 如果 [a-z] 后面加上
\/
代表訪問 URL 必須攜帶最后的/
,http://wph.pages.example.com/v0.6e/。
php 代碼
location ~ ".*\.php$" {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME /home/app/example/api/web/$fastcgi_script_name;
}
- 原來有一句
fastcgi_index index.php;
其實并不需要,因為 location 已經做了限定; - fastcgi_params 文件內容
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
- 每一行指定了一個 fastcgi_param,在 PHP 代碼里面可以通過 $_SERVER 變量來引用,比如:$_SERVER['REMOTE_ADDR'];
- fastcgi.conf 和 fastcgi_params 文件幾乎一樣
fastcgi.conf 在最開頭多了一行:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
,而這個 SCRIPT_FILENAME 我們是要自定義的。 - 這篇文章 有深度;
- 設置自定義的 fastcgi_param;
fastcgi_param SITE_TPL_DIR /home/app/example/www.satellite/share/tpl/;
這里設置了 SITE_TPL_DIR 這個自定義的 fastcgi_param,在 php 代碼中可以使用,便于每個站點使用自己的 TPL 目錄。
安全
隱藏版本號
http {
server_tokens off;
}
- 在 Response Headers 中只會返回:
Server:nginx
; - 默認 nginx 錯誤頁也遵從這個指令;
- 如果要 刪除 Server 這個 Header,則需要重新編譯 Nginx,然后
more_clear_headers Server;
PHP 版本隱藏問題(和 nginx 無關)
- 在 php.ini 中配置:expose_php = Off 即可;
- HTTP 回應頭
X-Powered-By:PHP/5.6.11
就不會再顯示了; - 使用
php --ini
查看 php.ini 在哪兒; - 重啟 php-fpm:
/usr/local/php/sbin/restart.sh
;
性能調整
Caching for IMAGES, CSS & JS
# Media: images, icons, HTC
location ~* \.(?:jpg|gif|png|svg|ico|htc)$ {
expires 1M;
access_log off;
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1y;
access_log off;
}
-
?:
表示不需要捕獲(non-capturing subpattern @ PCRE-Pattern,嵌套()時常見); -
?i:
中的 i,表示不區分大小寫,容錯 jpg,JPG;
gzip
有關 gzip 的設置,統一放在 nginx.conf 的 http 指令下即可;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_types text/css application/javascript application/json text/plain;
ETag
- Nginx 默認是開啟的,其 算法 為:<last modified time(hex)>-<content length(hex)>.
- 示例:
ETag:"57af2761-fe2b"
,對應時間:2016-08-13 21:57:53.033453025 +0800,文件大小=65067字節; - ETag @ RFC7232:Conditional Requests;
Even if your components have a far future Expires header, a conditional GET request is still made whenever the user hits Reload or Refresh.
Miscs
- 方便使用 nginx
cd /usr/local/bin
ln -s /usr/local/nginx/sbin/nginx nginx
nginx 代理 websocket
注釋 Does nginx support comment blocks in configuration?
# 做注釋
通過本地 proxy server 上網
假如你通過本地的一個 proxy server 上網,則需要如下設置 git:
* stackoverflow: Getting git to work with a proxy server
備注
- 通常網站文件都要設置為 nginx:nginx。
- $NGINX_HOME/html/ 默認作為 listen 的 default_server 的 root
青云的負載均衡器的轉發策略比較靈活,比如 按域名轉發:
^example.com$
(將 http://example.com/ 訪問轉發到后端主機),api.example.com
,^.*example.com
,等規則,并且可以調整匹配順序,類似 nginx 的正則解釋。
在多個后端主機情況下,就體現出其匹配順序。
排查問題可就近使用 $NGINX_HOME/html/index.html 文件。