# -*- coding: utf-8 -*- r'''服务器整理:删隧道残留 + 加 9100 监听 + 修"用 IP 访问 404"。 == 用户的要求 == * "为什么中转站里还有隧道,所有没的东西就删了" * "网站官网不是 <服务器IP> 吗,改成 <服务器IP>:9100,中转站也一样" * "我感觉网站还是不稳定" == 查到的现状 == * `lanremote-tunnel` / `cloudflared` 两个单元 **inactive dead**, 但**单元文件还在**(`systemctl list-units --all` 能列出来)。 那是早年走 Cloudflare Tunnel 时留下的,现在早就换成 nginx + Let's Encrypt 直连了 —— 属于"没的东西",该删。 * **用 IP 直接访问 `http://<服务器IP>/` 返回 404** —— 因为唯一的 80 站点是 `server_name yk.xxmxxs.top`, Host 不匹配时 nginx 拿它当 default server,转给 relay, relay 不认这个 Host 就 404。 **这很可能就是"感觉不稳定"的来源**:用域名是对的,用 IP 就不对。 * 9100 端口**服务端没监听、AWS 防火墙也没开** —— 两头都要做。 == 这一版做什么 == 1. **删掉两个隧道单元**(先 stop + disable + 删文件 + daemon-reload) 2. **nginx 加 9100 监听**: * `http://<服务器IP>:9100/` 直接出官网 * 中转接口也在 9100 上(`/v1/...`、`/download/...`) ⚠ 这需要 **AWS Lightsail 控制台里开放 9100**, 只有用户能做(我没有他的 AWS 凭据)。 3. **修 IP 访问 404**:给 80 端口加一个 default server, 把不认识的 Host 也送到同一套后端 —— 这样 `http://IP/` 能用。 == 为什么 9100 用 HTTP 而不是 HTTPS == IP 地址**没法签证书**(Let's Encrypt 不给纯 IP 签)。 所以 `https://<服务器IP>:9100` 会报证书错。 9100 定位是"Cloudflare 出问题时的直连备用通道", 用 HTTP 就行 —— 中转的数据本身有自己的校验。 ''' 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, upload # noqa: E402 # ---------------------------------------------------------------- nginx 片段 # 在 ykxmz 站点的 443 server 里补 9100 监听,并加一个 80 的 default server。 # # 为什么加在**同一个文件**里:这样只有一份 server 块要维护, # 后端地址(127.0.0.1:13245)只写一次,改后端不用改两处。 EXTRA_LISTEN = """ # ---- 9100:Cloudflare 之外的直连通道 ---- # # 用户要求:"网站官网不是 <服务器IP> 吗,改成 <服务器IP>:9100"。 # # ⚠ 用 IP 没法签证书(Let's Encrypt 不给纯 IP 签),所以这里是 HTTP。 # 定位是备用通道:Cloudflare 出问题时还能直接连上。 # # ⚠ 还需要在 **AWS Lightsail 控制台**开放 9100 端口 —— # 光配 nginx 没用,外面照样连不上(实测 9100 现在不通)。 listen 9100; listen [::]:9100; """ DEFAULT_SERVER = """ # ====================================================================== # 80 端口的默认站点 # ====================================================================== # # 为什么需要它:原来唯一的 80 站点是 `server_name yk.xxmxxs.top`。 # 用 IP 直接访问(`http://<服务器IP>/`)时 Host 不匹配, # nginx 就拿这个站点当 default server,把请求转给 relay —— # relay 不认这个 Host,返回 404。 # # **这很可能就是"感觉网站不稳定"的来源**:用域名是对的,用 IP 就 404, # 用户不知道区别,只会觉得"时好时坏"。 # # 现在显式指定一个默认站点:不管什么 Host,都送到同一套后端。 server { listen 80 default_server; listen [::]:80 default_server; server_name _; access_log /var/log/nginx/ykxmz_default_access.log; error_log /var/log/nginx/ykxmz_default_error.log; # 用 IP 访问时不要跳 https —— IP 没证书,跳过去浏览器会报警告, # 用户会以为网站坏了。直接给内容。 client_max_body_size 64m; server_tokens off; location / { proxy_pass http://127.0.0.1:13245; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; proxy_connect_timeout 30s; } } """ def main() -> int: print("=" * 62) print(" 服务器整理:删隧道 + 加 9100 + 修 IP 访问") print("=" * 62) print() # ---------------------------------------------------------------- 1. 删隧道 print("── 1. 删掉隧道残留 ──") r = run(r''' for u in lanremote-tunnel cloudflared lanremote-relay; do if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then echo " 处理 $u" sudo systemctl stop $u 2>/dev/null sudo systemctl disable $u 2>/dev/null sudo rm -f /etc/systemd/system/$u.service \ /lib/systemd/system/$u.service \ /etc/systemd/system/multi-user.target.wants/$u.service 2>/dev/null fi done # 还有没有别的相关残留 sudo find /etc/systemd/system /lib/systemd/system -maxdepth 2 \ -iname "*lanremote*" -o -iname "*cloudflared*" -o -iname "*tunnel*" 2>/dev/null \ | while read f; do echo " 删 $f"; sudo rm -f "$f"; done sudo systemctl daemon-reload echo " --- 之后还剩什么 ---" systemctl list-units --all --no-pager --plain 2>/dev/null \ | grep -iE 'lanremote|cloudflared|tunnel' | sed 's/^/ /' || echo " (干净了)" ''', timeout=180, quiet=True) print(r[1] if isinstance(r, tuple) else r) # ---------------------------------------------------------------- 2. 改 nginx print() print("── 2. nginx:加 9100 监听 + 80 默认站点 ──") r = run("sudo cat /etc/nginx/sites-available/ykxmz", timeout=90, quiet=True) conf = r[1] if isinstance(r, tuple) else str(r) if "listen 9100" in conf: print(" 9100 已经配过了") else: # 在 443 那个 server 块的 listen 后面插 9100 anchor = " listen 443 ssl; # managed by Certbot" if anchor not in conf: # 换一个可能的形式 import re m = re.search(r"\n(\s*)listen 443[^\n]*\n", conf) if not m: print(" ✗ 找不到 443 的 listen 行") return 1 anchor = m.group(0).strip() conf = conf.replace(anchor, anchor + "\n" + EXTRA_LISTEN.rstrip(), 1) conf = conf.rstrip() + "\n" + DEFAULT_SERVER tmp = ROOT / "_build" / "_nginx_ykxmz.conf" tmp.write_text(conf, encoding="utf-8", newline="\n") upload(str(tmp), "/tmp/ykxmz.conf.new") tmp.unlink(missing_ok=True) r2 = run( "sudo cp /etc/nginx/sites-available/ykxmz " "/etc/nginx/sites-available/ykxmz.bak.$(date +%s) && " "sudo mv /tmp/ykxmz.conf.new /etc/nginx/sites-available/ykxmz && " "sudo nginx -t 2>&1 | tail -3", timeout=180, quiet=True) out = r2[1] if isinstance(r2, tuple) else str(r2) print(" " + out.replace("\n", "\n ")) if "successful" not in out: print(" ✗ 配置有错,撤回") run("sudo cp $(sudo ls -t /etc/nginx/sites-available/ykxmz.bak.* " "| head -1) /etc/nginx/sites-available/ykxmz", timeout=90, quiet=True) return 1 print(" ✓ 已写入并备份") print() print("── 3. 重载 nginx ──") r = run("sudo systemctl reload nginx && sleep 1 && systemctl is-active nginx", timeout=120, quiet=True) print(" nginx: " + (r[1] if isinstance(r, tuple) else str(r)).strip()) # ---------------------------------------------------------------- 4. 复核 print() print("── 4. 复核 ──") r = run(r''' echo " --- 监听端口 ---" sudo ss -tlnp 2>/dev/null | grep -E ':(80|443|9100) ' | sed 's/^/ /' echo " --- 用 IP 访问(不带 Host)---" curl -s -o /dev/null -w " http://127.0.0.1/ -> %{http_code} %{size_download} 字节\n" --max-time 10 http://127.0.0.1/ curl -s -o /dev/null -w " http://127.0.0.1:9100/ -> %{http_code} %{size_download} 字节\n" --max-time 10 http://127.0.0.1:9100/ echo " --- 用域名访问 ---" curl -s -o /dev/null -w " https://yk.xxmxxs.top/ -> %{http_code} %{size_download} 字节\n" --max-time 15 https://yk.xxmxxs.top/ curl -s -o /dev/null -w " /v1/health -> %{http_code}\n" --max-time 15 https://yk.xxmxxs.top/v1/health ''', timeout=180, quiet=True) print(r[1] if isinstance(r, tuple) else r) print() print(" ⚠ 还需要你在 **AWS Lightsail 控制台**里开放 9100 端口:") print(" 实例 -> 联网 -> IPv4 防火墙 -> 添加规则 -> 自定义 -> TCP 9100") print(" 光配 nginx 没用,外面照样连不上。") return 0 if __name__ == "__main__": sys.exit(main())