Nginx部署HTTPS服务过程与异常处理实践
一、背景
笔者所在团队需要开发ios的APP,而apptstore应用商店审核需要应用使用https,所以需要配置https证书,笔者将此次配置的过程与遇到的一些问题记录下来,方便自己和读者后续参考。
二、操作概要
- 申请证书与认证
- 证书下载与配置
- 问题分析与总结
三、申请证书与认证
要搭建https服务首先需有SSL证书,证书通常是在第三方申请,在阿里云的安全服务中有SSL证书这一项,可以在里面申请免费的证书;
也可以在自己电脑中生成,虽然也能完成加密,但是浏览器是不认可的,因此最好还是去第三方申请
3.1 证书申请
阿里云提供免费的证书,不需要人工审核,用来做测试是非常不错的选择,申请地址如下URL。
https://common-buy.aliyun.com/?spm=5176.2020520163.cas.1.1aa12b7aWWn20O&commodityCode=cas#/buy
免费型的证书隐藏的比较深,想要申请免费证书需要先选择 1个域名->Symantec->免费型 ,所以读者这里需要注意一下,如下图参考。
image选择之后,一直点击下一步,便可购买完成,免费购买证书之后笔者需要回到证书控制台,在控制台有一个补全信息的链接地址,需要通过此地址补充申请人的联系信息,参考下图填写
image3.2 域名验证
补全个人信息之后,笔者还需要给阿里云验证当前域名是属于本人的,验证方式有两种,第一种是通过dns解析认证,第二种是通过上传验证文件认证,笔者这里采用的是验证文件认证,首先需要下载文件,如下图
image在下载验证文件完成之后,笔者需要把文件放到服务器中去,这里提供一条复制命令
scp ~/Downloads/fileauth.txt tangqingsong@192.168.43.34:~/
将验证文件复制到服务器之后,笔者还需要将验证文件放到站点对应目录,参考命令如下:
mkdir -p /website/.well-known/pki-validation && cp fileauth.txt /website/.well-known/pki-validation/
现在笔者要验证文件放置的位置是否正确,笔者通过两种方式进行了验证,分别是手动验证,和阿里云验证。
4.1.1 手动验证
手动验证的目的是首先确保文件位置放置是否正确,可以通过访问站点的url是否成功进行判断,比如笔者可以访问如下URL,如果返回如果页面能够正常打开,并且可以看到某些值,则代表配置成功。
http://www.songboy.net/.well-known/pki-validation/fileauth.txt
4.1.2 通过阿里云来验证
在确保文件放置正确之后,关键的是能让阿里云能访问到,阿里云这里提供了一个检查配置的功能,在下载验证文件页面,有一个检测配置的链接,单击之后便可进行检查,如下图。
image当点击 检查配置 之后,如果阿里云能够正常访问,则会在左侧给出提示,现在可以返回证书列表,在列表中可以看到当前状态为审核中,如下图
image审核因为不需要人为干预,所以很快就能下发证书,笔者下发证书的时间大约是2分钟左右。
四 证书下载与配置
4.1 证书下载
证书签发之后,可以在列表中可以看到状态栏中为 已签发 ,同时操作栏可以下载以及查看详情等,如下图所示
image点击下载后,会跳转到下载详情页面,在下载详情页可以选择自己相对应的web服务,比如笔者使用nginx,当选择nginx之后,下方还会很贴心的提示如何配置,现在笔者下载nginx配置文件。
下载配置文件之后,笔者需要将其解压,解压之后可以看见里面包含了两个证书文件,如下图所示
image接着需要把这两个证书文件给复制到服务器当中去,首先需要在服务器创建对应的文件夹,参考命令如下
cd /usr/local/nginx/conf/ && mkdir cert #此命令在服务器执行
在服务器创建完成对应文件夹之后,执行命令将证书文件复制到服务器中,参考命令如下:
scp ~/Downloads/214905423420461/* tangqingsong@192.168.43.34:/usr/local/nginx/conf/cert
4.2 证书配置
证书复制完成之后,可以对nginx配置文件进行更改,使用vim命令编辑nginx配置文件,参考命令如下:
vim /usr/local/nginx/conf/nginx.conf
在vim界面把之前http的配置部分复制一份,复制之后修改监听的端口(listen)为443,并在其后面添加ssl的信息,参考配置如下:
listen 443;
ssl on;
ssl_certificate cert/214905423420461.pem;
ssl_certificate_key cert/214905423420461.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
4.3 重启Nginx
修改配置文件之后,笔者需要测试nginx配置文件是否正确,参考命令如下:
nginx -t
当nginx如果没有出现error相关信息,基本配置没有问题,下面是我的nginx返回结果:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
nginx配置没有问题之后,笔者需要重启nginx让其生效,参考命令如下
nginx -s reload
4.4 检验效果
现在所有该做的工作都做好了,笔者可以通过浏览器来访问可以正常访问,打开如下URL。
https://www.xxx.com
浏览器地址栏显示如下图所示
image如果看到浏览器,展示安全,并且显示绿色就说明大功告成了
五、问题分析与总结
到这里,虽然已经成功部署了https,但是依然会产生很多附带的问题,下面是笔者后续所遇到的几个问题,以及解决方案。
5.1 重定向405错误
在部署https后,笔者很急切让http全部重定向到https上来,这个时候可能会在nginx的配置文件中加入下面的代码
return 301 https://$server_name$request_uri;
这段代码实际上是有缺陷的,他只能帮你重定向get请求,如果客户端是以post请求,经过301重定向后会变成get请求,最终导致服务器返回405的问题;
除了405问题以外,还有一个隐患,301重定向是永久重定向,在部署https的时候容易出现坑,如果使用了永久重定向,服务器出现问题需要回滚的情况下,即使服务器回滚了,浏览器依然会跳转到https,因为有重定向缓存,所以不建议使用301重定向,而应该使用302;但是302也不好去处理post请求,所以还是用307把,配置代码如下:
return 307 https://$server_name$request_uri;
5.2 跨域问题
启用https证书后,会发现很多浏览器会存在跨域的问题,下面附带两种解决方法。
5.2.1 自适应协议
在http域下加载https资源浏览器是允许的,但是https加载http的资源,浏览器会阻止,所以在前端页面中的地址最好不要指定协议,可以吧"http://"或者"https://" 使用自适应协议来替换 "//",这样浏览器将会自动调用对应域的资源,而不会出现https站点不能加载http资源问题,而https请求http却出现跨域问题。
5.2.2 作用域设置
http和https并不在同一个作用域,所以当一些ajax请求时,会出现跨域问题,这个时候可以修改nginx配置文件,将其资源的作用域扩大,把以下代码放到http的配置项如下:
需要注意,如果让网站的资源让任意作用域都可以调用,那么会存在一个安全隐患,所以最好是指定几个作用域,而不要全部放开。
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie,Content-Type, Authorization';
add_header 'Access-Control-Allow-Methods' 'PUT,POST,GET,DELETE,OPTIONS';
5.3 同时支持,分批上线
在部署https证书的时候,会遇到很多小问题,一开始笔者打算将其一步到位,后来发现小问题不断,比如前面的跨域问题,以及301重定向问题;
这些问题看似不大,但是小问题却比较多,因此我建议大家在上线https的时候,最好分批上线,满足当前需求即可,不要一下子把所有http都切换过来需要注意https加载http资源被阻止的问题。
作者: 汤青松
微信:songboy8888