From 4ed2ae5a9d08f2610d8f1fe7a697ba1ad20944ad Mon Sep 17 00:00:00 2001 From: antcorp <527455294@qq.com> Date: Sun, 10 Aug 2025 11:25:14 +0800 Subject: [PATCH] Create cf-tunnel-mac --- dev/cf-tunnel-mac | 257 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 dev/cf-tunnel-mac diff --git a/dev/cf-tunnel-mac b/dev/cf-tunnel-mac new file mode 100644 index 0000000..c6c3bcf --- /dev/null +++ b/dev/cf-tunnel-mac @@ -0,0 +1,257 @@ +#!/bin/bash +# https://github.com/sky22333/shell +# macOS 兼容版本 - 修复了 BSD grep 和 launchctl 兼容性问题 + +set -e + +# === 颜色定义 === +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[1;34m' +NC='\033[0m' # 清除颜色 + +# 检测操作系统与架构 +OS_TYPE=$(uname -s) +ARCH=$(uname -m) +if [[ "$OS_TYPE" == "Darwin" ]]; then + # macOS 配置 + if [[ "$ARCH" == "arm64" ]]; then + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-darwin-arm64.tgz" + else + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-darwin-amd64.tgz" + fi + CLOUDFLARED_BIN="/usr/local/bin/cloudflared" + SERVICE_PATH="$HOME/Library/LaunchAgents/com.cloudflare.cloudflared.plist" + LOG_PATH="$HOME/Library/Logs/cloudflared.log" + USE_LAUNCHCTL=true +else + # Linux 配置 + if [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-linux-arm64" + else + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-linux-amd64" + fi + CLOUDFLARED_BIN="/usr/local/bin/cloudflared" + SERVICE_PATH="/etc/systemd/system/cloudflared-tunnel.service" + LOG_PATH="/var/log/cloudflared.log" + USE_LAUNCHCTL=false +fi + +# 检查 cloudflared 是否已存在 +if [[ -f "$CLOUDFLARED_BIN" ]]; then + echo -e "${GREEN}已存在文件,跳过下载。${NC}" +else + echo -e "${BLUE}正在下载 cloudflared...${NC}" + if [[ "$OS_TYPE" == "Darwin" ]]; then + # macOS: 下载 tgz 包并解压出可执行文件 + TMP_TGZ=$(mktemp /tmp/cloudflared.XXXXXX.tgz) + if ! curl -L "$CLOUDFLARED_URL" -o "$TMP_TGZ"; then + echo -e "${RED}下载失败,请检查网络连接或 URL。${NC}" + exit 1 + fi + tar -xzf "$TMP_TGZ" -C /tmp + # 解压后通常得到 cloudflared 可执行文件 + if [[ -f "/tmp/cloudflared" ]]; then + sudo mv /tmp/cloudflared "$CLOUDFLARED_BIN" + else + # 有些发布包会包含子目录 + FOUND=$(find /tmp -maxdepth 2 -type f -name cloudflared 2>/dev/null | head -n1) + if [[ -n "$FOUND" ]]; then + sudo mv "$FOUND" "$CLOUDFLARED_BIN" + else + echo -e "${RED}未能在压缩包中找到 cloudflared 可执行文件${NC}" + exit 1 + fi + fi + rm -f "$TMP_TGZ" + else + # Linux: 直接下载二进制 + if ! curl -L "$CLOUDFLARED_URL" -o "$CLOUDFLARED_BIN"; then + echo -e "${RED}下载失败,请检查网络连接或 URL。${NC}" + exit 1 + fi + fi + chmod +x "$CLOUDFLARED_BIN" +fi + +# 检查服务是否存在(根据系统选择 launchctl 或 systemd) +SERVICE_EXISTS=false +if [[ "$USE_LAUNCHCTL" == true ]]; then + if launchctl list | grep -q 'com.cloudflare.cloudflared'; then + SERVICE_EXISTS=true + echo -e "${YELLOW}已检测到 cloudflared launchctl 服务${NC}" + read -p "是否要卸载旧服务?(y/n): " UNINSTALL + if [[ "$UNINSTALL" == "y" || "$UNINSTALL" == "Y" ]]; then + echo -e "${BLUE}正在卸载旧服务...${NC}" + launchctl unload "$SERVICE_PATH" 2>/dev/null || true + rm -f "$SERVICE_PATH" + rm -f "$LOG_PATH" + SERVICE_EXISTS=false + echo -e "${GREEN}服务卸载完成${NC}" + else + echo -e "${YELLOW}将保留旧服务配置,仅修改穿透地址${NC}" + fi + fi +else + if sudo systemctl list-units --full --all | grep -q 'cloudflared-tunnel.service'; then + SERVICE_EXISTS=true + echo -e "${YELLOW}已检测到 cloudflared-tunnel systemd 服务${NC}" + read -p "是否要卸载旧服务?(y/n): " UNINSTALL + if [[ "$UNINSTALL" == "y" || "$UNINSTALL" == "Y" ]]; then + echo -e "${BLUE}正在卸载旧服务...${NC}" + sudo systemctl stop cloudflared-tunnel || true + sudo systemctl disable cloudflared-tunnel || true + sudo rm -f "$SERVICE_PATH" + sudo rm -f "$LOG_PATH" + sudo systemctl daemon-reload + SERVICE_EXISTS=false + echo -e "${GREEN}服务卸载完成${NC}" + else + echo -e "${YELLOW}将保留旧服务配置,仅修改穿透地址${NC}" + fi + fi +fi + +# 用户选择运行模式 +echo "" +echo -e "${YELLOW}请选择运行模式:${NC}" +echo "1) 临时运行(前台运行并显示临时访问域名)" +echo "2) 后台运行(自动配置后台服务并显示访问域名)" +read -p "请输入 1 或 2: " MODE + +# 输入内网地址 +read -p "请输入要穿透的本地地址(例如 127.0.0.1:8080): " LOCAL_ADDR + +if [[ "$MODE" == "1" ]]; then + echo -e "${BLUE}正在前台运行 cloudflared...${NC}" + + LOGFILE=$(mktemp) + # macOS 无 stdbuf,用 script 捕获输出(同时兼容 Linux) + if command -v stdbuf >/dev/null 2>&1; then + stdbuf -oL "$CLOUDFLARED_BIN" tunnel --url "$LOCAL_ADDR" 2>&1 | tee "$LOGFILE" & + else + "$CLOUDFLARED_BIN" tunnel --url "$LOCAL_ADDR" 2>&1 | tee "$LOGFILE" & + fi + PID=$! + + echo -e "${YELLOW}等待 cloudflared 输出访问域名...${NC}" + + for i in {1..30}; do + # BSD grep 无 -P,用 -E 实现扩展正则 + DOMAIN=$(grep -Eo 'https://[A-Za-z0-9-]+\.trycloudflare\.com' "$LOGFILE" | head -n1) + if [[ -n "$DOMAIN" ]]; then + echo "" + echo -e "${GREEN}成功获取公网临时访问域名:$DOMAIN${NC}" + echo "" + wait $PID + exit 0 + fi + sleep 1 + done + + echo -e "${RED}超时未能获取临时域名,日志保存在:$LOGFILE${NC}" + kill $PID 2>/dev/null || true + exit 1 + +elif [[ "$MODE" == "2" ]]; then + if [[ "$USE_LAUNCHCTL" == true ]]; then + echo -e "${BLUE}正在配置 launchctl 服务...${NC}" + mkdir -p "$(dirname "$SERVICE_PATH")" "$(dirname "$LOG_PATH")" + cat > "$SERVICE_PATH" < + + + + Label + com.cloudflare.cloudflared + ProgramArguments + + $CLOUDFLARED_BIN + tunnel + --url + $LOCAL_ADDR + + RunAtLoad + + StandardOutPath + $LOG_PATH + StandardErrorPath + $LOG_PATH + + +EOF + launchctl unload "$SERVICE_PATH" 2>/dev/null || true + launchctl load "$SERVICE_PATH" + launchctl start com.cloudflare.cloudflared || true + else + echo -e "${BLUE}正在配置 systemd 服务...${NC}" + + if [[ "$SERVICE_EXISTS" == false ]]; then + sudo bash -c "cat > $SERVICE_PATH" < $LOG_PATH" + sudo sed -i "s|ExecStart=.*|ExecStart=$CLOUDFLARED_BIN tunnel --url $LOCAL_ADDR|" "$SERVICE_PATH" + sudo systemctl daemon-reload + sudo systemctl restart cloudflared-tunnel + fi + fi + + echo -e "${GREEN}服务已启动,日志保存在 $LOG_PATH${NC}" + echo -e "${YELLOW}等待 cloudflared 输出访问域名...${NC}" + + # 等待日志文件创建 + for i in {1..10}; do + if [[ -f "$LOG_PATH" ]]; then + break + fi + sleep 1 + done + + # 如果日志文件仍不存在,尝试创建 + if [[ ! -f "$LOG_PATH" ]]; then + mkdir -p "$(dirname "$LOG_PATH")" + touch "$LOG_PATH" 2>/dev/null || true + fi + + for i in {1..30}; do + if [[ -f "$LOG_PATH" ]]; then + DOMAIN=$(grep -Eo 'https://[A-Za-z0-9-]+\.trycloudflare\.com' "$LOG_PATH" 2>/dev/null | head -n1) + if [[ -n "$DOMAIN" ]]; then + echo "" + echo -e "${GREEN}成功获取公网访问域名:$DOMAIN${NC}" + echo "" + exit 0 + fi + fi + sleep 1 + done + + echo -e "${RED}超时未能获取公网访问域名,请稍后手动查看:$LOG_PATH${NC}" + if [[ "$USE_LAUNCHCTL" == true ]]; then + echo -e "${YELLOW}您也可以使用以下命令查看服务状态:${NC}" + echo "launchctl list | grep cloudflared" + echo "tail -f $LOG_PATH" + fi + exit 1 + +else + echo -e "${RED}无效输入,请输入 1 或 2${NC}" + exit 1 +fi