oynix

于无声处听惊雷,于无色处见繁花

使用certbot管理免费证书

在AI盛行的时代,一句话就能解决问题,却还要坚持手搓的时候属实不多了。

原本我也是让Agent去VPS做这些事的,注册证书、自动更新,等等,但经过多次下来,发现VPS上的配置被它改的东一块、西一块的,最后就只好手动整理了一下,在此做个记录。

1. 简介

我用到证书的场景,主要是搭配域名一块儿使用,在VPS上暴露了几个服务,想要用https就需要有证书,权威机构颁发的证书动辄就几百几千,本着能省则省的原则,选了免费组织的证书:Let’s Encrypt。申请证书、更新证书,都是免费的,每次有效期90天,所以需要定时刷新证书。

对于这些操作,官方提供了一个工具,叫做:certbot,常见的申请、更新证书操作,通过这个工具都可实现。

2. 颁发流程

这里需要先说下Let’s Encrypt这个CA机构颁发证书的大致流程,这个说明白,后面关于certbot的多个参数就很好理解了。

假设,我需要给example.com这个域名申请证书,把这个请求发给机构之后,机构会返回一个token,之后,机构会访问一个固定URL,来验证我是不是这个域名的所有者:

1
http://example.com/.well-known/acme-challenge/<token>

所以,我拿到token之后,需要存到本地,并对外暴露,添加路由映射,比如通过Nginx,使得访问上面这个链接时,可以正确返回token,token是个文件名,文件内容除了包含token,还有一些其他用于验证的数据,机构访问URL,验证通过,则正式签发证书。

本质上,就是需要一个验证的操作:需要验证我是我申请的这个域名的所有者。

访问固定URL来验证是常见的方式,既然有常见的,就会有不太常见的,比如通过DNS验证:向机构申请某个域名的证书,机构会返回用于验证用的信息,在DNS解析中增加一条TXT类型的记录,内容就是这些验证用的信息,然后机构通过解析这条TXT类型的DNS记录,同样可以验证我就是这个域名的所有者,验证通过后,则正式签发证书。

添加TXT记录,一般都通过域名服务商提供的API来完成,比如Cloudflare,这种方式的优点是不受VPS端口限制,适用于无法暴露80端口,或者80端口在提供其他服务的情况。

证书下发到本地之后,要想证书生效,还需要一个操作:安装。

所谓安装证书,其实就是应用证书,对于需要证书的服务,把证书路径配置进去,对于正在使用证书的服务,能重载的就热重载一下,不支持重载的就重启一下,然后就可以了。

验证Authenticator + 安装Installer,就是全部流程。

3. 安装工具

我用的Linux是Debian,安装方式如下,root登录的话不用加sudo,直接跑即可:

1
2
$ sudo apt update
$ sudo apt install -y certbot

4.证书验证和安装

上面提到了多种证书验证的方式,这里只说其中的第一种,也就是通过80端口访问token文件的方式,而,对于这种方式,certbot提供了多种模式,分别是:

  • standalone
  • webroot
  • nginx

standalone是起一个单独的、临时的Python Web服务器,占用80端口,以供机构访问验证,webroot则是需要借用Nginx服务提供80端口,供机构访问验证,这2种都只是提供验证,不管安装,nginx模式则是在webroot的基础上,还提供安装证书,属于验证、安装一把抓,虽然省心,但是它会动态修改nginx的配置文件,修改端口,这是个很危险的操作,容易产生副作用。

这里我用的都是webroot方式,也是业内较为标准的方式。不使用standalone是因为大多数VPS都安装了Nginx,使用很方便,同时,certbot提供了hook,每次申请、更新证书之后,都会执行hook,在hook中,重启或者重载一下用到证书的服务,也不用每次都手动安装证书。

1
certbot certonly --webroot -w /var/www/html -d sub.domain.com

这里需要带着certonly,表示只申请、更新证书,不安装,使用webroot这种不带安装的方式时,就需要带着这个参数,不然就会报错,使用nginx则可以不带。后面的-w就是token文件存放的位置,这个也可以写别的路径,但一般都用这个,最终的存放路径是:

1
/var/www/html/.well-known/acme-challenge/<token>

Nginx还需要增加配置,让这个token可访问,80端口如果没用,直接加载default中就可以了:

1
2
3
4
5
6
7
8
9
10
11
# /etc/nginx/sites-enabled/default
server {
listen 80 default_server;
listen [::]:80 default_server

server_name _;

location /.well-known/acme-challenge/ {
root /var/www/html;
}
}

证书验证完成并下发后,存储的路径是:

1
2
3
4
/etc/letsencrypt/live/sub.domain.com/cert.pem
/etc/letsencrypt/live/sub.domain.com/chain.pem
/etc/letsencrypt/live/sub.domain.com/fullchain.pem
/etc/letsencrypt/live/sub.domain.com/privkey.pem

证书自动更新的配置路径是:

1
/etc/letsencrypt/renewal/sub.domain.com.conf

可通过这个命令查看当前所有证书信息:

1
$ certbot certificates

5. hooks

在/etc/letsencrypt/renewal-hooks下有3个目录,分别是:pre、deploy和post,分别对应3个回调时机:

  • pre:续签前调用
  • deploy:续签成功后调用
  • post:续签结束后调用,成功、失败都会调用

在deploy下创建文件reload.sh,并增加如下内容:

1
2
3
4
5
6
7
8
9
# /etc/letsencrypt/renewal-hooks/deploy/reload.sh

#!/bin/bash
# 证书更新后自动执行
systemctl reload nginx

# 其他使用证书的服务,比如sing-box
# systemctl restart sing-box

给hook增加执行权限:

1
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload.sh

这样,当签发成功后,会自动调用reload.sh,完成证书安装。

至此,证书自动更新就算完成了。

------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2026/10/10a7954d3fcf/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道