简介

随着https越来越火,似乎也将是未来的大势所趋,这几天就抽空把自己的博客也给升级了一下。

部署https需要有一张被信任的 CA ( Certificate Authority )也就是证书授权中心颁发的 SSL 安全证书,虽然也可以自己签发SSL 安全证书,但自己签发的安全证书不会被主流的浏览器信任,所以需要被信任的证书授权中心( CA )签发的安全证书。而一般的 SSL 安全证书签发服务都比较贵,比如GodaddyGlobalSign等机构签发的证书一般都需要20美金一年甚至更贵,不过为了加快推广 https 的普及, EEF 电子前哨基金会Mozilla 基金会美国密歇根大学成立了一个公益组织叫ISRG ( Internet Security Research Group ),这个组织从 2015 年开始推出了 Let’s Encrypt免费证书,Let’s Encrypt免费证书有效期为3个月,不过可以无限次续签,作为个人使用已经绰绰有余了,所以这里我选择了 Let’s Encrypt 提供的免费证书来部署 https

使用Certbot申请证书

Certbot是一个易于使用的自动客户端,可为Web服务器提取和部署SSL/TLS证书。CertbotEFF和其他人开发,作为Let's Encrypt的客户端,之前被称为“官方Let's加密客户端“Let's Encrypt Python客户端

访问Certbot官方网址:https://certbot.eff.org/,选择自己的web server和操作系统,官方会有相应的使用方式,我是Nginx + CentOS 7.5.1804

安装Certbot

由于CentOS 7没有官网教程说的python2-certbot-nginx插件,因此我并没有使用官网的安装教程,而是使用下面的命令来获取安装插件副本:

wget https://dl.eff.org/certbot-auto
chmod a + x certbot-auto

证书申请

certbot-auto插件所在目录下使用下列命令生成证书:

./certbot-auto certonly --manual --email myemail@gmail.com -d *.wujx.top --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory

参数解释:

  • certonly:表示安装模式,Certbot有安装模式和验证模式两种类型的插件。
  • --manual:表示手动安装插件,Certbot有很多插件,不同的插件都可以申请证书,用户可以根据需要自行选择。
  • --email:证书申请者邮箱地址。
  • -d:为哪些主机申请证书,如果是申请的通配符证书,输入 *.wujx.top(替换为自己的域名)
  • --preferred-challenges dns:使用 DNS 方式校验域名所有权。在申请证书的时候,需要校验域名是否当前申请者所有,而校验方式certonly提供了三种:
  1. dns-01:给域名添加一个 DNS TXT 记录。
  2. http-01:在域名对应的 Web 服务器下放置一个 HTTP well-known URL 资源文件。
  3. tls-sni-01:在域名对应的 Web 服务器下放置一个 HTTPS well-known URL 资源文件。

而申请通配符证书,只能使用dns-01的方式。

  • --server:指定请求的Let's Encrypt地址,不同版本可能会出现请求地址不同,所以显式指定。

过程中会出现交互提示,第一条是说明要下载的文件大小,询问是否下载,输入y确认下载:

Total download size: 71 M
Is this ok [y/d/N]: y

请阅读并同意服务条款,输入A

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A

是否允许向设置的邮箱发送邮件,我选择了

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N

是否对域名和机器(IP)进行绑定,选择

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y

接着出现了一条非常重要的提示,要求配置DNS TXT记录,从而验证证书申请者是否拥有域名的所有权:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.wujx.top with the following value:

2pwGozLTXn_rSJ-Jto9Er2Kt1K4ydukN7TgKfBZXz_B

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

上诉提示要求给_acme-challenge.wujx.top配置一条值为2pwGozLTXn_rSJ-Jto9Er2Kt1K4ydukN7TgKfBZXz_B的TXT记录,在没有确认TXT记录生效前不要回车执行。

我用的是阿里云的域名服务,登陆阿里云控制台,添加一条域名解析,具体解析设置如下图:

配置完解析记录之后,可以在开一个ssh连接,先使用dig工具确认一下TXT记录是否生效,如果没有安装digCentOS 7下安装dig的命令是yum install bind-utils

输入命令dig -t txt _acme-challenge.wujx.top @8.8.8.8确认TXT记录是否生效,已生效可见如下信息:

; <<>> DiG 9.9.4-RedHat-9.9.4-72.el7 <<>> -t txt _acme-challenge.wujx.top @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22443
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;_acme-challenge.wujx.top.	IN	TXT

;; ANSWER SECTION:
_acme-challenge.wujx.top. 599	IN	TXT	"2pwGozLTXn_rSJ-Jto9Er2Kt1K4ydukN7TgKfBZXz_B"

;; Query time: 4192 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Tue Jan 22 00:19:45 CST 2019
;; MSG SIZE  rcvd: 109

这时回到之前的地方,按下回车键确认进行下一步,可以看到如下提示:

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/wujx.top/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/wujx.top/privkey.pem
   Your cert will expire on 2019-04-21. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

至此,证书申请成功,可以查看一下证书保存的目录:

