nature book bug burger costumes doctors hospital office shoes skull rocket

在 Nginx 上使用免费SSL证书,配置全站HTTPS访问来装逼

使用可信的 HTTPS 证书后,URL 左边会多一个小锁,并且最左边会显示绿色的 HTTPS。这一切真的很炫酷,所以我把全站都变成了 HTTPS。但是网上讲关于 Nginx 配置 SSL 的文章,大多使用过时的方法,为此ED走了许多弯路,所以决定自己做一个笔记。要阅读这份笔记,需要了解 Nginx 基础,因为我暂时只会通过 Nginx 配置。为此需要先拥有自己的域名,以及服务器。

准备环境

  1. 有一个自己的域名,最好是顶级域名(我使 edlad.com)
  2. 有自己的 Linux 服务器(我使 Ubuntu)
  3. 服务器安装了 Nginx 代理服务器(我使 Nginx v1.8)
  4. 有一个HTTPS证书文件,以及一个配套的秘钥文件(下面就讲如何获取)

另外我的 edlad.com 域名,@ 和 www 已经解析到服务器IP。关于域名解析,请另参阅网上其他资料。

证书是啥

互联网本质决定了第三方可能截获客户端和服务器之间传输的数据包,而HTTPS会对那些包进行加密,令攻击者极难访问到所传输的信息。HTTPS协议基于服务器上的公钥证书, 也叫SSL证书。通常这类证书由特殊机构颁发,证书颁发机构指的是被认可的具有颁发SSL证书的权威机构,简称CA。CA让浏览器产商能够访问受信根证书,在你安装浏览器时,其中就已经包含了这些这些受信根证书。浏览器靠它们建立起CA和浏览器之间的信任链。 — 《Node与Express开发》

证书是一个文件,扩展名通常是 .crt、cer 或 .der,通常还带着一个秘钥 .key 文件。但是 der 不太常见,本站使用的免费证书是 .crt 扩展名的文件。将这两个文件放在服务器上,配置服务器后会自动使用。

证书获取

HTTPS 需要 SSL证书,证书的获取分三种途径。

  1. 可以自己生成证书,这种证书通常用于测试
  2. 从被认可的权威机构申请免费证书
  3. 从被认可的权威机构购买商业证书

自己生成的证书并不影响使用,只是浏览器访问的时候会有安全提示,并且不建议用户继续访问,这个体验绝对会让你失去客户。所以我们选择向被认可的权威机构申请,或者购买证书。所以有必要先知道证书有哪些类型,这样才能知道如何选择。

证书是和域名有关的,他们是和域名绑定的关系。证书大致有四种类型:

  1. 单域证书
  2. 多子域证书
  3. 通配证书
  4. 多域证书

下面就来简单的说说区别,根据自己的需要选择合适的类型~

  • 单域证书就是只能绑定一个域名,比如你想在 edlad.com 和 www.edlad.com 下同时使用 HTTPS 就不行了。大部分免费和便宜的证书都是这样的,但我们有更好的选择~
  • 多子域证书之后会重点介绍,因为本站使用的免费证书就是这类。多子域证书的好处是可以绑定一个域名以及它多个子域名,就是一个证书可以同时搞定 edlad.com 和 www.edlad.com 甚至是 blog.edlad.com (假如有的话)。不足之处在于你预先就要知道,你想把证书用在哪些子域上。如果你无法预见自己会使用哪些子域,那么不妨考虑一下通配证书。
  • 通配证书通常会更贵,它能够作用于任何子域名,你根本不用指出哪些子域名下使用。
  • 多域名证书就更贵更贵,除了具有通配证书的功能,还支持域名变体。例如 edlad.com 和 edlad.net 都可以用了。

主流浏览器中装的50个根证书中,将近90%属于四家公司:Symantec、Comodo、Go Daddy、GlobalSign。但是直接从他们家购买会比较昂贵,通过代理购买会便宜一些。贵的证书通常还带有保险,如果有人在你的网站交易遭受经济损失,并且他们提供证明损失是因为加密不充分导致,那么保险公司就会承担你的损失。

本站使用的是 WoSign的免费证书,申请需要有顶级域名绑定了企业邮箱。在网页上输入域名和子域名,然后提交申请。之后需要创建一个16位的密码,由数字和大小写字母组成,建议生成一个随机密码并且确保记录下来。然后“沃通”会发邮件到企业邮箱,打开邮件里的链接把证书和秘钥文件下载,备份之。(特别感谢群友“丸子”前辈指点)

端口说明

当你访问网站时,总是会连接到特定的端口上,即使URL中没有明确指定,也是隐含的。HTTP 使用的是 80 端口,访问域名的时候,浏览器会把 :80 隐藏。而 HTTPS 使用的是 443 端口,同样也会被浏览器隐藏。Nginx 代理服务器配置的网站,默认是走 80 端口。要想继续修改 Nginx 配置,首先需要明白这一点。

好,接下来和ED一起拿下HTTPS吧!

放置证书

我们需要把 SSL证书 和 秘钥文件 放置在网站使用的服务器上。可以是服务器的任意目录,我放置 证书 和 秘钥 位置分别是:

/etc/nginx/certificate/edlad.com_bundle.crt
/etc/nginx/certificate/edlad.com.key

配置访问

我的虚拟主机配置在 Nginx 的 conf.d 目录下,每个文件是一个虚拟主机。

