通过certbot工具生成ssl证书

一、简要概述

certbot 是一个用于部署 Let’s Encrypt SSL 证书的免费、开源、自动化工具。它可以帮助网站管理员轻松地实现 HTTPS 和浏览器绿锁等功能,提高网站的安全性和可靠性。

Let’s Encrypt 是一个由非营利组织 Internet Security Research Group(ISRG)推出的一个免费、自动化、开放和安全的 SSL/TLS 证书颁发机构。

Let’s Encrypt SSL 证书使用了 SHA-256 签名算法,并支持最新版本的 TLS 协议,因此可以提供强大的加密和认证保护,保障网站和用户数据的安全。同时,Let’s Encrypt 证书的根证书已被所有主流浏览器信任,这意味着用户不需要手动添加任何信任条目或 CA 证书到浏览器中。

二、安装 certbot

1
2
3
4
5
6
#apt包管理器安装certbot
apt-get install certbot

#yum包管理器安装certbot
yum -y install epel-release
yum -y install certbot

三、申请签发证书

1. 简要概述

在 certbot 申请证书时,证书是由 Let’s Encrypt 官方 ACME 服务器生成的,而不是由本地服务器生成的。certbot 将向 Let’s Encrypt CA(证书颁发机构)发出签发请求,并将验证域名的控制权。一旦验证通过,Let’s Encrypt 将向 Certbot 返回 SSL 证书,以便在您的 Web 服务器上部署和使用。

2. certbot 常用的选项和参数

  • --webroot:使用 Web 根目录验证插件(默认模式)。在 .well-known/acme-challenge/ 路径下创建一个临时文件,并通过 HTTP 获取该文件来验证域名所有权。

  • --manual:手动模式,该模式需要您手动执行一些步骤,例如在 DNS 记录中添加 TXT 记录以验证域名所有权。

  • --nginx:使用 Nginx Web 服务器插件。该模式允许 Certbot 自动配置 Nginx Web 服务器,以便验证域名所有权并部署证书。

  • --apache:使用 Apache Web 服务器插件。该模式允许 Certbot 自动配置 Apache Web 服务器,以便验证域名所有权并部署证书。

  • --standalone:使用独立 Web 服务器插件。该模式允许 Certbot 在自己的 Web 服务器(standalone)上运行,以验证域名所有权和颁发证书

  • --server: ACME 服务器地址。默认为 Let’s Encrypt 官方 ACME 服务器地址,即:https://acme-v02.api.letsencrypt.org/directory

  • --domains DOMAIN(简写:-d DOMAIN):要签发证书的域名。如:-d example.com

  • --staging:签发测试环境证书。

  • --cert-name CERTNAME:为证书命名。

  • --expand:更新现有证书以包括新的子域名。

  • --duplicate:复制现有证书。

  • --reinstall:重新安装现有证书。

  • --force-renewal:在有效期内强制更新证书。

  • --email EMAIL(简写:-m EMAIL):账号邮箱地址。可用于自动注册ACME账号,还可用于证书到期前 20 天、10 天和 1 天时接收到到期通知邮件。如:--email user@example.com

  • --agree-tos:同意 Let’s Encrypt 的服务条款,并接受由 Let’s Encrypt 颁发的 SSL/TLS 证书。如果您不同意服务条款,则无法使用 Let’s Encrypt 颁发的证书。

  • --preferred-challenges PREF_CHALLENGES:首选的域名所有权验证类型。如:--preferred-challenges dns-01

    支持的验证类型如下:

    (1)http-01:默认验证方法,将向公开在 HTTP 上运行的 Web 服务器发送请求,在 .well-known/acme-challenge/ 路径下创建一个临时文件,并通过 HTTP 获取该文件来验证您拥有该域名。

    (2)dns-01:使用 DNS 记录验证域名所有权。此方法需要您手动更新相应的 DNS 记录。在 DNS 记录更新后,Let’s Encrypt 将使用 DNS 查找该记录以验证您拥有该域名。

    (3)tls-sni-01:已弃用,不再使用。原本是在 HTTPS 连接的 SNI 扩展中发送验证信息,但由于安全问题而被弃用。

    (4)tls-alpn-01:一种基于 TLS 的验证方法,它使用新的 ALPN 协议扩展来发送验证信息。与 tls-sni-01 不同,它不会公开任何信息,因此更加安全。

  • --non-interactive:禁用交互式模式。(默认certonly 命令是交互式的)

  • --no-eff-email:禁止发生统计信息邮件给EFF。(默认情况下,Certbot 在生成 SSL/TLS 证书时会向 EFF 发送电子邮件,以便收集有关证书使用情况的统计信息)

  • --dry-run:测试证书颁发流程,但不实际签发证书。

  • -h:获取帮助信息。

  • --version:查看 Certbot 版本号。

  • --config-dir CONFIG_DIR:指定配置文件目录。

  • --work-dir WORK_DIR:指定工作目录。

  • --logs-dir LOGS_DIR:指定日志目录。

