写在前面

现在大部分网站都使用https协议,而不是传统的http,因此本篇就来学习如何使用Nginx配置网站HTTPS和如何将http重定向到https,同时也会学到如何进行泛域名路径分离和请求转发,静态服务的相关配置,这些都是企业日常开发过程中经常会遇到的情况。

Nginx配置网站HTTPS

HTTPS

HTTPS是超文本传输安全协议(英文为Hyper Text Transfer Protocol Secure,简称HTTPS)是超文本传输协议HTTP和SSL/TLS的组合,用以提供加密通信以及对网络服务器身份的鉴定。HTTPS连接通常被用于万维网上的交易支付和企业信息系统中敏感信息的传输。请不要将HTTPS协议与在RFC2600中定义的安全超文本传输协议(S-HTTP)相混淆。

HTTPS目前已经是所有注重隐私和安全的网站的首选,随着技术的不断发展,HTTPS网站已经大面积创建了,个人和站长均可以自己动手搭建一个安全的加密网站。

第一步,创建本地SSL证书,依次执行如下命令:

1
2
3
4
// 创建存储文件目录
mkdir -p /etc/nginx/ssl
// 创建有效期为100年,加密算法为RSA2018的SSL密钥key和x509证书文件
openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

之后会一次填写如下信息:

1
2
3
4
5
6
7
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:New York
Locality Name (eg, city) [Default City]:New York City
Organization Name (eg, company) [Default Company Ltd]:Book Hero,Inc
Organizational Unit Name (eg, section) []:Book Hero
Common Name (eg, your name or your server's hostname) []:book.com
Email Address:admin@book.com

第二步,首先使用nginx -V(注意是大写)命令来查看已经安装的插件,可以发现目前并没有安装http_ssl_module模块:

1
2
3
4
[root@envythink ssl]# nginx -V
nginx version: Envythink/1.1.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
configure arguments: --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module

第三步,回到Nginx下载目录,笔者为/home/envythink/nginx-1.17.0,使用如下命令来进行编译安装http_ssl_module模块:

1
./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module --with-http_ssl_module

之后使用make命令进行安装,切记不可使用make install命令,这样会覆盖前面已经安装的Nginx。

第四步,更新二进制文件。由于此处执行了编译和安装命令,那么接下来就需要将安装目录中的nginx命令进行更新,也就是将/home/envythink/nginx-1.17.0/objs目录下的nginx覆盖掉之前的/usr/local/nginx/sbin/目录下的nginx,使用的命令如下:

1
cp /home/envythink/nginx-1.17.0/objs/nginx /usr/local/nginx/sbin/nginx

之后开发者再次使用nginx -V(注意是大写)命令来查看已经安装的模块,可以发现http_ssl_module模块已经安装成功了:

1
2
3
4
5
6
[root@envythink nginx-1.17.0]# nginx -V
nginx version: Envythink/1.1.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --prefix=/usr/local/nginx --add-module=/usr/local/nginx/third_module/echo-nginx-module-0.61 --with-http_stub_status_module --with-http_ssl_module

第五步,在vhost目录下新建一个hellobook.com.conf文件,其中的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
server {
listen 443 ssl;
server_name hellobook.com;

ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;

# 禁止在header中出现服务器版本信息,防止黑客利用版本漏洞进行攻击
server_tokens off;

# 设置ssl/tls会话缓存的类型和大小。这个参数默认是none,但是一般设置为shared,如果使用buildin,那么可能会参数内存碎片。
#这里设置的是shared:SSL:1m,表示所有的Nginx工作进程会共享SSL会话缓存,官网介绍说1M可以存放大约4000的sessions
ssl_session_cache shared:SSL:1m;

# 客户端可以重用会话缓存中ssl参数的过期时间,内网系统默认为5分钟,这个时间比较短,一般可以设置为30m即30分钟
ssl_session_timeout 5m;

# 选择加密套件,注意不同浏览器所支持的套件种类和套件顺序是不一样的
# 这里指的的是OpenSSL库能够识别的写法,开发者可以使用openssl -v cipher 'RC4:HIGH:!aNULL:!MD5' (后面是你所指定的套件加密算法)来查看所支持的算法
ssl_ciphers HIGH:!aNULL:!MD5;

# 设置协商加密算法时,优先使用我们服务端的加密套件,而不是客户端的加密套件
ssl_prefer_server_ciphers on;

location / {
root /usr/share/nginx/html/hellobook;
index index.html index.htm index.php;
}
}

第六步,新建/usr/share/nginx/html/hellobook目录,并在里面新建index.html文件,其中的内容如下所示:

1
<h1 style="color:red;text-align:center">The web site is running by using ssl</h1>

第七步,使用nginx -t命令来检查Nginx语法并使用nginx -s reload命令来重启Nginx。然后在浏览器中访问https://hellobook.com,结果如下所示:

请注意,HTTPS默认使用的是443端口,而HTTP默认使用的是80端口,因此当开发者直接访问http://hellobook.com,结果如下所示:

HTTP重定向到HTTPS

很明显上面是不太友好的方式,正确的做法是,当用户访问http://hellobook.com时,应当将其重定向到https://hellobook.com,那么这个重定向应该如何操作呢?

开发者需要在hellobook.com.conf文件中新增如下配置信息:

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name hellobook.com;
# 强制将http重定向到https
rewrite ^ https://$http_host$request_uri? permanent;

# 禁止在header中出现服务器版本信息,防止黑客利用版本漏洞进行攻击
server_tokens off;
}

