VPS 网站自动申请免费 SSL 证书+自动续期全过程记录

最近给自己服务器上的两个网站换了 SSL 证书,顺便把整个过程记录一下。

以前用的是阿里云申请的免费证书,每隔一段时间就要手动续期、替换证书文件,太麻烦了。其实如果只是个人网站,直接用 Let’s Encrypt 就挺方便,免费、有效期短一些,但可以通过 Certbot 自动续期,基本配置好以后就不用管了。

这次我给两个 Nginx 网站配置了 HTTPS,并且顺便把自动续期也一起弄好了。

一、先安装 Certbot

如果服务器还没有 Certbot,可以先安装它。

以 Linux 服务器为例,我这里采用 Python 虚拟环境安装,这样不会影响系统自带的 Python,后面升级 Certbot 也比较方便。

先确认 Python 版本:

python3 --version

如果服务器已经安装了 Python 3.11,可以直接创建一个专门给 Certbot 使用的虚拟环境:

python3.11 -m venv /opt/certbot311

激活虚拟环境:

source /opt/certbot311/bin/activate

然后升级 pip:

pip install -U pip

安装 Certbot:

pip install certbot

安装完成后检查:

certbot --version

如果能正常显示 Certbot 版本号,就说明安装成功。

为了以后直接输入 certbot 就能使用,而不用每次手动进入虚拟环境,可以创建一个软链接:

ln -sf /opt/certbot311/bin/certbot /usr/local/bin/certbot

再检查:

which certbot
certbot --version

正常情况下会看到:

/usr/local/bin/certbot
certbot x.x.x

这样 Certbot 就安装好了。

为什么我更喜欢这种安装方式?

主要是为了不折腾系统自带的 Python

很多 Linux 系统自己的管理工具依赖系统 Python,如果为了装一个 Certbot 直接升级或替换 /usr/bin/python3,反而容易把系统环境搞乱。

单独给 Certbot 建一个 Python 虚拟环境,相当于把它“关”在自己的小环境里,和系统其他程序互不影响。我个人觉得这种方式更适合自己维护 VPS。

二、申请 Let’s Encrypt 证书

我的网站使用 Nginx,比较喜欢 webroot 这种方式,因为它不会直接修改 Nginx 配置。

例如:

certbot certonly --webroot \
  -w /home/wwwroot/heqianwei \
  -d heqianwei.com \
  -d www.heqianwei.com

另一个网站同样操作:

certbot certonly --webroot \
  -w /home/wwwroot/ihacksoft \
  -d ihacksoft.com \
  -d www.ihacksoft.com

这里的 -w 后面填写的是网站实际的 Web 根目录。

申请成功后,证书一般会放在:

/etc/letsencrypt/live/

例如:

/etc/letsencrypt/live/heqianwei.com/
├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem

Nginx 通常使用:

fullchain.pem
privkey.pem

三、让 Nginx 使用新证书

我原来的 Nginx 配置是使用 /etc/nginx/cert/ 下面的证书文件,所以没有直接修改 Nginx 配置结构,而是把 Let’s Encrypt 生成的证书复制过去。

例如:

cp -L /etc/letsencrypt/live/heqianwei.com/fullchain.pem \
/etc/nginx/cert/heqianwei.com.pem

cp -L /etc/letsencrypt/live/heqianwei.com/privkey.pem \
/etc/nginx/cert/heqianwei.com.key

另一个网站:

cp -L /etc/letsencrypt/live/ihacksoft.com/fullchain.pem \
/etc/nginx/cert/ihacksoft.com.pem

cp -L /etc/letsencrypt/live/ihacksoft.com/privkey.pem \
/etc/nginx/cert/ihacksoft.com.key

然后检查 Nginx:

nginx -t

如果看到:

syntax is ok
test is successful

就可以重新加载:

systemctl reload nginx

到这里,网站的 HTTPS 基本就已经正常了。


