运维_基础设施_证书


目录:

published: - djangoblog aliases: - HTTP 工作原理 - HTTPS 原理 - HTTPS原理 - HTTPS证书自动续期全流程 created_time: 2024-08-16 09:03:58 modify_time: 2024-12-21 16:02:47 title: 运维_基础设施_证书 author: dhr2333 published_time: tags: - Collect/acme - Collect/Apache - Collect/CA - Collect/HTTP - Collect/HTTPS - Collect/MongoDB - Collect/Nginx - Collect/OpenSSL - Tools/Docker


HTTP 工作原理

HTTP(HyperText Transfer Protocol,超文本传输协议)是用于在网络上进行通信的应用层协议,主要用于 Web 浏览器和 Web 服务器之间的数据交换。其工作原理简要如下:

  1. 客户端发起请求:用户在浏览器中输入网址或点击链接时,浏览器作为 HTTP 客户端,向目标服务器发送 HTTP 请求。这个请求包含请求方法(如 GET、POST)、请求的 URL、协议版本、请求头信息和可选的请求体。
  2. 服务器接收请求并处理:服务器接收到客户端的请求后,解析请求信息,根据请求的资源路径和参数,执行相应的操作。这可能涉及读取文件、查询数据库、执行脚本等。
  3. 服务器返回响应:处理完成后,服务器生成 HTTP 响应,包含状态行(如 HTTP/1.1 200 OK)、响应头信息(如内容类型、内容长度)、以及响应体(实际内容,如 HTML 页面、JSON 数据等)。
  4. 客户端接收响应并处理:浏览器收到服务器的响应后,解析响应头和响应体。如果是网页内容,浏览器会渲染并显示给用户;如果响应包含需要进一步请求的资源(如图片、CSS、脚本),浏览器会继续发送请求获取这些资源。
  5. 连接关闭:默认情况下,HTTP/1.0 在完成一次请求 - 响应后会关闭连接。HTTP/1.1 及之后的版本支持持久连接(Keep-Alive),允许在同一条连接上进行多个请求 - 响应,减少连接开销。
  6. 无状态特性:HTTP 是无状态协议,每次请求都是独立的,服务器不会自动保留上一请求的状态信息。为了实现会话管理,需要借助 Cookie、Session 等机制。

总结:HTTP 工作原理基于请求 - 响应模型,由客户端发起请求,服务器处理并返回响应。通过这种方式,客户端可以获取 Web 服务器上的资源,实现浏览网页、提交数据等功能。

HTTPS 原理

HTTPS,也称作 HTTP over TLS。TLS 的前身是 SSL,TLS 1.0 通常被标示为 SSL 3.1,TLS 1.1 为 SSL 3.2,TLS 1.2 为 SSL 3.3。

随着谷歌浏览器对 https 证书的大力推行,几乎所有大型网站都部署了 https 证书,我们在开发时,也时常会用到 https,比如开发微信小程序,微信官方要求小程序内部发送异步请求必须是 https 协议。

https 好处多多,用 https 协议传输信息,信息的安全性会得到保障,用 http 传递信息几乎等于裸奔了,如图所示:

对称加密

https 在传输信息的时候是需要对信息进行加密的。https 用到的加密方式有两种,分别是对称加密和非对称加密,首先咱们看一下对称加密的图解:

对称加密有个特点,端点两端的密钥是一样的,不能被第三方知道。

但是大家仔细观察,对称加密有个缺点,那就是就是密钥如何交换。这句话的意思是指,客户端如何把密钥交给服务端,或者服务端如何把密钥交给客户端,但是不能被第三方知道,因为第三方也得到了这个密钥,那么信息就不安全了。

因为只有客户端和服务端都知道密钥才能实现加密解密,如果只有客户端或者只有服务端其中一方持有密钥,是不能完成加密解密整个过程的。

那么这个问题如何解决呢?先搁置一边,下面看一下非对称加密。

非对称加密

非对称加密需要两把不同的密钥,这点和对称加密不同,分别是一把私钥,一把公钥,并且这两把钥匙是配对的。公钥私钥有如下几个特性:

1、公钥加密必须使用与其匹配的私钥才能解密