💁‍♂ 说明:如果不指定选项和参数,则一些必要的选项参数将会在交互式命令中要求指定。

3. Let’s Encrypt 证书申请请求限制

  • 生产环境限制

    • 每个域名/证书每周最多只能签发 5 次

    • 每个 IP 地址每小时最多能提交 300 个证书申请请求

  • 测试环境限制(certbot 使用 --staging 选项时)

    • 测试环境下颁发的证书无法被浏览器或操作系统信任
    • 测试环境下每个域名/证书每周最多可签发 50 次
    • 测试环境下每个 IP 地址每小时最多能提交 300 个请求
    • 测试环境下没有通过 HSTS 预载的域名(生产环境支持通过 HSTS 预载的域名)

4. 申请证书方式

Let’s Encrypt CA(ACME 服务器)判断是否允许用户申请域名对应的证书,需要验证用户是否为域名的拥有者,只有确定用户为域名拥有者才能签发证书。

方式1:HTTP 验证模式申请证书

简要概述:

(1)certbot(ACME 客户端)会在 Web 服务器的根目录下自动创建一个特定的临时文件(即:.well-known/acme-challenge/<random_token> ),然后 Let’s Encrypt CA(ACME 服务器)通过 HTTP 协议请求访问此文件(访问地址:http://example.com/.well-known/acme-challenge/<random_token>),访问到该文件则说明用户对域名具有控制权,通过用户的控制权情况间接确定用户是否是域名的拥有者。

(2)如果验证确定用户是域名的拥有者,则允许为其签发生成SSL证书,否则申请失败。

(3)验证完成并签发生成证书后,certbot 会自动删除 Web 服务器根目录下的.well-known临时目录文件。

1)单域名证书

准备工作:

(1)需要有一个需要申请证书的域名。如:test.qcmoke.site

(2)需要有一台公网服务器,并且公网服务器里运行有 Web 服务(如:nginx,tomcat等)。设公网服务器 IP 为:45.129.11.99

(3)需要提前在 DNS 托管服务提供商的管理后台里把所有需要申请证书的域名都解析到公网服务器的IP上。如:test.qcmoke.site -> 45.129.11.99

1
2
3
4
5
6
7
8
9
10
11
12
13
#HTTP 验证模式申请签发单域名证书(模板)
sudo certbot certonly \
--agree-tos --no-eff-email \
--webroot -w /opt/nginx/html \
-m user@example.com \
-d example.com

#示例:(可加 --staging 选项来申请签发测试环境的证书)
sudo certbot certonly \
--agree-tos --no-eff-email \
--webroot -w /opt/nginx/html \
-m qcmoke@gmail.com \
-d test.qcmoke.site

💁‍♂ 说明:

  • --webroot:指定 certbot 创建临时文件所在的 Web 服务器根目录路径。

除了通过指定--webroot选项使用 HTTP 验证模式外,还可以使用 --preferred-challenges http-01 (或都使用,因为 http-01 是默认值),但这种方式需要手动创建.well-known/acme-challenge/<random_token> 临时文件,并根据提示给文件写入内容,明显会比较麻烦,故不推荐。

