nginx的rewrite模块和反reverse proxy

目录 升级 OpenSSL 版本 Rewrite 模块 if 指令 全局变量  set 指令 break 指令  return 指令 rewrite

目录

升级 OpenSSL 版本

Rewrite 模块

if 指令

全局变量 

 set 指令

break 指令 

 return 指令

rewrite 指令

 rewrite flag 使用介绍 

flag 说明

break 与 last 

永久与临时重定向 

永久重定向301

临时重定向302

redirect与permanent区别

 自动跳转 https

判断文件是否存在 

指定客户端类型跳转新的域名 

网站维护跳转 

其它案例 

Nginx 防盗链

实现防盗链

范例: 定义防盗链: 

Nginx 反向代理 

添加响应报文的头部信息

反向代理示例: 缓存功能

 这里两个的区别在于X-Real-IP用于显示真实的前端IP但是只能显示一个,X-Forwarded-For是显示前端的多个IP (三个一起用)

 proxy_set_header Host $http_host;的使用

proxy_set_header X-Real-IP $remote_addr; 客户端IP后端显示

 X-Forwarded-For $proxy_add_x_forwarded_for; 前面(多个代理)代理都显示出来

实现反向代理客户端 IP 透传

 实现反向代理客户端 IP 透传(二级)

利用Nginx解决跨域问题

 Http 反向代理负载均衡

  实战案例:基于Cookie 实现会话绑定

 实战案例: 实现 HTTPS 的负载均衡


升级 OpenSSL 版本

升级OpenSSL解决安全漏洞

#准备OpenSSL源码包:
[root@centos8 ~]#cd /usr/local/src
[root@centos8 src]#wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
[root@centos8 src]#tar xvf openssl-1.1.1h.tar.gz

#编译安装Nginx并制定新版本OpenSSL路径:
[root@centos8 ~]#cd /usr/local/src/nginx-1.18.0/
[root@centos8 nginx-1.18.0]#./configure --prefix=/apps/nginx --user=nginx --
group=nginx --with-http_ssl_module --with-http_v2_module --with-
http_realip_module --with-http_stub_status_module --with-http_gzip_static_module
--with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module --
add-module=/usr/local/src/echo-nginx-module --with-
openssl=/usr/local/src/openssl-1.1.1h
[root@centos8 nginx-1.18.0]#make && make install

#验证并启动Nginx:
[root@centos8 ~]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[root@centos8 ~]#systemctl restart nginx

[root@centos8 ~]#nginx -V
nginx version: wanginx/1.68.

...........................................

Rewrite 模块

ngx_http_rewrite_module 模块指令
官方文档: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html 

现在 Nginx 已经成为很多公司作为前端反向代理服务器的首选,在实际工作中往往会 遇到很多跳转(重写 URL)的需求。比如:更换域名后需要保持旧的域名能跳转到新的域名上、某网页发生改变需要跳转到新的页面、网站防盗链等等需求。 和Apache相比Nginx 跳转效率会更高

if 指令

Nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatibler egularexpression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性。

官方文档:

Module ngx_http_rewrite_module

表达式语法:

  1. 当表达式只是一个变量时,如果值为空或任何以0开头的字符串都会当做false
  2. 直接比较变量和内容时,使用=或!=
  3. -f和!-f用来判断是否存在文件
  4. -d和!-d用来判断是否存在目录
  5. -e和!-e用来判断是否存在文件或目录
  6. -x和!-x用来判断文件是否可执行

全局变量 

为了配置if的条件判断,这里需要用到nginx中内置的全局变量 

  1. $args               这个变量等于请求行中的参数,同$query_string
  2. $content_length     请求头中的Content-length字段。
  3. $content_type       请求头中的Content-Type字段。(指定HTTP请求或响应中的实体的MIME类型)
  4. $document_root      当前请求在root指令中指定的值。
  5. $host               请求主机头字段,否则为服务器名称。
  6. $http_user_agent    客户端agent信息
  7. $http_cookie        客户端cookie信息
  8. $limit_rate         这个变量可以限制连接速率。
  9. $request_method     客户端请求的动作,通常为GET或POST。
  10. $remote_addr        客户端的IP地址。
  11. $remote_port        客户端的端口。
  12. $remote_user        已经经过Auth Basic Module验证的用户名。
  13. $request_filename   当前请求的文件路径,由root或alias指令与URI请求生成。
  14. $scheme             HTTP方法(如http,https)。
  15. $server_protocol    请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
  16. $server_addr        服务器地址,在完成一次系统调用后可以确定这个值。
  17. $server_name        服务器名称。
  18. $server_port        请求到达服务器的端口号。
  19. $request_uri        包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
  20. $uri                不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
  21. $document_uri       与$uri相同。 

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接: 

