6

静态资源web服务

Nginx作为保存静态资源的web服务,对静态资源直接做出响应。减少后端服务器的负载压力。

基础配置

配置实践

# 先把上一节的配置备份下来
cd /etc/nginx/conf.d
mv auth_basic.conf auth_basic.conf.bak
# 从备份目录恢复一个初始配置并改名
cp /opt/backup/default.conf static.conf
# 修改配置
vi static.conf
# 配置如下
server {
    ...
    
    # 开启sendfile,提高网络包的传输效率
    sendfile on;
    
    # 配置图片资源的路径
    location ~ .*\.(jpg|gif|png)$ {
        root /opt/app/code/images;
    }

    # 配置txt|xml资源的路径
    location ~ .*\.(txt|xml)$ {
        root /opt/app/code/doc;
    }
    # 配置html网页资源路径
    location ~ .*\.(html|htm)$ {
        root /opt/app/code;
    }

}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载配置
systemctl reload nginx.service
# 我们准备了一个图片资源
[root@centos7 conf.d]# cd /opt/app/code/images
[root@centos7 images]# ls
react.jpg

验证结果

clipboard.png

开启压缩

开启压缩,可以加快资源响应速度,同时节省网络带宽资源。

配置实践

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
# 配置如下
server {
    ...
    
    #开启sendfile,提高网络包的传输效率
    sendfile on;
    
    #配置图片资源的路径
    location ~ .*\.(jpg|gif|png)$ {
        #开启压缩
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        root /opt/app/code/images;
    }

    #配置txt|xml资源的路径
    location ~ .*\.(txt|xml)$ {
        #开启压缩
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 1;
        gzip_types text/plain application/xml;
        root /opt/app/code/doc;
    }
    # 配置html网页资源路径
    location ~ .*\.(html|htm)$ {
        root /opt/app/code;
    }

}
# 验证配置,先不重载配置
nginx -tc /etc/nginx/nginx.conf

相比图片,用文件来演示压缩,压缩效果会更好:

cd /opt/app/code/doc
# 直接把nginx访问日志拷贝到静态资源目录
cp /var/log/nginx/access.log access.txt
chmod 777 access.txt

在重载配置之前,我们先访问一次http://39.104.93.171/access.txt

# access.log输出如下:
39.104.93.171 115.198.157.60 - admin [03/Feb/2018:21:51:23 +0800] "GET /access.txt HTTP/1.1" 200 20626 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"

可以看到传输内容大小是20626。

# 然后我们重载配置
systemctl reload nginx.service

浏览器清空缓存(避免304影响)后再次访问http://39.104.93.171/access.txt

# access.log输出如下:
39.104.93.171 115.198.157.60 - admin [03/Feb/2018:21:58:56 +0800] "GET /access.txt HTTP/1.1" 200 1895 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"

可以看到传输数据大小已经被压缩到只有1895了。

跨域访问

浏览器基于安全考虑,采用同源策略,限制了跨域访问。然而企业内部站点之间通常会有跨域访问的需求。尤其是现在前后端分离的方式,前端采用诸如React或Vue等MVVM框架开发纯Ajax的SPA应用时,页面间的路由是前端控制,前端同学往往要求相关服务器开放跨域访问。

我准备了另外一台服务器:39.104.116.91,有如下页面,通过ajax跨域请求本nginx服务器的html资源:

<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <title>测试ajax跨域访问</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
    <script src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
    $(document).ready(function(){
        $.ajax({
            type: "GET",
            url: "http://39.104.93.171/someone.html",
            success: function(data) {
                alert("跨域访问成功!");
            },
            error: function(data) {
                alert("跨域访问失败!");
            }
        });
    });
</script>
</head>
<body>测试跨域访问</body>
</html>

那么,我们要在当前nginx服务器上,配置允许39.104.116.91的跨域访问。