2)多域名证书(推荐)

准备工作:

(1)需要有多个需要申请证书的域名。如下:

  • qcmoke.site
  • www.qcmoke.site

(2)需要有一台公网服务器,并且公网服务器里运行有 Web 服务(如:nginx,tomcat等)。设公网服务器 IP 为:45.129.11.99

(3)需要提前在 DNS 托管服务提供商的管理后台里把所有需要申请证书的域名都解析到公网服务器的IP上。如下:

  • qcmoke.site -> 45.129.11.99
  • www.qcmoke.site -> 45.129.11.99

多域名证书可以通过类似 -d example.com -d www.example.com 的指定方式申请签发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#HTTP 验证模式申请签发多域名证书(模板)
sudo certbot certonly \
--agree-tos --no-eff-email \
--webroot -w /opt/nginx/html \
-m user@example.com \
-d example.com \
-d www.example.com

#示例:(可加 --staging 选项来申请签发测试环境的证书)
sudo certbot certonly \
--agree-tos --no-eff-email \
--webroot -w /opt/nginx/html \
-m qcmoke@gmail.com \
-d qcmoke.site \
-d www.qcmoke.site

说明:

  • 多域名证书如果不指定名称,将会以第一个域名作为证书名称。
  • Let’s Encrypt CA(ACME 服务器)会根据指定的多个域名依次发起 HTTP 请求访问 Web 服务器根目录下的临时文件以确定申请用户对每个域名的所有权。

注意:多域名证书是一个 SSL 证书,该证书可以包含多个域名的信息,故一个证书可以同时用于多个域名的 SSL 验证。

3)通配符域名证书(不支持)

使用 HTTP 验证模式不支持通配符域名证书申请,Let’s Encrypt 只允许使用 DNS-01 验证模式来获取通配符域名证书。

💁‍♂ 关于“使用 HTTP 验证模式不支持申请通配符域名证书”的说明:

申请通配符域名(如:*.example.com)证书时,Let’s Encrypt CA(ACME 服务器)需要验证用户是否为通配符域名的父级域名(如:example.com)的拥有者,只有确定用户为域名拥有者才能签发证书。

使用 HTTP-01 验证模式验证用户是否为域名的拥有者时,ACME 客户端会在 Web 服务器上放置一个特定的临时文件,ACME 服务器通过 HTTP 协议请求访问此文件是否存在来证明用户对该域名的控制权,再通过域名控制权验证结果来间接确定用户是否是域名的拥有者,由于其验证是间接的,不能直接确定用户就是域名的拥有者,所以使用 HTTP 验证模式不支持申请通配符域名证书。

而使用 DNS 验证模式验证用户是否是域名的拥有者是可以直接确定的,因为拥有 DNS 域名解析权限的用户那肯定可以理解为域名的拥有者。所以使用 DNS 验证模式支持申请通配符域名证书。

如下测试在HTTP 验证模式下申请通配符域名证书会提示不支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ sudo certbot certonly \
--staging \
--agree-tos --no-eff-email \
--webroot -w /opt/nginx/html \
-m qcmoke@gmail.com \
-d qcmoke.site \
-d *.qcmoke.site

#如下是申请失败提示内容:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Requesting a certificate for qcmoke.site and *.qcmoke.site
Performing the following challenges:
Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.
Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.

方式2:DNS 验证模式申请证书

简要概述:

(1)certbot(ACME 客户端)会生成一串随机字符串,并要求用户将这个字符串作为域名的 TXT 记录值设置到DNS域名托管平台的对应域名解析设置里。等用户设置完成后,certbot 将会请求域名地址,通过判断是否能获取有效且与生成字符串相等的记录值来确定用户是否是域名的拥有者。这个过程中添加 TXT 记录情况如下:

  • 记录类型:TXT
  • 主机记录:_acme-challenge.example.com
  • 记录值: certbot 工具生成的随机字符串(如:x5XGviJAe9Lxk4JmJtn7VnQEB5wAIO1yv_W3lG9kP5s

(2)如果验证确定用户是域名的拥有者,则允许为其签发生成SSL证书,否则申请失败。

1)单域名证书

