无80端口情况下使用 CertBot 申请证书并使用nginx更新证书

443端口不知道是电信不想封还是怎么样,一直无需备案就能开启对外服务。公司的对外访问服务都是通过443端口对外访问的。

而443端口就必须使用合法的 SSL 证书,合法的 SSL 证书很多,我一直使用 letsencrypt 提供的SSL证书服务。

但是 letsencrypt 的证书只有90天的有效期,必须在有效期内 renew,否则过期了只好重新申请了。

申请 letsencrypt 证书网上一堆都是需要开放 80 端口才能申请,其实 CertBot 在很早之前就已经支持 https 的方式申请证书。

使用 CertBot 通过 443 端口申请证书

前提条件:

  1. 首先将需要申请证书的域名指向你本地的公网IP地址。
  2. 路由器开放443端口映射指向 WEB 服务器的IP地址。

安装 CertBot

访问 [Certbot 官网](https://certbot.eff.org] 可以获得所有系统的安装方法及使用方法

我这里是 Centos 7

1
2
yum install epel-release
yum install certbot

申请 letsencrypt 证书

申请之前我们必须停止 nginx 等一切占用443端口的程序,certbot 会自动使用443端口来申请证书,你也可以用参数 --preferred-challenges tls-sni 强制使用 443 端口申请证书。

1
2
certbot certonly --standalone -d example.com -d www.example.com
certbot certonly --standalone --preferred-challenges tls-sni -d example.com -d www.example.com

-d 后面填写你的域名,这里例子是可以批量申请多个证书,但我不建议这样做因为后面renew的时候也会一起renew,我不太喜欢这样。所以只写一个域名就好了。

在不停止 nginx 的情况下更新证书

在生产环境中,我们不可能设置定时任务来停止 nginx 再更新证书,有些情况 nginx 可能启动失败等导致业务中断,所以我们可以使用 CertBot 在 0.9.0 添加的 nginx 参数来实现更新证书。

修改该网站的 nginx 配置文件

先给 certbot 添加一个网站目录

1
mkdir /usr/share/nginx/example.com

再修改需要更新证书网站的配置文件

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
server {
listen 443 ssl http2;
server_name example.com;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# log files
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
location / {
...
}
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /usr/share/nginx/example.com;
}
location = /.well-known/acme-challenge/ {
return 404;
}
}

修改完后应用配置

1
nginx -s reload

修改 CertBot renew 配置文件,使其实用 nginx 方式更新证书

编辑 /etc/letsencrypt/renewal/example.com.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
# renew_before_expiry = 30 days
version = 0.14.1
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem
# Options used in the renewal process
[renewalparams]
authenticator = nginx
installer = nginx
account = 702abbe388e806128233df7516707c73

authenticatorinstaller 修改成 nginx 即可。

测试

运行 certbot renew --dry-run 测试更新证书

结果会看到所有证书更新成功。

设置自动更新

可以使用 CronTab 来建立计划任务执行更新证书操作,但这里会有一些坑。

由于 CronTab 的环境变量问题,和我们登陆用户的环境变量不同,故此使用 certbot 的 nginx 时候会报错,具体报错信息如下

1
Could not choose appropriate plugin: The nginx plugin is not working; there may be problems with your existing configuration.

故此我们需要让 CronTab 的环境变量符合运行条件。

1
30 16 * * 4 date >> /var/log/certbot.log && . /etc/profile;/usr/bin/certbot renew --dry-run >> /var/log/certbot.log 2>&1
  • 30 16 * * 4 这里是 CronTab 的任务执行时间,这里意思是每周四下午4点半运行下面的命令
  • date >> /var/log/certbot.log && 记录时间到日志文件
  • . /etc/profile; 让 CronTab 应用系统的环境变量,注意 . 后面是有空格的
  • /usr/bin/certbot renew --dry-run >> /var/log/certbot.log 2>&1 执行 renew 操作并且记录所有信息到日志文件里
  • --dry-run 这个表示测试的意思,不添加是无法测试是否能够自动更新证书,测试正常后将这个参数取消。

最终的命令是

1
2
crontab -e
30 16 * * 4 date >> /var/log/certbot.log && . /etc/profile;/usr/bin/certbot renew >> /var/log/certbot.log 2>&1

写在最后

这里我留了一个坑,就是在 CertBot 使用 nginx 插件部分我记得这里需要初始化的,但是我已经找不到当时我配置参考的文档,而我现在环境已经初始化好了,当初又没做笔记,以后一定部署好要做笔记,好记性不如烂笔头啊。

所以如果遇到什么问题,多 Google 吧,不负责任的博主。

2017年11月22日更新

填坑,记得了,需要安装 nginx 插件,否则会提示 The requested nginx plugin does not appear to be installed. Skipping.

Debian 安装 python-certbot-nginx

1
sudo apt install python-certbot-nginx -t

Centos 安装 certbot-nginx

1
yum install certbot-nginx -y