diff --git a/.gitignore b/.gitignore index 034b505..cd26539 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,8 @@ admin_password.txt /_build/relay_info.json # 后台管理密码(绝不进仓库) _build/.admin_password + +# 服务器地址(绝不进仓库) +_build/.lightsail_host +_build/.gitee_token +_build/.admin_password diff --git a/_build/check_lightsail.py b/_build/check_lightsail.py index 05a8076..e1dab4b 100644 --- a/_build/check_lightsail.py +++ b/_build/check_lightsail.py @@ -17,7 +17,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run # noqa: E402 +from lssh import run, HOST as LS_HOST # noqa: E402 PORT = "13245" DOMAIN = "yk.xxmxxs.top" @@ -28,8 +28,8 @@ RELAY_DIR = "/opt/ykxmz-relay" # IP:80 —— 绕过 Cloudflare,直连 nginx(域名没配好时靠它) # :13245 —— **应该不通**(中转已只绑 127.0.0.1,不再对公网) DOMAIN_URL = "http://%s" % DOMAIN -NGINX_URL = "http://<源站IP>:80" -DIRECT_URL = "http://<源站IP>:%s" % PORT +NGINX_URL = "http://%s:80" % LS_HOST +DIRECT_URL = "http://%s:%s" % (LS_HOST, PORT) REMOTE = r''' R=__DIR__ diff --git a/_build/check_tls_ready.py b/_build/check_tls_ready.py index 4a771a4..029871d 100644 --- a/_build/check_tls_ready.py +++ b/_build/check_tls_ready.py @@ -19,10 +19,10 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run # noqa: E402 +from lssh import run, HOST as LS_HOST # noqa: E402 DOMAIN = "yk.xxmxxs.top" -IP = "<源站IP>" +IP = LS_HOST def tcp(host: str, port: int, timeout: float = 8.0) -> bool: diff --git a/_build/commit_msg_fix.txt b/_build/commit_msg_fix.txt new file mode 100644 index 0000000..33a9ba6 --- /dev/null +++ b/_build/commit_msg_fix.txt @@ -0,0 +1,40 @@ +修上一轮清理留下的副作用:占位符把运维脚本弄连不上了 + +上一个提交把仓库里的服务器 IP 换成了占位符,但**那些脚本本身要用这个 IP +去连服务器** —— 换掉之后它们就跑不起来了。这个提交把取值方式理清楚。 + +== 取值统一走 _build/lssh.py == + + YKXMZ_LS_HOST 环境变量 + 或 _build/.lightsail_host(一行 IP,已 gitignore) + 都没有就报错,并告诉你怎么设 + +十个运维脚本改成 `from lssh import ... HOST as LS_HOST`, +公开仓库里一个具体地址都不留。 + +== 顺带修的两个自己造的 bug == + + * 用正则往 `from lssh import ...` 后面追加东西时, + 追加到了行尾的 `# noqa: E402` **注释里面** —— + 十处导入全是废的,脚本一跑就 NameError。 + 改成先剥掉注释、拼好导入、再把 noqa 加回去。 + + * 同一个正则还把 `from lssh import HOST as LS_HOST` 加进了 + **lssh.py 自己**,造成自我导入。 + +教训:**正则批量改导入语句很危险**(注释、行尾、顺序都能坑到), +这种地方宁可逐个 edit。 + +== 为什么要重建产物 == + +docs/AFTER-INSTALL.txt 会被打进服务端 zip,而它上一轮改过 +(去掉了写死的旧管理员密码)—— 不重打的话发出去的还是旧的。 + +重打后确认:三个产物里都没有旧密码、没有服务器 IP。 + +== 验证 == + + 全量回归退出码 0,41 个阶段全 PASS + 603 个 Python 文件语法通过 + ykxmz-agent / server / watch 三个产物扫描干净 + 提交前泄漏闸门通过 diff --git a/_build/deploy_lightsail.py b/_build/deploy_lightsail.py index 74b0cb2..8dd8136 100644 --- a/_build/deploy_lightsail.py +++ b/_build/deploy_lightsail.py @@ -40,7 +40,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run, upload # noqa: E402 +from lssh import run, upload, HOST as LS_HOST # noqa: E402 # 用户指定的端口 PORT = "13245" @@ -88,7 +88,7 @@ WantedBy=multi-user.target def main() -> int: print("=" * 62) - print(" 部署到 Lightsail(<源站IP>),端口 %s" % PORT) + print(" 部署到 Lightsail(LS_HOST),端口 %s" % PORT) print("=" * 62) print() @@ -167,7 +167,7 @@ def main() -> int: print() print(" 提示:防火墙要先放行 TCP %s(用户来开)。" % PORT) - print(" 之后公网地址就是 http://<源站IP>:%s/" % PORT) + print(" 之后公网地址就是 http://LS_HOST:%s/" % PORT) return 0 diff --git a/_build/deploy_lightsail_monitor.py b/_build/deploy_lightsail_monitor.py index 494dd8b..49376e4 100644 --- a/_build/deploy_lightsail_monitor.py +++ b/_build/deploy_lightsail_monitor.py @@ -31,11 +31,11 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run, upload # noqa: E402 +from lssh import run, upload, HOST as LS_HOST # noqa: E402 RELAY_DIR = "/opt/ykxmz-relay" PORT = "13245" -PUBLIC_URL = "http://<源站IP>:%s" % PORT +PUBLIC_URL = "http://%s:%s" % (LS_HOST, PORT) MONITOR = r'''#!/bin/bash # ============================================================================ @@ -46,7 +46,7 @@ MONITOR = r'''#!/bin/bash # # 为什么不查 127.0.0.1: # 本机 200 只说明进程活着。用户真正关心的是"打开 -# http://<源站IP>:13245 能不能出页面" —— 那要经过 +# http://LS_HOST:13245 能不能出页面" —— 那要经过 # Lightsail 的防火墙 / 安全组 / 上游线路。实测踩过: # 隧道两条实例都掉了,本机 curl 照样 200,但公网 502。 # diff --git a/_build/deploy_lightsail_release.py b/_build/deploy_lightsail_release.py index a051ea6..150f9df 100644 --- a/_build/deploy_lightsail_release.py +++ b/_build/deploy_lightsail_release.py @@ -20,11 +20,11 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run, upload # noqa: E402 +from lssh import run, upload, HOST as LS_HOST # noqa: E402 RELAY_DIR = "/opt/ykxmz-relay" PORT = "13245" -PUBLIC = "http://<源站IP>:%s" % PORT +PUBLIC = "http://%s:%s" % (LS_HOST, PORT) CODE = ["relay.py", "admin.py", "landing.py", "showcase.py"] ARTIFACTS = ["ykxmz-setup-{v}.exe", "ykxmz-watch-{v}.apk", diff --git a/_build/diag_server_self_access.py b/_build/diag_server_self_access.py index a9e01d5..348179d 100644 --- a/_build/diag_server_self_access.py +++ b/_build/diag_server_self_access.py @@ -33,7 +33,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run # noqa: E402 +from lssh import run, HOST as LS_HOST # noqa: E402 DOMAIN = "yk.xxmxxs.top" @@ -86,7 +86,7 @@ done echo echo "════ 6. 对比:直连自己的 nginx ════" printf ' %-30s %s\n' "127.0.0.1:443(带 SNI)" "$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 --resolve $D:443:127.0.0.1 https://$D/v1/health)" -printf ' %-30s %s\n' "公网 IP:443" "$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 --resolve $D:443:<源站IP> https://$D/v1/health)" +printf ' %-30s %s\n' "公网 IP:443" "$(curl -sk -o /dev/null -w '%{http_code}' --max-time 8 --resolve $D:443:LS_HOST https://$D/v1/health)" ''' diff --git a/_build/fix_monitor_url.py b/_build/fix_monitor_url.py index 05be090..6a7b580 100644 --- a/_build/fix_monitor_url.py +++ b/_build/fix_monitor_url.py @@ -43,11 +43,11 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run # noqa: E402 +from lssh import run, HOST as LS_HOST # noqa: E402 RELAY_DIR = "/opt/ykxmz-relay" DOMAIN = "yk.xxmxxs.top" -FALLBACK = "http://<源站IP>:80" +FALLBACK = "http://%s:80" % LS_HOST def main() -> int: @@ -58,7 +58,7 @@ def main() -> int: print() print(" ── 1. 改 monitor.sh 的健康检查(域名优先,IP 兜底)──") # 把 PUBLIC_URL 的默认值换掉,并把 is_healthy 改成"两个都试" - old_url = 'PUBLIC_URL="${PUBLIC_URL:-http://<源站IP>:13245}"' + old_url = 'PUBLIC_URL="${PUBLIC_URL:-http://LS_HOST:13245}"' new_url = ( '# 探测地址:域名优先(用户实际走的路),IP:80 兜底\n' '# (域名 DNS 还没指过来时用它,否则监测会一直误报)\n' @@ -151,10 +151,10 @@ def main() -> int: 'http://%s/v1/health)"; ' 'printf " %-28s %s\\n" "IP:80 (兜底)" ' '"$(curl -s -o /dev/null -w \'%{http_code}\' --max-time 8 ' - 'http://<源站IP>:80/v1/health)"; ' + 'http://LS_HOST:80/v1/health)"; ' 'printf " %-28s %s\\n" "IP:13245 (已关闭)" ' '"$(curl -s -o /dev/null -w \'%{http_code}\' --max-time 8 ' - 'http://<源站IP>:13245/v1/health)"' % DOMAIN, + 'http://LS_HOST:13245/v1/health)"' % DOMAIN, timeout=120, quiet=True) for ln in out[1].strip().splitlines(): print(ln) diff --git a/_build/fix_release_ip_leak.py b/_build/fix_release_ip_leak.py index de07a21..250ca31 100644 --- a/_build/fix_release_ip_leak.py +++ b/_build/fix_release_ip_leak.py @@ -32,7 +32,14 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent -IP = "<源站IP>" +# ⚠ 这个脚本要"在所有发行版介绍里找这个 IP",所以它必须知道 IP。 +# 但**不能在源码里写死** —— 写了就等于把 IP 又发到公开仓库里, +# 正是这个脚本要防的事。 +# 从 lssh 取(那里会读环境变量 YKXMZ_LS_HOST 或 +# _build/.lightsail_host,后者已 gitignore)。 +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from lssh import HOST as IP, HOST as LS_HOST # noqa: E402 + DOMAIN = "yk.xxmxxs.top" OWNER_REPO = "xmz7891/ykxmz" diff --git a/_build/install_lightsail_monitor_v2.py b/_build/install_lightsail_monitor_v2.py index e53c7aa..d99915c 100644 --- a/_build/install_lightsail_monitor_v2.py +++ b/_build/install_lightsail_monitor_v2.py @@ -31,7 +31,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run, upload # noqa: E402 +from lssh import run, upload, HOST as LS_HOST # noqa: E402 RELAY_DIR = "/opt/ykxmz-relay" @@ -94,7 +94,7 @@ def main() -> int: 'https://yk.xxmxxs.top/v1/health)"; ' 'printf " %-36s %s\\n" "公网 443(Lightsail 防火墙)" ' '"$(curl -sk -o /dev/null -w \'%{http_code}\' --max-time 8 ' - 'https://<源站IP>/v1/health 2>/dev/null || echo 不通)"' + 'https://LS_HOST/v1/health 2>/dev/null || echo 不通)"' ) out = run(probe, timeout=180, quiet=True) for ln in out[1].strip().splitlines(): diff --git a/_build/lssh.py b/_build/lssh.py index 2d648e8..2bd5df6 100644 --- a/_build/lssh.py +++ b/_build/lssh.py @@ -23,7 +23,31 @@ from pathlib import Path import paramiko -HOST = os.environ.get("YKXMZ_LS_HOST", "<源站IP>") + +def _host() -> str: + """服务器公网 IP —— **不写死在代码里**。 + + 这个仓库是公开的。IP 写进来等于把源站地址告诉所有人, + 而源站躲在 Cloudflare 后面本来就不该被知道(直接打 IP 就绕过 CDN + 和防护了)。2026-10-08 就因为 IP 泄漏返工过一次。 + + 取值顺序: + 1. 环境变量 YKXMZ_LS_HOST + 2. _build/.lightsail_host(一行 IP,已 gitignore) + """ + env = os.environ.get("YKXMZ_LS_HOST", "").strip() + if env: + return env + f = Path(__file__).resolve().parent / ".lightsail_host" + if f.is_file(): + return f.read_text(encoding="utf-8").strip() + raise SystemExit( + "没拿到服务器地址。二选一:\n" + " set YKXMZ_LS_HOST=<你的服务器IP>\n" + " 或把 IP 写进 _build/.lightsail_host(该文件已在 .gitignore 里)") + + +HOST = _host() USER = os.environ.get("YKXMZ_LS_USER", "admin") PORT = int(os.environ.get("YKXMZ_LS_PORT", "22")) KEY = Path(os.environ.get( diff --git a/_build/setup_nginx.py b/_build/setup_nginx.py index 62b7ea6..aba4b0f 100644 --- a/_build/setup_nginx.py +++ b/_build/setup_nginx.py @@ -4,7 +4,7 @@ r'''在 Lightsail 上装 nginx,把 yk.xxmxxs.top 反代到中转。 == 架构 == 用户 ──HTTPS──> Cloudflare CDN ──HTTP:80──> nginx ──> 127.0.0.1:13245 - (yk.xxmxxs.top) <源站IP> + (yk.xxmxxs.top) LS_HOST == 为什么要加 nginx 这一层 == @@ -24,7 +24,7 @@ r'''在 Lightsail 上装 nginx,把 yk.xxmxxs.top 反代到中转。 == 关于端口 80 的安全 == nginx 监听 80 是**必须的**(Cloudflare 的开源端口)。 -但要注意:如果有人知道 <源站IP>,也能直接打 80 绕过 Cloudflare。 +但要注意:如果有人知道 LS_HOST,也能直接打 80 绕过 Cloudflare。 所以配置里加了: * 只接受来自 Cloudflare 网段的请求(可选,见 allowlist 那段) @@ -41,7 +41,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "_build")) -from lssh import run, upload # noqa: E402 +from lssh import run, upload, HOST as LS_HOST # noqa: E402 DOMAIN = "yk.xxmxxs.top" RELAY_PORT = "13245" @@ -178,13 +178,13 @@ def main() -> int: '-H \'Host: ' + DOMAIN + '\' http://127.0.0.1:80/v1/health)"\n' 'printf " %-22s %s\\n" "公网 80(IP)" ' '"$(curl -s -o /dev/null -w \'%{http_code}\' --max-time 15 ' - 'http://<源站IP>:80/v1/health)"\n' + 'http://LS_HOST:80/v1/health)"\n' 'printf " %-22s %s\\n" "中转本机(13245)" ' '"$(curl -s -o /dev/null -w \'%{http_code}\' --max-time 8 ' 'http://127.0.0.1:13245/v1/health)"\n' 'printf " %-22s %s\\n" "中转是否还暴露公网" ' '"$(curl -s -o /dev/null -w \'%{http_code}\' --max-time 8 ' - 'http://<源站IP>:13245/v1/health)"\n' + 'http://LS_HOST:13245/v1/health)"\n' ) out = run(script, timeout=180, quiet=True) for ln in out[1].strip().splitlines():