#!/bin/bash # 建具名隧道(固定域名),替换掉会变地址的匿名隧道。 # # 前提:已经 cloudflared tunnel login 授权过(/root/.cloudflared/cert.pem 存在) # # 做的事: # 1. 建一个叫 lanremote 的隧道 # 2. 把 relay.<域名> 指到它 # 3. 写隧道配置(指向本机 8080) # 4. 改 systemd 服务,改成跑具名隧道 # 5. 重启并验证 # # 具名隧道的好处(对比匿名): # * 地址固定,不用每次重启都改客户端配置 # * 不受匿名隧道限流(实测匿名隧道经常 context deadline exceeded) # * Cloudflare 官方支持的生产用法 set -u DOMAIN="${1:-xxmxxs.top}" HOSTNAME_FULL="${2:-relay.${DOMAIN}}" TUNNEL_NAME=lanremote CF_DIR=/root/.cloudflared RELAY_DIR=/root/lanremote-relay CONF="$CF_DIR/config.yml" echo "============================================================" echo " 建具名隧道:$TUNNEL_NAME 域名:$HOSTNAME_FULL" echo "============================================================" echo # ---------- 0. 检查授权 ---------- echo "[0/6] 检查授权" if [ ! -f "$CF_DIR/cert.pem" ]; then echo " ✗ 还没有 cert.pem —— 请先在浏览器里完成授权" echo " 链接: $(cat /root/cf_login_url.txt 2>/dev/null)" exit 1 fi echo " ✓ cert.pem 存在" # ---------- 1. 建隧道 ---------- echo echo "[1/6] 创建隧道" EXISTING=$(cloudflared tunnel list 2>/dev/null | awk -v n="$TUNNEL_NAME" '$2 == n {print $1}') if [ -n "$EXISTING" ]; then TUNNEL_ID="$EXISTING" echo " 已存在,ID: $TUNNEL_ID" else OUT=$(cloudflared tunnel create "$TUNNEL_NAME" 2>&1) echo "$OUT" | sed 's/^/ /' TUNNEL_ID=$(echo "$OUT" | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | head -1) if [ -z "$TUNNEL_ID" ]; then TUNNEL_ID=$(cloudflared tunnel list 2>/dev/null | awk -v n="$TUNNEL_NAME" '$2 == n {print $1}') fi fi if [ -z "$TUNNEL_ID" ]; then echo " ✗ 拿不到隧道 ID" exit 1 fi echo " 隧道 ID: $TUNNEL_ID" # ---------- 2. 凭据文件 ---------- echo echo "[2/6] 检查凭据文件" CRED="$CF_DIR/${TUNNEL_ID}.json" if [ ! -f "$CRED" ]; then echo " ✗ 找不到凭据 $CRED" ls -la "$CF_DIR" exit 1 fi echo " ✓ $CRED" # ---------- 3. 配 DNS ---------- echo echo "[3/6] 把 $HOSTNAME_FULL 指向这个隧道" DNS_OUT=$(cloudflared tunnel route dns "$TUNNEL_NAME" "$HOSTNAME_FULL" 2>&1) echo "$DNS_OUT" | sed 's/^/ /' if echo "$DNS_OUT" | grep -qi 'already exists'; then echo " (DNS 记录已存在,跳过)" fi # ---------- 4. 写配置 ---------- echo echo "[4/6] 写隧道配置" cat > "$CONF" < /etc/systemd/system/lanremote-tunnel.service </dev/null || true pkill -f 'cloudflared tunnel --no-autoupdate' 2>/dev/null || true sleep 2 rm -f "$RELAY_DIR/tunnel.log" systemctl start lanremote-tunnel echo " 已启动" # ---------- 6. 验证 ---------- echo echo "[6/6] 等着并验证" # 一定要带 https:// —— public_url() 只认以 http 开头的, # 少了协议头 /url 接口会显示"还没有地址"。 echo "https://$HOSTNAME_FULL" > "$RELAY_DIR/public_url.txt" sleep 12 for i in 1 2 3 4 5 6; do CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 \ "https://$HOSTNAME_FULL/v1/health") if [ "$CODE" = "200" ]; then echo " 第 $i 次: ✓ 通了" break fi echo " 第 $i 次: HTTP $CODE(隧道可能还在建)" sleep 8 done echo echo " 服务状态: $(systemctl is-active lanremote-tunnel)" echo " 隧道日志尾部:" tail -5 "$RELAY_DIR/tunnel.log" | sed 's/^/ /' echo echo "============================================================" echo " 公网地址(固定,不会再变):" echo " https://$HOSTNAME_FULL" echo " 管理页:" echo " https://$HOSTNAME_FULL/?key=\$(cat $RELAY_DIR/data/admin_key.txt)" echo "============================================================" echo echo " 接下来在被控端执行一次:" echo " LanRemote-Agent.exe --relay https://$HOSTNAME_FULL" echo " 手表首页「中转设置」里填同一个地址。"