2、私钥加密必须使用与其匹配的公钥才能解密

3、私钥必须严格保密,不能泄露,非对称加密建立在私钥严格保密的基础上。

4、公钥可以随意分发给任何人。

非对称加密相较于对称加密,主要的作用是弥补了对称加密密钥分发的问题。

我们用一张图来演示一下非对称加密:

从图中我们可以看到,非对称加密的公钥可以随意分发给任何人,私钥必须自己保存,不能交给别人,在信息进行交互的时候,我们只要用公钥加密私钥解密,或者私钥加密公钥解密即可。

上面的方案看上去很美,但是有两个非常大的漏洞无法解决:

1、公私钥加密解密是非常耗时的,而 web 的用户体验不允许我们直接使用公私钥加密

2、公钥的分发是个问题,假如服务器端将公钥作为响应发送给客户端,但是这个过程被一个中间人劫持了,然后中间人假装服务器,给客户端发送了一个假的公钥,客户端并不知道中间人的存在,使用假的公钥加密信息,中间人拿到后用和假公钥匹配的私钥解密,信息就泄露了,过程如图:

观察图中的中间人,中间人劫持了真的公钥,自己生成一对公私钥,用这对公私钥和客户端沟通交流,完全以假乱真。

我们可以将对称加密和非对称加密结合起来使用,用非对称加密方式来交换对称加密用的密钥,然后用对称加密的密钥来加密交互信息

CA 证书机构

这里还有一点大家需要注意,https 的加密必须借助第三方来实现,也就是 CA 证书,为什么需要这个东西呢?

因为我们将公钥分发出去的时候为了防止被中间人替换或者窃取,需要对公钥做特殊处理,这个特殊处理通常就是加密,但是加密后,加密的密钥如何给到客户端呢?这就形成了一个无限的死循环,所以需要引入第三方机构,CA 证书机构。

大家的操作系统和浏览器都内置了各大权威证书的公钥也就是CA 的公钥,简而言之就是我们的操作系统内置 CA 公钥,我们要做的就是去这些机构申请我们的公钥证书,这个证书是被和CA 的公钥匹配的CA 私钥加密过的。

当客户端和服务器端进行通信的时候,服务器端将公钥证书发送给客户端,客户端拿到证书,用系统和浏览器内置的权威 CA 公钥解密验证证书,得到服务器的公钥。

然后用服务器公钥加密对称密钥发送到服务器端,服务器用服务器自己的私钥解密得到对称密钥,这样就可以用对称密钥进行数据交换了。

流程图如下:

仔细观察上面这张图:

  1. 客户端(大部分客户端内置权威 CA 证书)发送请求
  2. 服务器将证书发(证书包含发布机构、有效期、所有者、公钥、指纹及指纹算法、签名算法,暂定该证书由权威机构发布)送给客户端,证书的本质是第三方 CA 的私钥加密的内容,其内容是服务器的公钥。
  3. 客户端接收到证书后,用操作系统和浏览器内置的 CA 公钥(本地受信任的发布机构)去匹配验证证书,如果能解密,说明网站安全
    1. 用 CA 公钥(公钥是内置在客户该端中的 CA 公钥)解密证书,并将服务器公钥解密出来。到这一步,客户端安全的拿到了服务器端的公钥。
    2. 对证书进行解密得到指纹和指纹算法
    3. 用指纹算法来解密指纹验证是否被篡改;
    4. 验证证书中包含的地址是否与正在访问的地址一致;
  4. 客户端生成随机数密钥,用服务器公钥加密随机数密钥(后续通信基于该随机数密钥)发送到服务器端。
  5. 服务器端用服务器私钥解密信息,得到随机数密钥,利用该随机数密钥对进行密文通信;

在这里我再给大家总结一下:

1、服务器端必须生成自己的私钥和公钥,我们称其为服务器公钥,服务器私钥。客户端不用生成公私钥。

2、https 除了服务器端的公私钥参与,还有一对公私钥,CA 公钥,CA 私钥

CA 公钥内置在客户端系统里面,CA 私钥呢?仔细阅读下面一条。

