反向代理与前向代理
前向代理:作为客户端的代理,将从互联网上获取的资源返回给一个或多个的客户端,服务端(如Web服务器)只知道代理的IP地址而不知道客户端的IP地址;
反向代理:是作为服务器端(如Web服务器)的代理使用,而不是客户端,客户端知道代理服务器IP地址而不知道具体后台服务器的IP地址。
举个例子,在公司通过代理服务器访问外网,这里代理服务器属于前向代理服务器,而客户通过代理服务器从外网访问我们公司的服务器,这里的代理服务器就是反向代理服务器。Nginx实现反向代理很简单,使用一个proxy_pass指令将请求转发给指定的后台服务器即可。
基本配置
#工作进程个数,通常设置和逻辑cpu个数一致
worker_processes 1;
# 用户和用户组
user root owner;
#cpu亲和性,每个进程分配一个cpu 00000001表示第一个cpu,00000010表示第二个cpu,依次类推
#worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
#如果是两个逻辑cpu,可以设置worker_processes 2; #worker_cpu_affinity 01 10;
#一个nginx工作进程最多可以打开的文件描述符个数 ,最好和linux最多能打开的文件描述符个数(查看命令:ulimit-n)保持一致。
#出现报错:too open many file,这时我们把#worker_rlimit_nofile 值设置大一些就可以了。
#worker_rlimit_nofile 65535
#记录的级别严重程度:debug<info<notice<warn<error<crit,一般记录warn/error级别
#error_log logs/error.log;
#错误日志,级别为notice
#error_log logs/error.log notice;
#错误日志,级别为info
#error_log logs/error.log info;
#记录nginx的master进程的pid
#pid logs/nginx.pid;
events {
#多路复用IO的一种方式,效率很高,支持linux2.6以上内核
use epoll;
#每个工作进程的最大连接数,一台nginx的理论最大连接数就是(单个工作进程的最大连接数*工作进程个数)
worker_connections 1024;
#尽可能多地接受请求
multi_accept on;
}
http {
#媒体类型,定义在nginx/conf/mine.types中
include mime.types;
#默认的媒体类型
default_type application/octet-stream;
#main日志格式
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#访问日志 日志格式为main中定义的格式
#access_log logs/access.log main;
#nginx是否调用sendfile函数(zero,copy等)来输出文件,普通应用都应该设置成on
sendfile on;
#默认开启,nginx接受到数据包不马上发送,等到数据包达到一定大小再发送,使用Nagle算法控制。减少tcp传输次数,防止网络阻塞
#tcp_nopush on;
#tcp不延迟,和tcp_nopush相反,接收到数据包就发送,提高数据的实时响应
#tcp_nodelay off;
#长连接,请求资源获取完毕后不断开连接,65s后关闭该连接
#keepalive_timeout 0;
keepalive_timeout 65;
#上传时单个文件最大为10M
client_max_body_size 10m;
#客户端的请求头缓冲区大小,一般设置为系统分页大小即可(查询系统分页命令:getconf PAGESIZE)
#client_header_buffer_size 4k;
#客户端的请求体缓冲区大小,超过这个大小存放在临时文件中,
#client_body_buffer_size 8k;
######超时管理 代理服务器时才有用 (超时都返回502超时错误)
#nginx连接后台服务器超时时间,
proxy_connect_timeout 90;
#后台服务器回传数据超时时间,90s传输数据未完成就报错
proxy_send_timeout 90;
#连接成功,等待后台服务器响应的超时时间
proxy_read_timeout 90;
#域名解析超时,默认30s
resolver_timeout 30;
#可以理解为TCP连接关闭时的SO_LINGER延时设置,默认5s;
lingering_timeout 5;
#接收客户端body超时, 默认60s, 如果连续的60s内没有收到客户端的1个字节, 返回408
client_body_timeout 60;
#接收客户端header超时, 默认60s, 如果60s内没有收到完整的http包头, 返回408(不能在location里面)
client_header_timeout 60;
#为打开文件设定缓存,默认是不启用的,max指定缓存数量,建议和最多能打开文件描述符个数(查询命令:ulimit -n)一致,inactive是指经过多长时间文件没被请求后删除缓存
open_file_cache max=65535 inactive=60s;
#多久检查一次缓存的有效信息
open_file_cache_valid 30s;
}
负载均衡
放在http模块下面
#定义负载均衡模块,访问localhost会被分到myServers中的服务器上。
#1.down表示的server暂时不参与负载均衡,请求不会转发给这台服务器,一般和iphash一起使用;
#2.weight为weight越大,负载的权重就越大;
#3.max_fails续请求失败的次数默认为1.当超过最大次数时,不再转发请求给这台服务器;
#4.fail_timeout:max_fails次失败后,暂停多久后再向这台服务器转发请求,默认10s;
#5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
#6.ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,适用后台服务器缓存多的场合,也可以解决session的问题。
# 注意,当upstream中只有一个server 时,max_fails 和 fail_timeout 参数可能不会起作用。weight\backup 不能和 ip_hash 关键字一起使用。
upstream myServers{
ip_hash;
server 192.168.1.2:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.1.3:8080 weight=2 max_fails=2 fail_timeout=30s;
server 192.168.1..4:8080 backup;
server 192.168.1.5:8080 down;
}
server {
listen 80;
server_name localhost;#主机名或者域名
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#将请求转发给myServers中的服务器
proxy_pass http://myServers;
#支持的HTTP版本
proxy_http_version 1.1;
#用来重定义发往后端服务器的请求头
#在nginx的配置文件中,如果当前模块中没有proxy_set_header的设置,则会从上级别继承配置。继承顺序为:http, server, location。
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
也可以使用第三方模块实现其他负载均衡模式:
1.添加nginx-upstream-fair模块可以实现按响应性能进行负载均衡,响应速度越快的服务器分发请求的几率越大;
2.添加nginx_upstream_hash模块可以实现按请求url来进行转发请求,url相同的请求由同一个服务器处理,适用于缓存较多场景。
如果nginx.conf中要添加很多的server节点,那么查找和修改server节点就比较麻烦,而且也容易误操作。这种情况下我们可以给每个虚拟主机配置一个配置文件,这样修改某一个虚拟主机的配置就很方便了。
1.首先我们创建目录 /usr/local/nginx/conf/vhosts ,这个目录用于存放各个虚拟主机的配置。
2.为每个server节点新建一个文件,命名为主机名。
3.将server节点的配置信息放进新建的文件中去,如下:
server {
listen 80;
server_name localhost;#主机名或者域名
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#将请求转发给myServers中的服务器
proxy_pass http://myServers;
#支持的HTTP版本
proxy_http_version 1.1;
#用来重定义发往后端服务器的请求头
#在nginx的配置文件中,如果当前模块中没有proxy_set_header的设置,则会从上级别继承配置。继承顺序为:http, server, location。
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
4.在nginx.conf中添加include vhosts/*
表示加载vhosts目录下的文件
压缩配置
gzip可以放在http/server/location/if下,用于压缩请求资源,减小网络传输的数据尺寸。gzip压缩常用于文本类型(css/js等)文件压缩,二进制文件(如图片,视频)压缩比不大,建议使用缓存(expires)进行优化:
#开启gzip压缩
gzip on;
#最小压缩大小4000字节,小于4000字节就不压缩了
gzip_min_length 4000;
#压缩的缓冲设置,缓冲32块开始输出,每块4k大小
#gzip_buffers 32 4k;
#压缩采用的版本
gzip_http_version 1.1;
#压缩级别,级别越大压缩后尺寸越小方便传输,但同时压缩时耗费cpu资源也越大(最大为9,一般不要超过6)
gizp_comp_level 4;
#压缩的文件类型,不属于这些类型的就不压缩(可以通过 cat nginx/conf/mine.types查看文件类型),注:二进制文件如图片/视频的压缩比不大,不建议压缩
gzip_types application/javascript text/plain text/css text/xml;
#是否传输gzip压缩标志,请求头中有vary标志的返回压缩版本文件,没有vary头的返回原始文件
gzip_vary on;
location表达式
Nginx中每一个server可以有多个location。location支持正则表达式,其的作用是转发用户请求。location配置的解释如下表:
符号 | 含义 |
---|---|
location = /url | 表示精确匹配,uri必须完全一致才能匹配成功 |
location ^~ /Purl | 普通匹配,Puri和请求url的开头相同就匹配成功,且不再去匹配正则 |
location /Purl | 普通匹配,Purl和用户请求url的开头相同就匹配成功,然后继续向下匹配,如果匹配成功多个则按最长的。 |
location ~ reg | 区分大小写的正则匹配 |
location ~* reg | 不区分大小写的正则匹配 |
location优先级说明:
在nginx的location和配置中location的顺序没有太大关系。与location表达式的类型有关。相同类型的表达式,字符串长的会优先匹配。
-
第一优先级:等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
-
第二优先级:^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
-
第三优先级:正则表达式类型(~ ~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
-
第四优先级:/ 类型表达式,常规字符串匹配类型。按前缀匹配。
rewrite
rewrite可以实现URI重定向。rewrite可以通过正则匹配重写URI,然后内部跳转再匹配location,或者直接做30x重定向返回客户端。rewrite功能需要PCRE的支持。rewrite指令的语法十分简单如下:
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flag标记
flag标记说明:
-
last :匹配完成后不再匹配当前环境下的其他rewrite指令,开始匹配新的location URI规则
-
break:匹配完成即终止,不再匹配后面的任何规则
-
redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址
-
permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
location中可以有多个rewrite指令,如果有多个rewrite则按照从上到下依次执行,并按最后一个匹配成功的作为最终结果。但是当替代内容中包含http/https等协议名时,直接302跳转到替代内容t指定的url,不再执行后续的rewrite指令。
如果替代内容中不包含http/https等协议名又想在执行一条rewrite指令后不再执行后续指令可以用rewrite中的flag标记,四种flag标记都可以实现不再往下执行其他rewrite指令的作用,但是每种flag标记的使用场景不同。
例子:
server{
listen 80;
server_name localhost;
location = /{
#跳转到百度
rewrite ^/(.*) http://www.baidu.com;
#跳转到/test1
rewrite ^/(.*) /test1;
#跳转到/test2
rewrite ^/(.*) /test2;
root html;
index index.html;
}
location /test1{
return 401;
}
location /test2{
return 402;
}
#日志记录
error_log logs/mysite.error.log error;
access_log logs/mysite.access.log main;
}
server进行上边的配置时,访问localhost会跳转到百度页面,因为替换内容中包含了http协议名,不在执行后续的rewrite指令;
如果把第一个rewrite注释掉,会调整到402错误页,因为rewrite的最终结果时以最后一个匹配成功的为准,最后匹配到 rewite /test2指令,然后找到location /test2返回402错误码;
如果我们在rewrite ^?(.*) /test1后边加上last标记 ,表示不再匹配后边的rewrite,会跳到401错误页,浏览器的url不变还是http://localhost;
如果我们在rewrite ^?(.*) /test1后边加上redirect 或者 permanent 标记 ,表示不再匹配后边的rewrite,会跳转到401错误页(redirect的跳转码为302,permanet的跳转码时301),url会改变成 http://localhost/test1;
如果我们在rewrite ^?(.*) /test1后边加上break标记 ,表示不再匹配任何规则,会跳转到404错误页;因为break标记不会再执行任何规则,所以不会再去找location test1,而是直接找 html/test1资源,所以出现404错误。
if指令
指令 | 使用范围 | 作用 |
---|---|---|
if ( condition ){ // 符合条件执行} | location,server | 条件判断。 != 判断是否相等;~ 、~* 判断是否符合正则;-e、!-e 判断文件,目录,符号链接是否存在;-d 、!-d 判断目录是否存在;-f 、!-f 判断文件是否存在;-x、!-x 判断是否可执行 |
break | server,location,if | 不再继续执行任何指令,直接退出规则的执行 |
return | server,location,if | 结束规则的执行和返回状态码给客户端;如 return 403; |
set variable ‘value’ | http,server,location,if | 新建变量,并赋值 ;如 set varx ‘hello’ |
常用的全局变量
变量 | 含义 |
---|---|
$args | 请求中的参数,同$query_string |
$content length | 请求头中的Content-length字段。 |
$content_type | 请求头中的Content-Type字段。 |
$document_root | 当前请求在root指令中指定的值。 |
$host | 请求主机头字段,否则为服务器名称。 |
$http_user_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,https)。 |
$server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$request_uri | 包含请求参数的原始URI,不包含主机名,如”/user/getuser?id=100”。 |
$uri | 不带请求参数的当前URI,$uri不包含主机名,如”/user/getuser”。 |
$document_uri | 与$uri相同。 |