这里回顾一下基础,修改 conf 文件后通过 nginx -t 检查配置是否通过正确性验证。
然后不需要重启 Nginx,但仍需要重载配置 nginx -s reload 让配置生效。

我主站配置文件叫 www.conf ,内容差不多是:

server {
  listen 80;  #指定使用端口,默认即 80,所以也可以不写
  server_name www.edlad.com;  #指定网站的域名
  root /var/www/html/www;  #指定网站文件目录
  index index.html;  #默认首页文件
}

其实以前 server_name 设置是采用正则的方式:

server_name ~^(www\.|)edlad.com

这么做目的是方便支持顶级域名跳转 www,但是这不是必要的。

把上面的配置换成下面这样,可以同时允许HTTP和HTTPS协议。(但是并不建议这么玩,稍后会讲。)

server {
  listen 80;  #指定使用80端口
  listen 443 ssl;  #指定使用443端口,开启SSL
  server_name www.edlad.com;  #指定网站域名
  ssl_certificate /etc/nginx/certificate/edlad.com_bundle.crt;  #指定证书位置
  ssl_certificate_key /etc/nginx/certificate/edlad.com.key;  #指定秘钥位置
  root /var/www/html/www;  #指定网站文件目录
  index index.html;  #设置网站默认首页文件名
}

这么干以后,仍可像往常一样浏览网站,需要以 HTTPS 协议访问,只需在域名前加 https:// 即可。但是这么干不容易维护,因为 HTTPS 要求页面所有的请求都是 HTTPS,虽然我们可以在请求资源的时候省略协议使其自动选择,但是仍需要维护两套接口。而且绝大多数支持 HTTPS 的网站,输入域名就会自动跳转去 HTTPS,而不用手动加。为此,我们需要修改一下配置!

首先注释掉刚刚指定的 80 端口,仅指配 443:

server {
  #listen 80;  #指定使用80端口
  listen 443 ssl;  #指定使用443端口,开启SSL
  server_name www.edlad.com;  #指定网站域名
  ssl_certificate /etc/nginx/certificate/edlad.com_bundle.crt;  #指定证书位置
  ssl_certificate_key /etc/nginx/certificate/edlad.com.key;  #指定秘钥位置
  root /var/www/html/www;  #指定网站文件目录
  index index.html;  #设置网站默认首页文件名
}

这样改完后,我们需要加两段内容在 www.conf 内容最前:

server {
  listen 443 ssl;
  server_name edlad.com;
  ssl_certificate /etc/nginx/certificate/edlad.com_bundle.crt;
  ssl_certificate_key /etc/nginx/certificate/edlad.com.key;
  return 301 https://www.edlad.com$request_uri;  #设置301重定向
}
server {
  listen 80;
  server_name www.edlad.com;
  return 301 https://$server_name$request_uri;  #设置301重定向
}

这里有两段 server,现在这个文件总共有三段 server。

这两端中第一段 server 指配 edlad.com 域名使用 443 端口,为此需要指定证书位置。重点是最后配置了一个永久性重定向,这么设置搜索引擎也会知道这个地址被永久性迁移了,然后自动处理~ 当用户访问 edlad.com 的时候,就会跳转去 www.edlad.com。

这两端中第二段 server 指定 www.edlad.com 使用默认 80 端口,使用 80 端口的是 HTTP 协议,所以我们要帮忙重定向去 HTTPS 协议。

这样配置以后就实现了输入域名自动 HTTPS 访问,整个 www.conf 的内容如下:

server {
  listen 80;
  server_name www.edlad.com;
  return 301 https://$server_name$request_uri;
}
server {
  listen 443 ssl;
  server_name www.edlad.com;
  ssl_certificate /etc/nginx/certificate/edlad.com_bundle.crt;
  ssl_certificate_key /etc/nginx/certificate/edlad.com.key;
  root /var/www/html/www;
  index index.html;
}

上面配置的意思是,访问 80 端口的时候重定向去 https 协议,这时就走下面的配置。

到目前为止就实现了全站 HTTPS,实现以后 ED 进行了几天的观察,是否就说明 HTTPS 绝对比 HTTP 好呢?

注意事项

开始最担心的是网站 HTTPS 化以后,是否会影响搜索引擎收录。群友“丸子”前辈指点后明白,百度最近已经开始鼓励使用 HTTPS 协议。这里不仅是支持,而是比对待 HTTP 的网站更友好,因为百度认为使用HTTPS协议的网站更安全,更可信。而 Google 则更早就开始支持 HTTPS。
但是 HTTPS 后第二天在百度搜索结果里,网站排名一下掉了很多。本来已经生无可恋的时候,过几日又直接去了百度搜索最前面(此处应有掌声)。所以至少百度是对 HTTPS 友好的,Google 上根本搜索不到小博记录,所以请忘了吧~

之后是小博使用的第三方评论多说出了问题,以及百度统计也出现了错误。经查,在 HTTPS 页面里,引用或请求 HTTP 协议的资源至少会被警告,甚至是出现错误。如果你正在使用的第三方库,很可能你将要舍弃它了。
网上常规做法是,后端做一个HTTPS代理,把HTTP请求代理成HTTPS。然后程序请求后端的代理接口,这样避免HTTP请求。不过小博是纯静态页面,所以这种方法并不适用。(感谢群友♬荒野无灯♬前辈指点)