一、模块概述
Nginx 的内部结构是由核心部分和一系列功能模块组成的,正是由于 Nginx 的高度模块化设计,使得每个模块的功能相对简单,便于实现功能的扩展性。
Nginx 从总体上来说是由许多个模块构成的,通常将 Nginx 分为 5 大模块,分别为核心模块、标准 HTTP 模块、可选 HTTP 模块、邮件服务模块和第三方模块。其中,核心模块是 Nginx 服务器正常运行必不可少的模块,如同操作系统的内核。它提供了 Nginx 最基本的核心服务,例如权限控制、错误日志记录等;标准 HTTP 类型的模块用于支持标准 HTTP 的相关功能,是编译 Nginx 时默认安装的模块;可选 HTTP 模块主要用于扩展的 HTTP 功能,让 Nginx 能处理一些特殊的服务;邮件服务模块主要用于支持邮件服务;第三方模块是为了扩展 Nginx 的应用,完成开发者想要的功能。
为了查看 Nginx 默认加载的核心模块和标准 HTTP 模块,切换到 Nginx 的解压目录中,打开 objs 目录下的 ngx_modules.c 文件,可以看到很多使用 extern 关键字定义的模块:
extern ngx_module_t ngx_core_module;
extern ngx_module_t ngx_errlog_module;
extern ngx_module_t ngx_conf_module;
extern ngx_module_t ngx_openssl_module;
extern ngx_module_t ngx_regex_module;
extern ngx_module_t ngx_events_module;
extern ngx_module_t ngx_event_core_module;
extern ngx_module_t ngx_epoll_module;
extern ngx_module_t ngx_http_module;
extern ngx_module_t ngx_http_core_module;
extern ngx_module_t ngx_http_log_module;
......
二、调试输出
2.1 配置
对于 Nginx 服务器来说,其常用的使用方式就是修改相关的配置文件。但是它本身又不能像编程语言一样通过输出语句对需要调试的信息进行打印输出。比如在使用 Nginx 的一些内置变量时,就不能直观地看到其具体的值。因此,若要实现这样的功能,可以使用第三方提供的 echo-nginx-module 模块。
首先从 https://github.com/openresty/echo-nginx-module 下载 echo-nginx-module 模块,然后上传到 /opt/apps 目录下,解压并重命名:
root@wuychn:/opt/apps# unzip echo-nginx-module-master.zip
root@wuychn:/opt/apps# mv echo-nginx-module-master echo-nginx-module
查看当前 Nginx 版本及其编译选项:
root@wuychn:/opt/apps# nginx -V
nginx version: nginx/1.14.2
built by gcc 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
built with OpenSSL 1.1.0g 2 Nov 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --with-http_ssl_module --add-module=/opt/apps/ngx_cache_purge
在原编译选项的基础上添加对 echo 模块的编译:
root@wuychn:/opt/apps/nginx-1.14.2# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --add-module=/opt/apps/ngx_cache_purge --add-module=/opt/apps/echo-nginx-module
root@wuychn:/opt/apps/nginx-1.14.2# make
按照上述命令执行完毕后,在 Nginx 解压目录下的 objs 目录下将会重新生成一个 nginx 二进制可执行文件。需要注意的是,对于已经安装的 Nginx,在编译时不再需要 make install,只需要执行 make 命令重新编译一个 nginx 二进制可执行文件即可:
root@wuychn:/opt/apps/nginx-1.14.2/objs# ll
总用量 5700
drwxr-xr-x 4 root root 4096 5月 7 16:08 ./
drwxr-xr-x 9 1001 1001 4096 4月 24 18:43 ../
drwxr-xr-x 5 root root 4096 5月 7 16:06 addon/
-rw-r--r-- 1 root root 17529 5月 7 16:06 autoconf.err
-rw-r--r-- 1 root root 45722 5月 7 16:06 Makefile
-rwxr-xr-x 1 root root 5668296 5月 7 16:08 nginx*
-rw-r--r-- 1 root root 5341 5月 7 16:08 nginx.8
-rw-r--r-- 1 root root 7186 5月 7 16:06 ngx_auto_config.h
-rw-r--r-- 1 root root 657 5月 7 16:06 ngx_auto_headers.h
-rw-r--r-- 1 root root 6010 5月 7 16:06 ngx_modules.c
-rw-r--r-- 1 root root 53064 5月 7 16:08 ngx_modules.o
drwxr-xr-x 9 root root 4096 4月 24 18:43 src/
备份并复制 nginx 的可执行文件:
root@wuychn:/opt/apps/nginx-1.14.2/objs# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
root@wuychn:/opt/apps/nginx-1.14.2/objs#
root@wuychn:/opt/apps/nginx-1.14.2/objs# cp nginx /usr/local/nginx/sbin/nginx
经过以上安装配置,echo-nginx-module 模块就可以使用了。
打开 Nginx 的配置文件,在 location 下使用 echo 指令输出一段字符串,用于测试:
location / {
root html;
index index.html index.htm;
default_type text/plain;
echo "This is an echo module.";
}
其中,default_type 指令用于指定 MIME 类型,这里将其设置为文本格式;echo 指令用于输出其后的内容。配置完成后,重启 Nginx。
在浏览器中 访问 http://192.168.11.225/,若能看到如下图所示的效果,证明 echo 模块添加成功,在Nginx 配置文件中就可以使用 echo 指令进行调试了。
2.2 常见案例
在第三方模块 echo-nginx-module 中最常用的就是 echo 指令,且该指令只能在 location 块或 location 块下 if 指令中使用。下面演示几种 echo 指令常见的用法。
2.2.1 普通输出
location / {
root html;
index index.html index.htm;
default_type text/plain;
echo 45 * 67;
echo "This is an echo module.";
echo $args;
}
第 5、6 行用于输出字符串,第 7 行 $args 内置变量用于输出 HTTP 请求时传递的参数。重启 Nginx 使配置生效:
2.2.2 带参数输出
location / {
root html;
index index.html index.htm;
default_type text/plain;
echo -n Hello, ;
echo "This is an echo module.";
}
若要想在 echo 指令输出后不换行,可以像上述第 5 行配置一样,添加一个 -n 参数:
2.2.3 输出特殊字符
location / {
root html;
index index.html index.htm;
default_type text/plain;
echo \"Welcome to china\";
echo \'Welcome to china\';
echo \\n and \\t is Special characters;
echo -- -n is an option;
echo -- ----is the seperator;
}
在使用 echo 输出内容时,若要同时输出特殊字符, 如双引号、单引号、换行符(\n)、制表符等时(\t),可以使用转义字符 “\” 进行转换;若想要输出横杠 “-” 时,则需要使用双横杠 "--” 对其转义。对于 Nginx 来说,$是一个特殊的符号,echo 指令对其不能进行输出。
对于 echo 模块,除了上述提到的 echo 指令外,还有很多其他常用的指令,具体可以网上搜索。
三、查看响应状态与替换响应内容
对于一个网站来说,若想要查看当前网站的响应状态、修改响应内容中的敏感词汇或是临时想要在网站中添加一个通用的 css 文件等,则可以使用 Nginx 服务器提供的 ngx_http_stub_status_module 和 ngx_http_sub_module 模块。
首先,重新编译 Nginx,添加对 ngx_http_stub_status_module 和 ngx_http_sub_module 的支持:
root@wuychn:/opt/apps/nginx-1.14.2# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --add-module=/opt/apps/ngx_cache_purge --add-module=/opt/apps/echo-nginx-module
root@wuychn:/opt/apps/nginx-1.14.2# make
root@wuychn:/opt/apps/nginx-1.14.2# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak2
root@wuychn:/opt/apps/nginx-1.14.2# cd objs/
root@wuychn:/opt/apps/nginx-1.14.2/objs#
root@wuychn:/opt/apps/nginx-1.14.2/objs# cp nginx /usr/local/nginx/sbin/nginx
3.1 查看网站响应状态
修改 nginx.conf:
server {
listen 80;
server_name www.test.com;
root html/test.com;
index index.html index.htm;
stub_status;
}
重启 Nginx,在浏览器中访问 http://www.test.com/:
可以看出,当前显示的状态数据包含 7 部分内容,分别为 Active connections (活跃连接数量)、server accepts (服务器处理连接数)、handled (服务器创建的握手次数)、requests (服务器处理请求连接的数量)、Reading (读取客户端的连接数 )、Writing(响应数据到客户端的数量)以及 Waiting (正在等候下一次请求指令的驻留连接数)。
3.2 替换网站响应内容
修改 nginx.conf:
server {
listen 80;
server_name www.test.com;
root html/test.com;
index index.html index.htm;
sub_filter name ' 张三';
}
sub_filter 用于将响应内容中的 anme 替换为中文的“张三”。为了查看到响应效果,接下来在域名为 www.test.com 的网站目录下编写 index.html 文件,内容如下:
<h1>Welcome, name</h1>
<h1>Hello, name</h1>
启动 Nginx,访问 http://www.test.com/:
可以看出,根据 Nginx 的配置,仅替换了第一行中的 name,第二行中的内容并未被替换。这是由于默认情况下,sub_filter 指令执行替换的次数由 sub_filter_once 指令决定,默认情况下 sub_filter_once 指令的值设置为 on,表示仅替换一次。
修改上述的 Nginx 配置文件,添加 sub_filter_once off,允许替换响应内容中全部出现的 name:
server {
listen 80;
server_name www.test.com;
root html/test.com;
index index.html index.htm;
sub_filter name ' 张三';
sub_filter_once off;
}
重启 Nginx 之后再次访问结果如下:
除了上述提到的指令外,在替换网站响应内容时,还可以使用 sub_filter_types 指令设置需要被替换的响应内容 MIME 类型,其默认值为 text/html。另外,sub_filter_types 指令还有一个特殊的值*,表示所有 MIME 类型。
四、网页压缩传输
4.1 gzip
gzip(GNU-ZIP)是一种压缩技术,经过 gzip 压缩后,页面大小可以变为原来的 30% 甚至更小。这样,用户浏览页面的时候速度会快得多。 gzip 网页压缩的实现需要浏览器和服务器的支持。
gzip 压缩的过程,首先在服务器端压缩,然后传到浏览器端后解压。当浏览器支持 gzip 解压时,会在请求消息头中包含 Accept-Encoding:gzip,这样 Nginx 就会向浏览器发送经过 gzip 后的内容,同时在响应消息头中加入 Content-Encoding:gzip,声明这是 gzip 后的内容,告知浏览器要先解压后才能解析输出。
4.2 配置
Nginx 服务器为网页压缩专门提供了 gzip 模块,并且模块中的相关指令均可以设置在http、server 或 location 块中,实现服务器端按照指定的设置进行压缩。具体的指令及含义如下表:
指令 | 说明 |
---|---|
gzip | 该指令用于开启或关闭 gzip 模块 |
gzip_buffers | 设置系统获取几个单位的缓存用于存储 gzip 的压缩结果数据流 |
gzip_comp_level | gzip 压缩比,压缩级别是 1~9。1 的压缩级别最低,9 压缩级别最高。压缩级别越高压缩率越大,压缩时间越长 |
gzip_disable | 可以通过该指令对一些特定的 User-Agent 不使用压缩功能 |
gzip_min_length | 设置允许压缩的页面最小字节数,页面字节数从响应消息头的 Content-Length 中进行获取 |
gzip_http_version | 识别 HTTP 协议版本,其值可以是 1.1(默认值)或 1.0 |
gzip_proxied | 用于设置启用或禁用从代理服务器上收到响应内容的 gzip压缩功能 |
gzip_types | 匹配 MIME 类型进行压缩。且无论是否指定,text/ html 类型总是会被压缩的 |
gzip_vary | 用于在响应消息头中添加 Vary:Accept-Encoding,使代理服务器根据请求头中的Accept-Encoding 识别是否启用 gzip 压缩 |
下面进行演示。打开 nginx.conf 配置文件,在 http 块中添加以下配置,用于完成网页压缩输出功能:
gzip on;
gzip_types text/plain application/javascript text/json;
第 1 行用于启用 gzip 模块,第 2 行用于在客户端访问网页时,对文本、JavaScript 和 css 文件进行压缩输出。
重启 Nginx,在浏览器中访问测试,按 F12 键打开开发者工具,单击当前的请求,在标签栏中选择 Headers,查看 HTTP 响应头信息:
可以看出,当前 Content-Encoding(内容编码)为 gzip 类型,Content-Type(内容类型)为 HTML 网页类型,Transfer-Encoding(传输编码)为 chunked (块编码)表示内容长度不确定。
除了上述的基本配置外,在实际开发中还可以具体配置压缩比、缓存大小、对于代理是否采用压缩等详细的设置,具体示例如下:
gzip_buffers 4 16k;
gzip_comp_level 4;
gzip_disable "MSIE [1-6].";
gzip_min_length 5k;
gzip_http_version 1.0;
gzip_proxied any;
gzip_vary on;
上述第 1 行中的 4 16k,表示按照原始数据大小以 16KB 为单位的 4 倍申请内存;如果没有设置,默认值是申请与原始数据相同大小的内存空间去存储 gzip 压缩结果。第 2 行表示压缩级别为 4,由于压缩级别越高,则需要压缩的时间越长,CPU 消耗也越大。因此,一般推荐将压缩级别设置为 4。第 3 行用于设置浏览器为 IE 6 时,不进行压缩,防止出现页面假死的现象。第 4 行用于设置当响应内容大于 5KB 时进行压缩输出,且一般建议最小值设置为1KB,当小于 1KB 时,可能会出现越压越大的问题。第 5 行表示只有是 HTTP/1.0 协议的请求时才会进行 gzip 压缩。第 6 行用于设置 Nginx 作为反向代理服务器时,无条件压缩所有结果数据,第 7 行 gzip_vary 指令设置为 on,表示在响应消息头中添加 Vary:AcceptEncoding,使代理服务器根据请AcceptEncoding 识别是否启用 Gzip 压缩。
五、重写与重定向
在实际网站运营的过程中,为了能够在修改网站结构或域名后,避免造成网站中的链接或在其他网站中的外链失效,以及提高该网站在搜索引擎的收录量和排名等目的。通常会采用 URL 重写与重定向,在增强网站专业化的同时,为用户提供更加舒适的使用体验。
重写与重定向功能是现在大多数 Web 服务器都支持的一项功能,相对于其他产品而言,Nginx 中的 rewrite 模块提供的功能在配置上更加的灵活自由,可定制性非常的高。它的实现方式也非常的简单,只需要通过 rewrite 指令根据 Nginx 提供的全局变量或自定义的变量,结合正则表达式以及进一步处理的标识就可以完成 URL 重写或重定向。
在使用 rewrite 指令实现重写前,首先看一下 rewrite 指令的基本语法:
rewrite regex replacement [flag];
上述语法表示,符合 rewrite 编写的正则语法规则,就执行相应的替换算法。其中,参数 regex 表示正则表达式,参数 replacement 表示符合正则规则的替换算法,可选参数 flag 用于指定进一步处理的标识,flag 的可选值如下表所示:
参数值 | 说明 |
---|---|
last | 终止 rewrite,继续匹配其他规则 |
break | 终止rewrite,不再继续匹配 |
redirect | 临时重定向,返回的 HTTP 状态码为 302 |
permanent | 永久重定向,返回的 HTTP 状态码为 301 |
当 flag 的值为 last 或 break 时,表示当前的设置为重写,当 flag 的值为 redirect 或 permanent 时表示重定向。
5.1 rewrite重写
5.1.1 添加 rewrite 指令
编辑 Nginx 的配置文件,配置域名为 rewrite.test 的虚拟主机,并规定访问不到文件或目录时执行重写操作,具体配置如下所示:
server {
listen 80;
server_name rewrite.com;
root html;
index index.html index.htm;
if (!-e $request_filename) {
rewrite "^/.*" /default/default.html break;
}
}
上述配置中,通过 if 指令判断访问不到用户请求的文件或目录时,执行第 7 行指令。 其中,!-e 用于判断不存在指定的文件或目录 时,执行 if 块内的语句。内置变量$request_filename 表示当前请求的文件路径;^/.* 用于匹配当前网站下的所有请求,/default/default.html 用于替换符合指定规则的请求。
if 指令根据给定的条件进行判断,如果判断结果为 true,则执行大括号内的指令。当判断条件仅是一个变量时,如果值为空或任何以 0 开头的字符串都会当做 false,不再执行大括号内的指令。if 指令中可以使用的判断符号如下表所示:
判断符号 | 说明 |
---|---|
= | 判断变量与内容相符 |
!= | 判断变量与内容不符 |
~ | 区分大小写正则匹配 |
~* | 不区分大小写正则匹配 |
!~ | 区分大小写正则不匹配 |
!~* | 不区分大小写正则不匹配 |
-f | 判断文件存在 |
!-f | 判断文件不存在 |
-d | 判断目录存在 |
!-d | 判断目录不存在 |
-e | 判断文件或目录存在 |
!-e | 判断文件或目录不存在 |
-x | 判断可执行文件 |
!-x | 判断不可执行文件 |
在网站根目录下创建default目录,并在该目录下编写default.html文件,内容如下:
<h1>Welcome to default.html</h1>
重启 Nginx,在浏览器中访问一个不存在的文件:
可以看到,浏览器的 URL 请求地址不变,Nginx 仅按照定义的重写规则,将 html/default/default.html 文件中的内容重写到当前的 HTTP 请求中。
5.1.2 break 和 last 标识的区别
在使用 rewrite 实现重写时,需要注意 flag 可选参数值 break 和 last 的区别,前者在rewrite 指令匹配成功后就不再进行匹配,而后者在 rewrite 后会根据 rewrite 匹配的规则重新发起一个请求继续进行匹配。
5.2 rewrite重定向
rewrite 的重定向就是将用户访问的 URL 修改为重定向的地址,只需将 flag 的可选参数值设置为 redirect 或 permanent 即可:
server {
listen 80;
server_name rewrite.com;
root html;
index index.html index.htm;
set $name $1;
rewrite ^/img-([0-9]+).jpg$ /img/$name.jpg permanent;
}
上述第 6 行配置,利用 set 指令为变量 $name 赋值,$1 表示符合正则表达式第一个子模式的值,如第 7 行中的子模式 ([0-9]+) 匹配到的值,可以是 2、45 等由一个或多个数字组成的字符串。第 7 行用于在用户请求 “http://rewrite.com/img-数字.jpg” 时,重定向到 “http://rewrite.com/img/数字.jpg”。
接下来,在网站根目录中创建一个用于存放图片的 img 目录,然后在该目录中保存一个文件名为 2.jpg 的图片。为了测试当前配置是否成功,通过浏览器访问 http://rewrite.com/img-2.jpg,运行结果如下图所示:
可以看出,用户发出的 URL 请求只要符合 rewrite 定义的正则规则,就会按照其后的替换规则执行。
需要注意的是,redirect 和 permanent 在使用时有一定的区别,前者返回的 HTTP 状态码是302(临时重定向),使得搜索引擎在抓取新内容的同时保留旧的网址,后者返回的 HTTP 状态码是301 (永久重定向)会让搜索引擎在抓取新内容的同时也将旧的网址永久替换为重定向之后的网址。
六、防盗链配置
盗链是指有一些不良网站,为了在不增加成本的前提下扩充自己站点的内容,直接盗用其他网站的资源链接,而大部分用户又不会发现。这样的做法一方面损害了原网站的合法利益,另一方面又加重了原网站服务器的流量负担。
6.1 图片防盗链
图片是一个网站中最容易被盗取的资源。HTTP 请求消息中有一个名称为 referer 的字段,它用于保存当前网页的来源 URL 地址。 当用户打开一个含有图片内容的网页时,浏览器会在图片的请求消息中将网页的 URL 放在 referer 中,从而使图片所在的服务器能够跟踪到它被显示的网页地址。因此,要实现图片防盗链,最简单的防护手段就是判断 referer 的值,来判断当前图片的引用是否合法,一旦检测到来源不是本站,就立即阻止图片的发送,或换成一张禁止防盗链提示的图片。
在 nginx.conf 文件中,配置两个虚拟主机 www.test1.com 和 www.test2.com,用于在网站 www.test1.com 中盗用网站 www.test2.com 中的图片链接,配置如下:
server {
listen 80;
server_name www.test1.com;
root html/test1.com;
index index.html index.htm;
}
server {
listen 80;
server_name www.test2.com;
root html/test2.com;
index index.html index.htm;
}
接下来,在网站 www.test1.com 的目录 html/test1.com 中创建 img 子目录,用于存放网页中的图片资源。然后,分别在网站 www.test1.com 和 www.test2.com 中创建测试网页,具体如下:
在网站 www.test1.com 下,创建 index.html 文件,用于展示自己网站中的图片,内容如下:
<h1>Welcome to www.test1.com</h1>
<img src="img/2.jpg" width="200" heigh="200"/>
在网站 www.test2.com 中盗用网站 www.test1.com 中的图片链接,index.html 的内容如下:
<h1>Welcome to www.test2.com</h1>
<img src="http://www.test1.com/img/2.jpg" width="200" heigh="200"/>
在浏览器中分别访问网站 http://www.test1.com 和 http://www.test2.com,分别如下所示:
从图中可以看出 www.test2.com 网站从 www.test1.com 中盗链成功。此时按 F12 键查看图片的请求消息,在 Request Headers 中可以查看当前Referer 的值:
接下来修改 www.test1.com 的 server 配置,添加允许文件链出的域名白名单:
server {
listen 80;
server_name www.test1.com;
root html/test1.com;
index index.html index.htm;
location ~*\.(gif|jpg|png|swf|flv)$ {
valid_referers www.test1.com;
if ($invalid_referer) {
return 403;
}
}
}
上述第 6 行配置,用于匹配文件扩展名为 gif、jpg、png、swf、flv 的资源;第 7 行中的 valid_referers 指令用于设置允许访问资源的网站列表(即白名单)。当请求消息头中的referer 符合白名单时,内置变量 $invalid_referer 的值为空字符串,否则为 1。因此,通过以上配置,可以禁止白名单之外的网站访问资源,并返回 403 状态码。
valid_referers 指令的参数可以叠加设置,中间使用空格分隔即可。关于 valid_referers 指令后可以设置的参数值以及相关说明如下表所示:
参数值 | 说明 |
---|---|
none | 匹配没有 Referer 的 HTTP 请求,如 valid_referers none; |
blocked | 匹配 HTTP 请求中含有 Referer,但是被防火墙或者代理服务器修改,去掉了https:// 或 http:// 的情况,如 valid_referers blocked; |
server_names | 允许文件资源链出的域名白名单,如 valid_referers www.test1.com tets2.test; |
string | 任意的字符串,如 valid_referers *.test.com bxg.*; |
regular_expression | 正则表达式,如 valid_referers ~\.img\.; |
经过以上配置,重启Nginx,访问 http://www.test1.com/ 可以看到图片,而访问 http://www.test2.com/ 时图片返回了 403 错误码:
需要注意的是,不是所有的浏览器都会发送 referer 请求头,并且 referer 的值还可以被客户端随意修改。也就是说,referer 是可以被伪造的。因此,上述讲解的方式只能用于防范普通用户对图片资源的盗用 。
6.2 下载防盗链(未完)
上一节讲解的图片防盗链只能根据请求消息中的 referer 进行验证,这种方式存在伪造 referer 的问题。对于图片之外的下载资源,如果不需要考虑资源链接的长期有效性,可以使用 Nginx 提供的 secure_link 和 secure_link_md5 指令来实现下载地址的加密和时效性。
下载防盗链的实现原理就是在服务器端根据特定规则对下载地址进行加密,并在用户请求下载链接时,验证加密链接是否有效,防止用户伪造下载链接。同时,为了避免加密后的链接被盗链,在加密时添加过期时间,使得下载地址只在一定时间内有效,过期后只能到原网站获取新的地址。
接下来,这里以 PHP 结合 Nginx 的方式讲解如何实现下载防盗链,具体步骤如下。
首先需要重新编译 Nginx。由于指令 secure_link 和 secure_link_md5 是由 ngx_http_secure_link_module 模块提供的,要想使用此模块提供的功能必须在编译 Nginx 时指定:
root@wuychn:/opt/apps/nginx-1.14.2# ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_secure_link_module --add-module=/opt/apps/ngx_cache_purge --add-module=/opt/apps/echo-nginx-module
root@wuychn:/opt/apps/nginx-1.14.2# make
编译完成后,使用重新生成 Nginx 的二进制可执行文件,替换掉 Nginx 安装目录中的可执行文件 /usr/local/nginx/sbin/nginx 即可:
root@wuychn:/opt/apps/nginx-1.14.2# mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak3
root@wuychn:/opt/apps/nginx-1.14.2#
root@wuychn:/opt/apps/nginx-1.14.2# cd objs/
root@wuychn:/opt/apps/nginx-1.14.2/objs#
root@wuychn:/opt/apps/nginx-1.14.2/objs# cp nginx /usr/local/nginx/sbin/nginx
接下来创建 PHP 文件 cdown.php,用于生成加密的下载链接,具体代码如下:
<?php
// 自定义秘钥
$secret = 'test';
// 下载路径
$path='/down/web/echo-nginx-module-master.zip';
// 生成过期时间,time()是当前时间,60表示60秒,及从现在开始60秒之内有效
$expire = time() + 60;
// 用文件路径、秘钥、过期时间生成加密串
$md5 = base64_encode(md5($secret.$path.$expire, true));
$md5 = strtr($md5, '+/', '-_');
$md5 = str_replace('=', '', $md5);
// 生成加密后的下载链接
echo '<a href="http://www.test1.com/down/web/echo-nginx-module-master.zip?st='.$md5.'&e='.$expire.'">echo-nginx-module-master.zip</a>';
// 输出加密后的下载地址
echo '<br>http://www.test1.com/down/web/echo-nginx-module-master.zip?st='.$md5.'&e='.$expire;
?>
上述代码中,第 9 ~ 11 行在生成加密串时,遵循了 secure_link_md5 指令的加密算法,该算法是根据密钥、URI 的 MD5 哈希值和过期时间组成的,且是由 BASE64 进行编码的。因此,在 PHP 中生成的下载链接加密串,必须在使用 md5() 函数生成哈希值后,再使用base64_encode() 函数进行 BASE64 编码,并对编码后字符串中的 +/ 和 = 分别使用 “-_” 和空格进行替换。第 13 行代码用于在网页中生成下载链接,同时将加密串和过期时间作为参数 st 和 e 添加到下载链接后。第 15 行代码用于直接输出加密后的下载地址,方便学习查看。
需要注意的是,为了测试成功,需要在域名为 www.test1.com 的网站根目录下,创建目录 down/web 并上传 echo-nginx-module-master.zip 文件,用于用户下载。
之后编辑 Nginx 的配置文件,在 www.test1.com 网站的 server 块中添加如下配置,验证用户的请求的下载链接是否有效:
location / {
secure_link $arg_st,$arg_e;
secure_link_md5 test$uri$arg_e;
if ($secure_link = "") { #处理加密串不等的情况
return 403;
}
if ($secure_link = "0") { #处理下载链接过期的情况
return 403;
}
}
上述第 2 行的配置中的secure_link指令,用户获取从客户端传递的参数,形如 $arg_参数名 的内置变量保存了相应的参数值。第3行的 secure_link_md5 指令后的字符串 test 是服务器指定的加密密钥,该指令用于根据其后的表达式 test$uri$arg_e 生成加密串,并与用户传递过来的 $arg_st 加密串进行对比,对比结果一致则内置变量$secure_link为1,否则为空串或0。
重启 Nginx,在浏览器中访问 http://www.test1.com/cdown.php,
七、配置 HTTPS
7.1 什么是 HTTPS
HTTPS( Hypertext Transfer Protocol Secure)超文本传输安全协议是 HTTP(超文本传输协议)、SSL(Secure Sockets Layer)安全套接层和 TLS(Transport Layer Security)传输层安全的组合,用于提供加密通信和鉴定网络服务器的身份。随着互联网的飞速发展,网上的支付交易、个人隐私和企业中的敏感信息等越来越受到人们的关注和保护。因此,HTTPS 目前已经是所有注重隐私和安全的网站首选。
要想实现 HTTPS 加密网站,在服务器端首先要获得 CA(CertificationAuthority)认证机构颁发的服务器数字证书(CRT ),然后浏览器在发起 HTTPS 请求时会验证服务器的 CRT 是否合法,若不合法则给出一个 warning 提示信息;若合法,用户在与网站交互时,所传输的数据都是加密后的数据,达到了安全可靠的效果。
Nginx 服务器中的 ngx_http_ssl_module 模块用于提供 HTTPS 网站的配置。由于专业的 CA 机构颁发的证书是收费的,且需要 IP 地址和域名。在学习阶段,Nginx 服务器若要获取数字证书,可以使用 OpenSSL 开源软件将自己作为 CA 为自己颁发证书。
7.2 颁发认证证书
第一步、生成服务器的 RSA 私钥
root@wuychn:/usr/local/nginx/conf# mkdir ssl
root@wuychn:/usr/local/nginx/conf#
root@wuychn:/usr/local/nginx/conf# cd ssl/
root@wuychn:/usr/local/nginx/conf/ssl#
root@wuychn:/usr/local/nginx/conf/ssl#
root@wuychn:/usr/local/nginx/conf/ssl# openssl genrsa -out server.key 2048
其中,genrsa 表示用于生产 RSA 私钥,-out server.key 表示输出的文件名为 server.key,2048 指定秘钥长度为 2048 位(推荐至少 2048 位,越长越安全)。
在执行完上述 openssl 命令设置后,通过 ll 查看生成的 server.key:
root@wuychn:/usr/local/nginx/conf/ssl# ll
总用量 12
drwxr-xr-x 2 root root 4096 5月 8 16:41 ./
drwxr-xr-x 4 root root 4096 5月 8 16:41 ../
-rw------- 1 root root 1675 5月 8 16:41 server.key
第二步、生成服务器的 CSR 证书请求文件
CSR 证书请求文件是服务器的公钥,用于提交给 CA 机构进行签名。生成 CSR 的命令如下:
root@wuychn:/usr/local/nginx/conf/ssl# openssl req -new -key server.key -out server.csr
req 表示证书签发申请,-new 表示新请求,-key server.key 指定私钥为 server.key,-out server.csr 表示生成的 CSR 证书请求文件的名称为 server.csr。
在执行上述命令的过程中,程序会要求用户填写一些信息:
参数 | 说明 |
---|---|
Country Name (2 letter code) | 符合 ISO 的 2 个字母的同家代码,如中国 CN |
State or Province Name (full name) | 省份,如填写 Beijing |
Locality Name (eg, city) | 城市,如Beijing |
Organization Name (eg, company) | 公司名称 |
Organizational Unit Name (eg, section) | 组织单位,如 IT |
Common Name (e.g. server FQDN or YOUR name) | 使用SSL加密的网站域名,如 www.test.com |
Email Address [] | 邮件地址,可以省略 |
A challenge password [] | 有些CA机构需要此密码,通常可以省略 |
An optional company name [] | 可选的格式名称,可以省略 |
上述信息都是可选的,若不填写,可直接按回车使用默认值。值得一提的是,在填写 common name 信息时,必须与实际使用 HTTPS 的网站域名吻合,否则会引发浏览器警报。
以上操作生成的文件,server.key 是服务器的私钥,而 server.csr 相当于公钥。利用公钥可以对数据进行加密,加密后只有用私钥才能解密。而私钥用于对数据进行数字签名,签名后的数据可以利用公钥进行验证。因此,用户应妥善保管私钥,一旦泄露或丢失将无法保证安全。
第三步、CA 为服务器认证证书
root@wuychn:/usr/local/nginx/conf/ssl# openssl x509 -req -days 30 -in server.csr -signkey server.key -out server.crt
上述指令用于使用 CA 的私钥 server.key 为服务器的 CSR 证书申请文件 server.csr 进行签名认证。其中,x509 是自签名证书格式,-days 30 用于设置签发证书的有效期为 30 天。
在 CA 利用私钥签名证书后,该证书将用于浏览器验证请求的网站是杏其实,防止网络通信过程中被伪造。浏览器保存了受信任的 CA 机构的公钥,在请求 HTTPS 网站时,会利用 CA 公钥验证服务器的证书,并检查域名是否吻合、证书是否过期、证书是否已经被吊销等。由于当前的证书是服务器自己作为 CA 签名的,因此浏览器无法信任,会出现瞥告,但不影响学习和测试。
CA 的认证证书颁发完成后,在 Nginx 中添加 CRT 证书和服务器的私钥即可完成 HTTPS 网站的配置。在加密通信时,浏览器通过网站的证书可以获得服务器的公钥,然后利用公钥加密请求信息,Nginx 收到后再利用服务器私钥解开信息。
浏览器在证书认证后,会在请求信息中包含一个自动生成的高强度密钥(或称为随机数),服务器收到后会利用该密钥加密响应信息。由于证书认证和 RSA 非对称加密的过程复杂,为了提高效率,在证书认证后的一 段时间内是直接利用这个密钥进行对称加密通信的。
7.3 配置 HTTPS 网站
在 Nginx 服务器中配置 SSL 服务,首先需要在编译安装 Nginx 时添加对 ngx_http_ssl_module 模块的支持,前面已经安装过此模块。接下来,打开 Nginx 的配置文件 nginx.conf,在该配置文件中配置一个支持 HTTPS 的网站 www.test.com,常用设置如下所示:
server {
listen 443;
server_name www.test.com;
root html/test.com;
ssl on;
ssl_certificate /usr/local/nginx/conf/ssl/server.crt;
ssl_certificate_key /usr/local/nginx/conf/ssl/server.key;
}
上述第 2 行用于设置提供 HTTPS 服务的端口号,443 端口专门用于 HTTPS。第 5 行指令用于开启 Nginx 对 SSL 的支持,第 6 行用于指定 CA 认证后的 CRT 文件的路径,第 7 行用于指定服务器私钥的路径。
配置完成后,重启 Nginx,在浏览器中访问 https://www.test.com/ 效果如下图,这是由于自行颁发的 SSL 证书虽然能够实现加密传输功能,但浏览器并不信任,因此会出现提示信息。
选择 "高级”,选择 “继续前往 www.test.com(不安全)” 后,即可访问该网站下的文件。
通过 F12 键打开开发者工具,选择 View certificate 可以查看证书: