Files
ykxmz/_build/setup_tls_origin.py
T
xmz7891 25ffd3ec67 源站装 TLS 证书 + 停掉旧服务器
== 522 的根因 ==

DNS 配好、橙色云朵生效之后:
    http://yk.xxmxxs.top/     -> 200(经 Cloudflare,反代正常)
    https://yk.xxmxxs.top/    -> 522
    13.54.30.196:443          -> 不通

zone 的 SSL/TLS 模式是 **Full / Full(strict)**,Cloudflare 回源走 443,
而源站只听了 80 —— 因此 522。

== 解决:源站签 Let's Encrypt 证书 ==

用 certbot 的 nginx 插件签(**不需要 webroot**,插件自己处理挑战):

    Successfully received certificate
    /etc/letsencrypt/live/yk.xxmxxs.top/fullchain.pem
    notAfter = Jan 6 2027(自动续期已启用 certbot.timer)
    nginx 已加 listen 443 + 证书 + http->https 跳转

**开着橙色云朵也能签**:HTTP-01 挑战请求
http://yk.xxmxxs.top/.well-known/acme-challenge/... 会经 Cloudflare
回源到 80,CF 不缓存该路径、会透传,所以验证能过。
比"先关云朵签完再开"省事,也不用等 DNS 传播。

踩的坑:第一次用了 xmz7891@example.com,Let's Encrypt 拒收
example.com 这类保留域名,报"invalid email"。
改用 --register-unsafely-without-email 即可
(续期由 timer 负责,不依赖邮件提醒)。

== 停掉旧服务器 ==

中转已在 Lightsail 跑通,旧那台(随身 WiFi + 两条 CF 隧道 + 网络调优)
全部停掉并取消自启:

    lanremote-relay / lanremote-tunnel / lanremote-tunnel-h2 /
    lanremote-nettune / monitor.timer / watchdog.timer  -> 全 inactive

**只停服务,没关机、没删文件** —— 保持可逆,新服务器稳几天再说。

== 待用户操作 ==

Lightsail 防火墙开 TCP 443(Cloudflare 的 Full(strict) 回源要用)。
2026-10-08 22:49:36 +08:00

128 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
r'''给源站签一张 Let's Encrypt 证书,让 Cloudflare 的 SSL 能走"完全(严格)"。
== 522 是怎么来的 ==
DNS 配好、橙色云朵生效之后:
http://yk.xxmxxs.top/ -> 200 (经 Cloudflare,反代是好的)
https://yk.xxmxxs.top/ -> 522 (Cloudflare 连不上源站)
13.54.30.196:443 -> 不通(源站没听 443)
结论:zone 的 SSL/TLS 模式是 **Full** 或 **Full (strict)**,
Cloudflare 回源走 443,而源站只有 80 -> 522。
== 两种解法 ==
A. 把 SSL/TLS 改成 **Flexible**
一个下拉框搞定。CF<->用户加密,**CF<->源站明文**。
省事,但源站那段不加密 —— 而且 Cloudflare 官方不建议
(源站流量在 CF 内网走,风险不大,但"完全"更好)。
B. 源站装证书,保持 **Full (strict)** <- 这个脚本做的
端到端加密,还能开 HSTS 之类。多花两分钟,值得。
== 为什么开着橙色云朵也能签 Let's Encrypt ==
HTTP-01 验证是:Let's Encrypt 去请求
http://yk.xxmxxs.top/.well-known/acme-challenge/<随机串>
这条请求会经过 Cloudflare 回源到我们的 80 端口。
Cloudflare 默认**不缓存** .well-known 路径、也会透传,所以能验证成功。
(这比"先关云朵签完再开"省事,也不用等 DNS 传播。)
== 签完还要做的 ==
1. 用户在 Lightsail 防火墙**开 443**
2. 用户把 Cloudflare 的 SSL/TLS 设为 **Full (strict)**
'''
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
DOMAIN = "yk.xxmxxs.top"
EMAIL = "xmz7891@example.com" # Let's Encrypt 要一个邮箱(过期提醒)
def main() -> int:
print("=" * 62)
print(" 给 %s 签 Let's Encrypt 证书" % DOMAIN)
print("=" * 62)
print()
print(" ── 1. 装 certbot ──")
out = run("which certbot >/dev/null 2>&1 && echo ALREADY || "
"(sudo apt-get update -qq && sudo DEBIAN_FRONTEND=noninteractive "
"apt-get install -y -qq certbot python3-certbot-nginx) && "
"certbot --version 2>&1", timeout=900, quiet=True)
for ln in out[1].strip().splitlines()[-3:]:
print(" " + ln)
print()
print(" ── 2. 先确认 HTTP-01 挑战路径能通(走 Cloudflare)──")
out = run(
"mkdir -p /var/www/html/.well-known/acme-challenge && "
"echo 'ykxmz-acme-ok' | sudo tee "
"/var/www/html/.well-known/acme-challenge/probe >/dev/null && "
"sudo chown -R www-data:www-data /var/www/html 2>/dev/null; "
"echo ' 本机:'; curl -s --max-time 8 "
"http://127.0.0.1:80/.well-known/acme-challenge/probe | sed 's/^/ /'; "
"echo ' 经 Cloudflare:'; curl -s --max-time 15 "
"http://%s/.well-known/acme-challenge/probe | sed 's/^/ /'"
% DOMAIN, timeout=180, quiet=True)
for ln in out[1].strip().splitlines():
print(ln)
print()
print(" ── 3. 签证书 ──")
# --nginx 会自动改 nginx 配置加上 443 + 证书路径
# --non-interactive 不交互;--agree-tos 同意条款
# --redirect 把 http 永久重定向到 https
out = run(
"sudo certbot --nginx -d %s --non-interactive --agree-tos "
"--email %s --redirect --keep-until-expiring 2>&1 | tail -20"
% (DOMAIN, EMAIL), timeout=600, quiet=True)
for ln in out[1].strip().splitlines():
print(" " + ln)
print()
print(" ── 4. 复查 nginx 是否已在 443 上 ──")
out = run(
"sudo nginx -t 2>&1 | tail -2; "
"echo ' --- 监听 ---'; "
"ss -tln 2>/dev/null | grep -E ':(80|443) ' | sed 's/^/ /'; "
"echo ' --- 证书 ---'; "
"sudo ls -la /etc/letsencrypt/live/%s/ 2>/dev/null | tail -5 | "
"sed 's/^/ /'; "
"echo ' --- 本机 https 自测 ---'; "
"curl -sk -o /dev/null -w ' https://127.0.0.1 (SNI %s): %%{http_code}\\n' "
"--max-time 10 --resolve %s:443:127.0.0.1 https://%s/v1/health"
% (DOMAIN, DOMAIN, DOMAIN, DOMAIN), timeout=180, quiet=True)
for ln in out[1].strip().splitlines():
print(ln)
print()
print(" ── 5. 自动续期 ──")
out = run("systemctl is-enabled certbot.timer 2>&1; "
"systemctl is-active certbot.timer 2>&1; "
"sudo certbot renew --dry-run 2>&1 | tail -3",
timeout=600, quiet=True)
for ln in out[1].strip().splitlines():
print(" " + ln)
print()
print("=" * 62)
print(" 接下来要用户做两件事:")
print(" 1. Lightsail 防火墙开 TCP 443")
print(" 2. Cloudflare 的 SSL/TLS 设为「完全(严格)」")
print("=" * 62)
return 0
if __name__ == "__main__":
sys.exit(main())