# -*- coding: utf-8 -*- r'''给 xxmxxs.top 签 Let's Encrypt 证书,并加回 443 块。 == 现在的状态 == * `xxmxxs.top` 的 A 记录已经指过来(走 Cloudflare 代理)✓ * `www.xxmxxs.top` **还没解析** —— 先不带它签 * 80 端口上博客已经能用(`http://<服务器IP>/console` 可以进控制台) == 为什么先不签 www == `certbot -d xxmxxs.top -d www.xxmxxs.top` 会**同时校验两个域名**。 www 没解析的话整张证书都签不下来(Let's Encrypt 要求所有域名都通过校验)。 所以先签主域名,等 www 记录加了再 `--expand` 补进去。 == 走 Cloudflare 代理时的一个风险 == ACME 的 HTTP-01 挑战要求: http://xxmxxs.top/.well-known/acme-challenge/ 能直接返回文件。 但 Cloudflare 如果开了 **"Always Use HTTPS"**,会把 80 端口的请求 301 到 https —— **certbot 就跟不上那个跳转,签不下来**。 不过 Cloudflare **默认不代理 `.well-known/acme-challenge/`**, 而且我们是 `--nginx` 插件(它会临时插一个 location)。 真出问题的话,报错信息会明确说"challenge 拿不到", 那时候再去 Cloudflare 加一条"绕过规则"。 == 443 块怎么加回来 == 之前在配置文件里**故意没写** 443 段(没证书时 `nginx -t` 会失败: "no ssl_certificate is defined")。 现在证书有了,用 `certbot --nginx` 让它**自己写** —— 比我手写靠谱, 因为它会把续期需要的所有行都带上。 ''' from __future__ import annotations import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) from lssh import run # noqa: E402 def main() -> int: print("=" * 62) print(" 给 xxmxxs.top 签证书 + 开 HTTPS") print("=" * 62) print() print("── 1. 签证书(certbot 自己改 nginx 配置)──") out = run(r''' sudo certbot --nginx -d xxmxxs.top \ --non-interactive --agree-tos --register-unsafely-without-email \ --redirect --keep-until-expiring 2>&1 | tail -20 ''', timeout=900, quiet=True) print(out[1] if isinstance(out, tuple) else out) print() print("── 2. 复核 ──") out = run(r''' echo " --- 证书文件 ---" sudo ls -1 /etc/letsencrypt/live/ 2>/dev/null | sed 's/^/ /' echo echo " --- 证书信息 ---" sudo openssl x509 -in /etc/letsencrypt/live/xxmxxs.top/fullchain.pem \ -noout -subject -dates 2>/dev/null | sed 's/^/ /' echo echo " --- nginx 配置现在有几个 server 块 ---" sudo grep -cE "^\s*server \{" /etc/nginx/sites-available/halo | sed 's/^/ halo: /' echo echo " --- 443 块有了吗 ---" sudo grep -c "listen 443 ssl" /etc/nginx/sites-available/halo | sed 's/^/ listen 443: /' echo echo " --- nginx 检查 + 重载 ---" sudo nginx -t 2>&1 | tail -2 | sed 's/^/ /' sudo systemctl reload nginx && echo " 重载完成" || echo " 重载失败" echo " nginx: $(systemctl is-active nginx)" echo echo " --- 各入口复核 ---" printf " %-42s " "http://<服务器IP>/console (IP 控制台)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1/console printf " %-42s " "https://xxmxxs.top/ (博客)" curl -s -o /dev/null -w "HTTP %{http_code} %{size_download} 字节\n" --max-time 15 https://xxmxxs.top/ printf " %-42s " "https://xxmxxs.top/console (控制台)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 https://xxmxxs.top/console printf " %-42s " "http://xxmxxs.top/ (应该 301 到 https)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 http://xxmxxs.top/ printf " %-42s " "https://yk.xxmxxs.top/ (中转站没坏)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 https://yk.xxmxxs.top/ printf " %-42s " "http://<服务器IP>:3001/ (直连 Halo)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1:3001/ printf " %-42s " "http://<服务器IP>:9100/ (官网)" curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1:9100/ echo echo " --- ACME 挑战路径还是通的吗(关系到 90 天后能不能续)---" printf " %-42s " "http://127.0.0.1/.well-known/acme-challenge/probe" sudo sh -c 'echo ok > /var/www/html/.well-known/acme-challenge/probe' curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 8 -H "Host: xxmxxs.top" http://127.0.0.1/.well-known/acme-challenge/probe sudo rm -f /var/www/html/.well-known/acme-challenge/probe ''', timeout=400, quiet=True) print(out[1] if isinstance(out, tuple) else out) return 0 if __name__ == "__main__": sys.exit(main())