= #比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!= #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false
~ #区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~ #区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假
~* #不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~* #不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真
-f 和 !-f #判断请求的文件是否存在和是否不存在
-d 和 !-d #判断请求的目录是否存在和是否不存在
-x 和 !-x #判断文件是否可执行和是否不可执行
-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
#注意:
#如果$变量的值为空字符串或0,则if指令认为该条件为false,其他条件为true。
#nginx 1.0.1之前$变量的值如果以0开头的任意字符串会返回false

举例说明

若不存在则显示文件下没有

server {
    listen 80 ;
    server_name www.wang.org;
    root /data/nginx/html/pc/;
    location /if {
    index index.html;
    default_type text/html;
    echo "if-----> $scheme";
    if (!-e $request_filename) {
        echo "$request_filename is not exist";
        #return 409;
        }
}
}


1、如果文件不存在则返回400

if (!-f $request_filename) {
    return 400;
}

2、如果host不是jouypub.com,则301到jouypub.com中

if ( $host != 'jouypub.com' ){
    rewrite ^/(.*)$ https://jouypub.com/$1 permanent;
}

3、如果请求类型不是POST则返回405

if ($request_method = POST) {
    return 405;
}

4、如果参数中有a=1则301到指定域名

if ($args ~ a=1) {
    rewrite ^ http://example.com/ permanent;
}

5、在某种场景下可结合location规则来使用,如:

# 访问 /test.html 时
location = /test.html {
    # 设置默认值为xiaowu
    set $name xiaowu;
    # 如果参数中有 name=xx 则使用该值
    if ($args ~* name=(\w+?)(&|$)) {
        set $name $1;
    }
    # 301
    rewrite ^ /$name.html permanent;
}

 set 指令

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $keyvalue,value可以是text, variables和两者的组合。

范例

location /set {
root /data/nginx/html/pc;
index index.html;
default_type text/html;
set $name wang;
echo $name;
set $my_port $server_port;
echo $my_port;
}

范例:根据网络判断是否限速