准备工作:

(1)需要有一台能访问互联网的主机(可为内网主机)。

(2)需要有一个需要申请证书的域名。如:test.qcmoke.site

(3)需要在 DNS 托管服务提供商的管理后台里添加域名的 TXT 记录。如下:

  • _acme-challenge.test.qcmoke.site - > vrZwcxxxxxx5k42XUr025UWRNl4

提示:TXT 记录值由下方执行certbot命令获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
#DNS 验证模式申请签发单域名证书(模板)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m user@example.com \
-d example.com

#示例:(可加 --staging 选项来申请签发测试环境的证书)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m qcmoke@gmail.com \
-d test.qcmoke.site

2)多域名证书

准备工作:

(1)需要有一台能访问互联网的主机(可为内网主机)。

(2)需要准备多个需要申请证书的域名。如下:

  • qcmoke.site
  • www.qcmoke.site

(3)需要在 DNS 托管服务提供商的管理后台里为每个域名添加 TXT 记录。如下:

  • _acme-challenge.qcmoke.site - > vrZwcxxxxxx5k42XUr025UWRNl4

  • _acme-challenge.www.qcmoke.site - > fr5wcxxxxxx7ko2PUr025UWRGo5

提示:TXT 记录值由下方执行certbot命令获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#DNS 验证模式申请签发多域名证书(模板)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m user@example.com \
-d example.com \
-d www.example.com

#示例:(可加 --staging 选项来申请签发测试环境的证书)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m qcmoke@gmail.com \
-d qcmoke.site \
-d www.qcmoke.site
  • 多域名证书可以通过类似 -d example.com -d www.example.com 的指定方式申请签发。
  • 多域名证书申请过程中,需要给每个域名添加 TXT 记录,Let’s Encrypt CA(ACME 服务器)会依次校验每个域名的 TXT 记录以确定每个域名的所有权。

3)通配符域名证书

准备工作:

(1)需要有一台能访问互联网的主机(可为内网主机)。

(2)需要有一个需要申请证书的域名。如:qcmoke.site

(3)需要在 DNS 托管服务提供商的管理后台里添加域名的 TXT 记录。如下:

  • _acme-challenge.qcmoke.site - > vrZwcxxxxxx5k42XUr025UWRNl4

提示:TXT 记录值由下方执行certbot命令获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#DNS 验证模式申请签发通配符证书(模板)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m user@example.com \
-d example.com \
-d *.example.com