服务器端用服务器公钥去 CA 机构申请证书,CA 机构用 CA 私钥加密服务器公钥(先暂时这样理解)。这样的话,客户端系统内置的 CA 公钥就可以从证书中解密出服务器公钥了。并且 CA 机构的私钥只有 CA 机构知道。

3、客户端用解密出的服务器公钥加密随机生成的对称密钥发送给服务器端,这样客户端和服务器端就有相同的对称密钥了,并且第三方不可能知道。从而实现加密通信。

从以上我们可以看出,我们的操作系统是内置了各大权威 CA 的公钥的,如果安装了盗版的或者来路不明的操作系统,就算访问 https 网站,也有裸奔的风险。

使用 OPENSSL 生成证书

http2 服务是建立在 TSL/SSL 基础之上的,类似于 https,所以咱们先要搞清楚如何搭建一个 https 服务器,搭建 https 服务器的话就需要 https 证书,证书从哪里来呢?可以去阿里云买个域名,获得免费赠送的证书,也可以去 https 厂商那里申请收费证书,也可以用 openssl 这个工具自己生成自签名证书。

yum install -y openssl  # 安装工具

证书生成流程

先上一张图,这张图就是用 openssl 生成证书的整个流程了,如何看这个图呢?

这个图有 A、B、C 三个部分,分别用三种颜色框选了一下,A 部分是 CA 机构根证书的生成过程,这个过程需要先生成 CA 机构的私钥,再由 CA 机构的私钥生成 CA 机构证书申请文件,然后再由这两个文件生成根证书。

B 部分是生成服务器私钥,然后由服务器私钥生成服务器证书申请文件。

C 部分是最后一部分,也就是生成服务器的公钥证书,服务器的公钥证书需要三部分一起来生成,A 部分的 CA 机构的私钥,CA 机构的申请证书文件,B 部分的服务器证书申请文件,这三部分一起来生成服务器的公钥证书。

证书生成操作

根据图示,分为如下几个步骤:

openssl genrsa -out server.key 2048  # 生成服务器私钥。
openssl req -new -key server.key -out server.csr  # 根据服务器私钥文件生成证书请求文件,这个文件中会包含申请人的一些信息,所以执行下面这行命令过程中需要用户在命令行输入一些用户信息
openssl genrsa -out ca.key 2048  # 生成CA机构私钥,命令和生成服务器私钥一样,只不过这是CA的私钥
openssl req -new -key ca.key -out ca.csr  # 生成CA机构自己的证书申请文件
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt  # 生成自签名证书,CA机构用自己的私钥和证书申请文件生成自己签名的证书,俗称自签名证书,这里可以理解为根证书。
openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt  # 根据CA机构的自签名证书ca.crt或者叫根证书、CA机构的私钥ca.key、服务器的证书申请文件server.csr生成服务端证书。

上面的过程其实是模拟了各大 https 证书厂商生成 https 证书的过程,其中涉及到了根证书等等一些概念。如果只想要证书,不想搞得太深,那么请使用如下方法:

openssl genrsa -out server.key 1024  # 生成服务器私钥
openssl req -new -key server.key -out server.csr  # 根据私钥和输入的信息生成证书请求文件
openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650  # 第一步的私钥和第二步的请求文件生成证书

openssl 的参数说明如下:

genrsa 使用 RSA 算法产生密钥

2048 指定私钥长度

-in 要输入的文件路径

-out 输出文件的路径

-req 执行证书签发命令

-new 新证书签发请求

-key 指定私钥路径

x509 生成 x509 格式的证书

-days 证书的有效期 (天)

-signkey 签发证书的私钥

-CA 指定 CA 证书的路径

-CAkey 指定 CA 证书的私钥路径

这样我们就拿到了私钥 server.key 和证书 server.crt。

为什么第二种方式比第一种简单并且步骤还少呢?这里简单介绍一下,第一种方式是模拟 https 厂商生成 https 证书的简易过程,https 证书厂商一般都会有一个根证书,这里我们模拟生成了 https 厂商根证书,也就是第一种方法的 3、4、5 步骤。

实际应用