[root@certbot]# tree /etc/letsencrypt/live/wujx.top/
/etc/letsencrypt/live/wujx.top/
├── cert.pem -> ../../archive/wujx.top/cert1.pem
├── chain.pem -> ../../archive/wujx.top/chain1.pem
├── fullchain.pem -> ../../archive/wujx.top/fullchain1.pem
├── privkey.pem -> ../../archive/wujx.top/privkey1.pem
└── README

0 directories, 5 files

可以使用openssl校验一下证书信息:

openssl x509 -in /etc/letsencrypt/live/wujx.top/cert.pem -noout -text

输出的信息比较多,有一行关键输出如下:

X509v3 Subject Alternative Name: 
	DNS:*.wujx.top

与预期一致,申请下来的证书对*.wujx.top整个通配符域名都有效。

Nginx配置

申请完证书之后,需要在Nginx中进行相应的配置,编辑Nginx里的域名配置文件,添加SSL配置:

server {
    add_header X-Frame-Options SAMEORIGIN;
    listen       443 ssl;
    server_name  wujx.top www.wujx.top;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/wujx.top/fullchain.pem; # 证书文件路径
    ssl_certificate_key /etc/letsencrypt/live/wujx.top/privkey.pem; # 证书私钥路径
    ssl_session_timeout 5m; 
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
	# 其他配置省略........
}

保存后重启Nginx

nginx -s reload

访问https://www.wujx.top,网页正常出现没问题。除了上面的配置,还可以在Nginx中配置HTTP强制重定向跳转到HTTPS,在上诉server块上面在加入一个server块,写入以下配置:

server{
    add_header X-Frame-Options SAMEORIGIN;
    listen       80;
    server_name  wujx.top www.wujx.top;

    # rewrite ^(.*)$  https://$host$1 permanent; # 强制将http重定向到https,早期的写法
    return      301 https://$server_name$request_uri; # http重定向到https,新写法
}

保存后重启Nginx

nginx -s reload

自动续签

申请下来的证书只有三个月的有效期,但可以无限续签,Certbot提供了续签的工具,在加上定时任务,即可做到自动检测自动续签。

使用Linux内置的crond服务定时执行续订任务。

编辑当前用户定时任务文件:

crontab -e

在文件中添加新的定时任务:

0 0 3 * * ? /wujx/certbot/certbot-auto renew

参数解释:

  • 0 0 3 * * ?Cron表达式,表示每天凌晨三点时执行,可根据自己需要设定执行时间。
  • /wujx/certbot/certbot-autoCertbot插件所在完整路径,在第一步进行安装Certbot时处于哪个目录,下载下来的Certbot插件就在哪个目录下。
  • renew:检查所有已安装的证书是否即将到期并尝试续订它们。

添加完配置任务,保存并使用以下命令查看当前用户的定时任务:

crontab -l

重启crond

service crond restart

设置为开机自启动:

systemctl enable crond.service

错误解决

在整个证书申请、部署配置的过程中,我出现了两处错误

错误一:内存分配不足

遇到的第一个错误是我生成证书的时候报了个内存分配不足的错误:

Error downloading packages:
  libss-1.42.9-13.el7.x86_64: [Errno 5] [Errno 12] Cannot allocate memory
  libkadm5-1.15.1-34.el7.x86_64: [Errno 5] [Errno 12] Cannot allocate memory
  libXft-2.3.2-2.el7.x86_64: [Errno 5] [Errno 12] Cannot allocate memory
  .........

直接重启了一下服务器:

reboot

顺道修改了一下最大进程数,先查看当前最大进程数:

sysctl kernel.pid_max

设置为无限大:

echo "kernel.pid_max=1000000 " >> /etc/sysctl.conf
sysctl -p

错误二:Nginx配置完无法访问

遇到的第二个问题是在配置完Nginx后,访问网址却连不上,浏览器提示:

此网站无法提供安全连接 www.wujx.top 发送的响应无效。
尝试运行 Windows 网络诊断。
ERR_SSL_PROTOCOL_ERROR

出现这个问题是因为Nginx配置里监听了443 HTTPS端口,但却没有强制要求使用443端口使用SSL连接,所以出现SSL协议错误连接不上,解决方式是监听443端口配置加上ssl参数,强制使用SSL连接:

server {
    add_header X-Frame-Options SAMEORIGIN;
    listen       443 ssl; # 这里加上ssl参数,强制使用ssl
    server_name  wujx.top www.wujx.top;
    #其他配置省略........
}

Nginx配置除了出现上诉错误,还有可能出现下面这个错误:

无法访问此网站 www.wujx.top 意外终止了连接。
请试试以下办法:

检查网络连接
检查代理服务器和防火墙
运行 Windows 网络诊断
ERR_CONNECTION_CLOSED

Nginx错误日志提示:

*720 no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: 21.133.66.122, server: 0.0.0.0:443

这一个错误则是因为在Nginx的其他server块配置里面,也有监听443端口的配置,但它们却没有实际使用,也就是只打开了监听443端口的配置,却没有配置相关的SSL证书。

解决方式是检查其他的server配置,注释掉没有实际使用的监听443端口的配置,或者为该server配置相关ssl证书也可以。

注释掉监听443端口配置:

server {
    add_header X-Frame-Options SAMEORIGIN;
    listen       80;
    # listen       443;
    # 其他配置省略.........
}