#示例:(可加 --staging 选项来申请签发测试环境的证书)
sudo certbot certonly \
--manual --preferred-challenges dns-01 \
--agree-tos --no-eff-email \
-m qcmoke@gmail.com \
-d qcmoke.site \
-d *.qcmoke.site
  • DNS-01 验证模式是支持通配符域名证书申请的。
  • 通配符域名证书可以通过类似-d *.example.com的指定方式来申请签发。
  • 通配符域名证书申请过程中,对于通配符域名,只需要给除去通配符后剩下的域名添加一条 TXT 记录即可完成验证。这种验证方式不需要为通配符中的每个子域名添加记录,这也是 DNS-01 验证模式比 HTTP-01 更加灵活和安全的重要原因。
  • 通常做三级通配符域名证书时,为了支持其父级域名,申请证书时都会加上其父级域名(即二级域名),如:-d example.com
  • *.example.com表示的通配符域名证书表示只支持三级域名证书(如:www.example.comblog.example.commail.example.com 等),但这个通配符不支持其父级域名(如:example.com),也不支持四级域名(如:dev.www.example.com

四、列出拥有的证书信息

1
2
3
4
5
#列出拥有的证书及其有效期等信息
certbot certificates

#查看证书有效期
openssl x509 -noout -dates -in cert.pem

五、配置使用证书

certbot申请签发的证书默认存储在 /etc/letsencrypt/live/example.com/etc/letsencrypt/archive/example.com 目录下。

  • /etc/letsencrypt/live/example.com 目录:包含当前使用的 SSL/TLS 证书的符号链接,指向 /etc/letsencrypt/archive 目录中相应的证书文件。
  • /etc/letsencrypt/archive/example.com 目录:包含按域名和时间戳命名的 SSL/TLS 证书文件。

使用 certbot 申请签发证书时,会得到以下几个文件:

  • 服务端证书 (cert.pem):该文件主要包含有域名和公钥,由证书颁发机构(CA)签发,用于客户端验证服务器上域名的身份。
  • 中间证书 (chain.pem):该文件包含 CA 的证书链,其中可能包含一个或多个中间证书和根证书。中间证书由 CA 签发,用于将 CA 根证书和服务端证书连接起来,以能够使客户端验证服务端证书的真实性。
  • 全链证书 (fullchain.pem):也称证书链文件,该文件包含了服务端证书以及所有中间证书和根证书,包含了完整的 SSL 证书链。用于客户端验证服务端证书的真实性。
  • 私钥文件 (privkey.pem):该文件包含私钥内容。用于解密请求的数据以及加密响应的数据。

证书的定义:证书是一种用于验证身份和加密通信的电子文件。通常包含了身份信息、公钥、有效期限、颁发机构信息等内容。(注意:一般证书都是不包含私钥内容的)

常见的 Web 服务器软件有 nginx、apache、tomcat等。在这些 Web 服务器软件中配置 SSL 证书的方式不经相同,但它们都是支持使用 Let’s Encrypt SSL 证书的。

六、吊销证书

吊销证书是一种在证书到期之前废止其有效性的方法。如果您认为您的 SSL/TLS 证书已经被盗用或不再需要使用,则应该立即将其吊销。通过吊销证书,您可以确保不会有人再使用该证书来进行恶意活动。

1
2
3
4
5
6
7
8
9
#吊销指定域名的证书
sudo certbot revoke --cert-name example.com
#吊销指定文件路径的证书
sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem
#此命令将吊销存储在 /etc/letsencrypt/live/example.com/cert.pem 中的 SSL/TLS 证书

#吊销所有的证书
sudo certbot revoke --cert-path /etc/letsencrypt/archive/ -d example.com
#此命令将吊销 /etc/letsencrypt/archive/ 目录中与 example.com 域名相关的所有证书

七、删除证书

1
2
3
4
5
6
#删除指定域名的证书
sudo certbot delete --cert-name example.com

#删除指定域名的证书(certbot delete操作同下)
sudo rm -rf /etc/letsencrypt/live/example.com
sudo rm -rf /etc/letsencrypt/archive/example.com

💁‍♂ 如果仅仅删除证书,但原本证书没有注销或过期,那么再次申请签发生成新的证书时,默认生成的新证书与旧证书的一些基本信息(如私钥、公钥和有效期等)会保持相同,仅到期日期和其他元数据(例如序列号、版本号和指纹)不同。

八、证书续期申请

1. 简要概述

Let’s Encrypt 证书的有效期是90天,证书到期前 20 天、10 天和 1 天时将会接收到到期通知邮件,提醒用户进行证书续期申请操作。用户可以通过certbot renew命令来给即将过期的证书续期,续期会生成新的证书并自动替换掉原来的证书。

💁‍♂ 说明:

  • 如果证书已经过期或者被吊销,则 certbot 将无法对其进行续期,对于这种情况只能重新申请签发新的证书。
  • 证书到期前 30 天内才可以续订,多于30天则不允许续订。
  • 通过certbot renew命令来续订,默认生成的新证书与旧证书的一些基本信息(如私钥、公钥和有效期等)会保持相同,仅到期日期和其他元数据(例如序列号、版本号和指纹)不同。
  • 如果希望通过旧的证书信息强制重新申请签发新的证书并替换则需要加选项 --force-renewal
  • 如果续期的是测试环境的证书则需要加选项:--break-my-certs

2. HTTP 验证模式续期申请

(1)手动续期

1
2
3
4
#证书续期
sudo certbot renew
#查看更详细的日志信息,可以使用 -v(--verbose)选项,如下:
sudo certbot renew -v

💁‍♂ 注意:HTTP 验证模式下只支持单域名证书和多域名证书的续期,不支持通配符域名证书。

(2)自动续期

可以通过Linux的定时任务来完成自动续期的需求,操作如下:

1
2
3
4
5
6
7
#设置系统的定时任务
sudo crontab -e
#在最后添加如下定时规则:
0 3 1 * * certbot renew --renew-hook "sudo /opt/nginx/sbin/nginx -s reload"

#列出系统的定时任务
sudo crontab -l
  • 0 3 1 * *:表示每天凌晨1点3分0秒。
  • 定时任务规则中 certbot renew--renew-hook 选项用于指定证书续期更新完成后自动触发执行某自定义脚本或命令,这里填写的是命令是重新加载 nginx 配置以使得新的 SSL 证书生效。

3. DNS 验证模式续期申请

(1)简要概述

通过手动 DNS 验证模式申请签发证书的方式,每次 certbot renew 续期证书都需要通过指定 --manual-auth-hook 选项执行 shell 脚本来更新 DNS TXT 记录,否则无法进行续期申请。

💁‍♂ certbot renew时不指定 --manual-auth-hook 选项进行证书续期时报错如下:

Failed to renew certificate example.com with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError(‘An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.’,

💁‍♂ 提示:不论是单域名证书、多域名证书、还是通配符证书,都是需要指定 --manual-auth-hook 选项。

(2)安装并配置阿里云 CLI 工具

更新 DNS TXT 记录一般是调用对应域名托管服务商的 API 来实现。不同的域名托管服务商 API 的具体调用方式可能不一同,下面以阿里云的的域名解析服务为例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#安装
#pip install aliyuncli
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-3.0.16-amd64.tgz
tar xzvf aliyun-cli-linux-3.0.16-amd64.tgz
sudo mv aliyun /usr/local/bin

#配置(配置调用阿里云资源所需的凭证信息、地域、语言等)
aliyun configure set \
--profile akProfile \
--mode AK \
--region cn-hangzhou \
--access-key-id LTAxxxxxxxx9x7a \
--access-key-secret oNYXxxxxxxxxvFcz8F


#卸载
sudo rm -rf /usr/local/bin/aliyun
sudo rm -rf ~/.aliyun

阿里云 API 的密钥 AccessKey 可在阿里云管理后台创建获取。

参考:

(3)创建dns txt 记录脚本文件

创建 /opt/alidns/alidns.sh 文件,内容如下:

1
2
3
4
5
6
7
8
#!/bin/bash

# 获取 Certbot 提供的域名和 token 参数
DOMAIN="$CERTBOT_DOMAIN"
TOKEN="$CERTBOT_VALIDATION"

# 使用 Aliyun CLI 添加 TXT 记录到 DNS 中
aliyuncli dns AddDomainRecord --RecordType TXT --RR "_acme-challenge.${DOMAIN}" --Value "${TOKEN}" --DomainName "${DOMAIN}"

(4)手动续期

1
2
3
4
chmod +x /opt/alidns/alidns.sh
sudo certbot renew \
--preferred-challenges dns-01 \
--manual-auth-hook "/opt/alidns/alidns.sh"

(5)自动续期

可以通过Linux的定时任务来完成自动续期的需求,操作如下:

1
2
3
4
5
6
7
#设置系统的定时任务
sudo crontab -e
#在最后添加如下定时规则:
0 3 1 * * certbot renew --preferred-challenges dns-01 --manual-auth-hook "/opt/alidns/alidns.sh" --renew-hook "sudo /opt/nginx/sbin/nginx -s reload"

#列出系统的定时任务
sudo crontab -l


----------- 本文结束 -----------




如果你觉得我的文章对你有帮助,你可以打赏我哦~
0%