之后使用nginx -t命令来检查Nginx语法并使用nginx -s reload命令来重启Nginx。然后在浏览器中访问http://hellobook.com,结果如下所示:

除了上述配置外,我们还可以使用其他的配置方式,如下所示,开发者可以根据需要选择合适的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name hellobook.com;

# 单域名重定向配置方式
if ($host = "hellobook.com") {
return 301 https://hellobook.com$request_uri;
}

# 当使用非HTTPS协议时全部重定向到HTTPS
if ($scheme != "https") {
return 301 https://$server_name$request_uri;
}

# 无论使用何种协议,一律重定向到HTTPS
return 301 https://$server_name$request_uri;
}

可以看到这三种方式的适用场景是不同的,开发者需要结合实际需求来进行选择。

当然,开发者也可以在server区块中新增几个用于提升网站安全性的命令,如下所示:

1
2
3
4
5
6
# 减少点击劫持
add_header X-Frame-Options DENY;
# 禁止服务器自动解析资源类型
add_header X-Content-Type-Options nosniff;
# 防XSS攻击
add_header X-Xss-Protection 1;

其他更多的命令参数,大家可以参阅Nginx官方网站进行学习。

泛域名

所谓的泛域名是指某一个或者一些域名的子域名,举个例子,如域名为envythink.com,它的子域名可能为test.envythink.comhello.envythink.comtest1.doc.envythink.comtest2.doc.envythink.com等域名,这些都可以看作是envythink.com域名的泛域名。

泛域名路径分离

泛域名路径分离这是一个非常实用的技能,在实际开发过程中我们可能需要配置一些二级、三级域名,并希望通过Nginx来实现自动指向对应目录这一功能。

举个例子,假设我们希望下面三或者多个子域名能自动指向服务器中的指定目录:

(1)test1.doc.envythink.com子域名自动指向服务器的/usr/share/nginx/html/doc/test1目录;

(2)test2.doc.envythink.com子域名自动指向服务器的/usr/share/nginx/html/doc/test2目录;

(3)test3.doc.envythink.com子域名自动指向服务器的/usr/share/nginx/html/doc/test3目录……

此时开发者可以在doc.envythink.com.conf配置文件中新增如下server区块,里面的内容如下所示:

1
2
3
4
5
6
7
server {
listen 80;
server_name ~^([\w-]+)\.doc\.envythink\.com$;

root /usr/share/nginx/html/doc/$1;
index index.html index.htm;
}

考虑到实际效果,这里以test1.doc.envythink.com为例进行介绍。新建/usr/share/nginx/html/doc/test1/目录,然后在里面新建一个index.html文件,其中的代码如下所示:

1
<h1 style="color:red;text-align:center">The web site domain is test1.doc.envythink.com</h1>

接下来使用nginx -t命令来检查Nginx语法并使用nginx -s reload命令来重启Nginx。

之后在浏览器地址栏中访问test1.doc.envythink.com,可以看到如下信息,这就表明我们泛域名路径分离设置是成功的:

泛域名转发

在上面我们学习的是如何进行泛域名的路径分离,其实还可以进行泛域名转发,需求和之前的非常类似。在实际开发过程中我们可能需要将一些二级、三级域名链接转发到我们希望的路径,然后让后端根据路径来解析不同的规则。

举个例子,假设我们希望下面三或者多个子域名链接能自动转发到我们指定的路径上:

(1)test1.server.envythink.com/api?name=envy子域名链接自动转发到127.0.0.1:88/test1/api?name=envy

(2)test2.server.envythink.com/api?name=envy子域名链接自动转发到127.0.0.1:88/test2/api?name=envy

(3)test3.server.envythink.com/api?name=envy子域名链接自动转发到127.0.0.1:88/test3/api?name=envy……

此时开发者可以在server.envythink.com.conf配置文件中新增如下server区块,里面的内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name ~^([\w-]+)\.server\.envythink\.com$;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:88/$1$request_uri;
}
}

接下来使用nginx -t命令来检查Nginx语法并使用nginx -s reload命令来重启Nginx。之后就可以测试我们对于泛域名转发的相关配置是否生效,可以发现的确生效了。

静态服务

尽管在前面或多或少的介绍了如何使用Nginx来配置静态服务,接下来将专门学习如何实现这个功能。

其实配置起来非常简单,开发者只需在*.conf文件中新增如下代码即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 80;
server_name static.envythink.com;
# 防止中文乱码
charset utf-8;

location /download {
alias /usr/share/nginx/html/static;


# 开启静态资源列目录
autoindex on;

# 默认是on,表示显示文件的精确大小,单位是byte
# 如果设置为off,则显示文件的大概大小,单位可以是KB、MB、GB
autoindex_exact_size off;

# 默认是off,表示显示的文件时间为服务器时间
# 如果设置为on,则显示的文件时间为GMT时间
autoindex_localtime off;
}
}

接下来使用nginx -t命令来检查Nginx语法并使用nginx -s reload命令来重启Nginx。之后就可以测试我们对于静态服务的设置是否生效,可以发现的确生效了。

那么这样,关于Nginx配置SSL、泛域名和静态服务的学习就到此为止,后续学习其他的知识。