以 Nginx 为反代服务端时以 Certbot 自动申请 HTTPS 证书的流程
小时候,我对 HTTPS 证书的印象还停留在“我自己只要 80 端口开着,其余就给平台处理吧”的阶段。随着阅历的提升,我越发意识到完全由自己网站掌握 HTTPS 通信链路的重要性,不然诸如 CDN 或者反代之类的优化手段就无法使用了。
下面是我在 Nginx 为反代服务端时以 Certbot 自动申请 HTTPS 证书的流程。
1. 安装 Nginx 与 Certbot
这里我以 Ubuntu 系统作例子,别的发行版的方法大同小异。先更新一下包管理器:
sudo apt update
sudo apt upgrade
然后安装 Nginx 与 Certbot:
sudo apt install nginx certbot
确保 Nginx 服务已经启动:
sudo systemctl start nginx
这里有个小坑,建议以
systemctl
作为 daemon (守护进程) 启动 nginx,这样它才能有权限正常操作/etc/nginx
目录下的内容。不要直接用nginx
命令启动,否则很可能会导致权限问题、nginx 无权读取配置文件。
2. 配置 Nginx 以临时给 .well-known 目录开口
Certbot 会在申请证书时,通过让对面的鉴权服务器访问 http://xxx.com/.well-known/
来验证你对该域名的控制权,所以我们需要配置 Nginx 以临时给 .well-known
目录开口。
我们先在 /etc/nginx/conf.d/
下新建一个专门只开 80 端口的配置文件,例如 site.conf
:
server {
listen 80;
server_name xxx.com;
location ~ ^/\.well-known/ {
root /usr/share/nginx/html;
}
location / {
return https://xxx.com$uri;
}
}
然后重启 Nginx 服务,开始监听:
nginx -s reload
可以先用
nginx -t
检查一下配置文件是否有语法错误。
3. 申请 HTTPS 证书
现在我们可以用 Certbot 申请第一次的 HTTPS 证书了:
certbot certonly --webroot -w /usr/share/nginx/html -d xxx.com -m [email protected] --agree-tos
其中,-w
参数指定了 webroot 的路径,-d
参数指定了域名,-m
参数指定了邮箱。
后续的证书更新,只需要执行
certbot renew
即可,不需要打完整指令。
4. 启动后台服务,例如 docker 容器
例如,后台开一个 wordpress 的 docker 容器,放在 3000 端口:
docker run -d -p 3000:80 --name wordpress wordpress:latest
这里的
-d
是放在后台运行,跑完指令之后容器不会直接原地退出;-p 3000:80
是将容器中的80
端口映射到宿主机的3000
端口;--name
参数是给容器起个名字,方便后续操作。这里的
3000
端口是随便取的,只要不和宿主机的其他端口冲突就行;后续给服务器设置防火墙时,不要放行3000
端口,以免直接暴露容器。
5. 配置 Nginx 以使用 HTTPS 证书
在 /etc/nginx/conf.d/
下新增一个专门开 443 端口的配置文件,例如 site-ssl.conf
:
server {
listen 443 ssl;
server_name xxx.com;
ssl_certificate /etc/letsencrypt/live/xxx.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/xxx.com/privkey.pem;
location ~ ^/\.well-known/ {
root /usr/share/nginx/html;
}
location ~ .* {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Ssl on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:3000;
}
}
然后重新加载 Nginx 配置:
nginx -s reload
6. 增加计划任务
最后,我们可以增加一个计划任务,每个月自动更新一次证书。
首先准备一个脚本,例如放在 /home/cert-update.sh
,先以 Certbot 更新证书,然后通知 Nginx 更新证书:
#!/bin/bash
certbot renew
nginx -s reload
然后增加一个计划任务,每个月执行一次。先打开计划任务编辑器:
crontab -e
选择完编辑器后,在打开的编辑器中增加一行:
0 0 1 * * /bin/bash /home/cert-update.sh
这里的
0 0 1 * *
是指每个月的第一天零点零分执行一次。