nginx让多个虚拟主机的域名同时支持https方式访问

这些年来,主流浏览器对http访问越来越不友好,一个网站如果不支持https生存空间会越来越小。不用说别的,打开网站地址栏提示“不安全”,让用户对网站的第一印象就很不好。

一直想让一台主机的多个nginx站点都支持通过https方式访问,但之前的多次尝试都没有成功。不同域名的证书之间互相影响,同时总是只有一个域名是生效的。其他站点都提示证书域名不匹配之类的警告。

这次比较深入的学习了一下并且在虚拟机上实验,终于搞清楚了这个问题:

并不是我的配置写的不对,而是nginx在编译的时候并不支持这个功能。要想让nginx支持多个站点https访问需要在编译的时候增加一个参数:

--with-openssl-opt="enable-tlsext"

而我使用的nginx当初不是自己编译的而是通过rpm方式安装的,可以通过nginx -V来查看这个版本的编译参数,果然缺少“--with-openssl-opt="enable-tlsext"”。

下面记录了给一个运行中的网站增加https方式的全过程,大致分为几个步骤:

1 重新编译nginx,确认支持多域名证书

2 购买/申请域名证书

3 修改nginx配置文件

4 检查页面所有元素均启用https

5 使CDN支持https

6 全面检查确认

7 正式启用https


1

先安装依赖的库

yum install -y gcc pcre pcre-devel openssl-devel libxml2-devel libxslt-devel gd-devel perl-devel perl-ExtUtils-Embed geoip-devel gperftools-devel

再配置和编译:

./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-http_auth_request_module --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-openssl-opt="enable-tlsext"

在nginx官网下载最新的nginx稳定版(1.16.1),解压缩后编译安装(参考:通过编译方式安装nginx),make install成功后,确认一下:

nginx -v

已经显示新版本号了。

再执行:

nginx -V

可以看到编译参数也正确了。

2

接下来就是获得证书文件了。主流的云服务厂商都提供证书服务,有免费的也有收费的。

收费证书的优点是兼容更多的浏览器、支持泛域名;缺点是贵。

免费证书的优点是:免费,缺点是:不支持泛域名,有效期短,数量限制。

证书申请成功后会提供一个证书的下载地址,下载后是一个压缩包,其中包括了用于nginx、Apache httpd等主流服务器的证书文件。

解压缩后找到nginx的版本,将其上传到服务器上,随便找个目录,比如:/etc/nginx/ssl/

3

接下来修改配置文件,为https增加站点,其实在http站点上修改理论上也可以,但是我怕影响线上业务,为了稳妥起见,还是新建站点保险一些。

server {
	listen 443 ssl;
	server_name zlck.com;
	ssl_certificate "/etc/nginx/ssl/1_xxx.com_bundle.crt";
	ssl_certificate_key "/etc/nginx/ssl/2_xxx.com.key";
	
	root /www/xxx;
}

其中的

ssl_certificate 对应的是 SSL证书文件

ssl_certificate_key 对应的是 SSL证书文件私钥(这个文件是保密的不要让别人知道)

修改配置文件后,测试一下配置文件是否正确

nginx -t

如果测试成功是这样的:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

然后重启nginx,让新的配置文件生效

4

此时如果通过浏览器https访问网站,大概率浏览器会显示一个不安全的icon。原因是如果要启用https,不但网页本身是https,页面所有元素也都要通过https方式发起请求,包括:图片,媒体文件、js、css、ajax等等。

所以接下来要改造网站模板,将所有固定写死http://的都改成https://。

https方式增加了查询和校验,虽然增加了安全性,但是也有副作用:

a 对服务器增加了资源的消耗

b 对客服端增加了请求的延时

如果保留http访问方式,当http的时候,那其中的元素通过https也没有意义(安全性几乎没有提高)。所以建议将http://改成//,这种写法可以让页面元素使用和网页相同的方式请求:当页面是https时,通过https加载元素提高安全性;当页面是http时,也通过http加快速度节省资源。

5

访问量较高的网站通常使用CDN来处理静态请求,所以CDN也需要支持https。

主流CDN厂商都支持上传证书文件,界面大同小异。以腾讯云为例:

内容分发网络/证书管理:

证书来源选择:自有证书

证书内容和私钥内容分别把证书文件的内容复制过来就可以了。

备注:有的厂商强调证书格式必须时PEM格式,其实nginx证书就是PEM格式的,也是同样的复制内容过来就可以了。

6

以上步骤完成后,页面通过https方式打开后,地址栏应该显示一个锁头icon。如果不是,就说明其中还有http请求存在,仔细检查依次处理,直至出现锁头。IE浏览器提示“本页不但包含安全的内容,也包含不安全的内容。是否显示不安全的内容?”也是同样的原因,也是将http请求全部干掉就好了。

如果明明网页种找不到http了,但是还是不行,考虑ajax异步请求,重点排查。

地址栏出现锁头icon后,建议再进行全面的检查,确保无误。

7

如果不需要保留http访问方式,可以强行将http跳转到https。具体修改旧站点的配置文件:

server {listen 80; server_name xxx.com; rewrite ^(.*) https://xxx.com$1 permanent;}

这个做的一个弊端是,多一次跳转请求。虽然这些增加的请求不太消耗资源,但是终归增加了访问的延迟,用户体验也不好。如何能让用户直接通过https访问呢?如果流量来源主要是百度的话,可以这样操作。

先在百度搜索平台(https://ziyuan.baidu.com/)注册,并验证站点。

然后点击:搜索展现/HTTPS认证,申请认证。认证通过后,用户通过搜索引擎打开你的站点链接将直接使用https方式。

搜索引擎HTTPS认证

绕过一个坑:在反复测试证书的时候浏览器会将证书缓存,有时候明明配置已经对了但是浏览器总是显示证书错误,就可能是这种情况。关掉浏览器再重新启动,说不定就一切正常了。

扫码关注我的公众号