在实际应用中,这些步骤对用户来说是不可见的,这里只是简单模拟,通常证书申请用户只需要将服务器的公钥(注意不是私钥) 和服务器证书申请文件交给 https 证书厂商即可,之后 https 厂商会通过邮件回复一个服务器公钥证书,拿到这个证书和自己生成的服务器私钥就可以搭建 https 应用了。

第二种方法比较简单,是因为我们自己生成证书在本地测试,我们既是 https 厂商的角色也是用户角色,我们直接用自签名证书当做服务器证书就可以了,简单快捷,不过这里只适用于测试。此时我们已经得到自签名证书、密钥。只要将 NGINX 服务的 SSL 配置为相关路径,并将该证书添加为受信任的证书,通过 URL 访问就可实现加密通讯。

MONGODB 自签证书生成、应用和连接

服务器目录结构如下(test 目录保存该 Mongo 实例所有的信息,包括配置、数据):

/usr/local/wlhiot/mount/mongo/test
├── conf
│   ├── cert
│   │   ├── ca.pem
│   │   ├── ca.srl
│   │   ├── client.crt
│   │   ├── client.csr
│   │   ├── client.key
│   │   ├── client.pem
│   │   ├── privkey.pem
│   │   ├── server.crt
│   │   ├── server.csr
│   │   ├── server.key
│   │   └── server.pem
│   └── mongod.conf
└── data

证书配置

MongoDB 的 SSL 配置需要以 pem 格式的文件来指定

cd /usr/local/wlhiot/mount/mongo/test/conf/cert
openssl req -out ca.pem -new -x509 -days 3650  # 单条命令创建ca证书,同时会创建privkey.pem的私钥,pem格式与crt格式均为ca证书的格式。对该命令存疑可参考openssl的参数说明
# mongodb服务端配置
openssl genrsa -out server.key 2048  # 生成服务器端私钥
openssl req -new -key server.key -out server.csr  # 生成服务器端申请文件
openssl x509 -req -in server.csr -CA ca.pem -CAkey privkey.pem -CAcreateserial -out server.crt -days 3650  # 根据申请文件,ca证书,ca私钥共同生成服务器端证书
cat server.key server.crt > server.pem合并服务器端私钥和服务器端证书,生成server.pem
openssl verify -CAfile ca.pem server.pem  # 校验服务器端pem文件
server.pem: OK
# 客户端配置(通过客户端证书来访问mongodb)
openssl genrsa -out client.key 2048  # 生成客户端私钥
openssl req -new -key client.key -out client.csr  # 生成客户端申请文件
openssl x509 -req -in client.csr -CA ca.pem -CAkey privkey.pem -CAserial ca.srl  -out client.crt -days 3650  # 根据申请文件,ca证书,ca私钥共同生成客户端证书
cat client.key client.crt > server.pem合并客户端私钥和客户端证书,生成server.pem
openssl verify -CAfile ca.pem client.pem  # 校验客户端pem文件
client.pem: OK

Mongo 配置

vim /usr/local/wlhiot/mount/mongo/test/conf/mongod.conf
security:
  clusterAuthMode: x509
  authorization: "enabled"
net:
  port: 27017
  bindIp: 0.0.0.0
  ssl:
    mode: requireSSL
    PEMKeyFile: /data/conf/cert/server.pem
    CAFile: /data/conf/cert/ca.pem
    allowInvalidHostnames: true
    allowInvalidCertificates: true

通过指定配置文件启动 mongo 实例,由于 mongo 的特性会使用所有内存,所以限制容器的内存使用,并将配置文件及证书挂载至容器。

docker run -d -p 37017:27017  --name mongo --memory="5g" --memory-swap="-1" -v /etc/localtime:/etc/localtime:ro -v /usr/local/wlhiot/mount/mongo/test/data:/data/db -v /usr/local/wlhiot/mount/mongo/test/conf:/data/conf harbor.wlhiot.com:8080/library/mongo:4.2.16 --config /data/conf/mongod.conf

客户端连接

通过命令行连接,连接后创建 admin 库用户

mongo --tls --tlsCertificateKeyFile /data/conf/cert/server.pem --tlsCAFile /data/conf/cert/ca.pem --authenticationMechanism MONGODB-X509 --host=127.0.0.1 --port=27017

