From 73fba3ace3b1805c7f84a6b89ce291dc9bcfd810 Mon Sep 17 00:00:00 2001 From: fscarmen <62703343+fscarmen@users.noreply.github.com> Date: Sat, 13 Apr 2024 14:33:30 +0000 Subject: [PATCH] v1.2.0 Add Cloudflare Argo Tunnel. --- README.md | 55 ++-- sing-box.sh | 827 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 661 insertions(+), 221 deletions(-) diff --git a/README.md b/README.md index 8198b54..29a2d48 100644 --- a/README.md +++ b/README.md @@ -8,28 +8,31 @@ - [2.项目特点](README.md#2项目特点) - [3.Sing-box for VPS 运行脚本](README.md#3sing-box-for-vps-运行脚本) - [4.无交互极速安装](README.md#4无交互极速安装) -- [5.Vmess / Vless 方案设置任意端口回源以使用 cdn](README.md#5vmess--vless-方案设置任意端口回源以使用-cdn) -- [6.Docker 和 Docker compose 安装](README.md#6docker-和-docker-compose-安装) -- [7.Nekobox 设置 shadowTLS 方法](README.md#7nekobox-设置-shadowtls-方法) -- [8.主体目录文件及说明](README.md#8主体目录文件及说明) -- [9.鸣谢下列作者的文章和项目](README.md#9鸣谢下列作者的文章和项目) -- [10.免责声明](README.md#10免责声明) +- [5.Token Argo Tunnel 方案设置任意端口回源以使用 cdn](README.md#5token-argo-tunnel-方案设置任意端口回源以使用-cdn) +- [6.Vmess / Vless 方案设置任意端口回源以使用 cdn](README.md#6vmess--vless-方案设置任意端口回源以使用-cdn) +- [7.Docker 和 Docker compose 安装](README.md#7docker-和-docker-compose-安装) +- [8.Nekobox 设置 shadowTLS 方法](README.md#8nekobox-设置-shadowtls-方法) +- [9.主体目录文件及说明](README.md#9主体目录文件及说明) +- [10.鸣谢下列作者的文章和项目](README.md#10鸣谢下列作者的文章和项目) +- [11.免责声明](README.md#11免责声明) * * * ## 1.更新信息 -2024.04.01 sing-box + argo container version is newly launched, for details: https://github.com/fscarmen/sing-box/blob/main/README.md; sing-box 全家桶 + argo 容器版本全新上线,详细参考: https://github.com/fscarmen/sing-box/blob/main/README.md +2024.04.12 V1.2.0 1. Add Cloudflare Argo Tunnel, so that 10 protocols, including the transport mode of ws, no longer need to bring our own domain; 2. Cloudflare Argo Tunnel supports try, Json and Token methods. Use of [sb -t] online switching; 3. Cloudflare Argo Tunnel switch is [sb -a], and the Sing-box switch is changed from [sb -o] to [sb -s]; 4. If Json or Token Argo is used, the subscription address is the domain name; 5. For details: https://github.com/fscarmen/sing-box; 1. 增加 Cloudflare Argo Tunnel,让包括传输方式为ws在内的10个协议均不再需要自带域名; 2. Cloudflare Argo Tunnel 支持临时、Json 和 Token 方式,支持使用 [sb -t] 在线切换; 3. Cloudflare Argo Tunnel 开关为 [sb -a],Sing-box 开关从 [sb -o] 更换为 [sb -s]; 4. 若使用 Json 或者 Token 固定域名 Argo,则订阅地址则使用该域名; 5. 详细参考: https://github.com/fscarmen/sing-box -2024.03.27 v1.1.11 Add two non-interactive installation modes: 1. pass parameter; 2.kv file, for details: https://github.com/fscarmen/sing-box/blob/main/README.md; 增加两个的无交互安装模式: 1. 传参;2.kv 文件,详细参考: https://github.com/fscarmen/sing-box/blob/main/README.md - -2024.03.26 v1.1.10 Thanks to UUb for the official change of the compilation, dependencies jq, qrencode from apt installation to download the binary file, reduce the installation time of about 15 seconds, the implementation of the project's positioning of lightweight, as far as possible to install the least system dependencies; 感谢 UUb 兄弟的官改编译,依赖 jq, qrencode 从 apt 安装改为下载二进制文件,缩减安装时间约15秒,贯彻项目轻量化的定位,尽最大可能安装最少的系统依赖 - -2024.03.22 v1.1.9 1. In the Sing-box client, add the brutal field in the TCP protocol to make it effective; 2. Compatible with CentOS 7,8,9; 3. Remove default Github CDN; 1. 在 Sing-box 客户端,TCP 协议协议里加上 brutal 字段以生效; 2. 适配 CentOS 7,8,9; 3. 去掉默认的 Github 加速网 +2024.04.01 sing-box + argo container version is newly launched, for details: https://github.com/fscarmen/sing-box; sing-box 全家桶 + argo 容器版本全新上线,详细参考: https://github.com/fscarmen/sing-box
历史更新 history(点击即可展开或收起)
+>2024.03.27 v1.1.11 Add two non-interactive installation modes: 1. pass parameter; 2.kv file, for details: https://github.com/fscarmen/sing-box; 增加两个的无交互安装模式: 1. 传参;2.kv 文件,详细参考: https://github.com/fscarmen/sing-box +> +>2024.03.26 v1.1.10 Thanks to UUb for the official change of the compilation, dependencies jq, qrencode from apt installation to download the binary file, reduce the installation time of about 15 seconds, the implementation of the project's positioning of lightweight, as far as possible to install the least system dependencies; 感谢 UUb 兄弟的官改编译,依赖 jq, qrencode 从 apt 安装改为下载二进制文件,缩减安装时间约15秒,贯彻项目轻量化的定位,尽最大可能安装最少的系统依赖 +> +>2024.03.22 v1.1.9 1. In the Sing-box client, add the brutal field in the TCP protocol to make it effective; 2. Compatible with CentOS 7,8,9; 3. Remove default Github CDN; 1. 在 Sing-box 客户端,TCP 协议协议里加上 brutal 字段以生效; 2. 适配 CentOS 7,8,9; 3. 去掉默认的 Github 加速网 +> >2024.3.18 v1.1.8 Move nginx for subscription services to the systemd daemon, following sing-box startup and shutdown; 把用于订阅服务的 nginx 移到 systemd daemon,跟随 sing-box 启停 > >2024.3.13 v1.1.7 Subscription made optional, no nginx and qrcode installed if not needed; 在线订阅改为可选项,如不需要,不安装 nginx 和 qrcode @@ -71,10 +74,10 @@ ## 2.项目特点: * 一键部署多协议,可以单选、多选或全选 ShadowTLS v3 / XTLS Reality / Hysteria2 / Tuic V5 / ShadowSocks / Trojan / Vmess + ws / Vless + ws + tls / H2 Reality / gRPC Reality, 总有一款适合你 +* 所有协议均不需要域名,可选 Cloudflare Argo Tunnel 内网穿透以支持传统方式为 websocket 的协议 * 节点信息输出到 V2rayN / Clash Meta / 小火箭 / Nekobox / Sing-box (SFI, SFA, SFM),订阅自动适配客户端,一个订阅 url 走天下 * 自定义端口,适合有限开放端口的 nat 小鸡 * 内置 warp 链式代理解锁 chatGPT -* 不需要域名 ( vmess / vless 方案例外) * 智能判断操作系统: Ubuntu 、Debian 、CentOS 、Alpine 和 Arch Linux,请务必选择 LTS 系统 * 支持硬件结构类型: AMD 和 ARM,支持 IPv4 和 IPv6 * 无交互极速安排模式: 一个回车完成超 10 个协议的安装 @@ -99,7 +102,8 @@ sb | -u | Uninstall 卸载 | | -n | Export Nodes list 显示节点信息 | | -p | Change the nodes start port 更改节点的起始端口 | - | -o | Stop / Start the Sing-box service 停止/开启 Sing-box 服务 | + | -s | Stop / Start the Sing-box service 停止/开启 Sing-box 服务 | + | -a | Stop / Start the Argo Tunnel service 停止/开启 Argo Tunnel 服务 | | -v | Sync Argo Xray to the newest 同步 Argo Xray 到最新版本 | | -b | Upgrade kernel, turn on BBR, change Linux system 升级内核、安装BBR、DD脚本 | | -r | Add and remove protocols 添加和删除协议 | @@ -141,7 +145,15 @@ bash <(wget -qO- https://raw.githubusercontent.com/fscarmen/sing-box/main/sing-b | --NODE_NAME_CONFIRM | 节点名 | -## 5.Vmess / Vless 方案设置任意端口回源以使用 cdn +## 5.Token Argo Tunnel 方案设置任意端口回源以使用 cdn +详细教程: [群晖套件:Cloudflare Tunnel 内网穿透中文教程 支持DSM6、7](https://imnks.com/5984.html) + +image + +image + + +## 6.Vmess / Vless 方案设置任意端口回源以使用 cdn 举例子 IPv6: vmess [2a01:4f8:272:3ae6:100b:ee7a:ad2f:1]:10006 image @@ -152,7 +164,7 @@ bash <(wget -qO- https://raw.githubusercontent.com/fscarmen/sing-box/main/sing-b image -## 6.Docker 和 Docker compose 安装 +## 7.Docker 和 Docker compose 安装 ### 说明: * 支持三种 Argo 类型隧道: 临时 (不需要域名) / Json / Token @@ -278,7 +290,7 @@ services: | -e ARGO_AUTH | 否 | Argo 认证信息,可以是 Json 也可以是 Token,与 ARGO_DOMAIN 一并使用才能生效,不指定的话将使用临时隧道 | -## 7.Nekobox 设置 shadowTLS 方法 +## 8.Nekobox 设置 shadowTLS 方法 1. 复制脚本输出的两个 Neko links 进去 image @@ -290,7 +302,7 @@ services: image -## 8.主体目录文件及说明 +## 9.主体目录文件及说明 ``` /etc/sing-box/ # 项目主体目录 @@ -331,17 +343,20 @@ services: |-- language # 存放脚本语言文件,E 为英文,C 为中文 |-- list # 节点信息列表 |-- sing-box # sing-box 主程序 +|-- cloudflared # Argo tunnel 主程序 +|-- tunnel.json # Argo tunnel Json 信息文件 +|-- tunnel.yml # Argo tunnel 配置文件 |-- sb.sh # 快捷方式脚本文件 |-- jq # 命令行 json 处理器二进制文件 `-- qrencode # QR 码编码二进制文件 ``` -## 9.鸣谢下列作者的文章和项目: +## 10.鸣谢下列作者的文章和项目: 千歌 sing-box 模板: https://github.com/chika0801/sing-box-examples 瞎折腾 sing-box 模板: https://t.me/ztvps/100 -## 10.免责声明: +## 11.免责声明: * 本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 文字、数据及图片均有所属版权, 如转载须注明来源。 * 使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。 \ No newline at end of file diff --git a/sing-box.sh b/sing-box.sh index e67d6ce..ba84610 100644 --- a/sing-box.sh +++ b/sing-box.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # 当前脚本版本号 -VERSION='v1.1.11 (2024.04.01)' +VERSION='v1.2.0 (2024.04.12)' # 各变量默认值 GH_PROXY='' @@ -23,8 +23,8 @@ mkdir -p $TEMP_DIR E[0]="Language:\n 1. English (default) \n 2. 简体中文" C[0]="${E[0]}" -E[1]="sing-box + argo container version is newly launched, for details: https://github.com/fscarmen/sing-box/blob/main/README.md" -C[1]="sing-box 全家桶 + argo 容器版本全新上线,详细参考: https://github.com/fscarmen/sing-box/blob/main/README.md" +E[1]="1. Add Cloudflare Argo Tunnel, so that 10 protocols, including the transport mode of ws, no longer need to bring our own domain; 2. Cloudflare Argo Tunnel supports try, Json and Token methods. Use of [sb -t] online switching; 3. Cloudflare Argo Tunnel switch is [sb -a], and the Sing-box switch is changed from [sb -o] to [sb -s]; 4. If Json or Token Argo is used, the subscription address is the domain name; 5. For details: https://github.com/fscarmen/sing-box" +C[1]="1. 增加 Cloudflare Argo Tunnel,让包括传输方式为ws在内的10个协议均不再需要自带域名; 2. Cloudflare Argo Tunnel 支持临时、Json 和 Token 方式,支持使用 [sb -t] 在线切换; 3. Cloudflare Argo Tunnel 开关为 [sb -a],Sing-box 开关从 [sb -o] 更换为 [sb -s]; 4. 若使用 Json 或者 Token 固定域名 Argo,则订阅地址则使用该域名; 5. 详细参考: https://github.com/fscarmen/sing-box" E[2]="Downloading Sing-box. Please wait a seconds ..." C[2]="下载 Sing-box 中,请稍等 ..." E[3]="Input errors up to 5 times.The script is aborted." @@ -89,8 +89,8 @@ E[32]="Upgrade kernel, turn on BBR, change Linux system (sb -b)" C[32]="升级内核、安装BBR、DD脚本 (sb -b)" E[33]="Uninstall (sb -u)" C[33]="卸载 (sb -u)" -E[34]="Install Sing-box multi-protocol script" -C[34]="安装 Sing-box 协议全家桶脚本" +E[34]="Install Sing-box" +C[34]="安装 Sing-box" E[35]="Exit" C[35]="退出" E[36]="Please enter the correct number" @@ -135,16 +135,16 @@ E[55]="The script runs today: \$TODAY. Total: \$TOTAL" C[55]="脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL" E[56]="Process ID" C[56]="进程ID" -E[57]="Runtime" -C[57]="运行时长" +E[57]="" +C[57]="" E[58]="Memory Usage" C[58]="内存占用" E[59]="Install ArgoX scripts (argo + xray) [https://github.com/fscarmen/argox]" C[59]="安装 ArgoX 脚本 (argo + xray) [https://github.com/fscarmen/argox]" E[60]="The order of the selected protocols and ports is as follows:" C[60]="选择的协议及端口次序如下:" -E[61]="(DNS your own domain in Cloudflare is required.)" -C[61]="(必须在 Cloudflare 解析自有域名)" +E[61]="" +C[61]="" E[62]="Add / Remove protocols (sb -r)" C[62]="增加 / 删除协议 (sb -r)" E[63]="(1/3) Installed protocols." @@ -179,8 +179,8 @@ E[77]="With sing-box installed, the script exits." C[77]="已安装 sing-box ,脚本退出" E[78]="Parameter [ $ERROR_PARAMETER ] error, script exits." C[78]="[ $ERROR_PARAMETER ] 参数错误,脚本退出" -E[79]="\(3/6\) Output subscription QR code and http service, need to install nginx\\\n If not, please enter [n]\\\n If you need, please enter the port number of nginx used for subscription service. Must be \${MIN_PORT} - \${MAX_PORT} \(Default is: \${PORT_NGINX_DEFAULT}\):" -C[79]="\(3/6\) 输出订阅二维码和 http 服务,需要安装依赖 nginx\\\n 如不需要,请输入 [n]\\\n 如需要请输入用于订阅服务的 nginx 端口号,必须是 \${MIN_PORT} - \${MAX_PORT} \(默认为: \${PORT_NGINX_DEFAULT}\):" +E[79]="\(3/6\) Please enter the port number of nginx. Must be \${MIN_PORT} - \${MAX_PORT} \(Default is: \${PORT_NGINX_DEFAULT}\):" +C[79]="\(3/6\) 请输入 nginx 端口号,必须是 \${MIN_PORT} - \${MAX_PORT} \(默认为: \${PORT_NGINX_DEFAULT}\):" E[80]="subscribe" C[80]="订阅" E[81]="Adaptive Clash / V2rayN / NekoBox / ShadowRocket / SFI / SFA / SFM Clients" @@ -191,6 +191,26 @@ E[83]="To uninstall Nginx press [y], it is not uninstalled by default:" C[83]="如要卸载 Nginx 请按 [y],默认不卸载:" E[84]="Set SElinux: enforcing --> disabled" C[84]="设置 SElinux: enforcing --> disabled" +E[85]="Please input Argo Token or Json ( User can easily obtain the json at https://fscarmen.cloudflare.now.cc ):" +C[85]="请输入 Argo Token 或者 Json ( 用户通过以下网站轻松获取 json: https://fscarmen.cloudflare.now.cc ):" +E[86]="Argo authentication message does not match the rules, neither Token nor Json, script exits. Feedback:[https://github.com/fscarmen/sba/issues]" +C[86]="Argo 认证信息不符合规则,既不是 Token,也是不是 Json,脚本退出,问题反馈:[https://github.com/fscarmen/sba/issues]" +E[87]="Please input the Argo domain (Default is temporary domain if left blank):" +C[87]="请输入 Argo 域名 (如果没有,可以跳过以使用 Argo 临时域名):" +E[88]="Please input the Argo domain (cannot be empty):" +C[88]="请输入 Argo 域名 (不能为空):" +E[89]="( Additional dependencies: nginx )" +C[89]="( 额外依赖: nginx )" +E[90]="Argo tunnel is: \$ARGO_TYPE\\\n The domain is: \$ARGO_DOMAIN" +C[90]="Argo 隧道类型为: \$ARGO_TYPE\\\n 域名是: \$ARGO_DOMAIN" +E[91]="Argo tunnel type:\n 1. Try\n 2. Token or Json" +C[91]="Argo 隧道类型:\n 1. Try\n 2. Token 或者 Json" +E[92]="Change the Argo tunnel (sb -t)" +C[92]="更换 Argo 隧道 (sb -t)" +E[93]="Can't get the temporary tunnel domain, script exits. Feedback:[https://github.com/fscarmen/sing-box/issues]" +C[93]="获取不到临时隧道的域名,脚本退出,问题反馈:[https://github.com/fscarmen/sing-box/issues]" +E[94]="Please bind \[\${ARGO_DOMAIN}] tunnel TYPE to HTTP and URL to \[\localhost:\${PORT_NGINX}] in Cloudflare." +C[94]="请在 Cloudflare 绑定 \[\${ARGO_DOMAIN}] 隧道 TYPE 为 HTTP,URL 为 \[\localhost:\${PORT_NGINX}]" # 自定义字体彩色,read 函数 warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 @@ -239,7 +259,7 @@ select_language() { } # 字母与数字的 ASCII 码值转换 -asc(){ +asc() { if [[ "$1" = [a-z] ]]; then [ "$2" = '++' ] && printf "\\$(printf '%03o' "$[ $(printf "%d" "'$1'") + 1 ]")" || printf "%d" "'$1'" else @@ -249,28 +269,26 @@ asc(){ input_cdn() { # 提供网上热心网友的anycast域名 - if [[ -z "$CDN" && -n "$VMESS_HOST_DOMAIN$VLESS_HOST_DOMAIN" ]]; then - echo "" - for c in "${!CDN_DOMAIN[@]}"; do hint " $[c+1]. ${CDN_DOMAIN[c]} "; done + echo "" + for c in "${!CDN_DOMAIN[@]}"; do + hint " $[c+1]. ${CDN_DOMAIN[c]} " + done - reading "\n $(text 53) " CUSTOM_CDN - case "$CUSTOM_CDN" in - [1-${#CDN_DOMAIN[@]}] ) - CDN="${CDN_DOMAIN[$((CUSTOM_CDN-1))]}" - ;; - ?????* ) - CDN="$CUSTOM_CDN" - ;; - * ) - CDN="${CDN_DOMAIN[0]}" - esac - fi + reading "\n $(text 53) " CUSTOM_CDN + case "$CUSTOM_CDN" in + [1-${#CDN_DOMAIN[@]}] ) + CDN="${CDN_DOMAIN[$((CUSTOM_CDN-1))]}" + ;; + ?????* ) + CDN="$CUSTOM_CDN" + ;; + * ) + CDN="${CDN_DOMAIN[0]}" + esac } -# | 选择输出模式 | 订阅 二维码输出 | nginx 输出 | 额外依赖 | -# | mode 1 | X | X | - | -# | mode 2 | √ | √ | nginx | -enter_export_mode() { +# 输入 Nginx 服务端口 +input_nginx_port() { local NUM=$1 local PORT_ERROR_TIME=6 # 生成 1000 - 65535 随机默认端口数 @@ -284,35 +302,129 @@ enter_export_mode() { [ -z "$PORT_NGINX" ] && reading "\n $(text 79) " PORT_NGINX fi PORT_NGINX=${PORT_NGINX:-"$PORT_NGINX_DEFAULT"} - if [ "${PORT_NGINX,,}" = 'n' ]; then - EXPORT_MODE=1 - break - elif [[ "$PORT_NGINX" =~ ^[1-9][0-9]{1,4}$ && "$PORT_NGINX" -ge "$MIN_PORT" && "$PORT_NGINX" -le "$MAX_PORT" ]]; then - EXPORT_MODE=2 + if [[ "$PORT_NGINX" =~ ^[1-9][0-9]{1,4}$ && "$PORT_NGINX" -ge "$MIN_PORT" && "$PORT_NGINX" -le "$MAX_PORT" ]]; then ss -nltup | grep -q ":$PORT_NGINX" && warning "\n $(text 44) \n" || break fi done } +# 输入 Argo 域名和认证信息 +input_argo_auth() { + local IS_CHANGE_ARGO=$1 + [ -n "$IS_CHANGE_ARGO" ] && local EMPTY_ERROR_TIME=5 + local DOMAIN_ERROR_TIME=5 + + # 处理可能输入的错误,去掉开头和结尾的空格,去掉最后的 : + if [ "$IS_CHANGE_ARGO" = 'is_change_argo' ]; then + until [ -n "$ARGO_DOMAIN" ]; do + (( EMPTY_ERROR_TIME-- )) || true + [ "$EMPTY_ERROR_TIME" = 0 ] && error "\n $(text 3) \n" + reading "\n $(text 88) " ARGO_DOMAIN + [ -n "$IS_CHANGE_ARGO" ] && ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN") + done + else + [ -z "$ARGO_DOMAIN" ] && reading "\n $(text 87) " ARGO_DOMAIN + ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN") + fi + + if [ -z "$ARGO_DOMAIN" ]; then + ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto --no-autoupdate --url http://localhost:$PORT_NGINX" + elif [[ -n "$ARGO_DOMAIN" && -z "$ARGO_AUTH" ]]; then + until [[ "$ARGO_AUTH" =~ TunnelSecret || "$ARGO_AUTH" =~ ^[A-Z0-9a-z=]{120,250}$ || "$ARGO_AUTH" =~ .*cloudflared.*service[[:space:]]+install[[:space:]]+[A-Z0-9a-z=]{1,100} ]]; do + (( DOMAIN_ERROR_TIME-- )) || true + [ "$DOMAIN_ERROR_TIME" != 0 ] && reading "\n $(text 85) " ARGO_AUTH || error "\n $(text 3) \n" + if [[ "$ARGO_AUTH" =~ TunnelSecret ]]; then + ARGO_JSON=${ARGO_AUTH//[ ]/} + [ "$IS_CHANGE_ARGO" = 'is_change_argo' ] && export_argo_json_file $WORK_DIR || export_argo_json_file $TEMP_DIR + ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto --config $WORK_DIR/tunnel.yml run" + elif [[ "$ARGO_AUTH" =~ ^[A-Z0-9a-z=]{120,250}$ ]]; then + ARGO_TOKEN=$ARGO_AUTH + ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto run --token ${ARGO_TOKEN}" + elif [[ "$ARGO_AUTH" =~ .*cloudflared.*service[[:space:]]+install[[:space:]]+[A-Z0-9a-z=]{1,100} ]]; then + ARGO_TOKEN=$(awk -F ' ' '{print $NF}' <<< "$ARGO_AUTH") + ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto run --token ${ARGO_TOKEN}" + else + warning "\n $(text 86) \n" + fi + done + fi +} + +# 更换 Argo 隧道类型 +change_argo() { + check_install + [[ ${STATUS[1]} = "$(text 26)" ]] && error " $(text 39) " + + case $(grep "ExecStart=" /etc/systemd/system/argo.service) in + *--config* ) + ARGO_TYPE='Json' + ;; + *--token* ) + ARGO_TYPE='Token' + ;; + * ) + ARGO_TYPE='Try' + cmd_systemctl enable argo && sleep 2 && [ "$(systemctl is-active argo)" = 'active' ] && fetch_quicktunnel_domain + esac + + fetch_nodes_value + hint "\n $(text 90) \n" + unset ARGO_DOMAIN + hint " $(text 91) \n" && reading " $(text 24) " CHANGE_TO + case "$CHANGE_TO" in + 1 ) + cmd_systemctl disable argo + [ -s $WORK_DIR/tunnel.json ] && rm -f $WORK_DIR/tunnel.{json,yml} + sed -i "s@ExecStart=.*@ExecStart=$WORK_DIR/cloudflared tunnel --edge-ip-version auto --no-autoupdate --url http://localhost:$PORT_NGINX@g" /etc/systemd/system/argo.service + ;; + 2 ) + [ -s $WORK_DIR/tunnel.json ] && rm -f $WORK_DIR/tunnel.{json,yml} + input_argo_auth is_change_argo + cmd_systemctl disable argo + if [ -n "$ARGO_TOKEN" ]; then + sed -i "s@ExecStart=.*@ExecStart=$WORK_DIR/cloudflared tunnel --edge-ip-version auto run --token ${ARGO_TOKEN}@g" /etc/systemd/system/argo.service + elif [ -n "$ARGO_JSON" ]; then + sed -i "s@ExecStart=.*@ExecStart=$WORK_DIR/cloudflared tunnel --edge-ip-version auto --config $WORK_DIR/tunnel.yml run@g" /etc/systemd/system/argo.service + fi + [ -s $WORK_DIR/conf/17_${NODE_TAG[6]}_inbounds.json ] && sed -i "s/VMESS_HOST_DOMAIN.*/VMESS_HOST_DOMAIN\": \"$ARGO_DOMAIN\"/" $WORK_DIR/conf/17_${NODE_TAG[6]}_inbounds.json + [ -s $WORK_DIR/conf/18_${NODE_TAG[7]}_inbounds.json ] && sed -i "s/\"server_name\":.*/\"server_name\": \"$ARGO_DOMAIN\",/" $WORK_DIR/conf/18_${NODE_TAG[7]}_inbounds.json + ;; + * ) + exit 0 + esac + + cmd_systemctl enable argo + fetch_nodes_value + export_nginx_conf_file + export_list +} + check_root() { [ "$(id -u)" != 0 ] && error "\n $(text 43) \n" } # 判断处理器架构 check_arch() { - case $(uname -m) in - aarch64|arm64 ) SING_BOX_ARCH=arm64; JQ_ARCH=arm64; QRENCODE_ARCH=arm64 ;; - x86_64|amd64 ) [[ "$(awk -F ':' '/flags/{print $2; exit}' /proc/cpuinfo)" =~ avx2 ]] && SING_BOX_ARCH=amd64v3 || SING_BOX_ARCH=amd64; JQ_ARCH=amd64; QRENCODE_ARCH=amd64 ;; - armv7l ) SING_BOX_ARCH=armv7; JQ_ARCH=armhf; QRENCODE_ARCH=arm ;; - * ) error " $(text 25) " + case "$(uname -m)" in + aarch64|arm64 ) + SING_BOX_ARCH=arm64; JQ_ARCH=arm64; QRENCODE_ARCH=arm64; ARGO_ARCH=arm64 + ;; + x86_64|amd64 ) + [[ "$(awk -F ':' '/flags/{print $2; exit}' /proc/cpuinfo)" =~ avx2 ]] && SING_BOX_ARCH=amd64v3 || SING_BOX_ARCH=amd64; JQ_ARCH=amd64; QRENCODE_ARCH=amd64; ARGO_ARCH=amd64 + ;; + armv7l ) + SING_BOX_ARCH=armv7; JQ_ARCH=armhf; QRENCODE_ARCH=arm; ARGO_ARCH=amd64 + ;; + * ) + error " $(text 25) " esac } -# 查安装及运行状态;状态码: 26 未安装, 27 已安装未运行, 28 运行中 +# 查安装及运行状态,下标0: sing-box,下标1: argo,下标2:docker;状态码: 26 未安装, 27 已安装未运行, 28 运行中 check_install() { - [ -s $WORK_DIR/nginx.conf ] && IS_NGINX=is_nginx || IS_NGINX=no_nginx - STATUS=$(text 26) && [ -s /etc/systemd/system/sing-box.service ] && STATUS=$(text 27) && [ "$(systemctl is-active sing-box)" = 'active' ] && STATUS=$(text 28) - if [[ $STATUS = "$(text 26)" ]] && [ ! -s $WORK_DIR/sing-box ]; then + [[ "$IS_SUB" = 'is_sub' || -s $WORK_DIR/subscribe/qr ]] && IS_SUB=is_sub || IS_SUB=no_sub + STATUS[0]=$(text 26) && [ -s /etc/systemd/system/sing-box.service ] && STATUS[0]=$(text 27) && [ "$(systemctl is-active sing-box)" = 'active' ] && STATUS[0]=$(text 28) + if [ "${STATUS[0]}" = "$(text 26)" ] && [ ! -s $WORK_DIR/sing-box ]; then { local VERSION_LATEST=$(wget --no-check-certificate -qO- "https://api.github.com/repos/SagerNet/sing-box/releases" | awk -F '["v-]' '/tag_name/{print $5}' | sort -r | sed -n '1p') local ONLINE=$(wget --no-check-certificate -qO- "https://api.github.com/repos/SagerNet/sing-box/releases" | awk -F '["v]' -v var="tag_name.*$VERSION_LATEST" '$0 ~ var {print $5; exit}') @@ -323,11 +435,24 @@ check_install() { wget --no-check-certificate --continue -qO $TEMP_DIR/qrencode https://github.com/fscarmen/client_template/raw/main/qrencode-go/qrencode-go-linux-$QRENCODE_ARCH >/dev/null 2>&1 && chmod +x $TEMP_DIR/qrencode >/dev/null 2>&1 }& fi + + STATUS[1]=$(text 26) && IS_ARGO=no_argo && [ -s /etc/systemd/system/argo.service ] && IS_ARGO=is_argo && STATUS[1]=$(text 27) && [ "$(systemctl is-active argo)" = 'active' ] && STATUS[1]=$(text 28) + if [ -s /etc/systemd/system/argo.service ]; then + local ARGO_CONTENT=$(cat /etc/systemd/system/argo.service) + if grep -q '\--token' <<< "$ARGO_CONTENT"; then + ARGO_TYPE=is_token_argo + elif grep -q '\--config' <<< "$ARGO_CONTENT"; then + ARGO_TYPE=is_json_argo + elif grep -q '\--url' <<< "$ARGO_CONTENT"; then + ARGO_TYPE=is_quicktunnel_argo + fi + fi + [[ "${STATUS[1]}" = "$(text 26)" ]] && [ ! -s $WORK_DIR/cloudflared ] && { wget --no-check-certificate -qO $TEMP_DIR/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-$ARGO_ARCH >/dev/null 2>&1 && chmod +x $TEMP_DIR/cloudflared >/dev/null 2>&1; }& } # 检测 sing-box 的状态 -check_sing-box_status(){ - case "$STATUS" in +check_sing-box_status() { + case "${STATUS[0]}" in "$(text 26)" ) error "\n Sing-box $(text 28) $(text 38) \n" ;; @@ -339,6 +464,21 @@ check_sing-box_status(){ esac } +# 检测 Argo 的状态 +check_argo_status() { + case "${STATUS[1]}" in + "$(text 26)" ) + error "\n Argo $(text 28) $(text 38) \n" + ;; + "$(text 27)" ) + cmd_systemctl enable argo + [ "$(systemctl is-active argo)" = 'active' ] && info "\n Argo $(text 28) $(text 37) \n" || error "\n Argo $(text 28) $(text 38) \n" + ;; + "$(text 28)" ) + info "\n Argo $(text 28) $(text 37) \n" + esac +} + # 为了适配 alpine,定义 cmd_systemctl 的函数 cmd_systemctl() { local ENABLE_DISABLE=$1 @@ -355,18 +495,18 @@ EOF rc-update add local >/dev/null 2>&1 elif [ "$IS_CENTOS" = 'CentOS7' ]; then systemctl enable --now $APP - [ "$IS_NGINX" = 'is_nginx' ] && $(type -p nginx) -c $WORK_DIR/nginx.conf + [ "$APP" = 'sing-box' ] && [[ "${IS_SUB}" = 'is_sub' || "${IS_ARGO}" = 'is_argo' ]] && $(type -p nginx) -c $WORK_DIR/nginx.conf else systemctl enable --now $APP fi elif [ "$ENABLE_DISABLE" = 'disable' ]; then if [ "$SYSTEM" = 'Alpine' ]; then systemctl stop $APP - [ "$IS_NGINX" = 'is_nginx' ] && ss -nltp | grep $(awk '/listen/{print $2; exit}' $WORK_DIR/nginx.conf) | tr ',' '\n' | awk -F '=' '/pid/{print $2}' | sort -u | xargs kill -15 >/dev/null 2>&1 + [ "$APP" = 'sing-box' ] && [[ "${IS_SUB}" = 'is_sub' || "${IS_ARGO}" = 'is_argo' ]] && ss -nltp | grep $(awk '/listen/{print $2; exit}' $WORK_DIR/nginx.conf) | tr ',' '\n' | awk -F '=' '/pid/{print $2}' | sort -u | xargs kill -15 >/dev/null 2>&1 rm -f /etc/local.d/$APP.start elif [ "$IS_CENTOS" = 'CentOS7' ]; then systemctl disable --now $APP - [ "$IS_NGINX" = 'is_nginx' ] && ss -nltp | grep $(awk '/listen/{print $2; exit}' $WORK_DIR/nginx.conf) | tr ',' '\n' | awk -F '=' '/pid/{print $2}' | sort -u | xargs kill -15 >/dev/null 2>&1 + [ "$APP" = 'sing-box' ] && [[ "${IS_SUB}" = 'is_sub' || "${IS_ARGO}" = 'is_argo' ]] && ss -nltp | grep $(awk '/listen/{print $2; exit}' $WORK_DIR/nginx.conf) | tr ',' '\n' | awk -F '=' '/pid/{print $2}' | sort -u | xargs kill -15 >/dev/null 2>&1 else systemctl disable --now $APP fi @@ -431,7 +571,7 @@ check_system_ip() { } # 输入起始 port 函数 -enter_start_port() { +input_start_port() { local NUM=$1 local PORT_ERROR_TIME=6 while true; do @@ -487,7 +627,7 @@ sing-box_variables() { if [ -z "$CHOOSE_PROTOCOLS" ]; then hint "\n $(text 49) " for e in "${!PROTOCOL_LIST[@]}"; do - [[ "$e" =~ '6'|'7' ]] && hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} $(text 61) " || hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} " + [[ "$e" =~ '6'|'7' ]] && hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} " || hint " $(asc $[e+98]). ${PROTOCOL_LIST[e]} " done reading "\n $(text 24) " CHOOSE_PROTOCOLS fi @@ -501,11 +641,11 @@ sing-box_variables() { for w in "${!INSTALL_PROTOCOLS[@]}"; do [ "$w" -ge 9 ] && hint " $[w+1]. ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} " || hint " $[w+1] . ${PROTOCOL_LIST[$(($(asc ${INSTALL_PROTOCOLS[w]}) - 98))]} " done - enter_start_port ${#INSTALL_PROTOCOLS[@]} + input_start_port ${#INSTALL_PROTOCOLS[@]} fi # 输出模式选择,输入用于订阅的 Nginx 服务端口号, 后台根据选择安装依赖 - enter_export_mode + [[ "$IS_SUB" = 'is_sub' || "$IS_ARGO" = 'is_argo' ]] && input_nginx_port # 输入服务器 IP,默认为检测到的服务器 IP,如果全部为空,则提示并退出脚本 [ -z "$SERVER_IP" ] && reading "\n $(text 10) " SERVER_IP @@ -514,23 +654,33 @@ sing-box_variables() { # 如选择有 h. vmess + ws 或 i. vless + ws 时,先检测是否有支持的 http 端口可用,如有则要求输入域名和 cdn if [[ "${INSTALL_PROTOCOLS[@]}" =~ 'h' ]]; then - local DOMAIN_ERROR_TIME=5 - until [ -n "$VMESS_HOST_DOMAIN" ]; do - (( DOMAIN_ERROR_TIME-- )) || true - [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VMESS && reading "\n $(text 50) " VMESS_HOST_DOMAIN || error "\n $(text 3) \n" - done + if [ "$IS_ARGO" = 'is_argo' ]; then + [ "$ARGO_READY" != 'argo_ready' ] && input_argo_auth + local ARGO_READY=argo_ready + else + local DOMAIN_ERROR_TIME=5 + until [ -n "$VMESS_HOST_DOMAIN" ]; do + (( DOMAIN_ERROR_TIME-- )) || true + [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VMESS && reading "\n $(text 50) " VMESS_HOST_DOMAIN || error "\n $(text 3) \n" + done + fi fi if [[ "${INSTALL_PROTOCOLS[@]}" =~ 'i' ]]; then - local DOMAIN_ERROR_TIME=5 - until [ -n "$VLESS_HOST_DOMAIN" ]; do - (( DOMAIN_ERROR_TIME-- )) || true - [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VLESS && reading "\n $(text 50) " VLESS_HOST_DOMAIN || error "\n $(text 3) \n" - done + if [ "$IS_ARGO" = 'is_argo' ]; then + [ "$ARGO_READY" != 'argo_ready' ] && input_argo_auth + local ARGO_READY=argo_ready + else + local DOMAIN_ERROR_TIME=5 + until [ -n "$VLESS_HOST_DOMAIN" ]; do + (( DOMAIN_ERROR_TIME-- )) || true + [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VLESS && reading "\n $(text 50) " VLESS_HOST_DOMAIN || error "\n $(text 3) \n" + done + fi fi # 选择或者输入 cdn - input_cdn + [[ -z "$CDN" && -n "${VMESS_HOST_DOMAIN}${VLESS_HOST_DOMAIN}${ARGO_READY}" ]] && input_cdn # 输入 UUID ,错误超过 5 次将会退出 UUID_DEFAULT=$(cat /proc/sys/kernel/random/uuid) @@ -595,12 +745,29 @@ check_dependencies() { check_nginx() { if [ ! $(type -p nginx) ]; then info "\n $(text 7) nginx \n" + ${PACKAGE_UPDATE[int]} >/dev/null 2>&1 ${PACKAGE_INSTALL[int]} nginx >/dev/null 2>&1 # 如果新安装的 Nginx ,先停掉服务 systemctl disable --now nginx >/dev/null 2>&1 fi } +# Json 生成两个配置文件 +export_argo_json_file() { + local FILE_PATH=$1 + [[ -z "$PORT_NGINX" && -s $WORK_DIR/nginx.conf ]] && local PORT_NGINX=$(awk '/listen/{print $2; exit}' $WORK_DIR/nginx.conf) + [ ! -s $FILE_PATH/tunnel.json ] && echo $ARGO_JSON > $FILE_PATH/tunnel.json + [ ! -s $FILE_PATH/tunnel.yml ] && cat > $FILE_PATH/tunnel.yml << EOF +tunnel: $(awk -F '"' '{print $12}' <<< "$ARGO_JSON") +credentials-file: $WORK_DIR/tunnel.json + +ingress: + - hostname: ${ARGO_DOMAIN} + service: http://localhost:${PORT_NGINX} + - service: http_status:404 +EOF +} + # 生成100年的自签证书 ssl_certificate() { mkdir -p $WORK_DIR/cert @@ -617,9 +784,8 @@ check_firewall_configuration() { } # Nginx 配置文件 -json_nginx() { - cat > $WORK_DIR/nginx.conf << EOF -user root; +export_nginx_conf_file() { + NGINX_CONF="user root; worker_processes auto; error_log /dev/null; @@ -629,8 +795,9 @@ events { worker_connections 1024; } - http { +" + [ "$IS_SUB" = 'is_sub' ] && NGINX_CONF+=" map \$http_user_agent \$path1 { default /; # 默认路径 ~*v2rayN /v2rayn; # 匹配 V2rayN 客户端 @@ -649,15 +816,18 @@ http { ~*ShadowRocket /shadowrocket; # 匹配 ShadowRocket 客户端 ~*SFM|SFI|SFA /sing-box2; # 匹配 Sing-box pc 和 phone 客户端 # ~*Chrome|Firefox|Mozilla /; # 添加更多的分流规则 - } + }" + [ "$IS_SUB" = 'is_sub' ] && NGINX_CONF+=" include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" ' '\$status \$body_bytes_sent "\$http_referer" ' '"\$http_user_agent" "\$http_x_forwarded_for"'; +" + NGINX_CONF+=" access_log /dev/null; sendfile on; @@ -681,7 +851,44 @@ http { # ssl_session_tickets on; # ssl_stapling off; # ssl_stapling_verify off; +" + [[ -n "$PORT_VMESS_WS" && "$IS_ARGO" = 'is_argo' ]] && NGINX_CONF+=" + # 反代 sing-box vmess websocket + location /${UUID_CONFIRM}-vmess { + if (\$http_upgrade != "websocket") { + return 404; + } + proxy_pass http://127.0.0.1:${PORT_VMESS_WS}; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header Host \$host; + proxy_redirect off; + } +" + + [[ -n "$PORT_VLESS_WS" && "$IS_ARGO" = 'is_argo' ]] && NGINX_CONF+=" + # 反代 sing-box vless websocket + location /${UUID_CONFIRM}-vless { + if (\$http_upgrade != "websocket") { + return 404; + } + proxy_http_version 1.1; + proxy_pass https://127.0.0.1:${PORT_VLESS_WS}; + proxy_ssl_protocols TLSv1.3; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header Host \$host; + proxy_redirect off; + } +" + + [ "$IS_SUB" = 'is_sub' ] && NGINX_CONF+=" # 来自 /auto2 的分流 location ~ ^/${UUID_CONFIRM}/auto2 { default_type 'text/plain; charset=utf-8'; @@ -700,9 +907,12 @@ http { default_type 'text/plain; charset=utf-8'; alias ${WORK_DIR}/subscribe/\$1; } - } -} -EOF +" + + NGINX_CONF+=" } +}" + + echo "$NGINX_CONF" > $WORK_DIR/nginx.conf } # 生成 sing-box 配置文件 @@ -1095,7 +1305,7 @@ EOF NODE_NAME[17]=${NODE_NAME[17]:-"$NODE_NAME_CONFIRM"} && UUID[17]=${UUID[17]:-"$UUID_CONFIRM"} && WS_SERVER_IP[17]=${WS_SERVER_IP[17]:-"$SERVER_IP"} && CDN[17]=${CDN[17]:-"$CDN"} && VMESS_WS_PATH=${VMESS_WS_PATH:-"${UUID[17]}-vmess"} cat > $WORK_DIR/conf/17_${NODE_TAG[6]}_inbounds.json << EOF // "WS_SERVER_IP_SHOW": "${WS_SERVER_IP[17]}" -// "VMESS_HOST_DOMAIN": "$VMESS_HOST_DOMAIN" +// "VMESS_HOST_DOMAIN": "${VMESS_HOST_DOMAIN}${ARGO_DOMAIN}" // "CDN": "${CDN[17]}" { "inbounds":[ @@ -1168,7 +1378,7 @@ EOF }, "tls":{ "enabled":true, - "server_name":"$VLESS_HOST_DOMAIN", + "server_name":"${VLESS_HOST_DOMAIN}${ARGO_DOMAIN}", "min_version":"1.3", "max_version":"1.3", "certificate_path":"${WORK_DIR}/cert/cert.pem", @@ -1313,7 +1523,7 @@ NoNewPrivileges=yes TimeoutStartSec=0 WorkingDirectory=$WORK_DIR " - [[ "$EXPORT_MODE" = '2' && "$IS_CENTOS" != 'CentOS7' ]] && SING_BOX_SERVICE+="ExecStartPre=$(type -p nginx) -c $WORK_DIR/nginx.conf + [[ -n "$PORT_NGINX" && "$IS_CENTOS" != 'CentOS7' ]] && SING_BOX_SERVICE+="ExecStartPre=$(type -p nginx) -c $WORK_DIR/nginx.conf " SING_BOX_SERVICE+="ExecStart=$WORK_DIR/sing-box run -C $WORK_DIR/conf/ ExecReload=/bin/kill -HUP \$MAINPID @@ -1327,17 +1537,40 @@ WantedBy=multi-user.target" echo "$SING_BOX_SERVICE" > /etc/systemd/system/sing-box.service } +# Argo 生成守护进程文件 +argo_systemd() { + cat > /etc/systemd/system/argo.service << EOF +[Unit] +Description=Cloudflare Tunnel +After=network.target + +[Service] +Type=simple +NoNewPrivileges=yes +TimeoutStartSec=0 +ExecStart=$ARGO_RUNS +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=multi-user.target +EOF +} + # 获取原有各协议的参数,先清空所有的 key-value fetch_nodes_value() { - unset FILE NODE_NAME PORT_XTLS_REALITY UUID TLS_SERVER REALITY_PRIVATE REALITY_PUBLIC PORT_HYSTERIA2 OBFS PORT_TUIC TUIC_PASSWORD TUIC_CONGESTION_CONTROL PORT_SHADOWTLS SHADOWTLS_PASSWORD SHADOWSOCKS_METHOD PORT_SHADOWSOCKS PORT_TROJAN TROJAN_PASSWORD PORT_VMESS_WS VMESS_WS_PATH WS_SERVER_IP WS_SERVER_IP_SHOW VMESS_HOST_DOMAIN CDN PORT_VLESS_WS VLESS_WS_PATH VLESS_HOST_DOMAIN PORT_H2_REALITY PORT_GRPC_REALITY + unset FILE NODE_NAME PORT_XTLS_REALITY UUID TLS_SERVER REALITY_PRIVATE REALITY_PUBLIC PORT_HYSTERIA2 OBFS PORT_TUIC TUIC_PASSWORD TUIC_CONGESTION_CONTROL PORT_SHADOWTLS SHADOWTLS_PASSWORD SHADOWSOCKS_METHOD PORT_SHADOWSOCKS PORT_TROJAN TROJAN_PASSWORD PORT_VMESS_WS VMESS_WS_PATH WS_SERVER_IP WS_SERVER_IP_SHOW VMESS_HOST_DOMAIN CDN PORT_VLESS_WS VLESS_WS_PATH VLESS_HOST_DOMAIN PORT_H2_REALITY PORT_GRPC_REALITY ARGO_DOMAIN # 获取公共数据 ls $WORK_DIR/conf/*-ws*inbounds.json >/dev/null 2>&1 && SERVER_IP=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4; exit}' $WORK_DIR/conf/*-ws*inbounds.json) || SERVER_IP=$(grep -A1 '"tag"' $WORK_DIR/list | sed -E '/-ws(-tls)*",$/{N;d}' | awk -F '"' '/"server"/{count++; if (count == 1) {print $4; exit}}') EXISTED_PORTS=$(awk -F ':|,' '/listen_port/{print $2}' $WORK_DIR/conf/*_inbounds.json) START_PORT=$(awk 'NR == 1 { min = $0 } { if ($0 < min) min = $0; count++ } END {print min}' <<< "$EXISTED_PORTS") + # 如有 Argo,获取 Argo Tunnel + [[ ${STATUS[1]} =~ $(text 27)|$(text 28) ]] && grep -q '\--url' /etc/systemd/system/argo.service && cmd_systemctl enable argo && sleep 2 && [ "$(systemctl is-active argo)" = 'active' ] && fetch_quicktunnel_domain + # 获取 Nginx 端口和路径 - [ "$IS_NGINX" = 'is_nginx' ] && local NGINX_JSON=$(cat $WORK_DIR/nginx.conf) && + [[ "${IS_SUB}" = 'is_sub' || "${IS_ARGO}" = 'is_argo' ]] && local NGINX_JSON=$(cat $WORK_DIR/nginx.conf) && PORT_NGINX=$(awk '/listen/{print $2; exit}' <<< "$NGINX_JSON") && UUID_CONFIRM=$(awk -F '/' '/location ~ \^/{print $2; exit}' <<< "$NGINX_JSON") @@ -1360,10 +1593,10 @@ fetch_nodes_value() { [ -s $WORK_DIR/conf/*_${NODE_TAG[5]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[5]}_inbounds.json) && NODE_NAME[16]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[5]}.*/\1/p" <<< "$JSON") && PORT_TROJAN=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && TROJAN_PASSWORD=$(awk -F '"' '/"password"/{print $4}' <<< "$JSON") # 获取 vmess + ws key-value - [ -s $WORK_DIR/conf/*_${NODE_TAG[6]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[6]}_inbounds.json) && NODE_NAME[17]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[6]}.*/\1/p" <<< "$JSON") && PORT_VMESS_WS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[17]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && VMESS_WS_PATH=$(sed -n 's#.*"path":"/\(.*\)",#\1#p' <<< "$JSON") && WS_SERVER_IP[17]=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4}' <<< "$JSON") && VMESS_HOST_DOMAIN=$(awk -F '"' '/"VMESS_HOST_DOMAIN"/{print $4}' <<< "$JSON") && CDN[17]=$(awk -F '"' '/"CDN"/{print $4}' <<< "$JSON") + [ -s $WORK_DIR/conf/*_${NODE_TAG[6]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[6]}_inbounds.json) && NODE_NAME[17]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[6]}.*/\1/p" <<< "$JSON") && PORT_VMESS_WS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[17]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && VMESS_WS_PATH=$(sed -n 's#.*"path":"/\(.*\)",#\1#p' <<< "$JSON") && WS_SERVER_IP[17]=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4}' <<< "$JSON") && CDN[17]=$(awk -F '"' '/"CDN"/{print $4}' <<< "$JSON") && [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] && ARGO_DOMAIN=$(awk -F '"' '/"VMESS_HOST_DOMAIN"/{print $4}' <<< "$JSON") || VMESS_HOST_DOMAIN=$(awk -F '"' '/"VMESS_HOST_DOMAIN"/{print $4}' <<< "$JSON") # 获取 vless + ws + tls key-value - [ -s $WORK_DIR/conf/*_${NODE_TAG[7]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[7]}_inbounds.json) && NODE_NAME[18]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[7]}.*/\1/p" <<< "$JSON") && PORT_VLESS_WS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[18]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && VLESS_WS_PATH=$(sed -n 's#.*"path":"/\(.*\)",#\1#p' <<< "$JSON") && WS_SERVER_IP[18]=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4}' <<< "$JSON") && VLESS_HOST_DOMAIN=$(awk -F '"' '/"server_name"/{print $4}' <<< "$JSON") && CDN[18]=$(awk -F '"' '/"CDN"/{print $4}' <<< "$JSON") + [ -s $WORK_DIR/conf/*_${NODE_TAG[7]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[7]}_inbounds.json) && NODE_NAME[18]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[7]}.*/\1/p" <<< "$JSON") && PORT_VLESS_WS=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[18]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && VLESS_WS_PATH=$(sed -n 's#.*"path":"/\(.*\)",#\1#p' <<< "$JSON") && WS_SERVER_IP[18]=$(awk -F '"' '/"WS_SERVER_IP_SHOW"/{print $4}' <<< "$JSON") && CDN[18]=$(awk -F '"' '/"CDN"/{print $4}' <<< "$JSON") && [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]] && ARGO_DOMAIN=$(awk -F '"' '/"server_name"/{print $4}' <<< "$JSON") || VLESS_HOST_DOMAIN=$(awk -F '"' '/"server_name"/{print $4}' <<< "$JSON") # 获取 H2 + Reality key-value [ -s $WORK_DIR/conf/*_${NODE_TAG[8]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[8]}_inbounds.json) && NODE_NAME[19]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[8]}.*/\1/p" <<< "$JSON") && PORT_H2_REALITY=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[19]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && TLS_SERVER[19]=$(awk -F '"' '/"server"/{print $4}' <<< "$JSON") && REALITY_PRIVATE[19]=$(awk -F '"' '/"private_key"/{print $4}' <<< "$JSON") && REALITY_PUBLIC[19]=$(awk -F '"' '/"public_key"/{print $4}' <<< "$JSON") @@ -1372,9 +1605,29 @@ fetch_nodes_value() { [ -s $WORK_DIR/conf/*_${NODE_TAG[9]}_inbounds.json ] && local JSON=$(cat $WORK_DIR/conf/*_${NODE_TAG[9]}_inbounds.json) && NODE_NAME[20]=$(sed -n "s/.*\"tag\":\"\(.*\) ${NODE_TAG[9]}.*/\1/p" <<< "$JSON") && PORT_GRPC_REALITY=$(sed -n 's/.*"listen_port":\([0-9]\+\),/\1/gp' <<< "$JSON") && UUID[20]=$(awk -F '"' '/"uuid"/{print $4}' <<< "$JSON") && TLS_SERVER[20]=$(awk -F '"' '/"server"/{print $4}' <<< "$JSON") && REALITY_PRIVATE[20]=$(awk -F '"' '/"private_key"/{print $4}' <<< "$JSON") && REALITY_PUBLIC[20]=$(awk -F '"' '/"public_key"/{print $4}' <<< "$JSON") } +# 获取 Argo 临时隧道域名 +fetch_quicktunnel_domain() { + unset CLOUDFLARED_PID METRICS_ADDRESS ARGO_DOMAIN + local QUICKTUNNEL_ERROR_TIME=10 + until [ -n "$ARGO_DOMAIN" ]; do + if [ -z "$CLOUDFLARED_PID" ]; then + [ "$SYSTEM" = 'Alpine' ] && CLOUDFLARED_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORKDIR"/cloudflared" {print $1; exit}') || CLOUDFLARED_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/cloudflared" {print $2; exit}') + fi + [[ -z "$METRICS_ADDRESS" && "$CLOUDFLARED_PID" =~ ^[0-9]+$ ]] && METRICS_ADDRESS=$(ss -nltp | grep "pid=$CLOUDFLARED_PID" | awk '{print $4}') + ARGO_DOMAIN=$(wget -qO- http://$METRICS_ADDRESS/quicktunnel | awk -F '"' '{print $4}') + [[ ! "$ARGO_DOMAIN" =~ trycloudflare\.com$ ]] && (( QUICKTUNNEL_ERROR_TIME-- )) && sleep 1 || break + [ "$QUICKTUNNEL_ERROR_TIME" = '0' ] && error " $(text 93) " + done + + # 把临时隧道写到 Sing-box 相应的 ws inbounds 文件 + [ -s $WORK_DIR/conf/17_${NODE_TAG[6]}_inbounds.json ] && sed -i "s/VMESS_HOST_DOMAIN.*/VMESS_HOST_DOMAIN\": \"$ARGO_DOMAIN\"/" $WORK_DIR/conf/17_${NODE_TAG[6]}_inbounds.json + [ -s $WORK_DIR/conf/18_${NODE_TAG[7]}_inbounds.json ] && sed -i "s/\"server_name\":.*/\"server_name\": \"$ARGO_DOMAIN\",/" $WORK_DIR/conf/18_${NODE_TAG[7]}_inbounds.json +} + +# 安装 sing-box 全家桶 install_sing-box() { sing-box_variables - [ "$EXPORT_MODE" = '2' ] && check_nginx + [ -n "$PORT_NGINX" ] && check_nginx [ ! -d /etc/systemd/system ] && mkdir -p /etc/systemd/system [ ! -d $WORK_DIR/logs ] && mkdir -p $WORK_DIR/logs ssl_certificate @@ -1388,8 +1641,14 @@ install_sing-box() { # 生成 sing-box systemd 配置文件 sing-box_systemd + # 生成 Argo systemd 配置文件,并复制 cloudflared 可执行二进制文件 + [ "$IS_ARGO" = 'is_argo' ] && cp $TEMP_DIR/cloudflared $WORK_DIR && argo_systemd + + # 如果是 Json Argo,把配置文件复制到工作目录 + [ -n "$ARGO_JSON" ] && cp $TEMP_DIR/tunnel.* $WORK_DIR + # 生成 Nginx 配置文件 - [ "$EXPORT_MODE" = '2' ] && json_nginx + [ -n "$PORT_NGINX" ] && export_nginx_conf_file # 如果 Alpine 系统,放到开机自启动 if [ "$SYSTEM" = 'Alpine' ]; then @@ -1406,6 +1665,7 @@ EOF check_install sleep 1 check_sing-box_status + [ "$IS_ARGO" = 'is_argo' ] && check_argo_status } export_list() { @@ -1414,7 +1674,7 @@ export_list() { check_install #### v1.1.9 处理的 jq 和 qrencode 二进制文件代替系统依赖的问题,此处预计6月30日删除 - if [ "$IS_NGINX" = 'is_nginx' ]; then + if [[ "${IS_SUB}" = 'is_sub' || "${IS_ARGO}" = 'is_argo' ]]; then [[ ! -s $WORK_DIR/jq && -s /usr/bin/jq ]] && cp /usr/bin/jq $WORK_DIR/ if [ ! -s $WORK_DIR/qrencode ]; then check_arch @@ -1433,6 +1693,12 @@ export_list() { SERVER_IP_2="$SERVER_IP" fi + # 使用 Argo 时,获取临时隧道域名 + ls /etc/sing-box/conf/*-ws*inbounds.json >/dev/null 2>&1 && [ -z "$ARGO_DOMAIN" ] && [ "${STATUS[1]}" = "$(text 28)" ] && fetch_quicktunnel_domain + + # 如果使用 Json 或者 Token Argo,则使用加密的而且是固定的 Argo 隧道域名,否则使用 IP:PORT 的 http 服务 + [[ "$ARGO_TYPE" = 'is_token_argo' || "$ARGO_TYPE" = 'is_json_argo' ]] && SUBSCRIBE_ADDRESS="https://$ARGO_DOMAIN" || SUBSCRIBE_ADDRESS="http://${SERVER_IP_1}:${PORT_NGINX}" + # 生成各订阅文件 # 生成 Clash proxy providers 订阅文件 local CLASH_SUBSCRIBE='proxies:' @@ -1462,20 +1728,46 @@ export_list() { local CLASH_SUBSCRIBE+=" $CLASH_TROJAN " - [ -n "$PORT_VMESS_WS" ] && local CLASH_VMESS_WS="- {name: \"${NODE_NAME[17]} ${NODE_TAG[6]}\", type: vmess, server: ${CDN[17]}, port: 80, uuid: ${UUID[17]}, udp: true, tls: false, alterId: 0, cipher: none, skip-cert-verify: true, network: ws, ws-opts: { path: \"/$VMESS_WS_PATH\", headers: {Host: $VMESS_HOST_DOMAIN} }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && - local WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && local TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && local TYPE_PORT_WS=$PORT_VMESS_WS && - local CLASH_SUBSCRIBE+=" + if [ -n "$PORT_VMESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local CLASH_VMESS_WS="- {name: \"${NODE_NAME[17]} ${NODE_TAG[6]}\", type: vmess, server: ${CDN[17]}, port: 80, uuid: ${UUID[17]}, udp: true, tls: false, alterId: 0, cipher: none, skip-cert-verify: true, network: ws, ws-opts: { path: \"/$VMESS_WS_PATH\", headers: {Host: $ARGO_DOMAIN} }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && + local CLASH_SUBSCRIBE+=" + $CLASH_VMESS_WS +" + [ "$ARGO_TYPE" = 'is_token_argo' ] && CLASH_SUBSCRIBE+=" + # $(text 94) +" + else + local CLASH_VMESS_WS="- {name: \"${NODE_NAME[17]} ${NODE_TAG[6]}\", type: vmess, server: ${CDN[17]}, port: 80, uuid: ${UUID[17]}, udp: true, tls: false, alterId: 0, cipher: none, skip-cert-verify: true, network: ws, ws-opts: { path: \"/$VMESS_WS_PATH\", headers: {Host: $VMESS_HOST_DOMAIN} }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && + local WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && local TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && local TYPE_PORT_WS=$PORT_VMESS_WS && + local CLASH_SUBSCRIBE+=" $CLASH_VMESS_WS # $(text 52) " - [ -n "$PORT_VLESS_WS" ] && local CLASH_VLESS_WS="- {name: \"${NODE_NAME[18]} ${NODE_TAG[7]}\", type: vless, server: ${CDN[18]}, port: 443, uuid: ${UUID[18]}, udp: true, tls: true, servername: $VLESS_HOST_DOMAIN, network: ws, skip-cert-verify: true, ws-opts: { path: \"/$VLESS_WS_PATH\", headers: {Host: $VLESS_HOST_DOMAIN}, max-early-data: 2048, early-data-header-name: Sec-WebSocket-Protocol }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && - local WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && local TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && local TYPE_PORT_WS=$PORT_VLESS_WS && - local CLASH_SUBSCRIBE+=" + fi + fi + + if [ -n "$PORT_VLESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local CLASH_VLESS_WS="- {name: \"${NODE_NAME[18]} ${NODE_TAG[7]}\", type: vless, server: ${CDN[18]}, port: 443, uuid: ${UUID[18]}, udp: true, tls: true, servername: $ARGO_DOMAIN, network: ws, skip-cert-verify: true, ws-opts: { path: \"/$VLESS_WS_PATH\", headers: {Host: $ARGO_DOMAIN}, max-early-data: 2048, early-data-header-name: Sec-WebSocket-Protocol }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && + local CLASH_SUBSCRIBE+=" + $CLASH_VLESS_WS +" + [ "$ARGO_TYPE" = 'is_token_argo' ] && CLASH_SUBSCRIBE+=" + # $(text 94) +" + else + local CLASH_VLESS_WS="- {name: \"${NODE_NAME[18]} ${NODE_TAG[7]}\", type: vless, server: ${CDN[18]}, port: 443, uuid: ${UUID[18]}, udp: true, tls: true, servername: $VLESS_HOST_DOMAIN, network: ws, skip-cert-verify: true, ws-opts: { path: \"/$VLESS_WS_PATH\", headers: {Host: $VLESS_HOST_DOMAIN}, max-early-data: 2048, early-data-header-name: Sec-WebSocket-Protocol }, smux: { enabled: true, protocol: 'h2mux', padding: true, max-connections: '8', min-streams: '16', statistic: true, only-tcp: false } }" && + local WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && local TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && local TYPE_PORT_WS=$PORT_VLESS_WS && + local CLASH_SUBSCRIBE+=" $CLASH_VLESS_WS # $(text 52) " + fi + fi + # Clash 的 H2 传输层未实现多路复用功能,在 Clash.Meta 中更建议使用 gRPC 协议,故不输出相关配置。 https://wiki.metacubex.one/config/proxies/vless/ [ -n "$PORT_H2_REALITY" ] @@ -1486,8 +1778,9 @@ export_list() { echo -n "${CLASH_SUBSCRIBE}" | sed -E '/^[ ]*#|^--/d' | sed '/^$/d' > $WORK_DIR/subscribe/proxies # 生成 clash 订阅配置文件 + # 模板1: 使用 proxy providers - wget --no-check-certificate -qO- --tries=3 --timeout=2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash | sed "s#NODE_NAME#${NODE_NAME_CONFIRM}#g; s#PROXY_PROVIDERS_URL#http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/proxies#" > $WORK_DIR/subscribe/clash + wget --no-check-certificate -qO- --tries=3 --timeout=2 ${GH_PROXY}${SUBSCRIBE_TEMPLATE}/clash | sed "s#NODE_NAME#${NODE_NAME_CONFIRM}#g; s#PROXY_PROVIDERS_URL#$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/proxies#" > $WORK_DIR/subscribe/clash # 模板2: 不使用 proxy providers CLASH2_PORT=("$PORT_XTLS_REALITY" "$PORT_HYSTERIA2" "$PORT_TUIC" "$PORT_SHADOWTLS" "$PORT_SHADOWSOCKS" "$PORT_TROJAN" "$PORT_VMESS_WS" "$PORT_VLESS_WS" "$PORT_GRPC_REALITY") @@ -1519,18 +1812,44 @@ ss://$(echo -n "${SHADOWSOCKS_METHOD}:${UUID[15]}@${SERVER_IP_2}:$PORT_SHADOWSOC [ -n "$PORT_TROJAN" ] && local SHADOWROCKET_SUBSCRIBE+=" trojan://$TROJAN_PASSWORD@${SERVER_IP_1}:$PORT_TROJAN?allowInsecure=1#${NODE_NAME[16]}%20${NODE_TAG[5]} " - [ -n "$PORT_VMESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local SHADOWROCKET_SUBSCRIBE+=" + if [ -n "$PORT_VMESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local SHADOWROCKET_SUBSCRIBE+=" +---------------------------- +vmess://$(echo -n "none:${UUID[17]}@${CDN[17]}:80" | base64 -w0)?remarks=${NODE_NAME[17]}%20${NODE_TAG[6]}&obfsParam=$ARGO_DOMAIN&path=/$VMESS_WS_PATH&obfs=websocket&alterId=0 +" + [ "$ARGO_TYPE" = 'is_token_argo' ] && SHADOWROCKET_SUBSCRIBE+=" + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local SHADOWROCKET_SUBSCRIBE+=" ---------------------------- vmess://$(echo -n "none:${UUID[17]}@${CDN[17]}:80" | base64 -w0)?remarks=${NODE_NAME[17]}%20${NODE_TAG[6]}&obfsParam=$VMESS_HOST_DOMAIN&path=/$VMESS_WS_PATH&obfs=websocket&alterId=0 # $(text 52) " - [ -n "$PORT_VLESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local SHADOWROCKET_SUBSCRIBE+=" + fi + fi + + if [ -n "$PORT_VLESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local SHADOWROCKET_SUBSCRIBE+=" +---------------------------- +vless://$(echo -n "auto:${UUID[18]}@${CDN[18]}:443" | base64 -w0)?remarks=${NODE_NAME[18]}%20${NODE_TAG[7]}&obfsParam=$ARGO_DOMAIN&path=/$VLESS_WS_PATH?ed=2048&obfs=websocket&tls=1&peer=$ARGO_DOMAIN&allowInsecure=1 +" + [ "$ARGO_TYPE" = 'is_token_argo' ] && SHADOWROCKET_SUBSCRIBE+=" + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local SHADOWROCKET_SUBSCRIBE+=" ---------------------------- vless://$(echo -n "auto:${UUID[18]}@${CDN[18]}:443" | base64 -w0)?remarks=${NODE_NAME[18]}%20${NODE_TAG[7]}&obfsParam=$VLESS_HOST_DOMAIN&path=/$VLESS_WS_PATH?ed=2048&obfs=websocket&tls=1&peer=$VLESS_HOST_DOMAIN&allowInsecure=1 # $(text 52) " + fi + fi + [ -n "$PORT_H2_REALITY" ] && local SHADOWROCKET_SUBSCRIBE+=" ---------------------------- vless://$(echo -n auto:${UUID[19]}@${SERVER_IP_2}:${PORT_H2_REALITY} | base64 -w0)?remarks=${NODE_NAME[19]}%20${NODE_TAG[8]}&path=/&obfs=h2&tls=1&peer=${TLS_SERVER[19]}&alpn=h2&mux=1&pbk=${REALITY_PUBLIC[19]} @@ -1619,17 +1938,41 @@ trojan://$TROJAN_PASSWORD@${SERVER_IP_1}:$PORT_TROJAN?security=tls&type=tcp&head # $(text 70)" - [ -n "$PORT_VMESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local V2RAYN_SUBSCRIBE+=" + if [ -n "$PORT_VMESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local V2RAYN_SUBSCRIBE+=" +---------------------------- +vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[18]}\", \"port\": \"80\", \"id\": \"${UUID[18]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"$ARGO_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0)" + [ "$ARGO_TYPE" = 'is_token_argo' ] && V2RAYN_SUBSCRIBE+=" + + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local V2RAYN_SUBSCRIBE+=" ---------------------------- vmess://$(echo -n "{ \"v\": \"2\", \"ps\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"add\": \"${CDN[18]}\", \"port\": \"80\", \"id\": \"${UUID[18]}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"$VMESS_HOST_DOMAIN\", \"path\": \"/$VMESS_WS_PATH\", \"tls\": \"\", \"sni\": \"\", \"alpn\": \"\" }" | base64 -w0) # $(text 52)" + fi + fi - [ -n "$PORT_VLESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local V2RAYN_SUBSCRIBE+=" + if [ -n "$PORT_VLESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local V2RAYN_SUBSCRIBE+=" +---------------------------- +vless://${UUID[18]}@${CDN[18]}:443?encryption=none&security=tls&sni=$ARGO_DOMAIN&type=ws&host=$ARGO_DOMAIN&path=%2F$VLESS_WS_PATH%3Fed%3D2048#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]}" + [ "$ARGO_TYPE" = 'is_token_argo' ] && V2RAYN_SUBSCRIBE+=" + + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local V2RAYN_SUBSCRIBE+=" ---------------------------- vless://${UUID[18]}@${CDN[18]}:443?encryption=none&security=tls&sni=$VLESS_HOST_DOMAIN&type=ws&host=$VLESS_HOST_DOMAIN&path=%2F$VLESS_WS_PATH%3Fed%3D2048#${NODE_NAME[18]// /%20}%20${NODE_TAG[7]} # $(text 52)" + fi + fi [ -n "$PORT_H2_REALITY" ] && local V2RAYN_SUBSCRIBE+=" ---------------------------- @@ -1668,17 +2011,41 @@ ss://$(echo -n "${SHADOWSOCKS_METHOD}:${UUID[15]}" | base64 -w0)@${SERVER_IP_1}: ---------------------------- trojan://$TROJAN_PASSWORD@${SERVER_IP_1}:$PORT_TROJAN?security=tls&allowInsecure=1&fp=random&type=tcp#${NODE_NAME[16]} ${NODE_TAG[5]}" - [ -n "$PORT_VMESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local NEKOBOX_SUBSCRIBE+=" + if [ -n "$PORT_VMESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + NEKOBOX_SUBSCRIBE+=" +---------------------------- +vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$ARGO_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"none\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0)" + [ "$ARGO_TYPE" = 'is_token_argo' ] && NEKOBOX_SUBSCRIBE+=" + + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VMESS_WS && local NEKOBOX_SUBSCRIBE+=" ---------------------------- vmess://$(echo -n "{\"add\":\"${CDN[17]}\",\"aid\":\"0\",\"host\":\"$VMESS_HOST_DOMAIN\",\"id\":\"${UUID[17]}\",\"net\":\"ws\",\"path\":\"/$VMESS_WS_PATH\",\"port\":\"80\",\"ps\":\"${NODE_NAME[17]} ${NODE_TAG[6]}\",\"scy\":\"none\",\"sni\":\"\",\"tls\":\"\",\"type\":\"\",\"v\":\"2\"}" | base64 -w0) # $(text 52)" + fi + fi - [ -n "$PORT_VLESS_WS" ] && WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local NEKOBOX_SUBSCRIBE+=" + if [ -n "$PORT_VLESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local NEKOBOX_SUBSCRIBE+=" +---------------------------- +vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$ARGO_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2048&host=$ARGO_DOMAIN&encryption=none#${NODE_NAME[18]}%20${NODE_TAG[7]}" + [ "$ARGO_TYPE" = 'is_token_argo' ] && NEKOBOX_SUBSCRIBE+=" + + # $(text 94) +" + else + WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && TYPE_PORT_WS=$PORT_VLESS_WS && local NEKOBOX_SUBSCRIBE+=" ---------------------------- vless://${UUID[18]}@${CDN[18]}:443?security=tls&sni=$VLESS_HOST_DOMAIN&type=ws&path=/$VLESS_WS_PATH?ed%3D2048&host=$VLESS_HOST_DOMAIN&encryption=none#${NODE_NAME[18]}%20${NODE_TAG[7]} # $(text 52)" + fi + fi [ -n "$PORT_H2_REALITY" ] && local NEKOBOX_SUBSCRIBE+=" ---------------------------- @@ -1717,22 +2084,37 @@ vless://${UUID[20]}@${SERVER_IP_1}:${PORT_GRPC_REALITY}?security=reality&sni=${T local INBOUND_REPLACE+=" { \"type\": \"trojan\", \"tag\": \"${NODE_NAME[16]} ${NODE_TAG[5]}\", \"server\": \"${SERVER_IP}\", \"server_port\": $PORT_TROJAN, \"password\": \"$TROJAN_PASSWORD\", \"tls\": { \"enabled\":true, \"insecure\": true, \"server_name\":\"\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_connections\": 8, \"min_streams\": 16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," && local NODE_REPLACE+="\"${NODE_NAME[16]} ${NODE_TAG[5]}\"," - [ -n "$PORT_VMESS_WS" ] && - local WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && - local TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && - local TYPE_PORT_WS=$PORT_VMESS_WS && - local PROMPT+=" - # $(text 52)" && - local INBOUND_REPLACE+=" { \"type\": \"vmess\", \"tag\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"server\":\"${CDN[17]}\", \"server_port\":80, \"uuid\":\"${UUID[17]}\", \"transport\": { \"type\":\"ws\", \"path\":\"/$VMESS_WS_PATH\", \"headers\": { \"Host\": \"$VMESS_HOST_DOMAIN\" } }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," && local NODE_REPLACE+="\"${NODE_NAME[17]} ${NODE_TAG[6]}\"," + if [ -n "$PORT_VMESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local INBOUND_REPLACE+=" { \"type\": \"vmess\", \"tag\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"server\":\"${CDN[17]}\", \"server_port\":80, \"uuid\":\"${UUID[17]}\", \"transport\": { \"type\":\"ws\", \"path\":\"/$VMESS_WS_PATH\", \"headers\": { \"Host\": \"$ARGO_DOMAIN\" } }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," && local NODE_REPLACE+="\"${NODE_NAME[17]} ${NODE_TAG[6]}\"," + [ "$ARGO_TYPE" = 'is_token_argo' ] && [ -z "$PROMPT" ] && local PROMPT=" + # $(text 94)" + else + local WS_SERVER_IP_SHOW=${WS_SERVER_IP[17]} && + local TYPE_HOST_DOMAIN=$VMESS_HOST_DOMAIN && + local TYPE_PORT_WS=$PORT_VMESS_WS && + local PROMPT+=" + # $(text 52)" && + local INBOUND_REPLACE+=" { \"type\": \"vmess\", \"tag\": \"${NODE_NAME[17]} ${NODE_TAG[6]}\", \"server\":\"${CDN[17]}\", \"server_port\":80, \"uuid\":\"${UUID[17]}\", \"transport\": { \"type\":\"ws\", \"path\":\"/$VMESS_WS_PATH\", \"headers\": { \"Host\": \"$VMESS_HOST_DOMAIN\" } }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," + fi + local NODE_REPLACE+="\"${NODE_NAME[17]} ${NODE_TAG[6]}\"," + fi - [ -n "$PORT_VLESS_WS" ] && - local WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && - local TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && - local TYPE_PORT_WS=$PORT_VLESS_WS && - local PROMPT+=" - # $(text 52)" && - local INBOUND_REPLACE+=" { \"type\": \"vless\", \"tag\": \"${NODE_NAME[18]} ${NODE_TAG[7]}\", \"server\":\"${CDN[18]}\", \"server_port\":443, \"uuid\":\"${UUID[18]}\", \"tls\": { \"enabled\":true, \"server_name\":\"$VLESS_HOST_DOMAIN\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/$VLESS_WS_PATH\", \"headers\": { \"Host\": \"$VLESS_HOST_DOMAIN\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," && - local NODE_REPLACE+="\"${NODE_NAME[18]} ${NODE_TAG[7]}\"," + if [ -n "$PORT_VLESS_WS" ]; then + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + local INBOUND_REPLACE+=" { \"type\": \"vless\", \"tag\": \"${NODE_NAME[18]} ${NODE_TAG[7]}\", \"server\":\"${CDN[18]}\", \"server_port\":443, \"uuid\":\"${UUID[18]}\", \"tls\": { \"enabled\":true, \"server_name\":\"$ARGO_DOMAIN\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/$VLESS_WS_PATH\", \"headers\": { \"Host\": \"$ARGO_DOMAIN\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," + [ "$ARGO_TYPE" = 'is_token_argo' ] && [ -z "$PROMPT" ] && local PROMPT=" + # $(text 94)" + else + local WS_SERVER_IP_SHOW=${WS_SERVER_IP[18]} && + local TYPE_HOST_DOMAIN=$VLESS_HOST_DOMAIN && + local TYPE_PORT_WS=$PORT_VLESS_WS && + local PROMPT+=" + # $(text 52)" && + local INBOUND_REPLACE+=" { \"type\": \"vless\", \"tag\": \"${NODE_NAME[18]} ${NODE_TAG[7]}\", \"server\":\"${CDN[18]}\", \"server_port\":443, \"uuid\":\"${UUID[18]}\", \"tls\": { \"enabled\":true, \"server_name\":\"$VLESS_HOST_DOMAIN\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/$VLESS_WS_PATH\", \"headers\": { \"Host\": \"$VLESS_HOST_DOMAIN\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" }, \"multiplex\": { \"enabled\":true, \"protocol\":\"h2mux\", \"max_streams\":16, \"padding\": true, \"brutal\":{ \"enabled\":true, \"up_mbps\":1000, \"down_mbps\":1000 } } }," + fi + local NODE_REPLACE+="\"${NODE_NAME[18]} ${NODE_TAG[7]}\"," + fi [ -n "$PORT_H2_REALITY" ] && local REALITY_H2_INBOUND=" { \"type\": \"vless\", \"tag\": \"${NODE_NAME[19]} ${NODE_TAG[8]}\", \"server\": \"${SERVER_IP}\", \"server_port\": ${PORT_H2_REALITY}, \"uuid\":\"${UUID[19]}\", \"tls\": { \"enabled\":true, \"server_name\":\"${TLS_SERVER[19]}\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" }, \"reality\":{ \"enabled\":true, \"public_key\":\"${REALITY_PUBLIC[19]}\", \"short_id\":\"\" } }, \"packet_encoding\": \"xudp\", \"transport\": { \"type\": \"http\" } }," && @@ -1754,26 +2136,26 @@ vless://${UUID[20]}@${SERVER_IP_1}:${PORT_GRPC_REALITY}?security=reality&sni=${T echo $SING_BOX_JSON2 | sed "s#\"\",#$INBOUND_REPLACE#; s#\"\"#${NODE_REPLACE%,}#g" | $WORK_DIR/jq > $WORK_DIR/subscribe/sing-box2 # 生成二维码 url 文件 - [ "$IS_NGINX" = 'is_nginx' ] && cat > $WORK_DIR/subscribe/qr << EOF + [ "$IS_SUB" = 'is_sub' ] && cat > $WORK_DIR/subscribe/qr << EOF $(text 81): $(text 82) 1: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto $(text 82) 2: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2 +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2 $(text 80) QRcode: $(text 82) 1: -https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto +https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto $(text 82) 2: -https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2 +https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2 $(text 82) 1: -$($WORK_DIR/qrencode "http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto") +$($WORK_DIR/qrencode "$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto") $(text 82) 2: -$($WORK_DIR/qrencode "http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2") +$($WORK_DIR/qrencode "$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2") EOF # 生成配置文件 @@ -1827,59 +2209,59 @@ ${PROMPT} $(text 72)") " -[ "$IS_NGINX" = 'is_nginx' ] && EXPORT_LIST_FILE+=" + [ "$IS_SUB" = 'is_sub' ] && EXPORT_LIST_FILE+=" ******************************************* $(hint "Index: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/ +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/ QR code: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/qr +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/qr V2rayN $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/v2rayn") +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/v2rayn") $(hint "NekoBox $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/neko") +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/neko") $(hint "Clash $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/clash -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/clash2 +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/clash +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/clash2 sing-box for pc $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/sing-box-pc +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/sing-box-pc sing-box for cellphone $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/sing-box-phone +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/sing-box-phone SFI / SFA / SFM $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/sing-box2 +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/sing-box2 ShadowRocket $(text 80): -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/shadowrocket") +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/shadowrocket") ******************************************* $(info " $(text 81): $(text 82) 1: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto $(text 82) 2: -http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2 +$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2 $(text 80) QRcode: $(text 82) 1: -https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto +https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto $(text 82) 2: -https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2") +https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=$SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2") $(hint "$(text 82) 1:") -$($WORK_DIR/qrencode http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto) +$($WORK_DIR/qrencode $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto) $(hint "$(text 82) 2:") -$($WORK_DIR/qrencode http://${SERVER_IP_1}:${PORT_NGINX}/${UUID_CONFIRM}/auto2) +$($WORK_DIR/qrencode $SUBSCRIBE_ADDRESS/${UUID_CONFIRM}/auto2) " # 生成并显示节点信息 @@ -1907,12 +2289,15 @@ change_start_port() { OLD_PORTS=$(awk -F ':|,' '/listen_port/{print $2}' $WORK_DIR/conf/*) OLD_START_PORT=$(awk 'NR == 1 { min = $0 } { if ($0 < min) min = $0; count++ } END {print min}' <<< "$OLD_PORTS") OLD_CONSECUTIVE_PORTS=$(awk 'END { print NR }' <<< "$OLD_PORTS") - enter_start_port $OLD_CONSECUTIVE_PORTS + input_start_port $OLD_CONSECUTIVE_PORTS cmd_systemctl disable sing-box for ((a=0; a<$OLD_CONSECUTIVE_PORTS; a++)) do [ -s $WORK_DIR/conf/${CONF_FILES[a]} ] && sed -i "s/\(.*listen_port.*:\)$((OLD_START_PORT+a))/\1$((START_PORT+a))/" $WORK_DIR/conf/* done - systemctl enable sing-box + fetch_nodes_value + [ -n "$PORT_NGINX" ] && export_nginx_conf_file + cmd_systemctl enable sing-box + [ -n "$ARGO_DOMAIN" ] && export_argo_json_file sleep 2 export_list [ "$(systemctl is-active sing-box)" = 'active' ] && info " Sing-box $(text 30) $(text 37) " || error " Sing-box $(text 30) $(text 38) " @@ -1921,7 +2306,7 @@ change_start_port() { # 增加或删除协议 change_protocols() { check_install - [ "$STATUS" = "$(text 26)" ] && error "\n Sing-box $(text 26) " + [ "${STATUS[0]}" = "$(text 26)" ] && error "\n Sing-box $(text 26) " # 查找已安装的协议,并遍历其在所有协议列表中的名称,获取协议名后存放在 EXISTED_PROTOCOLS; 没有的协议存放在 NOT_EXISTED_PROTOCOLS INSTALLED_PROTOCOLS_LIST=$(awk -F '"' '/"tag":/{print $4}' $WORK_DIR/conf/*_inbounds.json | grep -v 'shadowtls-in' | awk '{print $NF}') @@ -2074,10 +2459,18 @@ change_protocols() { CHECK_PROTOCOLS=$(asc "$CHECK_PROTOCOLS" ++) if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then local DOMAIN_ERROR_TIME=5 - until [ -n "$VMESS_HOST_DOMAIN" ]; do - (( DOMAIN_ERROR_TIME-- )) || true - [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VMESS && reading "\n $(text 50) " VMESS_HOST_DOMAIN || error "\n $(text 3) \n" - done + if [ "$IS_ARGO" = 'is_argo' ]; then + until [ -n "$ARGO_DOMAIN" ]; do + [ "$ARGO_READY" != 'argo_ready' ] && input_argo_auth is_change_argo + local ARGO_READY=argo_ready + done + else + until [ -n "$VMESS_HOST_DOMAIN" ]; do + (( DOMAIN_ERROR_TIME-- )) || true + [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VMESS && reading "\n $(text 50) " VMESS_HOST_DOMAIN || error "\n $(text 3) \n" + done + fi + [ "${#CDN[@]}" = '0' ] && RUN_ARGO_SYSTEMD=run_argo_systemd && argo_systemd && input_cdn POSITION=$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}") PORT_VMESS_WS=${REINSTALL_PORTS[POSITION]} fi @@ -2086,10 +2479,18 @@ change_protocols() { CHECK_PROTOCOLS=$(asc "$CHECK_PROTOCOLS" ++) if [[ "${INSTALL_PROTOCOLS[@]}" =~ "$CHECK_PROTOCOLS" ]]; then local DOMAIN_ERROR_TIME=5 - until [ -n "$VLESS_HOST_DOMAIN" ]; do - (( DOMAIN_ERROR_TIME-- )) || true - [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VLESS && reading "\n $(text 50) " VLESS_HOST_DOMAIN || error "\n $(text 3) \n" - done + if [ "$IS_ARGO" = 'is_argo' ]; then + until [ -n "$ARGO_DOMAIN" ]; do + [ "$ARGO_READY" != 'argo_ready' ] && input_argo_auth is_change_argo + local ARGO_READY=argo_ready + done + else + until [ -n "$VLESS_HOST_DOMAIN" ]; do + (( DOMAIN_ERROR_TIME-- )) || true + [ "$DOMAIN_ERROR_TIME" != 0 ] && TYPE=VLESS && reading "\n $(text 50) " VLESS_HOST_DOMAIN || error "\n $(text 3) \n" + done + fi + [ "${#CDN[@]}" = '0' ] && RUN_ARGO_SYSTEMD=run_argo_systemd && argo_systemd && input_cdn POSITION=$(awk -v target=$CHECK_PROTOCOLS '{ for(i=1; i<=NF; i++) if($i == target) { print i-1; break } }' <<< "${INSTALL_PROTOCOLS[*]}") PORT_VLESS_WS=${REINSTALL_PORTS[POSITION]} fi @@ -2108,14 +2509,17 @@ change_protocols() { PORT_GRPC_REALITY=${REINSTALL_PORTS[POSITION]} fi - # 选择可以输入 cdn - input_cdn + # 生成 Nginx 配置文件 + [ -n "$PORT_NGINX" ] && export_nginx_conf_file # 生成各协议的 json 文件 sing-box_json change + # 如有需要,重启 Argo 服务 + [ "$RUN_ARGO_SYSTEMD" = 'run_argo_systemd' ] && ( cmd_systemctl disable argo >/dev/null 2>&1; cmd_systemctl enable argo >/dev/null 2>&1 ) + # 运行 sing-box - systemctl start sing-box + cmd_systemctl enable sing-box # 再次检测状态,运行 Sing-box check_install @@ -2128,6 +2532,7 @@ change_protocols() { # 卸载 Sing-box 全家桶 uninstall() { if [ -d $WORK_DIR ]; then + [ -s /etc/systemd/system/argo.service ] && ( cmd_systemctl disable argo 2>/dev/null; rm -f /etc/systemd/system/argo.service ) if [ "$SYSTEM" = 'Alpine' ]; then cmd_systemctl disable sing-box 2>/dev/null else @@ -2144,7 +2549,7 @@ uninstall() { # 如果 Alpine 系统,删除开机自启动和python3版systemd if [ "$SYSTEM" = 'Alpine' ]; then - rm -f /etc/local.d/sing-box.start + rm -f /etc/local.d/{sing-box,argo}.start rc-update add local >/dev/null 2>&1 ! ls /etc/systemd/system/*.service >/dev/null 2>&1 && rm -f /bin/systemctl fi @@ -2174,57 +2579,75 @@ version() { # 判断当前 Sing-box 的运行状态,并对应的给菜单和动作赋值 menu_setting() { - if [[ "$STATUS" =~ $(text 27)|$(text 28) ]]; then - # 查进程号,sing-box 运行时长和内存占用 - if [ "$STATUS" = "$(text 28)" ]; then - if [ "$SYSTEM" = 'Alpine' ]; then - PID=$(pidof sing-box | sed -n 1p) - else - SYSTEMCTL_STATUS=$(systemctl status sing-box) - PID=$(awk '/PID/{print $3}' <<< "$SYSTEMCTL_STATUS") - RUNTIME=$(awk '/Active:/{for (i=5;i<=NF;i++)printf("%s ", $i);print ""}' <<< "$SYSTEMCTL_STATUS") + if [[ "${STATUS[0]}" =~ $(text 27)|$(text 28) ]]; then + # 查 argo 进程号,运行时长和内存占用 + if [[ "${STATUS[1]}" =~ $(text 27)|$(text 28) ]]; then + ARGO_VERSION=$($WORK_DIR/cloudflared -v | awk '{print $3}' | sed "s@^@Version: &@g") + if [ "${STATUS[1]}" = "$(text 28)" ]; then + [ "$SYSTEM" = 'Alpine' ] && ARGO_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/cloudflared" {print $1}') || ARGO_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/cloudflared" {print $2}') + [[ "$ARGO_PID" =~ ^[0-9]+$ ]] && ARGO_MEMORY_USAGE="$(text 58): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$ARGO_PID/status) MB" fi - MEMORY_USAGE="$(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$PID/status)" fi + # 查 sing-box 进程号,运行时长和内存占用 + if [ "${STATUS[0]}" = "$(text 28)" ]; then + [ "$SYSTEM" = 'Alpine' ] && SING_BOX_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/sing-box" {print $1}') || SING_BOX_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/sing-box" {print $2}') + [[ "$SING_BOX_PID" =~ ^[0-9]+$ ]] && SING_BOX_MEMORY_USAGE="$(text 58): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$SING_BOX_PID/status) MB" + fi + + # 查 Nginx 版本号 + [ $(type -p nginx) ] && NGINX_VERSION=$(nginx -v 2>&1 | sed "s#.*/#Version: #") + [ "$SYSTEM" = 'Alpine' ] && NGINX_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/nginx.conf" {print $1; exit}') || NGINX_PID=$(ps -ef | awk -v WORK_DIR="$WORK_DIR" '$0 ~ WORK_DIR"/nginx.conf" {print $2; exit}') + [[ "$NGINX_PID" =~ ^[0-9]+$ ]] && NGINX_MEMORY_USAGE="$(text 58): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$NGINX_PID/status) MB" + NOW_PORTS=$(awk -F ':|,' '/listen_port/{print $2}' $WORK_DIR/conf/*) NOW_START_PORT=$(awk 'NR == 1 { min = $0 } { if ($0 < min) min = $0; count++ } END {print min}' <<< "$NOW_PORTS") NOW_CONSECUTIVE_PORTS=$(awk 'END { print NR }' <<< "$NOW_PORTS") - [ -s $WORK_DIR/sing-box ] && SING_BOX_VERSION="version: $($WORK_DIR/sing-box version | awk '/version/{print $NF}')" + [ -s $WORK_DIR/sing-box ] && SING_BOX_VERSION="Version: $($WORK_DIR/sing-box version | awk '/version/{print $NF}')" [ -s $WORK_DIR/conf/02_route.json ] && { grep -q 'direct' $WORK_DIR/conf/02_route.json && RETURN_STATUS=$(text 27) || RETURN_STATUS=$(text 28); } OPTION[1]="1 . $(text 29)" - [ "$STATUS" = "$(text 28)" ] && OPTION[2]="2 . $(text 27) Sing-box (sb -o)" || OPTION[2]="2 . $(text 28) Sing-box (sb -o)" - OPTION[3]="3 . $(text 30)" - OPTION[4]="4 . $(text 31)" - OPTION[5]="5 . $(text 32)" - OPTION[6]="6 . $(text 62)" - OPTION[7]="7 . $(text 33)" - OPTION[8]="8 . $(text 59)" - OPTION[9]="9 . $(text 69)" - OPTION[10]="10. $(text 76)" + [ "${STATUS[0]}" = "$(text 28)" ] && OPTION[2]="2 . $(text 27) Sing-box (sb -s)" || OPTION[2]="2 . $(text 28) Sing-box (sb -s)" + [ "${STATUS[1]}" = "$(text 28)" ] && OPTION[3]="3 . $(text 27) Argo (sb -a)" || OPTION[3]="3 . $(text 28) Argo (sb -a)" + OPTION[4]="4 . $(text 92)" + OPTION[5]="5 . $(text 30)" + OPTION[6]="6 . $(text 31)" + OPTION[7]="7 . $(text 32)" + OPTION[8]="8 . $(text 62)" + OPTION[9]="9 . $(text 33)" + OPTION[10]="10. $(text 59)" + OPTION[11]="11. $(text 69)" + OPTION[12]="12. $(text 76)" ACTION[1]() { export_list; exit 0; } - [ "$STATUS" = "$(text 28)" ] && ACTION[2]() { cmd_systemctl disable sing-box; [[ "$(systemctl is-active sing-box)" =~ 'inactive'|'unknown' ]] && info " Sing-box $(text 27) $(text 37)" || error " Sing-box $(text 27) $(text 38) "; } || ACTION[2]() { cmd_systemctl enable sing-box && [ "$(systemctl is-active sing-box)" = 'active' ] && info " Sing-box $(text 28) $(text 37)" || error " Sing-box $(text 28) $(text 38) "; } - ACTION[3]() { change_start_port; exit; } - ACTION[4]() { version; exit; } - ACTION[5]() { bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit; } - ACTION[6]() { change_protocols; exit; } - ACTION[7]() { uninstall; exit; } - ACTION[8]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/argox/main/argox.sh) -$L; exit; } - ACTION[9]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } - ACTION[10]() { bash <(wget --no-check-certificate -qO- https://tcp.hy2.sh/); exit; } + [ "${STATUS[0]}" = "$(text 28)" ] && ACTION[2]() { cmd_systemctl disable sing-box; [[ "$(systemctl is-active sing-box)" =~ 'inactive'|'unknown' ]] && info " Sing-box $(text 27) $(text 37)" || error " Sing-box $(text 27) $(text 38) "; } || ACTION[2]() { cmd_systemctl enable sing-box && [ "$(systemctl is-active sing-box)" = 'active' ] && info " Sing-box $(text 28) $(text 37)" || error " Sing-box $(text 28) $(text 38) "; } + [ "${STATUS[1]}" = "$(text 28)" ] && ACTION[3]() { cmd_systemctl disable argo; [[ "$(systemctl is-active argo)" =~ 'inactive'|'unknown' ]] && info " Argo $(text 27) $(text 37)" || error " Argo $(text 27) $(text 38) "; } || ACTION[3]() { cmd_systemctl enable argo && sleep 2 && [ "$(systemctl is-active argo)" = 'active' ] && info " Argo $(text 28) $(text 37)" && ( grep -q '\--url' /etc/systemd/system/argo.service && fetch_quicktunnel_domain && export_list ) || error " Argo $(text 28) $(text 38) "; } + ACTION[4]() { change_argo; exit; } + ACTION[5]() { change_start_port; exit; } + ACTION[6]() { version; exit; } + ACTION[7]() { bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit; } + ACTION[8]() { change_protocols; exit; } + ACTION[9]() { uninstall; exit; } + ACTION[10]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/argox/main/argox.sh) -$L; exit; } + ACTION[11]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } + ACTION[12]() { bash <(wget --no-check-certificate -qO- https://tcp.hy2.sh/); exit; } else - OPTION[1]="1. $(text 34)" - OPTION[2]="2. $(text 32)" - OPTION[3]="3. $(text 59)" - OPTION[4]="4. $(text 69)" - OPTION[5]="5. $(text 76)" + OPTION[1]="1. $(text 34) + Argo + $(text 80) $(text 89)" + OPTION[2]="2. $(text 34) + Argo $(text 89)" + OPTION[3]="3. $(text 34) + $(text 80) $(text 89)" + OPTION[4]="4. $(text 34)" + OPTION[5]="5. $(text 32)" + OPTION[6]="6. $(text 59)" + OPTION[7]="7. $(text 69)" + OPTION[8]="8. $(text 76)" - ACTION[1]() { install_sing-box; export_list install; create_shortcut; exit; } - ACTION[2]() { bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit; } - ACTION[3]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/argox/main/argox.sh) -$L; exit; } - ACTION[4]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } - ACTION[5]() { bash <(wget --no-check-certificate -qO- https://tcp.hy2.sh/); exit; } + ACTION[1]() { IS_SUB=is_sub; IS_ARGO=is_argo; install_sing-box; export_list install; create_shortcut; exit; } + ACTION[2]() { IS_SUB=no_sub; IS_ARGO=is_argo; install_sing-box; export_list install; create_shortcut; exit; } + ACTION[3]() { IS_SUB=is_sub; IS_ARGO=no_argo; install_sing-box; export_list install; create_shortcut; exit; } + ACTION[4]() { install_sing-box; export_list install; create_shortcut; exit; } + ACTION[5]() { bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit; } + ACTION[6]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/argox/main/argox.sh) -$L; exit; } + ACTION[7]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } + ACTION[8]() { bash <(wget --no-check-certificate -qO- https://tcp.hy2.sh/); exit; } fi [ "${#OPTION[@]}" -ge '10' ] && OPTION[0]="0 . $(text 35)" || OPTION[0]="0. $(text 35)" @@ -2237,14 +2660,9 @@ menu() { info " $(text 17): $VERSION\n $(text 18): $(text 1)\n $(text 19):\n\t $(text 20): $SYS\n\t $(text 21): $(uname -r)\n\t $(text 22): $SING_BOX_ARCH\n\t $(text 23): $VIRT " info "\t IPv4: $WAN4 $WARPSTATUS4 $COUNTRY4 $ASNORG4 " info "\t IPv6: $WAN6 $WARPSTATUS6 $COUNTRY6 $ASNORG6 " - info "\t Sing-box: $STATUS\t $SING_BOX_VERSION " - [ -n "$PID" ] && info "\t $(text 56): $PID " - [ -n "$RUNTIME" ] && info "\t $(text 57): $RUNTIME " - [ -n "$MEMORY_USAGE" ] && info "\t $(text 58): $MEMORY_USAGE MB" - [ -n "$NOW_START_PORT" ] && info "\t $(text 45) " + info "\t Sing-box: ${STATUS[0]}\t $SING_BOX_VERSION\t\t $SING_BOX_MEMORY_USAGE\n\t Argo: ${STATUS[1]}\t $ARGO_VERSION\t\t $ARGO_MEMORY_USAGE\n \t Nginx: ${STATUS[0]}\t $NGINX_VERSION\t $NGINX_MEMORY_USAGE " echo -e "\n======================================================================================================================\n" - for ((b=1;b<${#OPTION[*]};b++)); do hint " ${OPTION[b]} "; done - hint " ${OPTION[0]} " + for ((b=1;b<=${#OPTION[*]};b++)); do [ "$b" = "${#OPTION[*]}" ] && hint " ${OPTION[0]} " || hint " ${OPTION[b]} "; done reading "\n $(text 24) " CHOOSE # 输入必须是数字且少于等于最大可选项 @@ -2263,6 +2681,7 @@ statistics_of_run-times [[ "${*^^}" =~ '-C'|'-B' ]] && L=C select_language +check_system_info # 可以是 Key Value 或者 Key=Value 的形式 ALL_PARAMETER=($(sed -E 's/(-c|-e|-C|-E) //; ; s/=/ /g' <<< $*)) @@ -2272,13 +2691,19 @@ ALL_PARAMETER=($(sed -E 's/(-c|-e|-C|-E) //; ; s/=/ /g' <<< $*)) for z in ${!ALL_PARAMETER[@]}; do case "${ALL_PARAMETER[z]^^}" in -P ) - ((z++)); START_PORT=${ALL_PARAMETER[z]}; check_install; [ "$STATUS" = "$(text 26)" ] && error "\n Sing-box $(text 26) "; change_start_port; exit 0 + ((z++)); START_PORT=${ALL_PARAMETER[z]}; check_install; [ "${STATUS[0]}" = "$(text 26)" ] && error "\n Sing-box $(text 26) "; change_start_port; exit 0 ;; - -O ) - check_system_info; check_install; [ "$STATUS" = "$(text 26)" ] && error "\n Sing-box $(text 26) "; [ "$STATUS" = "$(text 28)" ] && ( cmd_systemctl disable sing-box; [[ "$(systemctl is-active sing-box)" =~ 'inactive'|'unknown' ]] && info "\n Sing-box $(text 27) $(text 37)" ) || ( cmd_systemctl enable sing-box && [ "$(systemctl is-active sing-box)" = 'active' ] && info "\n Sing-box $(text 28) $(text 37)" ); exit 0 + -S ) + check_install; [ "${STATUS[0]}" = "$(text 26)" ] && error "\n Sing-box $(text 26) "; [ "${STATUS[0]}" = "$(text 28)" ] && ( cmd_systemctl disable sing-box; [[ "$(systemctl is-active sing-box)" =~ 'inactive'|'unknown' ]] && info "\n Sing-box $(text 27) $(text 37)" ) || ( cmd_systemctl enable sing-box && [ "$(systemctl is-active sing-box)" = 'active' ] && info "\n Sing-box $(text 28) $(text 37)" ); exit 0 + ;; + -A ) + check_install; [ "${STATUS[1]}" = "$(text 26)" ] && error "\n Argo $(text 26) "; [ "${STATUS[1]}" = "$(text 28)" ] && ( cmd_systemctl disable argo; [[ "$(systemctl is-active argo)" =~ 'inactive'|'unknown' ]] && info "\n Argo $(text 27) $(text 37)" ) || ( cmd_systemctl enable argo && sleep 2 && [ "$(systemctl is-active argo)" = 'active' ] && info "\n Argo $(text 28) $(text 37)" && ( grep -q '\--url' /etc/systemd/system/argo.service && fetch_quicktunnel_domain && export_list ) ); exit 0 + ;; + -T ) + change_argo; exit 0 ;; -U ) - check_system_info; check_install; uninstall; exit 0 + check_install; uninstall; exit 0 ;; -N ) [ ! -s $WORK_DIR/list ] && error " Sing-box $(text 26) "; export_list; exit 0 @@ -2290,7 +2715,7 @@ for z in ${!ALL_PARAMETER[@]}; do bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit ;; -R ) - check_system_info; change_protocols; exit 0 + change_protocols; exit 0 ;; -F ) ((z++)); VARIABLE_FILE=${ALL_PARAMETER[z]}; . $VARIABLE_FILE; NONINTERACTIVE_INSTALL=noninteractive_install