使用acme.sh在nginx代理中打造自续签SSL

前言

前几天,公司小程序无法访问了,经查是使用的腾讯云1年的免费SSL证书到期了。本想再申请个1年的免费SSL证书,结果发现只能申请3个月免费的了;到隔壁家阿里云看了一下,也只有免费3个月的了。没想到两家这么有默契,看来接下来的这几年SSL证书会被这两家大厂逐渐推向收费了啊。怎么讲,咱也是半个懂技术的主,被两大厂这么搞也是受不了了。于是想到了我们可以使用acme.sh申请免费3个月的证书,再配合Linux的定时任务在每个月续期1次达到自动白嫖的目的。

在开始操作之前,我先说一下当前的环境以及安装的软件吧。

1、CentOS 7.9 64位腾讯云CVM主机;
2、使用nginx做为请求入口,安装目录 /usr/local/nginx/ (使用源码编译安装方式),监听了80和443端口;
3、小程序的后台使用SpringBoot开发的jar包,运行在91端口;
4、系统开启了firewalld防火墙,仅开放了80和443端口。

一、安装acme.sh

安装acme.sh这个软件的教程很多,这里只是简单的写一下要执行的命令吧。

# 使用 root 登录到shh工具中,依次执行以下命令。

# 一键安装acme命令(这里不登记邮箱,要需要的自己加参数 -s email=myemail@xxx.com)
curl https://get.acme.sh | sh
# 安装socat(如果没有安装过的话最好安装一下),如果是debian、Ubuntu可以将yum改成apt
yum install socat
# 添加软链接:
ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh
# 切换CA机构(为了申请证书更快,也可以不更改)
acme.sh --set-default-ca --server letsencrypt

acme.sh软件说明地址如下:

acmesh-official/acme.sh: A pure Unix shell script implementing ACME client protocol (github.com)

二、申请证书

1、前提条件说明

示例中的域名为:meily.openea.net

域名meily.openea.net必须配置有A记录指向当前CVM云主机(只有IPv6的必须是AAAA记录指向CVM云主机)

因为在CentOS系统中已安装了nginx,并且监听了80端口,使用常规教程里的命令申请域名证书,必定会出现不能认证的情况或提示端口占用。所以在不关停nginx的情况下,申请域名证书必须要解决以下三个问题:

  • 1、申请证书时的命令需要指定其它非80和443的端口;
  • 2、验证SSL的时候,需要nginx监听的80端口将验证导到一个可用的路径;
  • 3、指定一个目录,在申请SSL时可被nginx代理后能访问到的存放验证文件的目录。

这里先贴出原nginx中nginx.config的配置内容:

worker_processes  4;
#pid logs/nginx.pid;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 60;
# 客户端上传文件限制
client_max_body_size 5M;

server {
listen 80;
# 监听以下域名
server_name meily.openea.net;
# 把http的域名请求转成https
return 301 https://$host$request_uri;
}

# meily.openea.net 小程序后台 91 端口
server {
# SSL 访问端口号为 443
listen 443 ssl;
# 绑定证书的域名
server_name meily.openea.net;
# 证书文件名称
ssl_certificate ./ssl/meily.openea.net.cer;
# 证书私钥文件名称
ssl_certificate_key ./ssl/meily.openea.net.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

# 请按照以下协议配置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;

location / {
# 指向本机的91端口
proxy_pass http://localhost:91/;
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

通过配置文件可以看到,nginx监听了80和443端口,并且将80端口的请求强制转成了443。

证书路被保存到了conf目录下的ssl目录下: /usr/local/nginx/conf/ssl/

2、开启SSL申请端口8081

firewall-cmd --zone=public --add-port=8081/tcp --permanent
systemctl restart firewalld.service
systemctl enable firewalld.service
firewall-cmd --list-port

3、设置证书验证路径

mkdir -p /data/web/ssl

4、设置nginx验证请求共用80端口

server {
listen 80;
# 监听以下域名
server_name sso.openea.net pay.openea.net wxpay.openea.net meily.openea.net;
location ~ /\.well-known/acme-challenge/ {
root /data/web/ssl/;
try_files $uri =404;
}
location / {
# 把http的域名请求转成https
return 301 https://$host$request_uri;
}
}

5、安装证书到nginx替换旧证书

acme.sh --issue -d atechyun.com -d www.atechyun.com -d top.atechyun.com -d tools.atechyun.com -d love.atechyun.com -w /data/www/ssl/ -k ec-256 --httpport 8081 --force

# 注意:域名的DNS解析中需要增加 @ 指向主机的A记录

acme.sh --installcert -d atechyun.com --ecc --key-file /usr/local/nginx/conf/ssl/atechyun.com.key --fullchain-file /usr/local/nginx/conf/ssl/atechyun.com.crt

三、设置crontab定时任务

1、编写脚本

mkdir -p /usr/local/shfile
vi /usr/local/shfile/auto_ssl.sh

## 注意这里要写应用全路径。
#!/bin/bash

/usr/local/bin/acme.sh --issue -d atechyun.com -d www.atechyun.com -d top.atechyun.com -d tools.atechyun.com -d love.atechyun.com -w /data/www/ssl/ -k ec-256 --httpport 8081 --force
/usr/local/bin/acme.sh --installcert -d atechyun.com --ecc --key-file /usr/local/nginx/conf/ssl/atechyun.com.key --fullchain-file /usr/local/nginx/conf/ssl/atechyun.com.crt
/usr/local/nginx/sbin/nginx -s reload

## 保存,退出vi

chmod +x /usr/local/shfile/auto_ssl.sh

提示:注意事项,不能带有.的目录。最好是公用目录

2、设置定时任务

crontab -u root -e

# 在文件最下方增加以下内容,即每月20号2:14分申请一次
14 2 20 * * /usr/local/shfile/auto_ssl.sh

提示:可以先设置一个时间较近的验证。由于证书时长是90天,这里设置每个月申请一次最为保险。