通过 robot3T 连接 admin 管理员

acme.sh 自动续期证书

官方推荐方式

acme.sh 实现了 acme 协议, 可以从 let‘s encrypt 生成免费的证书.官方说明见 https://github.com/acmesh-official/acme.sh

主要步骤:

  1. 安装 acme.sh
  2. 生成证书
  3. copy 证书到 nginx/apache 或者其他服务
  4. 更新证书
  5. 更新 acme.sh

下面详细介绍.

安装 acme.sh

安装很简单, 以下两种命令二选一即可:

curl https://get.acme.sh | sh -s email=my@example.com
git clone https://github.com/acmesh-official/acme.sh.git && cd acme.sh/ &&./acme.sh --install

普通用户和 root 用户都可以安装使用. 安装过程进行了以下几步:

  1. 把 acme.sh 安装到你的 home 目录下,并创建 一个 shell 的 alias, 例如 .bashrc,方便你的使用:
echo 'alias acme.sh=~/.acme.sh/acme.sh' >>/etc/profile
source /etc/profile
  1. 自动为你创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书.

更高级的安装选项请参考: https://github.com/Neilpang/acme.sh/wiki/How-to-install

安装过程不会污染已有的系统任何功能和文件, 所有的修改都限制在安装目录中: ~/.acme.sh/

生成证书

acme.sh 实现了 acme 协议支持的所有验证协议. 一般有两种方式验证: http 和 dns 验证.

Http 方式需要在你的网站根目录下放置一个文件, 来验证你的域名所有权,完成验证. 然后就可以生成证书了

acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/

只需要指定域名, 并指定域名所在的网站根目录. acme.sh 会全自动的生成验证文件, 并放到网站的根目录, 然后自动完成验证. 最后会聪明的删除验证文件. 整个过程没有任何副作用.

如果你用的 apache服务器, acme.sh 还可以智能的从 apache的配置中自动完成验证, 你不需要指定网站根目录:

acme.sh --issue -d mydomain.com --apache

如果你用的 nginx服务器, 或者反代, acme.sh 还可以智能的从 nginx的配置中自动完成验证, 你不需要指定网站根目录:

acme.sh --issue -d mydomain.com --nginx

注意, 无论是 apache 还是 nginx 模式, acme.sh 在完成验证之后, 会恢复到之前的状态, 都不会私自更改你本身的配置. 好处是你不用担心配置被搞坏, 也有一个缺点, 你需要自己配置 ssl 的配置, 否则只能成功生成证书, 你的网站还是无法访问 https. 但是为了安全, 你还是自己手动改配置吧.

如果你还没有运行任何 web 服务, 80 端口是空闲的, 那么 acme.sh 还能假装自己是一个 webserver, 临时听在80 端口, 完成验证:

acme.sh --issue -d mydomain.com --standalone

更高级的用法请参考: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert

手动 Dns 方式, 手动在域名上添加一条 Txt 解析记录, 验证域名所有权

这种方式的好处是, 你不需要任何服务器, 不需要任何公网 ip, 只需要 dns 的解析记录即可完成验证. 坏处是,如果不同时配置 Automatic DNS API,使用这种方式 acme.sh 将无法自动更新证书,每次都需要手动再次重新解析验证域名所有权。

acme.sh --issue --dns -d mydomain.com \
 --yes-I-know-dns-manual-mode-enough-go-ahead-please

然后, acme.sh 会生成相应的解析记录显示出来, 你只需要在你的域名管理面板中添加这条 txt 记录即可.

等待解析完成之后, 重新生成证书:

acme.sh --renew -d mydomain.com \
  --yes-I-know-dns-manual-mode-enough-go-ahead-please

注意第二次这里用的是 --renew

dns 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证.

acme.sh 目前支持 cloudflare, dnspod, cloudxns, godaddy 以及 ovh 等数十种解析商的自动集成.

以 dnspod 为例, 你需要先登录到 dnspod 账号, 生成你的 api idapi key, 都是免费的. 然后:

export DP_Id="1234"

export DP_Key="sADDsdasdgdsf"

acme.sh --issue --dns dns_dp -d aa.com -d www.aa.com