配置参考

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
# 配置如下
server {
    ...
    
    #开启sendfile,提高网络包的传输效率
    sendfile on;
    
    #配置图片资源的路径
    location ~ .*\.(jpg|gif|png)$ {
        #开启压缩
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        root /opt/app/code/images;
    }

    #配置txt|xml资源的路径
    location ~ .*\.(txt|xml)$ {
        #开启压缩
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 1;
        gzip_types text/plain application/xml;
        root /opt/app/code/doc;
    }
    # 配置html网页资源路径
    location ~ .*\.(html|htm)$ {
        #允许http://39.104.116.91跨域访问
        add_header Access-Control-Allow-Origin http://39.104.116.91;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        root /opt/app/code;
    }

}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载配置
systemctl reload nginx.service

防盗链

防盗链,简单来说就是你可以直接访问该资源,但是不能将我的资源链接放到你自己的服务器上让别人访问,尤其是图片或视频这种比较大的文件,容易导致服务器响应很慢,并且影响带宽。

配置实践

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
# 配置如下
server {
    ...
    
    #开启sendfile,提高网络包的传输效率
    sendfile on;
    
    #配置图片资源的路径
    location ~ .*\.(jpg|gif|png)$ {
        #开启压缩
        gzip on;
        gzip_http_version 1.1;
        gzip_comp_level 2;
        gzip_types image/jpeg image/gif image/png;
        # 防盗链
        valid_referers none blocked *.zhutx.com server_names ~\.google\. ~\.baidu\.;
        if ($invalid_referer) {
            return 403;
        }
        root /opt/app/code/images;
    }

    ...

}

valid_referers指定了合法的来源'referer', 他决定了内置变量$invalid_referer的值。

valid_referers语法

valid_referers none | blocked | server_names | string ...;
参数 说明
none “Referer” 来源头部为空的情况
blocked “Referer”来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头
server_names “Referer”来源头部包含当前的server_names(当前域名)
arbitrary string 任意字符串,定义服务器名或者可选的URI前缀。主机名可以使用*开头或者结尾,在检测来源头部这个过程中,来源域名中的主机端口将会被忽略掉
regular expression 正则表达式

因此,我们的防盗链配置,在以下情况下可以合法访问图片:

  1. 直接在浏览器输入你的图片地址。符合none这个规则;
  2. 来自*.zhutx.com的访问;
  3. 来自谷歌和百度的访问(SEO优化);

如果不合法,那么$invalid_referer等于1,会在if语句中返回一个403给用户。

网页缓存

配置实践

cd /etc/nginx/conf.d
# 修改配置
vi static.conf
# 配置如下
server {
    ...
    
    location ~ .*\.(html|htm)$ {
        # 协商客户端,应答时维护Cache-Control和Expires头信息
        expires 24h;
        add_header Access-Control-Allow-Origin http://39.104.116.91;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
        root /opt/app/code;
    }

    ...

}

代理服务

正向代理

正向代理即客户端代理。客户端通过主动设置代理服务,从而将对目标的访问委托给有权访问的代理服务器去访问。翻墙就是这种场景。

Nginx可以做正向代理服务器

配置参考

# 先将上节内容备份下来
cd /etc/nginx/conf.d
mv static.conf static.conf.bak
# 从备份目录恢复初始配置并改名
cp /opt/backup/default.conf zx_proxy.conf
# 修改配置
vi zx_proxy.conf
# 配置如下
server {
    ...
    # 可能会涉及到DNS域名解析
    resolver 8.8.8.8;
    location / {
        # 原封不动的让自己转发客户端的请求
        proxy_pass http://$http_host$request_uri;
    }
}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载配置
systemctl reload nginx.service

验证结果

我的chrome浏览器,安装了SwitchySharp插件,配置Nginx代理如下:

clipboard.png

接下来我访问了http://www.ttlsa.com/

访问正常,观察Nginx的access.log的输出日志:

www.ttlsa.com 115.198.157.60 - - [04/Feb/2018:11:13:40 +0800] "GET http://www.ttlsa.com/ HTTP/1.1" 200 18758 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"

可见,我们对目标网站的访问,已经由Nginx代理了。

反向代理

反向代理即服务端代理。对客户端隐藏真实服务器地址。

配置参考