server {
.....
location /set {
set $slow 1; #如果为0,则不限速,非0限速
if ($slow) {
limit_rate 10k;
}
}

break 指令 

简~解释

中止当前块中的后续rewrite块的指令的执行,包括if,break,rewrite,return,set指令,其他指令可继续执行。

易 ~解释

与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的 ngx_http_rewrite_module 模块中指令就不再执行,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和locationif块中使用

server {listen 80 ;server_name www.wang.org;root /data/nginx/html/pc/;
location /break {
default_type text/html;
set $name wang;
echo "break_before:name=$name" ;
break;
set $my_port $server_port;
echo "break_after:my_port=$my_port" ;
echo "break_after:name=$name" ;
}
}

 return 指令

return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if 和 location块进行配置

Syntax: return code [text];
return code URL;
return URL;
Default: —
Context: server, location, if
return code; #返回给客户端指定的HTTP状态码
return code [text]; #返回给客户端的状态码及响应报文的实体内容,可以调用变量,其中text如果有空格,需要用单或双引号
return code URL; #返回给客户端的URL地址
return URL; #302跳转返回给客户端的URL地址,注意:URL必须是完整的URL包括scheme,
如:http://www.wang.org/

范例: 

 location / {
root /data/nginx/html/pc;
default_type text/html;
index index.html;
if ( $scheme = http ){
#return 666;                                  #返回给客户端指定的HTTP状态码
#return 666 "not allow http"; #返回给客户端的状态码及响应报文的实体内容,可以调用变量,其中text如果有空格,需要用单或双引号
#return 301 http://www.baidu.com;   #返回给客户端的URL地址 可以直接跳转到百度 

如果301(永久重镜像)不写的话,会跳到302(临时重镜像)第一次跳转是不加密的http后续是https了
return 500 "service error";
echo "if-----> $scheme";         #return后面的将不再执行
}

#方法1
server {
listen 80;
server_name www.wang.org;
return 302 https://$server_name$request_uri;   #这种就可以了
}

#方法0:死循环,不要使用
server {
listen 80 ;
listen 443 ssl;
ssl_certificate /apps/nginx/ssl/www.wang.org.crt;
ssl_certificate_key /apps/nginx/ssl/www.wang.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name www.wang.org ;
root /data/nginx/html/pc;
return https://www.wang.org/;          #重镜像自己了又要重镜像自己于是死循环了
}

#方法2         说白了就是在下面重新写一个路径

server {
listen 80;
server_name www.wang.org;
return 302 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name www.wang.org;
ssl_certificate /etc/nginx/ssl/www.wang.org.crt;
ssl_certificate_key /etc/nginx/ssl/www.wang.org.key;
location / {
root /data/www/html;
}
}

rewrite 指令

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理

  • rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的
  • URI                                                                                                                                           注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则   替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制
  • 如果替换后的URL是以http://或https://开头,则替换结果会直接以重定向返回给客户端, 即永久重定向    301

正则表达式格式 

. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字,相当于[0-9]
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
(n) #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^magedu] #匹配除了magedu 这几个字母以外的任意字符

server {
...
rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last;
return 403;
...
}

http://www.wang.org/download/xxx/media/yyyy.zzz
http://www.wang.org/download/xxx/mp3/yyyy.mp3 

 rewrite flag 使用介绍 

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时重定向302)、permanent(永久重定向301)、break和last。
其中前两种是跳转型的flag,后两种是代理型
跳转型指由客户端浏览器重新对新地址进行请求,客户端的浏览器地址信息会发生变化,如:301,302
代理型是在WEB服务器内部实现跳转,客户端的浏览器地址信息不会发生变化,如: last,break

flag 说明

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;
使用相对路径,或者http://或https://开头,状态码:302
permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301
break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后
的其它配置;结束循环,建议在location中使用
#适用于一个URL一次重写
last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,
不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户 

范例: 测试代码

[root@centos8 ~]#cat /apps/nginx/conf.d/www.wang.org.conf
server {
listen 80;
server_name www.wang.org;
root /data/site;
location / {
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}

#准备对应代码
[root@centos8 ~]#mkdir -p /data/site
[root@centos8 ~]# echo "1.html" >/data/site/1.html
[root@centos8 ~]# echo "2.html" >/data/site/2.html
[root@centos8 ~]# echo "3.html" >/data/site/3.html
[root@centos8 ~]# echo "a.html" >/data/site/a.html
[root@centos8 ~]# echo "b.html" >/data/site/b.html
#测试结果: 当请求http://www.wang.org/1.html,最终将会访问/b.html 

break 与 last 

[root@centos8 ~]#cat /apps/nginx/conf.d/www.wang.org.conf
server {
listen 80;
server_name www.wang.org;

root /data/site;
location / {
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
#echo break;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}

#测试结果: 当请求/1.html,最终会访问/2.html
#原因:在location{}内部,遇到break,本location{}内以及后面的所有location{}内的所有指令都不再执行。

当l把break换成last时,就不是break的从头循环了而是last跳过当前子进程往下执行

永久与临时重定向 

域名的临时的调整,后期可能会变,之前的域名或者URL可能还用、或者跳转的目的域名和URL还会跳转,这种情况浏览器不会缓存跳转,临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。

location / {
root /data/nginx/html/pc;
index index.html;
rewrite / http://www.wang.com permanent;       #permanent 301永久重定向
#rewrite / http://www.wang.com redirect;          #redirect 302临时重定向
}
#重启Nginx并访问域名 http://www.wang.org 进行测试

永久重定向301

域名永久型调整,即域名永远跳转至另外一个新的域名,之前的域名再也不使用,跳转记录可以缓存到客户端浏览器永久重定向会缓存DNS解析记录, 浏览器中有 from disk cache 信息,即使nginx服务器无法访问,浏览器也会利用缓存进行重定向比如: 京东早期的域名 www.360buy.com 由于与360公司类似,于是后期永久重定向到了 www.jd.com 

临时重定向302

域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS解析记录,这也是临时重定向与永久重定向最大的本质区别。即当nginx服务器无法访问时,浏览器不能利用缓存,而导致重定向失败

redirect与permanent区别

redirect与permanent都会导致客户端上重新发起的请求,链接地址会发生变化,客户端可以感知到变化 

 自动跳转 https

案例:基于通信安全考虑公司网站要求全站 https,因此要求将在不影响用户请求的情况下将http请求全部自动跳转至 https,另外也可以实现部分 location 跳转

server {
listen 80;
server_name www.wang.org;
return 302 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name www.wang.org;
ssl_certificate /etc/nginx/ssl/www.wang.org.crt;
ssl_certificate_key /etc/nginx/ssl/www.wang.org.key;
location / {
root /data/www/html;
}

范例: 

[root@centos8 ~]#vim /apps/nginx/conf.d/pc.conf
server {
listen 443 ssl;
listen 80;
ssl_certificate /apps/nginx/certs/www.wang.org.crt;
ssl_certificate_key /apps/nginx/certs/www.wang.org.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name www.wang.org;
location / {                                                      #针对全站跳转
root /data/nginx/html/pc;
index index.html;
if ($scheme = http ){                                         #如果没有加条件判断,会导致死循环
rewrite ^/(.*) https://$host/$1 redirect;
}
}
location /login {                                                 #针对特定的URL进行跳转https
if ($scheme = http ){                                        #如果没有加条件判断,会导致死循环
rewrite / https://$host/login redirect;
}
}
}
#重启Nginx并访问测试
[root@centos7 ~]#curl -ikL www.wang.org
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.18.0
Date: Thu, 08 Oct 2020 15:23:48 GMT
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: https://www.wang.org 

判断文件是否存在 

案例:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页

[root@centos8 ~]#vim /apps/nginx/conf.d/pc.conf
server {
listen 80;
server_name www.wang.org;
location / {
root /data/nginx/html/pc;
index index.html;
if (!-e $request_filename) {
rewrite .* http://www.wang.org/index.html;         #实现客户端浏览器的302跳转
#rewrite .* /index.html;                                       #web服务器内部跳转
}
}
}
#重启Nginx并访问测试

指定客户端类型跳转新的域名 

#需求:用户通过手机设备访问 www.wang.org,跳转至m.wang.org
[root@centos8 ~]#vim /apps/nginx/conf.d/www.wang.org.conf
server {
listen 80;
server_name www.wang.org;
root /data/nginx/html/pc;
if ($http_user_agent ~* "android|iphone|ipad") {
rewrite ^/(.*)$ http://m.wang.org/$1 redirect;
#return 302 http://m.wang.org$request_uri ;
}
}

curl  -A"android" -v http://www.wang.org

网站维护跳转 

#需求: 公司网站在停机维护时,指定的IP能够正常访问,其他的IP跳转到维护页。
[root@centos8 ~]# cat /apps/nginx/conf.d/www.wang.org.conf
server {
        listen 80;
        server_name www.wang.org;
        root /data/site;
        index index.html;
        #在server层下设定ip变量值为0
        set $ip 0;
        #如果来源IP是10.0.0.101或102则设定变量为ip变量为1。
        if ($remote_addr = 10.0.0.101) {
                set $ip 1;
        }
        if ($remote_addr = 10.0.0.102) {
                set $ip 1;
        }
        #如果来源IP不是10.0.0.101或102、则跳转至/data/site/maintain.html这个页面,否则不做任何处理
        if ($ip = 0) {
                rewrite ^(.*)$ /maintain.html break;
        }
        #如果想针对某个location进行操作,则将如上配置写入location中即可
        }

其它案例 

#案例1:如果客户端浏览器包含MSIE,则rewrite客户端请求到/msie目录下

if ( $http_user_agent ~ MSIE){
        rewrite ^(.*)$ /msie/$1 break;
}

#案例2: 更换目录访问方式,目录转换为对象存储形式
#要求:

#/20200106/static ->/static?id=20200106
#/20200123/image ->/image?id=20200123
rewrite ^/(\d+)/(.+)/ /$2?id=$1 redirect;

#案例3:多目录转换访问方式
#要求: www.magedu.com/images/20200106/1.jpg => www.magedu.com/index.do?
name=images&dir=20200106=&file=1.jpg
#规则配置:

if ($host ~* (.*)\.magedu\.com) {
        rewrite ^/(.*)/(\d+)/(.*)$ /index.do?name=$1&dir=$2&file=$3 redirect;
}

Nginx 防盗链

防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名   这样他会消耗你网站的带宽,服务器的资源

 #新建一个主机www.wange.org,盗取另一台主机m.wang.org的图片

[root@ubuntu2004 conf.d]#cat www.wang.org.conf 
server {
    listen 80 ;
    server_name www.wang.org;
    root /data/nginx/html/pc;
    access_log /apps/nginx/logs/www.wang.org_access.log main; #指定日志文件格式名mian
}

#盗链服务器配置如下

[root@ubuntu2004 conf.d]#cat m.wang.org.conf 
server {
    listen 80;
    server_name m.wang.org;
    root /data/nginx/html/mobile;
}

#准备盗链web页面

[root@ubuntu2004 pc]#cat daolian.html 



盗链



欢迎大家


永劫无间欢迎你



#图片在这下面

[root@ubuntu2004 images]#pwd
  /data/nginx/html/mobile/images

[root@ubuntu2004 images]#ls
logo.jpg

#重启Nginx并访问http://www.wange.org/daolian.html 测试
#验证两个域名的日志,是否会在被盗链的web站点的日志中出现以下盗链日志信息:
[root@centos8 ~]#tail /apps/nginx/logs/wang.org_access.log

解析mian

mian是一种格式用来指定日志格式的,也可以不用他自己在外面加指定路径或者不指定用默认路径                                指定的话需要把这几行注释去掉。启用取来

[root@ubuntu2004 conf.d]#vim /apps/nginx/conf/nginx.conf
···············

 log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
·························

实现防盗链

基于访问安全考虑,nginx支持通过ngx_http_referer_module模块,检查访问请求的referer信息是否有效实现防盗链功能

语法:

Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location

none:#请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked:#请求报文有referer首部,但无有效值,比如为空。
server_names:#referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:#自定义指定字符串,但可使用*作通配符。示例: *.wang.org www.magedu.*
regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:
~.*\.magedu\.com

范例: 定义防盗链: 

盗链最好参数定义,域名直接定义可能会起冲突

[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
server {
index index.html;
valid_referers none blocked server_names *.wang.com *.wang.org ~\.google\.
~\.baidu\. ~\.bing\. ~\.so\. ;                 #定义有效的referer
if ($invalid_referer) {                         #假如是使用其他的无效的referer访问
return 403 "Forbidden Access";         #返回状态码403
#return 302 http://www.wangxiaochun.com/testdir/daotu.jpg;
#rewrite ^(.*)$ /daolian.jpg break;        #或者返回错误图片
}
......
}
#重启Nginx并访问测试
#指定referer为http://www.baidu.com进行访问
[root@centos7 ~]# curl -e 'http://www.baidu.com' www.wang.org
#指定referer为http://www.xxx.com进行访问,被拒绝
[root@centos7 ~]# curl -e 'http://www.xxx.com' www.wang.org
#不加http的referer不会拒绝

[root@centos7 ~]# curl -e 'www.xxx.com' www.wang.org

列: 除了指定参数及特殊定义其余的都会被拒绝并 返回403

[root@ubuntu2004 conf.d]#vim m.wang.org.conf 
server {
    listen 80;
    server_name m.wang.org;
    root /data/nginx/html/mobile;
    access_log /apps/nginx/logs/m.wang.org_access.log main;
    location /images {
    root /data/nginx/html/pc;
    index index.html;
    valid_referers none blocked server_names
      ~\.google\. ~\.baidu\.;

    if ($invalid_referer) {
    return 403;
}
}
    }

  

Nginx 反向代理 

代理Proxy有两种

  • 正向代理: 代理客户端访问服务器,可以实现缓存,科学上网,访问控制等功能
  • 反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。

 正向代理是客户端指定让代理去访问哪个服务。

翻墙服务是用户自己花钱买到,所以正向代理代表的是客户端的利益。

反向代理是代理将客户端的请求分发给某个服务器。

Nginx服务器是服务端搭建的,代表的是服务端的利益eorao.bilog.cstn.ne

Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能 

ngx_http_proxy_module     : #将客户端的请求以http协议转发至指定服务器进行处理
ngx_http_upstream_module   #用于定义为proxy_pass,fastcgi_pass,uwsgi_pass等指令引用的后端服务器分组
ngx_stream_proxy_module: #将客户端的请求以tcp协议转发至指定服务器处理
ngx_http_fastcgi_module:    #将客户端对php的请求以fastcgi协议转发至指定服务器助理
ngx_http_uwsgi_module:     #将客户端对Python的请求以uwsgi协议转发至指定服务器处理

访问逻辑图:

 LVS和nginx的区  nginx是伪四层就是七层装四层

  • 工作层:LVS四层,Nginx七层
  • 监听端口:LVS不监听,Nginx监听端口
  • 后端服务器看到客户端地址:LVS可以,Nginx不可以
  • 连接(三次握手):LVS 不参与连接,只负责转发,Nginx代替后端服务器和客户建立连接 

反向代理配置参数

1 不能放在http server 里 必须放在location里 或者嵌套里面也行

如果没有的话,他会返回默认站点

[root@localhost confd]#vim www.shuhong.com.conf
server {listen 80;server_name www.shuhong.com;location / {proxy_pass http://10.0.0.154;proxy_set_header Host $http_host; #转发主机头至后端服务器 不写IP头类转发proxy_connect_timeout 10s;}
}

 动静分离

[root@ubuntu2004 conf.d]#vim www.wang.org.conf 

server {
    listen 80;
    server_name www.wang.org;
    root /data/nginx/html/pc;
    access_log /apps/nginx/logs/www.wang.org_access.log main;
    location /api {                                                       动静分离                     
        proxy_pass http://10.0.0.11:8080/hello;
       #proxy_set_header Host $http_host;

    }
    location  ~* \.php$ {                         带他的转换为他
                  proxy_pass     
}
}

 指定 location 实现反向代理

[root@localhost confd]#vim www.shuhong.com.conf
server {listen 80;server_name www.shuhong.com;location / {index index.html index.php;root /data/www/html/pc;}location /static {proxy_pass http://10.0.0.11/; #注意有后面的/, 表示置换#proxy_pass http://10.0.0.11; #后面没有 / , 表示附加/static ,static如果有变量则不能加/ 否则会使变量无用}
}

 cd /usr/share/nginx/html/   访问

vim /apps/nginx/conf/nginx.conf   看

添加响应报文的头部信息

nginx基于模块ngx_http_headers_module可以实现对后端服务器响应给客户端的报文中添加指定的响应首部字段

#添加响应报文的自定义首部:
add_header name value [always];
#示例:
add_header X-Via $server_addr; #当前nginx主机的IP
add_header X-Cache $upstream_cache_status; #缓存命中HIT,未命中MISS
add_header X-Accel $server_name; #客户访问的FQDN

反向代理示例: 缓存功能

#示例:在http配置定义缓存信息

proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动

创建

levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录

keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数),一般1M可存放8000个左右的key

inactive=120s #缓存有效时间

max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值

#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等

proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存 

 #调用缓存功能,需要定义在相应的配置段,如server{...};或者location等

proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓
存 

proxy_cache_methods GET | HEAD | POST ...;
#对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存 

proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g;      #配置在nginx.conf http配置段

server {
    listen 80;
    server_name www.wang.org;
    root /data/nginx/html/pc;
    access_log /apps/nginx/logs/www.wang.org_access.log main;
        location / {       
        proxy_pass http://10.0.0.8;
       #proxy_set_header Host $http_host;
proxy_cache proxycache;   要缓存的URL 或者放在server配置项对所有URL都进行缓存
proxy_cache_key $request_uri;
#proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 302 301 10m;
proxy_cache_valid any 5m;                                 #必须指定哪些响应码的缓存
proxy_set_header Host $http_host;                   #转发主机头至后端服务器
#proxy_set_header clientip $remote_addr;
add_header X-Via $server_addr;                                   #当前nginx主机的IP
add_header X-Cache $upstream_cache_status;          #缓存命中HIT,未命中MISS
add_header X-Accel $server_name;                            #客户访问的FQDN
}
}                                         

 这里两个的区别在于X-Real-IP用于显示真实的前端IP但是只能显示一个,X-Forwarded-For是显示前端的多个IP (三个一起用)

 proxy_set_header Host $http_host;的使用

 proxy_set_header Host $http_host; #按下面的例子来讲,要我转发到154的shuhong里面

不写他就会跳转到154的页面写上他就会跳转到154服务器里面的shuhong页面

proxy_set_header X-Real-IP $remote_addr; 客户端IP后端显示

  • 把客户端IP转发至后端服务器里面。可以显示出来
  • 显示的前提是在 nginx/conf里面加上http_x_real_ip(就是把他全都变成小写)在能生效在里面显示出来,不加就显示不出来

然后就可以在这里面显示出来了

 X-Forwarded-For $proxy_add_x_forwarded_for; 前面(多个代理)代理都显示出来

实现反向代理客户端 IP 透传

[root@centos8 ~]# cat /apps/nginx/conf/conf.d/pc.conf
server {
listen 80;
server_name www.wang.org;
location / {
index index.html index.php;
root /data/nginx/html/pc;
proxy_pass http://10.0.0.18;
#proxy_set_header X-Real-IP $remote_addr;  #只添加客户端IP到请求报文头部,转发至后端服务器
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #添加客户端IP和反
向代理服务器IP到请求报文头部
}
}

#说明$proxy_add_x_forwarded_for
#此变量表示将客户端IP追加请求报文中X-Forwarded-For首部字段,多个IP之间用逗号分隔,如果请求中没有X-Forwarded-For,就使用$remote_addr

[root@rocky8 nginx]#vim /apps/nginx/conf/nginx.conf  

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" "$http_x_real_ip"'; #加这个

    access_log  logs/access.log  main;
#重新加载  nginx -s reload

#后端apache日志配置,查看穿透结果

root@rocky8 html]#tail -f /apps/nginx/logs/access.log 

 实现反向代理客户端 IP 透传(二级)

#代理服务器都开启访问者日志#第一台代理服务器配置153
[root@localhost confd]#vim www.shuhong.com.conf
server {listen 80;server_name www.shuhong.com;location / {#proxy_pass http://10.0.0.155;proxy_pass http://www.hh.com;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}#第二台代理服务器配置155
[root@rocky8 ~]#vim /etc/nginx/nginx.confserver {listen 80;server_name www.hh.com;location = / {proxy_pass http://10.0.0.154;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}

#访问站点

 #第一台代理服务器的访问日志 #第二台服务器访问日志

利用Nginx解决跨域问题

什么是跨域                    静态页面除外

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。

 简单来将就是前三个一样不算跨域,只要有前三个有一点不一样就算跨域,后面没事

就是在百度上的里面访问淘宝就属于跨域

通常由于同域安全策略(the same-origin security policy),浏览器会禁止跨域请求。
值得注意的是:虽然因为跨域的原因会导致浏览器禁止访问而获取数据失败,但返回的状态码仍为200
常见的解决方案有:CORS,JSONP,Nginx反向代理等

  1.  采用CORS(Cross-Origin Resource Sharing 跨域资源共享)技术,可以允许当前域的Web相关资源被其他域的脚本请求访问
  2. CORS是一种基于HTTP头的机制,该机制允许使用AJAX发送跨域请求,只要HTTP响应头中包含了相应的
  3. CORS响应头。CORS需要浏览器和服务器同时支持,CORS机制在老版本的浏览器中不支持,现代浏览
  4. 器都支持CORS。在使用CORS发送AJAX请求时浏览器端代码和过去一致,服务器端需要配置CORS的响应头。

 作为运维的解决办法就是配置反向代理,A访问C,让C访问B,然后返回来(同上)

这个还需要和前端商量,改下静态页面, 最好的办法就就是让后端工程师写代码解决

 Http 反向代理负载均衡

在上一个节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测
Nginx 可以基于ngx_http_upstream_module模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能

#自定义一组服务器,配置在http块内                          会自动跳转

upstream webservers {                   #自定义一组服务器,配置在http块内
    server 10.0.0.8;
    server 10.0.0.11;
}

server {
    listen 80;
    server_name www.wang.org;
    root /data/nginx/html/pc;
    access_log /apps/nginx/logs/www.wang.org_access.log main;
        location / {
        proxy_pass http://webservers;
 }

}

也支持加权重 不写就是1  weight=3;

upstream webservers {
    server 10.0.0.8 weight=3;
    server 10.0.0.11;
}
 

server支持的parameters如下:
weight=number #设置权重,默认为1,实现类似于LVS中的WRR,WLC等
max_conns=number #给当前后端server设置最大活动链接数,默认为0表示没有限制
max_fails=number #后端服务器的下线条件,当客户端访问时,对本次调度选中的后端服务器连续进行检测
多少次,如果都失败就标记为不可用,默认为1次,当客户端访问时,才会利用TCP触发对探测后端服务器健康性
检查,而非周期性的探测
fail_timeout=time #后端服务器的上线条件,对已经检测到处于不可用的后端服务器,每隔此时间间隔再次
进行检测是否恢复可用,如果发现可用,则将后端服务器参与调度,默认为10秒
backup #设置为备份服务器,当所有后端服务器不可用时,才会启用此备用服务器,和ip_hash指令冲突,
不能同时使用
down #标记为down状态,可以平滑下线后端服务器,新用户不再调度到此主机,正在访问的旧用户不受影响 

ip_hash;                    ip_hash 和backup起冲突,不能再一起用
#源地址hash调度方法,基于的客户端的remote_addr(源地址IPv4的前24位或整个IPv6地址)做hash计算,以实现会话保持,注意:如果是局域网可能会导致调度到同一台主机
#hash $remote_addr 则是对全部32bit的IPv4进行hash计算 

least_conn;
#最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于LVS中的WLC 

hash KEY [consistent];    hash $remote_addr   consistent;
#基于指定请求报文中首部字段或者URI等key做hash计算,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算
#示例
hash $request_uri consistent; #基于用户请求的uri做hash,可以实现调度到后端缓存服务器功能
hash $remote_addr consistent; #则是对全部32bit的IPv4进行一致性hash计算
hash $cookie_sessionid #基于cookie中的sessionid这个key进行hash调度,实现会话绑定 

Syntax: keepalive connections;
Default: —
Context: upstream
This directive appeared in version 1.1.4.
keepalived #该connections参数设置保留在每个工作进程缓存中的上游服务器的最大空闲保活连接数。当超过这个数字时,最近最少使用的连接将被关闭。

Syntax: keepalive_timeout timeout;
Default:
keepalive_timeout 60s;
Context: upstream
This directive appeared in version 1.15.3.
keepalive_timeout #设置一个超时时间,在此期间与上游服务器的空闲保活连接将保持打开状态。

roxy_connect_timeout time;
#配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒,用法如下:
proxy_connect_timeout 6s;

  实战案例:基于Cookie 实现会话绑定

[root@centos8 ~]#vim /apps/nginx/conf/nginx.conf
http {
upstream websrvs {
hash $cookie_hello;         #hello是cookie的key的名称
server 10.0.0.101:80 weight=2;
server 10.0.0.102:80 weight-1;
}
}

[root@centos8 ~]# vim /apps/nginx/conf/conf.d/pc.conf
server {
location /{
#proxy_cache mycache;
proxy_pass http://websrvs;
proxy_set_header Host $http_host;         #转发主机头至后端服务器
}
}
#测试
[root@centos8 ~]#curl -b hello=wang http://www.wang.org/
[root@centos8 ~]#curl -b hello=wei http://www.wang.org/ 

 实战案例: 实现 HTTPS 的负载均衡

[root@centos8 ~]#vim /apps/nginx/conf.d/proxy.conf
upstream websrvs {
server 10.0.0.101:80 ;
server 10.0.0.102:80 ;
}
server {
listen 80;
server_name www.wang.org;
return 302 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name www.wang.org;
ssl_certificate /apps/nginx/ssl/www.wang.org.pem;
ssl_certificate_key /apps/nginx/ssl/www.wang.org.key;
ssl_session_cache shared:sslcache:20m;                 #加速
ssl_session_timeout 10m;                                           #缓存,十分钟保存
location / {
proxy_pass http://websrvs;
proxy_set_header Host $http_host;
}