证书就会自动生成了. 这里给出的 api idapi key 会被自动记录下来, 将来你在使用 dnspod api 的时候, 就不需要再次指定了. 直接生成就好了:

acme.sh --issue -d mydomain2.com --dns  dns_dp

更详细的 api 用法: https://github.com/Neilpang/acme.sh/blob/master/dnsapi/README.md

copy/安装 证书

前面证书生成以后, 接下来需要把证书 copy 到真正需要用它的地方.

注意, 默认生成的证书都放在安装目录下: ~/.acme.sh/, 请不要直接使用此目录下的文件, 例如: 不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

正确的使用方法是使用 --install-cert 命令,并指定目标位置, 然后证书文件会被 copy 到相应的位置,所以需要提前修改 web 服务器的配置,将证书以及私钥路径指向部署路径。

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name nginx.wlhiot.com;

    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/nginx.wlhiot.com.key;

    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 4;
    gzip_types text/plain application/javascript application/x-javascript text/css application/x
ml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";
    underscores_in_headers on;

    location / {
        root /var/www/html;
        try_files $uri $uri/ /index.html;
    }
}

Apache Example

acme.sh --install-cert -d example.com \
--cert-file      /path/to/certfile/in/apache/cert.pem  \
--key-file       /path/to/keyfile/in/apache/key.pem  \
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd     "service apache2 force-reload"

Nginx Example

acme.sh --install-cert -d example.com \
--key-file       /etc/nginx/ssl/mydomain.com.key  \
--fullchain-file /etc/nginx/ssl/fullchain.cer \
--reloadcmd     "service nginx force-reload"

生成的证书文件推荐使用 fullchain.cer,私钥文件推荐为 [域名].key,例如 xxx.wlhiot.com.key。Nginx 的配置 ssl_certificate 使用 /etc/nginx/ssl/fullchain.cer ,而非 /etc/nginx/ssl/<domain>.cer ,否则 SSL Labs 的测试会报 Chain issues Incomplete 错误。

(一个小提醒, 这里用的是 service nginx force-reload, 不是 service nginx reload, 据测试, reload 并不会重新加载证书, 所以用的 force-reload)

--install-cert 命令可以携带很多参数, 来指定目标文件. 并且可以指定 reloadcmd, 当证书更新以后, reloadcmd 会被自动调用,让服务器生效.

详细参数请参考: https://github.com/Neilpang/acme.sh#3-install-the-issued-cert-to-apachenginx-etc

值得注意的是, 这里指定的所有参数都会被自动记录下来, 并在将来证书自动更新以后, 被再次自动调用.

查看已安装证书信息

acme.sh --info -d example.com
# 会输出如下内容:
DOMAIN_CONF=/root/.acme.sh/example.com/example.com.conf
Le_Domain=example.com
Le_Alt=no
Le_Webroot=dns_ali
Le_PreHook=
Le_PostHook=
Le_RenewHook=
Le_API=https://acme-v02.api.letsencrypt.org/directory
Le_Keylength=
Le_OrderFinalize=https://acme-v02.api.letsencrypt.org/acme/finalize/23xxxx150/781xxxx4310
Le_LinkOrder=https://acme-v02.api.letsencrypt.org/acme/order/233xxx150/781xxxx4310
Le_LinkCert=https://acme-v02.api.letsencrypt.org/acme/cert/04cbd28xxxxxx349ecaea8d07
Le_CertCreateTime=1649358725
Le_CertCreateTimeStr=Thu Apr  7 19:12:05 UTC 2022
Le_NextRenewTimeStr=Mon Jun  6 19:12:05 UTC 2022
Le_NextRenewTime=1654456325
Le_RealCertPath=
Le_RealCACertPath=
Le_RealKeyPath=/etc/nginx/ssl/mydomain.com.key
Le_ReloadCmd=service nginx force-reload
Le_RealFullChainPath=/etc/nginx/ssl/fullchain.cer

更新证书

目前证书在 60 天以后会自动更新, 你无需任何操作. 今后有可能会缩短这个时间, 不过都是自动的, 你不用关心.

请确保 cronjob 正确安装, 看起来是类似这样的:

