https取代http是大势所趋,https的好处本文不在赘述,很多公司和机构都在推进这一进程,Apple公司甚至规定,iOS上的App应用必须使用https。因此,正是受到Apple的限制,我们的站点,几乎是所有的站点,接近上百个,都支持了https。
我们可以自己为自己颁发SSL证书,这样的证书满足为http加密的要求,但这样的证书缺少权威性,不会被浏览器所承认。在客户端完全可控的情况下,例如没有经过浏览器,或者使用其他的框架,使用自签名证书也是可行的。此时你只需在客户端将自签名证书加入信任列表;或者修改客户端的证书认证流程,牺牲SSL证书的安全性,让自签名证书能够通过认证。
大多业务情况下,我们的SSL证书都需要得到浏览器的承认才有意义,因此必须寻找权威的证书颁发机构。SSL证书被分为很多种类,不同的证书颁发机构有不同的划分方法,大致分为企业型、专业版、增强型、高级版、域名型等等,而这些SSL证书基本都是收费的,根据安全性、权威性等差异,每年的收费从几千到上万不等。
免费的https证书也是有的,首先找到的是startcom机构,一家以色列公司,它提供免费的有效期为一年的https证书。但我们使用了startcom提供的证书不到一年,悲剧就发生了。startcom被国内的360公司的沃通秘密收购,隐瞒了主导权与架构的转移,还伪造SHA-1凭证的分发日期(主要浏览器开发商要求所有 CA 在 2016 年 1 月 1 日之后停止签发 SHA-1 证书,然而沃通 CA 在 2016 年 1 月 1 日之后仍然签发了 SHA-1 证书,通过故意倒填日期,将这些证书伪装成是在 2016 年前签发的),再加上WoSign的免费凭证服务有bug,广大浏览器均不再信任startcom所颁发的证书,包括WoSign的证书。据称,startcom目前已正式宣布将会停止证书业务并吊销现有的根数字证书,也就是说,startcom已经GG了。
为了推广自家业务,提供一站式服务,很多云计算厂商都已经直接提供SSL证书服务,其中也包含免费的域名型DV证书,这项业务使得SSL证书的获取变得容易很多,大大推进了HTTPS的普及度。但是这类免费证书的使用限制较多。例如不支持泛域名;一个主域名最多只能申请20个证书;一个云计算账号最多只能申请20个证书;一个证书只能匹配一个明细域名等等。总之,云计算服务商提供的免费证书比较适合个人和小微企业使用。试想,如果没有这些限制,还会有多少人花钱买证书呢。
由于云计算厂商对于免费SSL证书的种种限制,也为了避免绑定在某个云计算平台。后来找到的免费证书颁发机构是letsencrypt。它是开源,并且完全免费的,它颁发的证书已经被几乎所有的浏览器所认可。
SSL证书的有效期是由证书颁发机构设定的,通常会被设为一年。然而,对于letsencrypt,它的证书有效期很短,只有90天有效期,因此证书的更新频率较高。所幸的是,letsencrypt能够较为方便地实现证书的自动化更新。
操作系统:CentOS 7
Webserver:Nginx
yum install git python
git clone https://github.com/letsencrypt/letsencrypt
如若在执行git clone命令时出现以下错误:
Cloning into 'letsencrypt'...
fatal: unable to access 'https://github.com/letsencrypt/letsencrypt/': Peer reports incompatible or unsupported protocol version.
须执行以下命令升级nss、curl、libcurl:
yum update -y nss curl libcurl
使用以下命令运行一次客户端,将自动检查更新并升级(letsencrypt启动后,总是会自动检查更新并升级,除非使用--no-self-upgrade参数显示指定),如果一切正常(事实上,升级后letsencrypt在某些系统、某些云服务商的机器上常常不能正常运行,因为涉及到各种源,版本依赖等问题),将会显示完整的帮助文档。
cd letsencrypt
./letsencrypt-auto --help all
letsencrypt客户端插件的功能包括两个部分:认证和安装。
认证插件通过certonly命令启用,认证功能用于确认你是域名的所有者,并为你的域名获取证书,证书被放置在你的域名所在服务器的/etc/letsencrypt/live/[domain]目录。如果你一次性对多个域名进行认证,则这些域名将共用一个证书文件。
./letsencrypt-auto certonly
证书安装插件通过install命令启用,用于在你的服务器上安装证书,证书安装功能会修改服务器上webserver的配置文件,使得webserver能够提供https服务。
./letsencrypt-auto install
如果要使用同时支持获取证书和安装证书的插件来为你的webserver获取并安装证书,使用run命令,run命令是letsencrypt的默认命令,因此可以略去。run命令也可以分别为证书获取和证书安装指定不同的插件。
./letsencrypt-auto run
./letsencrypt-auto
Plugin | 认证 | 安装 | 备注 | 认证方式 (端口) |
apache | Y | Y | 自动获取和安装证书,适用于Apache2.4 on OSes with libaugeas0 1.0+。 | |
webroot | Y | N | 通过webserver的root目录认证来获取证书,适用于处于运行状态的webserver。 | |
nginx | Y | Y | 自动获取和安装证书,适用于Nginx。 | |
standalone | Y | N | 通过letsencrypt自带的standalone服务来获取证书,standalone服务将占用服务器的80或443端口,这就意味着服务器本身的webserver需要处于关闭状态,除非它使用特殊端口。 | http-01 (80) or tls-sni-01 (443) |
DNS plugins | Y | N | 通过修改DNS记录来认证域名所有者以获取证书,这是使用letsencrypt为通配符域名获取证书的唯一方式。 | |
manual | Y | N | 以用户自定义的方式获取证书,根据提示指令,用户自己来完成域名认证。即使用交互式或脚本钩子的方式获取证书。 | http-01 (80), dns-01 (53) or tls-sni-01 (443) |
由于篇幅所限,本文仅对最为基本,也是最关键的webroot、standalone两个证书获取命令进行说明,Apache、Nginx、DNS Plugins、Manual命令本文将不做介绍。
3.1 webroot
webroot通过http文件下载的方式来进行域名认证。通过webroot命令,在获取证书的过程中不用关闭webserver,并且不能关闭webserver。因为webroot将在webserver的对应域名的root目录生成验证文件,并通过webserver提供的http服务执行下载以对域名进行认证,webroot命令依赖于webserver本身。
命令:
./letsencrypt-auto certonly -m dancen@163.com --webroot -w /home/site/dancen -d src.dancen.com
certonly:获取证书
-m:邮箱,证书即将到期时,该邮箱将收到通知,--email
--webroot:获取证书使用的插件是webroot
-w:对应域名root目录的地址,--webroot-path
-d:要认证的域名,--domains
如果要对使用同一root目录的多个域名进行认证,直接增加-d即可:
./letsencrypt-auto certonly --webroot -w /home/site/dancen -d src.dancen.com -d dl.dancen.com
如果要对使用不同root目录的多个域名进行认证,增加一系列的-w -d -d即可:
./letsencrypt-auto certonly --webroot -w /home/site/dancen -d src.dancen.com -d dl.dancen.com -w /home/site/other -d src.other.com -d dl.other.com
webroot命令会在对应域名的${root-path}/.well-known/acme-challenge目录创建一个临时文件,例如对于src.dancen.com,该目录即为/home/site/dancen/.well-known/acme-challeng。letsencrypt服务器会对该临时文件发起http请求,以验证域名。因此,webserver必须得到正确的配置,能够响应letsencrypt服务器对该临时文件的下载请求。你甚至可以配置一个名为.well-known的location节点,专门用于webroot认证。
Nginx配置nginx.conf:
server {
listen 80;
server_name src.dancen.com dl.dancen.com;
access_log off;
root /home/site;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location /.well-known {
root /home/site/dancen;
}
location / {
index index.html index.htm;
}
}
证书获取成功后,letsencrypt会明确提示证书放置的位置,即前文所提到的/etc/letsencrypt/live目录。对于src.dancen.com,其证书所在路径为:
/etc/letsencrypt/live/src.dancen.com/privkey.pem #证书的私钥
/etc/letsencrypt/live/src.dancen.com/cert.pem #服务端证书
/etc/letsencrypt/live/src.dancen.com/chain.pem #证书链的根证书/中间证书
/etc/letsencrypt/live/src.dancen.com/fullchain.pem #完整的证书内容,即服务端证书cert.pem和根证书/中间证书chain.pem的合并内容。
Nginx要用到是privkey.pem和fullchain.pem两个文件,获取证书后,修改Nginx配置如下,重启Nginx后便可启用https了。
Nginx配置nginx.conf:
server {
listen 80;
listen 443 ssl on;
server_name src.dancen.com dl.dancen.com;
ssl_certificate /etc/letsencrypt/live/src.dancen.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/src.dancen.com/privkey.pem;
access_log off;
root /home/site;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location /.well-known {
root /home/site/dancen;
}
location / {
index index.html index.htm;
}
}
证书获取成功后,/etc/letsencrypt/renewal目录下产生的文件也需要留意一下:
/etc/letsencrypt/renewal/src.dancen.com.conf
该文件记录了对应域名在证书获取时的命令信息,后文中将会提到的,在执行renew命令更新证书时,将按照该文件所配置的证书获取方式来进行证书更新,与本次获取证书的方式一致。
对于通过webroot重新获取证书和更新证书的情况,Nginx配置前后没有变化,不需要修改,但重启Nginx仍然是必要的,因为Nginx不会重新加载SSL证书。
3.2 standalone
standalone是一个独立的服务,可以看作是一个小型的webserver,它使用80或443端口来和letsencrypt服务器进行通信。因此,在使用standalone获取证书时,需要关闭正在运行的webserver,除非webserver使用的是80端口和443端口之外特殊的端口。
命令:
./letsencrypt-auto certonly --standalone --preferred-challenges tls-sni --email dancen@163.com -d src.dancen.com
--standalone:获取证书使用的插件是standalone
--preferred-challenges tls-sni:使用443端口,如果要使用80端口,使用--preferred-challenges http指定,或者移除--preferred-challenges命令,因为standalone默认就是使用80端口
3.3 管理证书
3.3.1 查看letsencrypt在当前服务器获取的证书
命令:
./letsencrypt-auto certificates
返回:
Found the following certs:
Certificate Name: src.dancen.com
Domains: src.dancen.com, dl.dancen.com
Expiry Date: 2018-09-19 19:53:00+00:00 (VALID: 30 days)
Certificate Path: /etc/letsencrypt/live/src.dancen.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/src.dancen.com/privkey.pem
返回信息包括一系列的证书名称、证书包含的域名、证书的过期时间,以及证书、私钥路径。需要注意的是,较老版本的letsencrypt并不支持certificates命令。
3.3.2 操作证书
通过--cert-name来指定证书的名称,并对证书执行操作,可选的操作有run、certonly、certificates、renew、delete。
命令:
./letsencrypt-auto certonly --cert-name src.dancen.com
run:获取和安装证书
certonly:获取证书
certificates:查看和--cert-name指定的名称匹配的证书信息
renew:更新快要过期的证书
delete:删除证书
3.3.3 撤销证书
通过revoke命令,指定证书路径(请注意,这里不是指定证书名称),撤销该证书。
命令:
./letsencrypt-auto revoke --cert-path /etc/letsencrypt/live/src.dancen.com/cert.pem --reason keycompromise
--cert-path:证书的路径
--reason:撤销证书的原因,可选
证书被撤销以后,通过delete命令来删除证书相关的文件:
./letsencrypt-auto delete --cert-name src.dancen.com
3.3.4 更新证书
证书的更新命令是renew,renew命令会在本机找出所有的证书,并检查证书的过期时间,它只会对有效期不足30天的证书执行更新。如果证书不需要更新,它不会和letsencrypt服务器产生通信,因此,renew命令可以频繁地执行而不会受到letsencrypt服务器的连接次数限制的影响。也是基于这一特点,可以在crontab设置定期任务,频繁地执行renew操作,确保证书不会过期。
renew在更新证书时,是依照/etc/letsencrypt/renewal目录下的配置来运行的。也就是说,原来是通过webroot方式获取的证书,其更新方式也是webroot;原来是通过standalone方式获取的证书,其更新方式也是standalone。
需要补充的是,通过standalone方式来更新证书比较不稳定,letsencrypt常常在运行过程中卡死。而且在运行standalone时,需要关闭webserver。因此,使用standalone方式来更新证书时,不宜将renew操作写入crontab定期执行,其一旦卡死,webserver的启动将受到影响。
命令:
./letsencrypt-auto renew
./letsencrypt-auto renew --dry-run
./letsencrypt-auto renew --force-renewal
renew:对有效期不足30天的证书执行更新
--dry-run:测试续期命令, 使用这个参数并不会真正续期证书
--force-renewal:强制更新证书,即使证书有效期超过了30天
证书更新后,需要重启Nginx,因此可以在letsencrypt添加前置命令和后置命令,前置命令用于关闭Nginx,后置命令用于启动Nginx。
命令:
./letsencrypt-auto renew --pre-hook "/usr/sbin/nginx -s stop" --post-hook "/usr/sbin/nginx"
--per-hook:前置命令
--post-hook:后置命令
3.3.5 关闭letsencrypt自动更新
letsencrypt每次运行都会首先执行自动更新操作,然后才会执行用户指定的操作,这就产生了一些问题。
首先是自动更新操作的耗时问题,特别是在通过standalone来获取证书或更新证书时,首先得关闭webserver,如果letsencrypt的自动更新用时太久,就意味着webserver将长时间处于关闭状态,这势必对业务造成影响。这里引出的另一个问题是,webroot和standalone两种证书获取方式,那种更好?我的经验是,推荐webroot。一来webroot操作可以在webserver运行期间执行,对webserver的影响最小;二则是在实际操作中,webroot方式更加稳定,而standalone方式常常有执行过程中卡住的情况。
其次,升级后letsencrypt在某些系统、某些云服务商的机器上常常不能正常运行,因为涉及到各种源,版本依赖等问题。
因此,除非有必要,否则建议在启动letsencrypt时通过--no-self-upgrade指令关闭自动更新。
renew报错:
Automated renewal failed:
… …
Could not find a version that satisfies the requirement certbot==0.24.0 (from -r /tmp/tmp.GY8lPazOus/letsencrypt-auto-requirements.txt (line 206)) (from versions: 0.6.0, 0.7.0, 0.8.0, 0.8.1, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.10.0, 0.10.1, 0.10.2, 0.11.0, 0.11.1, 0.12.0, 0.13.0, 0.14.0, 0.14.1, 0.14.2, 0.15.0, 0.16.0, 0.17.0, 0.18.0, 0.18.1, 0.18.2, 0.19.0, 0.20.0, 0.21.0, 0.21.1, 0.22.0, 0.22.1, 0.22.2, 0.23.0)
No matching distribution found for certbot==0.24.0 (from -r /tmp/tmp.GY8lPazOus/letsencrypt-auto-requirements.txt (line 206))
Had a problem while installing Python packages.
以上便是letsencrypt自动更新报错的一种情况,版本依赖出了问题。面对这种情况,可以直接删除更新后的letsencrypt,然后使用git命令从新获取letsencrypt,并且将其回退至一个较旧的版本,例如ce4e00569e6d8ed3d51c5a078d4281bec5f8e5f0版本。之后再执行letsencrypt时,带上--no-self-upgrade参数,关闭自动更新就可以了。
命令:
rm -rf letsencrypt
git clone https://github.com/letsencrypt/letsencrypt/
cd letsencrypt
git reset --hard ce4e00569e6d8ed3d51c5a078d4281bec5f8e5f0
./letsencrypt-auto --no-self-upgrade renew
webroot or standalone?
这里引出的另一个问题是,webroot和standalone两种证书获取方式,那种更好?我的经验是,推荐webroot。
一来webroot操作可以在webserver运行期间执行,证书获取后再重启webserver即可,对webserver的影响最小;而在使用standalone获取证书时,必须先关闭webserver,如果证书获取时间过长,或者证书获取过程中出现错误需要处理,这期间webserver长时间无法对外服务,会对业务造成影响。
二则是在实际操作中,webroot方式更加稳定,而standalone方式常常有执行过程中卡住的情况。
第三,当站点启用了CDN后,域名的ip解析地址将不再是服务器所在地址,standalone模式会受到影响,无法获取证书,而webroot模式依然能够正常工作。
更多内容请参考:
https://letsencrypt.readthedocs.io/en/latest/using.html
https://github.com/certbot/certbot/blob/master/docs/using.rst