# 先把之前的配置备份下来
cd /etc/nginx/conf.d
mv zx_proxy.conf zx_proxy.conf.bak
# 从备份目录恢复一个原始配置并改名
cp /opt/backup/default.conf fx_proxy.conf
# 编辑配置
vi fx_proxy.conf
# 配置如下
#我们增加这个server,端口8080,充当演示Real Server
server {
    listen 8080;
    server_name localhost;

    location / {
        root /opt/app/code;
    }
}
server {
    location / {
        #把请求代理到本机8080端口
        proxy_pass http://127.0.0.1:8080;
        #引入代理相关通用配置
        include proxy_params;
    }
}
# 其他代理通用配置独立出去,方便复用
vi /etc/nginx/proxy_params
# default就可以了。除非返回301的场景,可能需要改写
proxy_redirect defalut;

#配置header信息,让Real Server了解实际客户端信息
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;

#一些代理超时设置
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;

#代理缓冲区设置
proxy_buffer_size 32k;
proxy_buffering on;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 由于这次增加了一个server端口要启动,因此重启nginx服务
systemctl restart nginx.service
# 验证8080端口已启动
netstat -lnp | grep 8080
# 显示如下
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      22091/nginx: master

验证结果

# 创建反向代理结果演示页面
cd /opt/app/code
vi test_fx_proxy.conf
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <title>反向代理测试</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
</head>
<body>反向代理访问成功了</body>
</html>

然后访问:

clipboard.png

以下是本次访问的access.log输出:

39.104.93.171 127.0.0.1 - - [04/Feb/2018:11:37:12 +0800] "GET /test_fx_proxy.html HTTP/1.0" 200 235 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"
39.104.93.171 115.198.157.60 - - [04/Feb/2018:11:37:12 +0800] "GET /test_fx_proxy.html HTTP/1.1" 200 235 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" "-"

可以看到2次请求,先是80端口的server收到用户请求,经反向代理后,Real Server收到了这个请求。

代理WebSocket的配置

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server 127.0.0.1:8010;
}

