直接查阅 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 文件。