如今 HTTPS 证书不再是像以前那么昂贵、缓慢,HTTP/2 等协议的支持使 HTTPS 变得快速甚至比 HTTP 要快,本篇教程利用 Monit 监控 Shell 脚本配合 ssl-cert-check 实现证书过期的自动续签,续签失败邮件告警的解决方案

证书的申请

以互联网安全小组提供的 Let’s Encrypt 证书为例,简单介绍从安装证书工具到申请证书的方法

安装 CertBoot 证书工具

Certbot 官方网站可取得各系统环境的安装教程,官方有列举的环境教程都比较简单,几乎都是通过系统的包管理工具即可顺利安装;这里以 Linux Debian9 / Nginx 举例

1
2
## 安装 CertBoot 证书工具
sudo apt-get install certbot -t stretch-backports

### Let’s Encrypt 证书的申请

前面我们已经安装了 Let’s Encrypt 的证书管理工具,现在我们通过这个管理工具取得证书。

申请证书过程中需要域名可以正常访问,证书管理工具需要访问网站下的 .well-known 目录

1
2
3
4
5
6
7
8
## 申请 Let's Encrypt 证书(/web/domain.com 为网站根目录,domain.com 是要申请的域名)
sudo certbot certonly --webroot -w /web/domain.com -d domain.com
## 成功提示
... 略 ...
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/domain.com/fullchain.pem.
## 生成 ssl_dhparam
sudo openssl dhparam -out /certificate/ser.domain.com/dhparam.pem 2048

取得的证书在/etc/letsencrypt/live/ser.domain.com/ 文件夹内,证书文件为: fullchain.pem 密钥文件为:privkey.pem ,直接在Nginx引用这两个文件就可以了,ssl_dhparam 证书假设存放在 /certificate 文件夹内。

如何配置网站的 HTTPS 这里推荐一个生成配置的网站 Mozilla SSL Configuration Generator

下面是 NGINX 的配置举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server {
listen 80 default_server;
listen [::]:80 default_server;

# 310 跳转HTTP流量到HTTPS
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

# 将上面生成的证书和密钥文件填到这里
ssl_certificate /etc/letsencrypt/live/ser.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ser.domain.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

# 将上面生成的ssl_dhparam证书填到这里
ssl_dhparam /certificate/ser.domain.com/dhparam.pem;

# intermediate configuration. tweak to your needs.
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

# HSTS 证书缓存,务必确认能正常访问后再开启 (15768000 seconds = 6 months)
#add_header Strict-Transport-Security max-age=15768000;

# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;

## verify chain of trust of OCSP response using Root CA and Intermediate certs
#ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

resolver <IP DNS resolver>;

....
}

NGINX HTTP/2 的启用

NGINX 启用 HTTP/2 协议需要满足下面几个条件:

  1. ngx_http_v2_module 模块
  2. ngx_http_ssl_module 模块
  3. NGINX V1.9.5 以上
  4. OpenSSL V1.0.2 以上

若系统的 OpenSSL 低于 V1.0.2 则需要更新系统 OpenSSL 或者编译 NGINX 的时候指定 OpenSSL 源码文件夹

1
2
## 指定 OpenSSL 编译 NGINX
sudo ./configure --with-http_v2_module --with-http_ssl_module --with-openssl=/installed/openssl-1.0.2l

Let’s Encrypt 证书自动续签

经过上面的安装生成后网站现在已经可以正常使用HTTPS协议,但是 Let’s Encrypt 只有 90 天的有效期,90天一过就需要重新申请证书,虽说申请挺方便,但是总有忘记的时候。网上的自动签署教程几乎都是清一色的利用 CronTab 或者 SYSTemd 定时签署;感觉不妥,万一程序出问题签署失败了自己也不知道,索性写个简单脚本实时监控证书过期时间,以及利用 Monit 监控 Shell 返回的退出码判断是否成功续签了证书。

Let’s Encrypt 证书续签脚本

Debian 执行 sudo apt-get install ssl-cert-check 安装,ssl-cert-check 用来读取证书过期时间

当证书还剩 30天过期,则运行 /usr/bin/certbot renew 进行续签证书

成功续签、无需续签脚本返回 0 ;续签失败脚本返回 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash

# 证书文件(有多少个证书就写多少个数组变量并指向证书文件)
certificate[0]="/etc/letsencrypt/live/domain.com/fullchain.pem"
certificate[1]="/etc/letsencrypt/live/domain.com/fullchain2.pem"

upssl=0;
sloop=${#certificate[@]}
let sloop-=1;
for k in $( seq 0 $sloop )
do
ssl-cert-check -c ${certificate[$k]} -x 30 -n -q
if [ $? == 1 ]
then
upssl=1;
else
echo "INFO: CertiFicate Newest"
exit 0
fi
done

if [ $upssl == 1 ]; then
/usr/bin/certbot renew
if [ $? == 0 ]
then
echo "INFO: UPdate CertiFicate OK !"
exit 0
else
echo "Error: UPdate CertiFicate Fail"
exit 1
fi
fi

安装 Monit 程序

邮件告警实现于 Monit 监控程序,由于我的服务器的服务都是由 Monit 监控的,索性就直接拿来用了。

RedHat / CentOS / Fedora 安装

1
sudo yum install monit

Ubuntu / Debian / Linux Mint 安装

1
sudo apt-get install monit

配置 Monit 监控脚本

配置 Monit 邮件告警功能,修改配置文件 sudo nano /etc/monit/monitrc

1
2
3
4
5
6
7
8
9
10
11
## 设置邮件通知服务器,已阿里云服务器举例
#服务器地址与端口
set mailserver smtp.mxhichina.com port 465
#用户名
username "admin@domain.com"
#密码
password "password"
#验证加密方式
using TLSV1
#登陆超时
with timeout 30 seconds

添加一个脚本监控 sudo nano /etc/monit/conf.d/shell

1
2
3
4
5
6
7
8
# 监控 /shell/certificate 执行超时时间 300 秒
check program Certificate with path /shell/certificate timeout 300 seconds
# 每 720 个周期执行一次脚本
every 720 cycles
# 脚本返回码不为 0 发送一封告警邮件到 hscbook@domain.com
# 360 个周期内多次报警只发送一次告警邮件
if status != 0 then alert
alert hscbook@domain.com with reminder on 360 cycles

其他自动签署方案

官方 Let’s Encrypt 看到的一款NGINX 插件 lua-resty-auto-ssl ,可以实现自动证书签署,过期自动续签,挺强大但是需要安装一些依赖环境,若没有其他环境用到 OpenResty LuaRocks 感觉有点小题大做了,各位看官视自己情况选着使用吧。

文章协议: Attribution-NonCommercial-NoDerivatives
文章地址: https://www.hscbook.com/article/code-autohttp/
除非注明,本博文章均为原创,转载请以链接形式标明本文地址