crontab  -l
56 * * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

关于修改 ReloadCmd

目前修改 ReloadCmd 没有专门的命令,可以通过重新安装证书来实现修改 reloadCmd 的目的。 此外,安装证书后,相关信息是保存在 ~/.acme.sh/example.com/example.conf 文件下的,内容就是 acme.sh --info -d example.com 输出的信息,不过 ReloadCmd 在文件中使用了 Base64 编码。理论上可以通过直接修改该文件来修改 ReloadCmd,且修改时,无需 Base64 编码,直接写命令原文 acme.sh 也可以识别。 不过,example.conf 文件的位置和内容格式以后可能会改变!example.conf 一直都是内部使用, 后面有可能会改为用 sqlite 或者 mysql 格式存储. 所以一般不建议自己修改。

更新 acme.sh

目前由于 acme 协议和 letsencrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步.

升级 acme.sh 到最新版 :

acme.sh --upgrade

如果你不想手动升级, 可以开启自动升级:

acme.sh --upgrade --auto-upgrade

之后, acme.sh 就会自动保持更新了.

你也可以随时关闭自动更新:

acme.sh --upgrade --auto-upgrade  0

容器方式

acme.sh 实现了 acme 协议, 可以从 let‘s encrypt 生成免费的证书.官方说明见 https://github.com/acmesh-official/acme.sh 但是大部分说明都是基于本地,对于 Docker 强迫症很不友好,所以记录下自动续期证书的过程,以便后续翻阅,但读者如果使用我列出来的方法有几个重点需要注意一下:

  1. 使用的是阿里云的 DNS 解析;
  2. 外部访问的 NGINX 容器正常访问;

申请阿里云 accesskey

因为我购买的是阿里云的服务器,所以顺便使用阿里云的 DNS 解析。需要申请一个 accessKey 和 accessSecret。如果是采用的其他 DNS 验证的话,则根据 https://github.com/acmesh-official/acme.sh/wiki/dnsapi 列出的 API 进行调用。

docker 运行 acme.sh

docker run -itd  \
  -v "$(pwd)/out":/acme.sh  \  # 生成的证书会在当前目录的out目录下
  -e Ali_Key=[accessKey] \
  -e Ali_Secret=[accessSecret] \
  --net=host \
  --name=acme.sh \
  neilpang/acme.sh daemon

申请证书

docker exec -it acme.sh /bin/sh
acme.sh --register-account -m [邮箱地址]
acme.sh --issue --dns dns_ali -d *.xxx.com  # 调用阿里云dns api接口申请泛域名证书,nginx只需要*.cer和*.key即可完成证书配置
root@dhr2333 daihaorui]# ll /root/out/dhr2333.cn/
total 36
-rw-r--r-- 1 root root 4399 2022-12-08 15:40 ca.cer
-rw-r--r-- 1 root root 2293 2022-12-08 15:40 dhr2333.cn.cer
-rw-r--r-- 1 root root  563 2022-12-08 15:40 dhr2333.cn.conf
-rw-r--r-- 1 root root 1009 2022-12-08 15:34 dhr2333.cn.csr
-rw-r--r-- 1 root root  200 2022-12-08 15:34 dhr2333.cn.csr.conf
-rw------- 1 root root 1675 2022-12-08 15:34 dhr2333.cn.key
-rw-r--r-- 1 root root 6692 2022-12-08 15:40 fullchain.cer

修改 nginx 以完成配置

[root@dhr2333 daihaorui]# cat conf/nginx/djangoblog.conf 
server {
    # listen 0.0.0.0:80; 不开放80端口,由主配置文件匹配响应域名直接转为https
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name www.dhr2333.cn;

    ssl_certificate /etc/nginx/ssl/dhr2333.cn.cer;
    ssl_certificate_key /etc/nginx/ssl/dhr2333.cn.key;

    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 4;
    gzip_types text/plain application/javascript application/x-javascript text/css application/x
ml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";
    underscores_in_headers on;

    location / {
        proxy_pass http://djangoblog:8000/;
        proxy_set_header Host $proxy_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

查看证书状态

查看证书是否生效,阿里云解析记录删除通知