Nginx部署Let's Encrypt的HTTPS证书
https,加密的http服务,当我们谈论这个话题时,多数情况下是讨论的HTTPS证书,其实https服务还包含如下几个方面:
- HTTPS证书验证
- SSL/TLS协议
简单看看使用https和http的区别
如果我们访问https://www.google.com
,浏览器实际上做了如下的事情:
- 通过DNS查询
www.google.com
服务器的IP地址 - 浏览器与服务器的443端口建立TCP连接
- 浏览器向服务器索要并验证HTTPS证书
- 浏览器与服务器协商好对话密钥
- 浏览器使用对话密钥加密明文的HTTP请求发送给服务器
- 服务器返回响应后浏览器使用对话密钥解密并渲染网页
再来看看如果我们访问http://www.baidu.com
,浏览器做了什么:
- 通过DNS查询
www.baidu.com
服务器的IP地址 - 浏览器与服务器的80端口建立TCP连接
- 浏览器发送明文的HTTP请求给服务器
- 服务器返回响应后浏览器渲染网页
对比之后你就会发现HTTPS证书是加密通信的关键点。
HTTPS证书是什么
HTTPS证书是一个文件,如图它包含三部分信息:
- 主题名称
- 签发名称
- 公共密钥信息
另外你也能发现,证书是有层次的,每一个层次的证书都包含上面的三部分信息。最底层的叫根证书(根证书会被内置到浏览器的可信库中),最上层的叫用户证书(用户是证书颁发机构对网站站长的称呼),中间的当然就是中间证书了。证书的这种层次关系被称为证书链。
浏览器在对证书进行验证的时候遵循证书链的顺序,首先验证根证书,依次验证中间证书,最后验证用户证书。任何未通过的验证都会导致浏览器出现警告,例如Chrome的警告:
如何获得HTTPS证书
HTTPS证书可以花钱购买也可以自己签发,但浏览器会显示警告信息,这不是我们想要的。
现在已经有许多免费的HTTPS证书服务可以让网站站长选择:
第一项是国内公司的服务,由于谷歌称CNNIC发布伪造CA证书事件,沃通免费证书也受到波及,业内已经不再信任国内机构签发的证书,所以不推荐使用。
第二项是老牌的国外服务,签发的免费证书有效期长达1年,但最近爆出StartSSL 的PKI 平台已由奇虎360 托管,由于奇虎360在业内名声不太好,导致业内不再信任StartSSL签发的证书,所以不推荐使用。
本文着重介绍第三项Let’s Encrypt的免费证书服务。
申请Let’s Encrypt免费HTTPS证书
Let’s Encrypt的证书生成过程使用了ACME协议并且开放了相关API,官方提供的工具我没有使用过,本文介绍使用acme-tiny这个开源库来生成证书。
准备私钥
私钥需要生成两份,一个是账户的私钥,另一个是域名的私钥。
$ openssl genrsa 4096 > account.key
$ openssl genrsa 4096 > mydomain.com.key
准备证书的配置文件
$ cat mydomain.com.cnf
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
[req_distinguished_name]
[req_ext]
subjectAltName=@alt_names
[alt_names]
DNS.1 = mydomain.com
DNS.2 = www.mydomain.com
这个配置文件可以定义许多信息,相关的配置文档请参考这里,本文就不介绍了,上面给出的配置是最小的配置规格。
生成证书请求文件
$ openssl req -new -sha256 -out mydomain.com.csr -key mydomain.com.key -config mydomain.com.cnf -subj "/"
配置Nginx提供域名的HTTP服务
HTTP服务主要是用来向Let’s Encrypt证明你确实是域名的拥有者,在tmp目录创建一个文件夹用来存放临时验证文件,然后配置Nginx。
$ cd /tmp/ && mkdir challenges
$ cat /etc/nginx/sites-enabled/default
server {
listen 80;
server_name mydomain.com www.mydomain.com;
# letsencrypt server
include /etc/nginx/letsencrypt;
}
$ cat /etc/nginx/letsencrypt
location ^~ /.well-known/acme-challenge/ {
alias /tmp/challenges/;
try_files $uri =404;
}
$ sudo service nginx restart
生成HTTPS证书
下载acme-tiny脚本
$ wget https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py
生成用户证书
$ python acme_tiny.py --account-key account.key --csr mydomain.csr --acme-dir /tmp/challenges/ > mydomain.com.pem
合并根证书
$ wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > letsencrypt.pem $ cat mydomain.com.pem letsencrypt.pem > mydomain.com.bundled.pem
使用HTTPS证书
生成的3个月有效期的HTTPS证书在Nginx中配置一下就好了。
$ cat /etc/nginx/sites-enabled/default
server {
listen 80;
listen 443 ssl;
server_name mydomain.com www.mydomain.com;
ssl_certificate /home/mydomain.com.bundled.pem;
ssl_certificate_key /home/mydomain.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:DES-CBC3-SHA;
# letsencrypt server
include /etc/nginx/letsencrypt;
}
由于证书只有3个月的有效期,可以将上面的命令写到一个脚本文件中,使用crontab定时去运行它,我就是这么干的,参考这里。