server {
    listen 8020;
    access_log /var/log/nginx/test_websocket.access.log main;
    location / {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

负载均衡服务

负载均衡技术可让多个后端服务器共同分担请求压力,解决大量并发访问服务问题。

参考配置

# 先备份反向代理配置
cd /etc/nginx/conf.d
mv fx_proxy.conf fx_proxy.conf.bak
# 从备份目录恢复一个初始配置并改名
cp /opt/backup/default.conf load_balance.conf
# 修改配置
vi load_balance.conf
#配置如下
server{
    listen 8001;
    server_name localhost;

    location / {
        root /opt/app/code/server_8001;
    }
}

server{
    listen 8002;
    server_name localhost;

    location / {
        root /opt/app/code/server_8002;
    }
}

server{
    listen 8003;
    server_name localhost;

    location / {
        root /opt/app/code/server_8003;
    }
}

server{
    listen 8004;
    server_name localhost;

    location / {
        root /opt/app/code/server_8004;
    }
}
upstream backend {
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004 backup;
}
server {
    ...
    location / {
        # 代理到upstream组
        proxy_pass http://backend;
        include proxy_params;
    }
}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载服务
systemctl reload nginx.service
# 可以看到4个端口都已就绪
[root@centos7 conf.d]# netstat -lnp | grep 8001
tcp        0      0 0.0.0.0:8001            0.0.0.0:*               LISTEN      22091/nginx: master
[root@centos7 conf.d]# netstat -lnp | grep 8002
tcp        0      0 0.0.0.0:8002            0.0.0.0:*               LISTEN      22091/nginx: master
[root@centos7 conf.d]# netstat -lnp | grep 8003
tcp        0      0 0.0.0.0:8003            0.0.0.0:*               LISTEN      22091/nginx: master
[root@centos7 conf.d]# netstat -lnp | grep 8004
tcp        0      0 0.0.0.0:8004            0.0.0.0:*               LISTEN      22091/nginx: master

接下来我们按照4个server的配置,创建各自的测试结果页面:

cd /opt/app/code
mkdir server_8001 server_8002 server_8003 server_8004
cd server_8001
vi test_load_balance.html
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <title>负载均衡测试页</title>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"/>
</head>
<body>my port is 8001</body>
</html>

同样的创建其他3个test_load_balance.html,只是显示port不同。

验证结果

我们尝试多次请求http://39.104.93.171/test_loa...

结果始终处于下面两个页面之间变换:
clipboard.png
clipboard.png

我们DROP掉8001和8002

iptables -I INPUT -p tcp --dport 8001 -j DROP
iptables -I INPUT -p tcp --dport 8002 -j DROP

再尝试多次请求http://39.104.93.171/test_loa...

这回页面始终显示:
clipboard.png

upstream的server参数

参数 说明
down 不参与负载均衡
backup 预留的备份服务器。当没有其他节点提供服务时,它才提供服务
max_fails 允许请求失败的次数
fail_timeout 经过max_fails失败后,服务暂停的时间
max_conns 限制最大接收的连接数

上面演示时,8003是指定了down,实验结果也验证了它没参与负载均衡。8004指定了backup,我们用iptables命令DROP了8001和8002后,已没有其他节点对外提供服务了,因此backup开始接收请求。

其他参数可以自行尝试。

负载均衡调度算法

方式 说明
轮询 按顺序逐一分配给不同的后端服务器
加权轮询 weight值越大,分配到的几率越大
ip_hash 同一IP固定访问同一个后端服务器
least_conn 哪个连接数少就发哪个机器
url_hash 按url参数的hash结果来分配
hash关键数值 hash自定义的key
# 负载均衡算法-加权轮询
upstream backend {
    server localhost:8001 weight=5;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004 backup;
}
# 负载均衡算法-最少连接数
upstream backend {
    least_conn;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}
# 负载均衡算法-IP HASH
upstream backend {
    ip_hash;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}
# 负载均衡算法-URL HASH
upstream backend {
    url_hash;
    server localhost:8001;
    server localhost:8002;
    server localhost:8003 down;
    server localhost:8004;
}

当配置负载均衡算法为IP HASH或URL HASH时,便不再接受backup的server,不然无法通过配置校验。不过由于backup违背了算法本身,所以这也在情理之中。

缓存服务

我们大致可以把缓存分为 客户端缓存、代理缓存和服务端缓存3类。

Nginx作为缓存服务,可以减少后端服务器的压力,当再次去访问之前访问过的数据时,在nginx前端就能拿到。是代理缓存。

参考配置

# 备份之前的配置
cd /etc/nginx/conf.d
mv load_balance.conf load_balance.conf.bak
# 从备份目录初始一份配置并改名
cp /opt/backup/default.conf cache.conf
# 修改配置
vi cache.conf
...

#定义用于存放缓存文件的空间
#/opt/app/cache 缓存文件存放目录
#keys_zone=my_cache:10m,缓存空间命名为my_cache,10m大概可以存8万个左右的缓存key了
#inactive=60m,超60分钟没有访问的缓存自动清理
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

server {
    ...

    if ($request_uri ~ ^/(login|register|password)) {
        set $cookie_nocache 1;
    }

    location / {
        # 缓存
        proxy_cache my_cache;
        # 基于代理
        proxy_pass http://backend;
        # 缓存过期周期配置,返回200 304状态的,缓存12小时过期
        proxy_cache_valid 200 304 12h;
        # 其他的缓存10分钟过期
        proxy_cache_valid any 10m;
        # 缓存key
        #proxy_cache_key $scheme$proxy_host$request_uri;
        proxy_cache_key $host$uri$is_args$args;
        #配置不缓存的请求
        proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
        proxy_no_cache $http_pragma $http_authorization;
        # 增加一个头信息给客户端,表示缓存是否命中
        add_header Nginx-Cache "$upstream_cache_status";
        # 后端服务器某一台返回不正常,则代理到下一台
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        include proxy_params;
    }
}

清理缓存

方式一:rm -rf 清空缓存目录。会清空所有缓存
方式二:第三方扩展模块ngx_cache_purge,可以清理指定缓存

缓存命中分析
在上面缓存的配置中,我们添加了Nginx-Cache这个响应头部信息

add_header Nginx-Cache "$upstream_cache_status";

关于$upstream_cache_status,有如下几个值:

状态 意义
MISS 缓存未命中,请求被传送到后台处理
HIT 缓存命中
EXPIRED 缓存过期,请求被传送到后台处理
UPDATING 正在更新缓存,将使用旧的应答
STALE 后端得到过期的应答

所以,我们可以分析nginx访问日志,hit次数/总请求次数就是缓存命中率

# 修改log_format,输出$upstream_cache_status
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"$upstream_cache_status"';
# 用awk命令统计
awk '{if($NF=="\"HIT\""){hit++}}END{printf "%.2f",hit/NR}' /var/log/nginx/access.log

大文件分割请求

ngx_http_slice_module模块是一个分割请求转换成子请求,每个返回一定范围内响应的滤波器。该过滤器提供了更有效的大响应缓存。

该模块不是默认生成的,它应该使用--with-http_slice_module配置参数启用。

如果你按Nginx笔记(一)Nginx安装的方式安装Nginx,那么该模块默认已经编译进来。可以用nginx -V命令验证。

配置示例

#定义用于存放缓存文件的空间
#/opt/app/cache 缓存文件存放目录
#keys_zone=my_cache:10m,缓存空间命名为my_cache,10m大概可以存8万个左右的缓存key了
#inactive=60m,超60分钟没有访问的缓存自动清理
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

location ~ \.apk$ {
    slice             5m;
    proxy_cache       my_cache;
    proxy_cache_key   $uri$is_args$args$slice_range;
    proxy_set_header  Range $slice_range;
    proxy_cache_valid 200 206 1h;
    proxy_pass        http://localhost:8999;
}

在这个例子中,响应被分割成5兆字节的可缓存切片。

安全链接校验

ngx_http_secure_link_module用于检查请求链接的真伪,保护资源免受未经授权的访问

该模块不是默认生成的,它应该使用--with-http_secure_link_module配置参数启用。

如果你按Nginx笔记(一)Nginx安装的方式安装Nginx,那么该模块默认已经编译进来。可以用nginx -V命令验证。

实际应用中,如需要对下载链接进行合法性校验,过期校验。

我们用shell脚本模拟服务端生成一个下载链接:

vim md5url.sh

输入以下内容

#!/bin/sh
#
download_file="/download/file.img"
expires=$(date -d "2019-02-12 00:00:00" +%s)
secret="123456"
# 我们用过期时间+下载url,加上密钥,生成md5。后面nginx配置的md5校验规则亦如此
md5=$(echo -n "${expires}${download_file} ${secret}"|openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)

servername="116.62.156.235"
echo "${servername}${download_file}?md5=${md5}&expires=${expires}"

执行sh md5url.sh,生成链接如下:

116.62.156.235/download/file.img?md5=kD4hdQLA-psd_QzPSzyrdA&expires=1549900800

我们在/opt/app/code下事先放一个下载文件/download/file.img

nginx配置示例

server {
    listen 80;
    server_name localhost;
    root /opt/app/code;
    
    location / {
        # 提取请求参数md5和expires
        secure_link $arg_md5,$arg_expires;
        # secure_link_md5定义的表达式MD5哈希值与请求参数中提取的md5值比较
        secure_link_md5 "$secure_link_expires$uri 123456";
        # 如果md5不相同,则该$secure_link变量设置为空字符串
        if ($secure_link = "") {
            return 403;
        }
        # 如果md5相同,则检查是否过期。如果已过期,则该$secure_link变量设置为0
        if ($secure_link = "0") {
            return 410;
        }
    }
}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载服务
systemctl reload nginx.service

访问生成的链接,便成功下载文件。当修改请求md5值,或者过期访问,便会显示403页面

geoip

基于IP地址匹配MaxMind GeoIP二进制文件,读取IP所在地域信息,包括国家以及城市信息

当需要为国内与国外用户提供不同的访问界面,如国内用户代理到简体中文的地址,国外用户代理到英文版地址;
再比如国内用户,需要基于用户所在城市提供本地化的服务,如访问58同城,网页默认就处于这个城市版面;
这些都可以通过ngx_http_geoip_module模块来实现。

该模块不是默认生成的,它应该使用--with-http_geoip_module配置参数启用

# 安装nginx的geoip模块
yum install nginx-module-geoip
# 查看已安装的库
cd /etc/nginx/modules
ls
ngx_http_geoip_module-debug.so  ngx_http_geoip_module.so  ngx_stream_geoip_module-debug.so  ngx_stream_geoip_module.so

cd ..
# 非默认编译进来的,所以load进来
vim nginx.conf
load_module "modules/ngx_http_geoip_module.so";
load_module "modules/ngx_stream_geoip_module.so";
mkdir geoip
cd geoip
下载地域信息
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoIP.dat.gz
gunzip GeoLiteCity.dat.gz
cd ../conf.d

nginx配置示例

vim test_geo.conf
geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;
server {
    listen 80;
    server_name localhost;
    location / {
        if ($geoip_country_code != CN) {
            return 403;
        }
        root /usr/share/nginx/html;
        index index.html index.htm;
    }
    location /myip {
        default_type text/plain;
        return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
    }
}
# 校验配置
nginx -tc /etc/nginx/nginx.conf
# 重载服务
systemctl reload nginx.service

当访问/myip时,我们简单显示了下本地出口ip以及国家名称,国家编码,以及城市编号。

HTTPS服务

动静分离

分离资源,减少不必要的请求消耗,减少请求延时。

参考配置

# 备份之前的配置
cd /etc/nginx/conf.d
mv cache.conf cache.conf.bak
# 从备份目录初始一份配置并改名
cp /opt/backup/default.conf dynamic_static.conf
# 修改配置
vi dynamic_static.conf
# 配置如下
upstream java_api {
    #事先在本机启动了tomcat负责接收jsp请求
    server 127.0.0.1:8080;
}

server {
    ...

    # 根目录也可以配置在location外面
    root /opt/app/code;
    
    # 动态的请求代理给backend
    location ~ \.jsp$ {
        proxy_pass http://java_api;
        index index.html index.htm;
    }

    # 静态请求自己处理
    location ~ \.(jpg|png|gif)$ {
        expires 1h;
        gzip on;
    }

    location / {
        index index.html index.htm
    }
}

rewrite

以下场景都可以使用到Nginx的rewrite功能:

  • URL重写以适配后端的接口设计;
  • 网站升级时候,对于部分老用户继续提供老版本的服务;
  • 简化前端url,方便SEO优化;
  • 维护时挂维护页面;
  • 伪静态,伪装真实url。

参考配置

vi /etc/nginx/conf.d/default.conf
server {
    ...

    root /opt/app/code;
    
    location ~ ^/break {
        # 匹配/break,寻到root目录下的/test目录去,如果没有找到则404
        rewrite ^/break /test/ break;
    }

    location ~ ^/last {
        # 匹配/last,内转/test/请求
        rewrite ^/last /test/ last;
        # 302临时重定向,让客户端浏览器重新访问/test
        #rewrite ^/last /test/ redirect;
    }
    
    location ~ ^/imooc {
        # 临时性重定向 302,
        #rewrite ^/imooc http://www.imooc.com/ permanent;
        # 永久性重定向 301,下次将不再经过nginx而直接跳转目标
        rewrite ^/imooc http://www.imooc.com/ redirect;
    }

    location /test/ {
        default_type application/json;
        return 200 '{"status":"success"}'
    }

    location / {
        rewrite ^/course-(\d+)-(\d+)-(\d+)\.html$ /course/$1/$2/course_$3.html break;
        # 以Chrome浏览器访问/nginx路径,跳转到慕课网nginx地址
        #if ($http_user_agent ~* Chrome) {
        #    rewrite ^/nginx http://conding.imooc.com/class/121.html break;
        #}
        
        # 不存在该文件,则重定向到百度
        #if (!-f $request_filename) {
        #    rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
        #}
        
        index index.html index.htm
    }
}

rewrite规则优先级

  • 执行server块的rewrite命令
  • 执行location匹配
  • 执行选定的location中的rewrite

优雅的rewrite规则规则

server {
    listen 80;
    server_name www.nginx.org nginx.org;
    if ($http_host = nginx.org) {
        rewrite (.*) http://www.nginx.org$1;
    }
}

可以改成:

server {
    listen 80;
    server_name nginx.org;
    rewrite ^ http://www.nginx.org$request_uri?;
}
server {
    listen 80;
    server_name www.nginx.org;
}

zhutianxiang
1.5k 声望327 粉丝