四、关键来了:设置自动续期

Let’s Encrypt 的证书有效期比较短,所以不能申请完就不管了。

Certbot 本身提供了:

certbot renew

这个命令的作用不是每次都重新申请证书,而是检查现有证书是否已经接近过期,需要续期时才自动续期

我这里直接用 Linux 的 cron 定时任务,每天凌晨 3 点执行一次:

crontab -e

加入:

0 3 * * * /usr/local/bin/certbot renew -q

然后检查:

crontab -l

看到:

0 3 * * * /usr/local/bin/certbot renew -q

就说明定时任务已经配置好了。

每天执行一次其实没什么问题,因为 Certbot 会自己判断证书是否需要续期。


五、还有一个容易忽略的问题

这里我一开始也觉得,配置好:

certbot renew

就万事大吉了。

但实际上还差一步。

因为我的 Nginx 使用的是:

/etc/nginx/cert/

下面的证书,而 Certbot 续期成功后,新证书是在:

/etc/letsencrypt/live/

下面。

也就是说:

Certbot 虽然把证书更新了,但 Nginx 还在使用旧的证书文件。

所以还需要一个 Deploy Hook。

先创建目录:

mkdir -p /etc/letsencrypt/renewal-hooks/deploy

然后创建脚本:

cat > /etc/letsencrypt/renewal-hooks/deploy/update-nginx-certs.sh <<'EOF'
#!/bin/bash
set -e

cp -L /etc/letsencrypt/live/heqianwei.com/fullchain.pem /etc/nginx/cert/heqianwei.com.pem
cp -L /etc/letsencrypt/live/heqianwei.com/privkey.pem /etc/nginx/cert/heqianwei.com.key

cp -L /etc/letsencrypt/live/ihacksoft.com/fullchain.pem /etc/nginx/cert/ihacksoft.com.pem
cp -L /etc/letsencrypt/live/ihacksoft.com/privkey.pem /etc/nginx/cert/ihacksoft.com.key

chmod 600 /etc/nginx/cert/heqianwei.com.key
chmod 600 /etc/nginx/cert/ihacksoft.com.key

nginx -t
systemctl reload nginx
EOF

然后给脚本执行权限:

chmod +x /etc/letsencrypt/renewal-hooks/deploy/update-nginx-certs.sh

以后 Certbot 只要真正续期成功,就会自动执行这个脚本。

整个过程就变成:

Certbot 自动续期
       ↓
复制新证书
       ↓
修改证书权限
       ↓
检查 Nginx 配置
       ↓
重新加载 Nginx
       ↓
网站自动使用新证书

这样就不用每隔几个月再登录服务器手动换证书了。


六、最后一定要测试一下

实际证书还没到续期时间,不可能现在真的给你换一张新证书。

所以可以用:

certbot renew --dry-run

模拟一次续期。

如果最后看到:

Congratulations, all simulated renewals succeeded

基本就说明自动续期流程没有问题。

如果还想连刚才配置的 Deploy Hook 一起测试,可以:

certbot renew --dry-run --run-deploy-hooks

我这次实际测试两个网站都成功了。


最后简单总结一下

其实整个方案并不复杂:

① Certbot 申请证书

certbot certonly --webroot ...

② Nginx 使用证书

/etc/letsencrypt/live/

或者根据自己的 Nginx 配置复制到指定目录。

③ 设置每天自动检查

0 3 * * * /usr/local/bin/certbot renew -q

④ 配置 Deploy Hook

续期成功后自动复制新证书,并:

nginx -t
systemctl reload nginx

⑤ 用 dry-run 测试

certbot renew --dry-run

我个人感觉这种方式还是挺省心的,尤其是自己维护好几个小网站的时候。证书申请一次,后面让服务器自己续期就行,平时基本不用再操心 SSL 证书过期的问题。

比较适合自己折腾 VPS、Nginx、Typecho、WordPress 这类网站的人。