准备

通过 sudo nginx -V 发现 debian apt 安装的 nginx 已经有 ssl 模块,可以支持 https。

开放 443 端口

sudo ufw allow 443

letsencrypt 提供免费 3 个月期证书https://letsencrypt.org/zh-cn/getting-started/

获取安装证书

使用 Certbot ACME 客户端既可以为你获取证书,也可以帮助你安装证书(如果您需要的话)。在 https://certbot.eff.org/instructions 上选择自己的 web 服务器和系统,可以看到适合自己的安装方法

sudo apt install certbot python-certbot-nginx

然后

sudo certbot --nginx
或
sudo certbot certonly --nginx

这里要输入一些信息。。

然后 certbot 将通过 cron 任务或 systemd 定时器自动更新证书。

泛域名

不幸的是这是单域名的搞法,泛域名不能这样搞。

由于 certbot 不支持阿里云的域名接口,需要手工配置证书。这里有 http 和 dns 两种选择。

http challenge 挑战将要求你在 web 服务器顶级目录(“web根目录”)中的 /.well-known/acme-challenge/ 中放置具有特定名称和特定内容的文件。本质上它和 webroot 插件是一样的,但不是自动的。

sudo certbot certonly --manual --preferred-challenges http -d *.pran.top

在使用 dns challenge 时,certbot 将要求你将包含特定内容的 TXT dns 记录放在域名下,该域名由你希望颁发证书的主机名组成,前缀为 _acme-challenge。

sudo certbot certonly --manual --preferred-challenges dns -d *.pran.top

因为前者比较麻烦,选择后者。。

需要添加 TXT 域名记录 _acme-challenge.pran.top,值为 Lf7G0NGzGu77ij417Jwdj9iI82CCvjozcde_LLk-TFY 。验证下

dig -t txt _acme-challenge.pran.top @8.8.8.8

然后回来,确定。成功后,证书保存在
/etc/letsencrypt/live/pran.top/fullchain.pem/etc/letsencrypt/live/pran.top/

通过

sudo certbot renew

即可更新

nginx配置

nginx 配置可以通过

sudo certbot --nginx

来自动生成,然后再改。。这里又生成的证书可以通过

sudo certbot delete

来删除。。

这是全部通过 https 的配置,以后可以参考这个进行手工配置了

server {
  server_name www.pran.top;

  location / {
    proxy_pass http://127.0.0.1:8000/;
  }

  listen 443 ssl; # managed by Certbot
  ssl_certificate /etc/letsencrypt/live/pran.top/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/pran.top/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
  if ($host = www.pran.top) {
    return 301 https://$host$request_uri;
  } # managed by Certbot

  listen 80;
  server_name www.pran.top;
  return 404; # managed by Certbot
}
sudo nginx -t 查看配置文件位置
sudo nginx -s reload

证书定时更新

Let’s Encrypt 的证书使用期限只有三个月,在证书到期前的一个月可以使用 certbot 来更新。Linux 的定时任务有两种方法:cron 和 systemd/timers,任何一种都能实现定时的更新任务,Certbot 两种都设置了。

sudo vi /etc/cron.d/certbot

可以看到 Certbot 设定的任务记录

0 */12 * * * root test -x /usr/bin/certbot -a ! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew

由于我们选择 timers 来自动更新,所以把 cron 任务注释掉:

0 */12 * * * root test -x /usr/bin/certbot -a ! -d /run/systemd/system && perl -e 'sleep int(rand(43200))' && certbot -q renew

Certbot 在 /lib/systemd/system/ 下生成了两个文件:certbot.service 和 certbot.timer,一个是服务,一个是定时器。

certbot.service:

[Unit]
Description=Certbot
Documentation=file:///usr/share/doc/python-certbot-doc/html/index.html
Documentation=https://letsencrypt.readthedocs.io/en/latest/
[Service]
Type=oneshotExecStart=/usr/bin/certbot -q renew
PrivateTmp=true

可以看到也是运行 certbot -q renew 命令。

certbot.timer:

[Unit]
Description=Run certbot twice daily
[Timer]
OnCalendar=--* 00,12:00:00
RandomizedDelaySec=43200
Persistent=true
[Install]
WantedBy=timers.target

每天 0 点和 12 点激活 certbot.service。其实不需要这么频繁的更新证书,而且在更新证书的时候我们加了钩子来关闭和开启 Nginx 服务,所以最好是在凌晨没人访问网站的时候更新证书,我们稍微修改一下:

[Unit]
Description=Run certbot every 05:00
[Timer]
OnCalendar=--* 05:00:00
Persistent=true
[Install]
WantedBy=timers.target

每天凌晨 5 点更新一次证书。因为只有过期前 30 天才会申请更新,所以前 60 天这个任务什么都没干。

保存修改以后需要重启定时器:

sudo systemctl daemon-reload
sudo systemctl restart certbot.timer

貌似没什么用,还是不能自动更新。脚本有问题