nginx 配置总结
nginx 介绍
nginx
是一个高性能的 web
服务器,常用作反向代理服务器。nginx
作为反向代理服务器,就是把 http
请求转发到另一个或者一些服务器上。 通过把本地一个 url
前缀映射到要跨域访问的 web
服务器上,就可以实现跨域访问。 对于浏览器来说,访问的就是同源服务器上的一个 url
。而 nginx
通过检测 url
前缀,把 http
请求转发到后面真实的物理服务器。并通过 rewrite
命令把前缀再去掉。这样真实的服务器就可以正确处理请求,并且并不知道这个请求是来自代理服务器的。 简单说,nginx
服务器欺骗了浏览器,让它认为这是同源调用,从而解决了浏览器的跨域问题。又通过重写 url
,欺骗了真实的服务器,让它以为这个 http
请求是直接来自与用户浏览器的。 这样,为了解决跨域问题,只需要动一下 nginx
配置文件即可。简单、强大、高效!
nginx.conf 配置文件
Nginx
配置文件主要分成四部分:main(全局设置)
、server(主机设置)
、upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)
和 location(URL 匹配特定位置后的设置)
,每部分包含若干个指令。
main
部分设置的指令将影响其它所有部分的设置;server
部分的指令主要用于指定虚拟主机域名、IP 和端口;upstream
的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;location
部分用于匹配网页位置(比如,根目录“/”,“/images”,等等)。
他们之间的关系是:server
继承 main
,location
继承 server
,upstream
既不会继承指令也不会被继承。它有自己的特殊指令,不需要在其他地方的应用。
通用
下面的 nginx.conf
简单的实现 nginx
在前端做反向代理服务器的例子,处理 js、png
等静态文件,jsp
等动态请求转发到其它服务器 tomcat
:
user www www;
worker_processes 2;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 2048;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
# tcp_nopush on;
keepalive_timeout 65;
# gzip压缩功能设置
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
# http_proxy 设置
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
# 设定负载均衡后台服务器列表
upstream backend {
#ip_hash;
server 192.168.10.100:8080 max_fails=2 fail_timeout=30s ;
server 192.168.10.101:8080 max_fails=2 fail_timeout=30s ;
}
# 很重要的虚拟主机配置
server {
listen 80;
server_name itoatest.example.com;
root /apps/oaapp;
charset utf-8;
access_log logs/host.access.log main;
#对 / 所有做负载均衡+反向代理
location / {
root /apps/oaapp;
index index.jsp index.html index.htm;
proxy_pass http://backend;
proxy_redirect off;
# 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
#静态文件,nginx自己处理,不去backend请求tomcat
location ~* /download/ {
root /apps/oa/fs;
}
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
root /apps/oaapp;
expires 7d;
}
location /nginx_status {
stub_status on;
access_log off;
allow 192.168.10.0/24;
deny all;
}
location ~ ^/(WEB-INF)/ {
deny all;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
## 其它虚拟主机,server 指令开始
}
常用指令说明
main 全局配置
nginx
在运行时与具体业务功能(比如 http
服务或者 email
服务代理)无关的一些参数,比如工作进程数,运行的身份等。
woker_processes 2
在配置文件的顶级
main
部分,worker
角色的工作进程的个数,master
进程是接收并分配请求给worker
处理。这个数值简单一点可以设置为cpu
的核数grep ^processor /proc/cpuinfo | wc -l
,也是auto
值,如果开启了ssl
和gzip
更应该设置成与逻辑CPU
数量一样甚至为 2 倍,可以减少I/O
操作。如果nginx
服务器还有其它服务,可以考虑适当减少。worker_cpu_affinity
也是写在
main
部分。在高并发情况下,通过设置cpu
粘性来降低由于多CPU
核切换造成的寄存器等现场重建带来的性能损耗。如worker_cpu_affinity 0001 0010 0100 1000
; (四核)。worker_connections 2048
写在
events
部分。每一个worker
进程能并发处理(发起)的最大连接数(包含与客户端或后端被代理服务器间等所有连接数)。nginx
作为反向代理服务器,计算公式最大连接数 = worker_processes \* worker_connections/4
,所以这里客户端最大连接数是1024
,这个可以增到到8192
都没关系,看情况而定,但不能超过后面的worker_rlimit_nofile
。当nginx
作为http
服务器时,计算公式里面是除以 2。worker_rlimit_nofile 10240
写在
main
部分。默认是没有设置,可以限制为操作系统最大的限制 65535。use epoll
写在
events
部分。在Linux
操作系统下,nginx
默认使用epoll
事件模型,得益于此,nginx
在Linux
操作系统下效率相当高。同时Nginx
在OpenBSD
或FreeBSD
操作系统上采用类似于epoll
的高效事件模型kqueue
。在操作系统不支持这些高效模型时才使用select
。
http 服务器
与提供 http
服务相关的一些配置参数。例如:是否使用 keepalive
啊,是否使用 gzip
进行压缩等。
sendfile on
开启高效文件传输模式,
sendfile
指令指定nginx
是否调用sendfile
函数来输出文件,减少用户空间到内核空间的上下文切换。对于普通应用设为on
,如果用来进行下载等应用磁盘IO
重负载应用,可设置为off
,以平衡磁盘与网络I/O
处理速度,降低系统的负载。keepalive_timeout 65
长连接超时时间,单位是秒,这个参数很敏感,涉及浏览器的种类、后端服务器的超时设置、操作系统的设置,可以另外起一片文章了。长连接请求大量小文件的时候,可以减少重建连接的开销,但假如有大文件上传,65s 内没上传完成会导致失败。如果设置时间过长,用户又多,长时间保持连接会占用大量资源。
send_timeout
用于指定响应客户端的超时时间。这个超时仅限于两个连接活动之间的时间,如果超过这个时间,客户端没有任何活动,Nginx 将会关闭连接。
client_max_body_size 10m
允许客户端请求的最大单文件字节数。如果有上传较大文件,请设置它的限制值
client_body_buffer_size 128k
缓冲区代理缓冲用户端请求的最大字节数
模块 http_proxy
这个模块实现的是 nginx
作为反向代理服务器的功能,包括缓存功能(另见文章)
proxy_connect_timeout 60
nginx 跟后端服务器连接超时时间(代理连接超时)
proxy_read_timeout 60
连接成功后,与后端服务器两个成功的响应操作之间超时时间(代理接收超时)
proxy_buffer_size 4k
设置代理服务器(nginx)从后端 realserver 读取并保存用户头信息的缓冲区大小,默认与 proxy_buffers 大小相同,其实可以将这个指令值设的小一点
proxy_buffers 4 32k
proxy_buffers 缓冲区,nginx 针对单个连接缓存来自后端 realserver 的响应,网页平均在 32k 以下的话,这样设置
proxy_busy_buffers_size 64k
高负荷下缓冲大小(proxy_buffers*2)
proxy_max_temp_file_size
当 proxy_buffers 放不下后端服务器的响应内容时,会将一部分保存到硬盘的临时文件中,这个值用来设置最大临时文件大小,默认 1024M,它与 proxy_cache 没有关系。大于这个值,将从 upstream 服务器传回。设置为 0 禁用。
proxy_temp_file_write_size 64k
当缓存被代理的服务器响应到临时文件时,这个选项限制每次写临时文件的大小。proxy_temp_path(可以在编译的时候)指定写到哪那个目录。
模块 http_gzip
gzip on
: 开启 gzip 压缩输出,减少网络传输。gzip_min_length 1k
: 设置允许压缩的页面最小字节数,页面字节数从 header 头得 content-length 中进行获取。默认值是 20。建议设置成大于 1k 的字节数,小于 1k 可能会越压越大。gzip_buffers 4 16k
: 设置系统获取几个单位的缓存用于存储 gzip 的压缩结果数据流。4 16k 代表以 16k 为单位,安装原始数据大小以 16k 为单位的 4 倍申请内存。gzip_http_version 1.0
: 用于识别 http 协议的版本,早期的浏览器不支持 Gzip 压缩,用户就会看到乱码,所以为了支持前期版本加上了这个选项,如果你用了 Nginx 的反向代理并期望也启用 Gzip 压缩的话,由于末端通信是 http/1.0,故请设置为 1.0。gzip_comp_level 6
: gzip 压缩比,1 压缩比最小处理速度最快,9 压缩比最大但处理速度最慢(传输快但比较消耗 cpu)gzip_types
:匹配 mime 类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的。gzip_proxied any
: Nginx 作为反向代理的时候启用,决定开启或者关闭后端服务器返回的结果是否压缩,匹配的前提是后端服务器必须要返回包含”Via”的 header 头。gzip_vary on
: 和 http 头有关系,会在响应头加个 Vary: Accept-Encoding ,可以让前端的缓存服务器缓存经过 gzip 压缩的页面,例如,用 Squid 缓存经过 Nginx 压缩的数据。。
server 虚拟主机
http 服务上支持若干虚拟主机。每个虚拟主机一个对应的 server 配置项,配置项里面包含该虚拟主机相关的配置。在提供 mail 服务的代理时,也可以建立若干 server。每个 server 通过监听地址或端口来区分。
listen
:监听端口,默认 80,小于 1024 的要以 root 启动。可以为 listen *:80、listen 127.0.0.1:80 等形式。server_name
:服务器名,如 localhost、www.example.com,可以通过正则匹配。
模块 http_stream
这个模块通过一个简单的调度算法来实现客户端 IP 到后端服务器的负载均衡,upstream 后接负载均衡器的名字,后端 realserver 以 host:port options; 方式组织在 {} 中。如果后端被代理的只有一台,也可以直接写在 proxy_pass 。
location
http 服务中,某些特定的 URL 对应的一系列配置项。
root /var/www/html
定义服务器的默认网站根目录位置。如果 locationURL 匹配的是子目录或文件,root 没什么作用,一般放在 server 指令里面或/下。
index.jsp index.html index.htm
定义路径下默认访问的文件名,一般跟着 root 放
proxy_pass http:/backend
请求转向 backend 定义的服务器列表,即反向代理,对应 upstream 负载均衡器。也可以
proxy_pass http://ip:port
。proxy_redirect off;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
这四个暂且这样设,如果深究的话,每一个都涉及到很复杂的内容,也将通过另一篇文章来解读。
其他
访问控制 allow/deny
Nginx 的访问控制模块默认就会安装,而且写法也非常简单,可以分别有多个 allow,deny,允许或禁止某个 ip 或 ip 段访问,依次满足任何一个规则就停止往下匹配。如:
location /nginx-status {
stub_status on;
access_log off;
# auth_basic "NginxStatus";
# auth_basic_user_file /usr/local/nginx-1.6/htpasswd;
allow 192.168.10.100;
allow 172.29.73.0/24;
deny all;
}
我们也常用 httpd-devel 工具的 htpasswd 来为访问的路径设置登录密码:
# htpasswd -c htpasswd admin
New passwd:
Re-type new password:
Adding password for user admin
# htpasswd htpasswd admin //修改admin密码
# htpasswd htpasswd sean //多添加一个认证用户
这样就生成了默认使用 CRYPT 加密的密码文件。打开上面 nginx-status 的两行注释,重启 nginx 生效。
列出目录 autoindex
Nginx 默认是不允许列出整个目录的。如需此功能,打开 nginx.conf 文件,在 location,server 或 http 段中加入 autoindex on;,另外两个参数最好也加上去:
autoindex_exact_size off;
默认为 on,显示出文件的确切大小,单位是 bytes。改为 off 后,显示出文件的大概大小,单位是 kB 或者 MB 或者 GB
autoindex_localtime on;
默认为 off,显示的文件时间为 GMT 时间。改为 on 后,显示的文件时间为文件的服务器时间
location /images {
root /var/www/nginx-default/images;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
重新加载 nginx 配置文件
nginx -s reload
location 正则写法
location = / {
# 精确匹配 / ,主机名后面不能带任何字符串
[ configuration A ]
}
location / {
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# 但是正则和最长字符串会优先匹配
[ configuration B ]
}
location /documents/ {
# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration C ]
}
location ~ /documents/Abc {
# 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration CC ]
}
location ^~ /images/ {
# 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
# 匹配所有以 gif,jpg或jpeg 结尾的请求
# 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
[ configuration E ]
}
location /images/ {
# 字符匹配到 /images/,继续往下,会发现 ^~ 存在
[ configuration F ]
}
location /images/abc {
# 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
# F与G的放置顺序是没有关系的
[ configuration G ]
}
location ~ /images/abc/ {
# 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
[ configuration H ]
}
location ~* /js/.*/\.js
- 以
=
开头表示精确匹配 - 如
A
中只匹配根目录结尾的请求,后面不能带任何字符串。 ^~
开头表示uri
以某个常规字符串开头,不是正则匹配~
开头表示区分大小写的正则匹配;~\*
开头表示不区分大小写的正则匹配/
通用匹配, 如果没有其它匹配,任何请求都会匹配到- 顺序
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)
按照上面的 location 写法,以下的匹配示例成立:
- / -> config A 精确完全匹配,即使/index.html 也匹配不了
- /downloads/download.html -> config B 匹配 B 以后,往下没有任何匹配,采用 B
- /images/1.gif -> configuration D 匹配到 F,往下匹配到 D,停止往下
- /images/abc/def -> config D 最长匹配到 G,往下匹配 D,停止往下 你可以看到 任何以/images/开头的都会匹配到 D 并停止,FG 写在这里是没有任何意义的,H 是永远轮不到的,这里只是为了说明匹配顺序
- /documents/document.html -> config C 匹配到 C,往下没有任何匹配,采用 C
- /documents/1.jpg -> configuration E 匹配到 C,往下正则匹配到 E
- /documents/Abc.jpg -> config CC 最长匹配到 C,往下正则顺序匹配到 CC,不会往下到 E
实际使用建议
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:
#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
proxy_pass http://tomcat:8080/index
}
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
#第三个规则就是通用规则,用来转发动态请求到后端应用服务器
#非静态文件请求就默认是动态请求,自己根据实际把握
#毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
proxy_pass http://tomcat:8080/
}
Rewrite 规则
rewrite
使用nginx
提供的全局变量或自己设置的变量,结合正则表达式
和标志位
实现 url 重写以及重定向。
rewrite
只能放在 server{},location{},if{}
中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 http://seanlook.com/a/we/index.php?id=1&u=str
只对/a/we/index.php
重写。
如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用 proxy_pass
反向代理。
表明看 rewrite
和 location
功能有点像,都能实现跳转,主要区别在于 rewrite
是在同一域名内更改获取资源的路径,而 location
是对一类路径做控制访问或反向代理,可以 proxy_pass
到其他机器。很多情况下 rewrite
也会写在 location
里,它们的执行顺序是:
- 执行
server
块的rewrite
指令 - 执行 location 匹配
- 执行选定的 location 中的 rewrite 指令
如果其中某步 URI
被重写,则重新循环执行 1-3
,直到找到真实存在的文件;循环超过 10 次,则返回 500 Internal Server Error 错误。
flag 标志位
last
: 相当于 Apache 的[L]
标记,表示完成 rewritebreak
: 停止执行当前虚拟主机的后续 rewrite 指令集redirect
: 返回 302 临时重定向,地址栏会显示跳转后的地址permanent
: 返回 301 永久重定向,地址栏会显示跳转后的地址
因为 301 和 302 不能简单的只返回状态码,还必须有重定向的 URL,这就是 return 指令无法返回 301,302 的原因了。这里 last 和 break 区别有点难以理解:
- last 一般写在 server 和 if 中,而 break 一般使用在 location 中
- last 不终止重写后的 url 匹配,即新的 url 会再从 server 走一遍匹配流程,而 break 终止重写后的匹配
- break 和 last 都能阻止继续执行后面的 rewrite 指令
if 指令与全局变量
if 判断指令
语法为 if(condition){...}
,对给定的条件 condition
进行判断。如果为真,大括号内的 rewrite
指令将被执行,if 条件(conditon
)可以是如下任何内容:
- 当表达式只是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false
- 直接比较变量和内容时,使用
=或!=
~
正则表达式匹配,~\*
不区分大小写的匹配,!~
区分大小写的不匹配-f 和!-f
用来判断是否存在文件- `-d 和!-d 用来判断是否存在目录
-e 和!-e
用来判断是否存在文件或目录-x 和!-x
用来判断文件是否可执行
例如:
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite请求到/msid/目录下
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
} //如果cookie匹配正则,设置变量$id等于正则引用部分
if ($request_method = POST) {
return 405;
} //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302
if ($slow) {
limit_rate 10k;
} //限速,$slow可以通过 set 指令设置
if (!-f $request_filename){
break;
proxy_pass http://127.0.0.1;
} //如果请求的文件名不存在,则反向代理到localhost 。这里的break也是停止rewrite检查
if ($args ~ post=140){
rewrite ^ http://example.com/ permanent;
} //如果query string中包含"post=140",永久重定向到example.com
location ~* \.(gif|jpg|png|swf|flv)$ {
valid_referers none blocked www.jefflei.com www.leizhenfang.com;
if ($invalid_referer) {
return 404;
} //防盗链
}
全局变量
下面是可以用作 if 判断的全局变量:
$args
: #这个变量等于请求行中的参数,同$query_string$content_length
: 请求头中的 Content-length 字段。$content_type
: 请求头中的 Content-Type 字段。$document_root
: 当前请求在 root 指令中指定的值。$host
: 请求主机头字段,否则为服务器名称。$http_user_agent
: 客户端 agent 信息$http_cookie
: 客户端 cookie 信息$limit_rate
: 这个变量可以限制连接速率。$request_method
: 客户端请求的动作,通常为 GET 或 POST。$remote_addr
: 客户端的 IP 地址。$remote_port
: 客户端的端口。$remote_user
: 已经经过 Auth Basic Module 验证的用户名。$request_filename
: 当前请求的文件路径,由 root 或 alias 指令与 URI 请求生成。$scheme
: HTTP 方法(如 http,https)。$server_protocol
: 请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。$server_addr
: 服务器地址,在完成一次系统调用后可以确定这个值。$server_name
: 服务器名称。$server_port
: 请求到达服务器的端口号。$request_uri
: 包含请求参数的原始 URI,不包含主机名,如:”/foo/bar.php?arg=baz”。$uri
: 不带请求参数的当前 URI,$uri 不包含主机名,如”/foo/bar.html”。$document_uri
: 与$uri 相同。
例:http://localhost:88/test1/test2/test.php
$host
:localhost
$server_port
:88
$request_uri
:http://localhost:88/test1/test2/test.php
$document_uri
:/test1/test2/test.php
$document_root
:/var/www/html
$request_filename
:/var/www/html/test1/test2/test.php
rewrite 实例
例 1:
http { # 定义 image 日志格式
log_format imagelog '[$time_local] ' $image_file ' ' $image_type ' ' $body_bytes_sent ' ' $status; # 开启重写日志
rewrite_log on;
server {
root /home/www;
location / {
# 重写规则信息
error_log logs/rewrite.log notice;
# 注意这里要用‘’单引号引起来,避免{}
rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
set $image_file $3;
set $image_type $4;
}
location /data {
# 指定针对图片的日志格式,来分析图片类型和大小
access_log logs/images.log mian;
root /data/images;
# 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里
try_files /$arg_file /image404.html;
}
location = /image404.html {
# 图片不存在返回特定的信息
return 404 "image not found\n";
}
}
对形如/images/ef/uh7b3/test.png
的请求,重写到/data?file=test.png
,于是匹配到 location /data
,先看/data/images/test.png
文件存不存在,如果存在则正常响应,如果不存在则重写 tryfiles
到新的 image404 location
,直接返回 404
状态码。
例 2:
rewrite ^/images/(.\*)\_(\d+)x(\d+)\.(png|jpg|gif)$ /resizer/$1.$4?width=$2&height=\$3? last;
对形如/images/bla_500x400.jpg
的文件请求,重写到/resizer/bla.jpg?width=500&height=400
地址,并会继续尝试匹配 location
。
其他参考:Nginx 极简教程