#!/usr/bin/env bash # 当前脚本版本号 VERSION='1.6.4 (2024.03.26)' # 各变量默认值 WS_PATH_DEFAULT='argox' WORK_DIR='/etc/argox' TEMP_DIR='/tmp/argox' TLS_SERVER=addons.mozilla.org METRICS_PORT='3333' CDN_DOMAIN=("cn.azhz.eu.org" "www.who.int" "skk.moe" "time.cloudflare.com" "csgo.com") SUBSCRIBE_TEMPLATE="https://raw.githubusercontent.com/fscarmen/client_template/main" SUBSCRIBE_API=("bav6.889876.xyz" "api.v1.mk") trap "rm -rf $TEMP_DIR; echo -e '\n' ;exit 1" INT QUIT TERM EXIT mkdir -p $TEMP_DIR E[0]="Language:\n 1. English (default) \n 2. 简体中文" C[0]="${E[0]}" E[1]="Thanks to UUb for the official change of the compilation, dependencies jq, qrencode from apt installation to download the binary files, 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." C[1]="感谢 UUb 兄弟的官改编译,依赖 jq, qrencode 从 apt 安装改为下载二进制文件,缩减安装时间约15秒,贯彻项目轻量化的定位,尽最大可能安装最少的系统依赖" E[2]="Project to create Argo tunnels and Xray specifically for VPS, detailed:[https://github.com/fscarmen/argox]\n Features:\n\t • Allows the creation of Argo tunnels via Token, Json and ad hoc methods. User can easily obtain the json at https://fscarmen.cloudflare.now.cc .\n\t • Extremely fast installation method, saving users time.\n\t • Support system: Ubuntu, Debian, CentOS, Alpine and Arch Linux 3.\n\t • Support architecture: AMD,ARM and s390x\n" C[2]="本项目专为 VPS 添加 Argo 隧道及 Xray,详细说明: [https://github.com/fscarmen/argox]\n 脚本特点:\n\t • 允许通过 Token, Json 及 临时方式来创建 Argo 隧道,用户通过以下网站轻松获取 json: https://fscarmen.cloudflare.now.cc\n\t • 极速安装方式,大大节省用户时间\n\t • 智能判断操作系统: Ubuntu 、Debian 、CentOS 、Alpine 和 Arch Linux,请务必选择 LTS 系统\n\t • 支持硬件结构类型: AMD 和 ARM\n" E[3]="Input errors up to 5 times.The script is aborted." C[3]="输入错误达5次,脚本退出" E[4]="UUID should be 36 characters, please re-enter \(\${a} times remaining\)" C[4]="UUID 应为36位字符,请重新输入 \(剩余\${a}次\)" E[5]="The script supports Debian, Ubuntu, CentOS, Alpine or Arch systems only. Feedback: [https://github.com/fscarmen/argox/issues]" C[5]="本脚本只支持 Debian、Ubuntu、CentOS、Alpine 或 Arch 系统,问题反馈:[https://github.com/fscarmen/argox/issues]" E[6]="Curren operating system is \$SYS.\\\n The system lower than \$SYSTEM \${MAJOR[int]} is not supported. Feedback: [https://github.com/fscarmen/argox/issues]" C[6]="当前操作是 \$SYS\\\n 不支持 \$SYSTEM \${MAJOR[int]} 以下系统,问题反馈:[https://github.com/fscarmen/argox/issues]" E[7]="Install dependence-list:" C[7]="安装依赖列表:" E[8]="All dependencies already exist and do not need to be installed additionally." C[8]="所有依赖已存在,不需要额外安装" E[9]="To upgrade, press [y]. No upgrade by default:" C[9]="升级请按 [y],默认不升级:" E[10]="(3/8) Please enter Argo Domain (Default is temporary domain if left blank):" C[10]="(3/8) 请输入 Argo 域名 (如果没有,可以跳过以使用 Argo 临时域名):" E[11]="Please enter Argo Token or Json ( User can easily obtain the json at https://fscarmen.cloudflare.now.cc ):" C[11]="请输入 Argo Token 或者 Json ( 用户通过以下网站轻松获取 json: https://fscarmen.cloudflare.now.cc ):" E[12]="\(6/8\) Please enter Xray UUID \(Default is \$UUID_DEFAULT\):" C[12]="\(6/8\) 请输入 Xray UUID \(默认为 \$UUID_DEFAULT\):" E[13]="\(7/8\) Please enter Xray WS Path \(Default is \$WS_PATH_DEFAULT\):" C[13]="\(7/8\) 请输入 Xray WS 路径 \(默认为 \$WS_PATH_DEFAULT\):" E[14]="Xray WS Path only allow uppercase and lowercase letters and numeric characters, please re-enter \(\${a} times remaining\):" C[14]="Xray WS 路径只允许英文大小写及数字字符,请重新输入 \(剩余\${a}次\):" E[15]="ArgoX script has not been installed yet." C[15]="ArgoX 脚本还没有安装" E[16]="ArgoX is completely uninstalled." C[16]="ArgoX 已彻底卸载" E[17]="Version" C[17]="脚本版本" E[18]="New features" C[18]="功能新增" E[19]="System infomation" C[19]="系统信息" E[20]="Operating System" C[20]="当前操作系统" E[21]="Kernel" C[21]="内核" E[22]="Architecture" C[22]="处理器架构" E[23]="Virtualization" C[23]="虚拟化" E[24]="Choose:" C[24]="请选择:" E[25]="Curren architecture \$(uname -m) is not supported. Feedback: [https://github.com/fscarmen/argox/issues]" C[25]="当前架构 \$(uname -m) 暂不支持,问题反馈:[https://github.com/fscarmen/argox/issues]" E[26]="Not install" C[26]="未安装" E[27]="close" C[27]="关闭" E[28]="open" C[28]="开启" E[29]="View links (argox -n)" C[29]="查看节点信息 (argox -n)" E[30]="Change the Argo tunnel (argox -t)" C[30]="更换 Argo 隧道 (argox -t)" E[31]="Sync Argo and Xray to the latest version (argox -v)" C[31]="同步 Argo 和 Xray 至最新版本 (argox -v)" E[32]="Upgrade kernel, turn on BBR, change Linux system (argox -b)" C[32]="升级内核、安装BBR、DD脚本 (argox -b)" E[33]="Uninstall (argox -u)" C[33]="卸载 (argox -u)" E[34]="Install ArgoX script (argo + xray)" C[34]="安装 ArgoX 脚本 (argo + xray)" E[35]="Exit" C[35]="退出" E[36]="Please enter the correct number" C[36]="请输入正确数字" E[37]="successful" C[37]="成功" E[38]="failed" C[38]="失败" E[39]="ArgoX is not installed." C[39]="ArgoX 未安装" E[40]="Argo tunnel is: \$ARGO_TYPE\\\n The domain is: \$ARGO_DOMAIN" C[40]="Argo 隧道类型为: \$ARGO_TYPE\\\n 域名是: \$ARGO_DOMAIN" E[41]="Argo tunnel type:\n 1. Try\n 2. Token or Json" C[41]="Argo 隧道类型:\n 1. Try\n 2. Token 或者 Json" E[42]="\(5/8\) Please select or enter the preferred domain, the default is \${CDN_DOMAIN[0]}:" C[42]="\(5/8\) 请选择或者填入优选域名,默认为 \${CDN_DOMAIN[0]}:" E[43]="\$APP local verion: \$LOCAL.\\\t The newest verion: \$ONLINE" C[43]="\$APP 本地版本: \$LOCAL.\\\t 最新版本: \$ONLINE" E[44]="No upgrade required." C[44]="不需要升级" E[45]="Argo authentication message does not match the rules, neither Token nor Json, script exits. Feedback:[https://github.com/fscarmen/argox/issues]" C[45]="Argo 认证信息不符合规则,既不是 Token,也是不是 Json,脚本退出,问题反馈:[https://github.com/fscarmen/argox/issues]" E[46]="Connect" C[46]="连接" E[47]="The script must be run as root, you can enter sudo -i and then download and run again. Feedback:[https://github.com/fscarmen/argox/issues]" C[47]="必须以root方式运行脚本,可以输入 sudo -i 后重新下载运行,问题反馈:[https://github.com/fscarmen/argox/issues]" E[48]="Downloading the latest version \$APP failed, script exits. Feedback:[https://github.com/fscarmen/argox/issues]" C[48]="下载最新版本 \$APP 失败,脚本退出,问题反馈:[https://github.com/fscarmen/argox/issues]" E[49]="\(8/8\) Please enter the node name. \(Default is \${NODE_NAME_DEFAULT}\):" C[49]="\(8/8\) 请输入节点名称 \(默认为 \${NODE_NAME_DEFAULT}\):" E[50]="\${APP[@]} services are not enabled, node information cannot be output. Press [y] if you want to open." C[50]="\${APP[@]} 服务未开启,不能输出节点信息。如需打开请按 [y]: " E[51]="Install Sing-box multi-protocol scripts [https://github.com/fscarmen/sing-box]" C[51]="安装 Sing-box 协议全家桶脚本 [https://github.com/fscarmen/sing-box]" E[52]="Memory Usage" C[52]="内存占用" E[53]="The xray service is detected to be installed. Script exits." C[53]="检测到已安装 xray 服务,脚本退出!" E[54]="Warp / warp-go was detected to be running. Please enter the correct server IP:" C[54]="检测到 warp / warp-go 正在运行,请输入确认的服务器 IP:" E[55]="The script runs today: \$TODAY. Total: \$TOTAL" C[55]="脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL" E[56]="\(4/8\) Please enter the Reality port \(Default is \${REALITY_PORT_DEFAULT}\):" C[56]="\(4/8\) 请输入 Reality 的端口号 \(默认为 \${REALITY_PORT_DEFAULT}\):" E[57]="Install sba scripts (argo + sing-box) [https://github.com/fscarmen/sba]" C[57]="安装 sba 脚本 (argo + sing-box) [https://github.com/fscarmen/sba]" E[58]="No server ip, script exits. Feedback:[https://github.com/fscarmen/sing-box/issues]" C[58]="没有 server ip,脚本退出,问题反馈:[https://github.com/fscarmen/sing-box/issues]" E[59]="\(2/8\) Please enter VPS IP \(Default is: \${SERVER_IP_DEFAULT}\):" C[59]="\(2/8\) 请输入 VPS IP \(默认为: \${SERVER_IP_DEFAULT}\):" E[60]="Quicktunnel domain can be obtained from: http://\${SERVER_IP_1}:\${METRICS_PORT}/quicktunnel" C[60]="临时隧道域名可以从以下网站获取: http://\${SERVER_IP_1}:\${METRICS_PORT}/quicktunnel" E[61]="Ports are in used: \$REALITY_PORT" C[61]="正在使用中的端口: \$REALITY_PORT" E[62]="Create shortcut [ argox ] successfully." C[62]="创建快捷 [ argox ] 指令成功!" E[63]="The full template can be found at:\n https://t.me/ztvps/67\n https://github.com/chika0801/sing-box-examples/tree/main/Tun" C[63]="完整模板可参照:\n https://t.me/ztvps/67\n https://github.com/chika0801/sing-box-examples/tree/main/Tun" E[64]="subscribe" C[64]="订阅" E[65]="To uninstall Nginx press [y], it is not uninstalled by default:" C[65]="如要卸载 Nginx 请按 [y],默认不卸载:" E[66]="Adaptive Clash / V2rayN / NekoBox / ShadowRocket / SFI / SFA / SFM Clients" C[66]="自适应 Clash / V2rayN / NekoBox / ShadowRocket / SFI / SFA / SFM 客户端" E[67]="template" C[67]="模版" E[68]="(1/8) Output subscription QR code and https service, need to install nginx\n If not, please enter [n]. Default installation:" C[68]="(1/8) 输出订阅二维码和 https 服务,需要安装依赖 nginx\n 如不需要,请输入 [n],默认安装:" E[69]="Set SElinux: enforcing --> disabled" C[69]="设置 SElinux: enforcing --> disabled" # 自定义字体彩色,read 函数 warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色 info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色 hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色 reading() { read -rp "$(info "$1")" "$2"; } text() { grep -q '\$' <<< "${E[$*]}" && eval echo "\$(eval echo "\${${L}[$*]}")" || eval echo "\${${L}[$*]}"; } # 自定义友道或谷歌翻译函数 translate() { [ -n "$@" ] && EN="$@" ZH=$(wget --no-check-certificate -qO- --tries=1 --timeout=2 "https://translate.google.com/translate_a/t?client=any_client_id_works&sl=en&tl=zh&q=${EN//[[:space:]]/}" 2>/dev/null) [[ "$ZH" =~ ^\[\".+\"\]$ ]] && cut -d \" -f2 <<< "$ZH" } # 检测是否解锁 chatGPT,以决定是否使用 warp 链式代理或者是 direct out check_chatgpt() { local CHECK_STACK=$1 local SUPPORT_COUNTRY=(AL DZ AD AO AG AR AM AU AT AZ BS BD BB BE BZ BJ BT BO BA BW BR BN BG BF CV CA CL CO KM CG CR CI HR CY CZ DK DJ DM DO EC SV EE FJ FI FR GA GM GE DE GH GR GD GT GN GW GY HT VA HN HU IS IN ID IQ IE IL IT JM JP JO KZ KE KI KW KG LV LB LS LR LI LT LU MG MW MY MV ML MT MH MR MU MX FM MD MC MN ME MA MZ MM NA NR NP NL NZ NI NE NG MK NO OM PK PW PS PA PG PY PE PH PL PT QA RO RW KN LC VC WS SM ST SN RS SC SL SG SK SI SB ZA KR ES LK SR SE CH TW TZ TH TL TG TO TT TN TR TV UG UA AE GB US UY VU ZM) [[ "${SUPPORT_COUNTRY[@]}" =~ $(wget --no-check-certificate -$CHECK_STACK -qO- --tries=3 --timeout=2 https://chat.openai.com/cdn-cgi/trace | awk -F '=' '/loc/{print $2}') ]] && echo 'unlock' || echo 'ban' } # 脚本当天及累计运行次数统计 statistics_of_run-times() { local COUNT=$(wget --no-check-certificate -qO- --tries=2 --timeout=2 "https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://raw.githubusercontent.com/fscarmen/ArgoX/main/argox.sh" 2>&1 | grep -m1 -oE "[0-9]+[ ]+/[ ]+[0-9]+") && TODAY=$(cut -d " " -f1 <<< "$COUNT") && TOTAL=$(cut -d " " -f3 <<< "$COUNT") } # 选择中英语言 select_language() { if [ -z "$L" ]; then case $(cat $WORK_DIR/language 2>&1) in E ) L=E ;; C ) L=C ;; * ) [ -z "$L" ] && L=E && hint "\n $(text 0) \n" && reading " $(text 24) " LANGUAGE [ "$LANGUAGE" = 2 ] && L=C ;; esac fi } # 只允许 root 用户安装脚本 check_root() { [ "$(id -u)" != 0 ] && error "\n $(text 47) \n" } # 判断处理器架构 check_arch() { case $(uname -m) in aarch64|arm64 ) ARGO_ARCH=arm64; XRAY_ARCH=arm64-v8a; JQ_ARCH=arm64; QRENCODE_ARCH=arm64 ;; x86_64|amd64 ) ARGO_ARCH=amd64; XRAY_ARCH=64; JQ_ARCH=amd64; QRENCODE_ARCH=amd64 ;; armv7l ) ARGO_ARCH=arm; XRAY_ARCH=arm32-v7a; JQ_ARCH=armhf; QRENCODE_ARCH=arm ;; * ) error " $(text 25) " ;; esac } # 查安装及运行状态,下标0: argo,下标1: xray,下标2:docker;状态码: 26 未安装, 27 已安装未运行, 28 运行中 check_install() { [ -s $WORK_DIR/nginx.conf ] && IS_NGINX=is_nginx || IS_NGINX=no_nginx STATUS[0]=$(text 26) && [ -s /etc/systemd/system/argo.service ] && STATUS[0]=$(text 27) && [ "$(systemctl is-active argo)" = 'active' ] && STATUS[0]=$(text 28) STATUS[1]=$(text 26) # xray systemd 文件存在的话,检测一下是否本脚本安装的,如果不是则提示并提出 if [ -s /etc/systemd/system/xray.service ]; then ! grep -q "$WORK_DIR" /etc/systemd/system/xray.service && error " $(text 53)\n $(grep 'ExecStart=' /etc/systemd/system/xray.service) " STATUS[1]=$(text 27) && [ "$(systemctl is-active xray)" = 'active' ] && STATUS[1]=$(text 28) fi [[ ${STATUS[0]} = "$(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; }& [[ ${STATUS[1]} = "$(text 26)" ]] && [ ! -s $WORK_DIR/xray ] && { wget --no-check-certificate -qO $TEMP_DIR/Xray.zip https://github.com/XTLS/Xray-core/releases/latest/download/Xray-linux-$XRAY_ARCH.zip >/dev/null 2>&1; unzip -qo $TEMP_DIR/Xray.zip xray *.dat -d $TEMP_DIR >/dev/null 2>&1; }& { wget --no-check-certificate --continue -qO $TEMP_DIR/jq https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$JQ_ARCH >/dev/null 2>&1 && chmod +x $TEMP_DIR/jq >/dev/null 2>&1; }& { 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; }& } # 订阅 api 函数,为保证节点数据的安全性,将置换为伪造数据去获取 api 配置信息,之后再置换为真实的 fetch_subscribe() { # 1. 获取参数 local TARGET=$1 local REAL_FILE=$2 local URL=$3 # 2. 获取重点键值,由于 sing-box 使用 v2ray 插件不成功的原因,所以 sing-box 去掉 shadowsocks+WSS 的协议 [ "$TARGET" = 'singbox' ] && local REAL_CONTENT=$(sed '/type: ss/d' $REAL_FILE) || local REAL_CONTENT=$(cat $REAL_FILE) local REAL_NAME=($(sed -n 's/.*\-[ ]*{[ ]*name:[ ]*"\([^"]*\)".*/\1/gp' <<< "$REAL_CONTENT")) local REAL_SERVER=($(sed -n 's/.*,[ ]*server:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_SERVERNAME=($(sed -n 's/.*servername:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_HOST=($(sed -n 's/.*ost:[ ]*\([^,}]\+\).*/\1/gp' <<< "$REAL_CONTENT")) local REAL_SNI=($(sed -n 's/.*sni:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_PORT=($(sed -n 's/.*,[ ]*port:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_UUID=($(sed -n 's/.*,[ ]*uuid:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_PASSWORD=($(sed -n 's/.*,[ ]*password:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_PUBLIC=($(sed -n 's/.*{[ ]*public-key:[ ]*\([^,]\+\),.*/\1/gp' <<< "$REAL_CONTENT")) local REAL_PATH=($(sed -n 's/.*path:[ ]*"\/\([^"]\+\)",.*/\1/gp' <<< "$REAL_CONTENT")) # 3. 混淆各键值 local FAKE_CONTENT=$REAL_CONTENT local FAKE_FILE=${REAL_FILE}-${TARGET}-fake local FAKE_URL=${URL}-${TARGET}-fake for d in ${!REAL_NAME[@]}; do local FAKE_NAME[d]=$(cat /proc/sys/kernel/random/uuid) local FAKE_CONTENT=$(sed "1,/name: \"${REAL_NAME[d]}/s/${REAL_NAME[d]}/${FAKE_NAME[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_SERVER[@]}; do local FAKE_SERVER[d]="$(cat /proc/sys/kernel/random/uuid)" local FAKE_CONTENT=$(sed "1,/server: ${REAL_SERVER[d]}/s/server: ${REAL_SERVER[d]}/server: ${FAKE_SERVER[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_SERVERNAME[@]}; do local FAKE_SERVERNAME[d]="$(cat /proc/sys/kernel/random/uuid)" local FAKE_CONTENT=$(sed "1,/servername: ${REAL_SERVERNAME[d]}/s/servername: ${REAL_SERVERNAME[d]}/servername: ${FAKE_SERVERNAME[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_SNI[@]}; do local FAKE_SNI[d]="$(cat /proc/sys/kernel/random/uuid)" local FAKE_CONTENT=$(sed "1,/sni: ${REAL_SNI[d]}/s/sni: ${REAL_SNI[d]}/sni: ${FAKE_SNI[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_HOST[@]}; do local FAKE_HOST[d]="$(cat /proc/sys/kernel/random/uuid)" local FAKE_CONTENT=$(sed "1,/ost: ${REAL_HOST[d]}/s/ost: ${REAL_HOST[d]}/ost: ${FAKE_HOST[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_PORT[@]}; do local FAKE_PORT[d]=$(shuf -i 10000-65535 -n 1) local FAKE_CONTENT=$(sed "1,/port: ${REAL_PORT[d]}/s/port: ${REAL_PORT[d]}/port: ${FAKE_PORT[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_UUID[@]}; do local FAKE_UUID[d]=$(cat /proc/sys/kernel/random/uuid) local FAKE_CONTENT=$(sed "1,/uuid: ${REAL_UUID[d]}/s/uuid: ${REAL_UUID[d]}/uuid: ${FAKE_UUID[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_PASSWORD[@]}; do local FAKE_PASSWORD[d]=$(cat /proc/sys/kernel/random/uuid) local FAKE_CONTENT=$(sed "1,/password: ${REAL_PASSWORD[d]}/s/password: ${REAL_PASSWORD[d]}/password: ${FAKE_PASSWORD[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_PUBLIC[@]}; do local FAKE_PUBLIC[d]=$(cat /proc/sys/kernel/random/uuid) local FAKE_CONTENT=$(sed "1,/public-key: ${REAL_PUBLIC[d]}/s/public-key: ${REAL_PUBLIC[d]}/public-key: ${FAKE_PUBLIC[d]}/" <<< "$FAKE_CONTENT") done for d in ${!REAL_PATH[@]}; do local FAKE_PATH[d]=$(cat /proc/sys/kernel/random/uuid) local FAKE_CONTENT=$(sed "1,/path: \"${REAL_PATH[d]}\"/s#path: \"/${REAL_PATH[d]}#path: \"/${FAKE_PATH[d]}#" <<< "$FAKE_CONTENT") done # 4. 把混淆节点保存到本地,以让外网能访问 echo "$FAKE_CONTENT" > $FAKE_FILE # 5. 通过转订阅后端 api 获取配置信息 FROM_API=$(wget --no-check-certificate -qO- --tries=3 --timeout=2 "https://${SUBSCRIBE_API[0]}/sub?target=$TARGET&url=$FAKE_URL&insert=false&config=https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini&emoji=true&list=false&tfo=false&scv=false&fdn=false&sort=false&new_name=true") # 6. 删除临时文件 rm -f $FAKE_FILE # 7. 还原数据 local REAL_CONFIG="$FROM_API" for d in ${!FAKE_NAME[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_NAME[d]}/${REAL_NAME[d]}/g" <<< "$REAL_CONFIG") done for d in ${!FAKE_SERVER[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_SERVER[d]}/${REAL_SERVER[d]}/g" <<< "$REAL_CONFIG") done for d in ${!FAKE_SERVERNAME[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_SERVERNAME[d]}/${REAL_SERVERNAME[d]}/" <<< "$REAL_CONFIG") done for d in ${!FAKE_SNI[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_SNI[d]}/${REAL_SNI[d]}/g" <<< "$REAL_CONFIG") done ### 此处修正理订阅服务里存在的 bug,在 trojan + WSS 协议转换中,server_name 本应是 sni 独立的,转换中 server_name 与 sni 一样了,故修正回来 local REAL_CONFIG=$(sed "s/${FAKE_SNI[0]}/${FAKE_HOST[2]}/" <<< "$REAL_CONFIG") for d in ${!FAKE_HOST[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_HOST[d]}/${REAL_HOST[d]}/" <<< "$REAL_CONFIG") done for d in ${!FAKE_PORT[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_PORT[d]}/${REAL_PORT[d]}/g" <<<"$REAL_CONFIG") done for d in ${!FAKE_UUID[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_UUID[d]}/${REAL_UUID[d]}/g" <<< "$REAL_CONFIG") done for d in ${!FAKE_PASSWORD[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_PASSWORD[d]}/${REAL_PASSWORD[d]}/g" <<< "$REAL_CONFIG") done for d in ${!FAKE_PUBLIC[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_PUBLIC[d]}/${REAL_PUBLIC[d]}/g" <<< "$REAL_CONFIG") done for d in ${!FAKE_PATH[@]}; do local REAL_CONFIG=$(sed "s/${FAKE_PATH[d]}/${REAL_PATH[d]}/g" <<< "$REAL_CONFIG") done # 8. 输出最终真实结果 echo "$REAL_CONFIG" } # 为了适配 alpine,定义 cmd_systemctl 的函数 cmd_systemctl() { [ -s $WORK_DIR/nginx.conf ] && local IS_NGINX=is_nginx || local IS_NGINX=no_nginx local ENABLE_DISABLE=$1 local APP=$2 if [ "$ENABLE_DISABLE" = 'enable' ]; then if [ "$SYSTEM" = 'Alpine' ]; then systemctl start $APP cat > /etc/local.d/$APP.start << EOF #!/usr/bin/env bash systemctl start $APP EOF chmod +x /etc/local.d/$APP.start rc-update add local >/dev/null 2>&1 elif [ "$IS_CENTOS" = 'CentOS7' ]; then systemctl enable --now $APP [[ "$APP" = 'argo' && "$IS_NGINX" = 'is_nginx' ]] && $(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 [[ "$APP" = 'argo' && "$IS_NGINX" = 'is_nginx' ]] && ss -nltp | grep "$(cat /var/run/nginx.pid)" | 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 [[ "$APP" = 'argo' && "$IS_NGINX" = 'is_nginx' ]] && ss -nltp | grep "$(cat /var/run/nginx.pid)" | tr ',' '\n' | awk -F '=' '/pid/{print $2}' | sort -u | xargs kill -15 >/dev/null 2>&1 else systemctl disable --now $APP fi fi } check_system_info() { # 判断虚拟化 if [ $(type -p systemd-detect-virt) ]; then VIRT=$(systemd-detect-virt) elif [ $(type -p hostnamectl) ]; then VIRT=$(hostnamectl | awk '/Virtualization/{print $NF}') elif [ $(type -p virt-what) ]; then VIRT=$(virt-what) fi [ -s /etc/os-release ] && SYS="$(grep -i pretty_name /etc/os-release | cut -d \" -f2)" [[ -z "$SYS" && $(type -p hostnamectl) ]] && SYS="$(hostnamectl | grep -i system | cut -d : -f2)" [[ -z "$SYS" && $(type -p lsb_release) ]] && SYS="$(lsb_release -sd)" [[ -z "$SYS" && -s /etc/lsb-release ]] && SYS="$(grep -i description /etc/lsb-release | cut -d \" -f2)" [[ -z "$SYS" && -s /etc/redhat-release ]] && SYS="$(grep . /etc/redhat-release)" [[ -z "$SYS" && -s /etc/issue ]] && SYS="$(grep . /etc/issue | cut -d '\' -f1 | sed '/^[ ]*$/d')" REGEX=("debian" "ubuntu" "centos|red hat|kernel|alma|rocky" "arch linux" "alpine" "fedora") RELEASE=("Debian" "Ubuntu" "CentOS" "Arch" "Alpine" "Fedora") EXCLUDE=("") MAJOR=("9" "16" "7" "3" "" "37") PACKAGE_UPDATE=("apt -y update" "apt -y update" "yum -y update" "pacman -Sy" "apk update -f" "dnf -y update") PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "pacman -S --noconfirm" "apk add --no-cache" "dnf -y install") PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "pacman -Rcnsu --noconfirm" "apk del -f" "dnf -y autoremove") for int in "${!REGEX[@]}"; do [[ "${SYS,,}" =~ ${REGEX[int]} ]] && SYSTEM="${RELEASE[int]}" && break done [ -z "$SYSTEM" ] && error " $(text 5) " # 针对各厂商的订制系统 if [ -z "$SYSTEM" ]; then [ $(type -p yum) ] && int=2 && SYSTEM='CentOS' || error " $(text 5) " fi # 先排除 EXCLUDE 里包括的特定系统,其他系统需要作大发行版本的比较 for ex in "${EXCLUDE[@]}"; do [[ ! "{$SYS,,}" =~ $ex ]]; done && [[ "$(echo "$SYS" | sed "s/[^0-9.]//g" | cut -d. -f1)" -lt "${MAJOR[int]}" ]] && error " $(text 6) " # 针对部分系统作特殊处理 [ "$SYSTEM" = 'CentOS' ] && IS_CENTOS="CentOS$(echo "$SYS" | sed "s/[^0-9.]//g" | cut -d. -f1)" } # 检测 IPv4 IPv6 信息 check_system_ip() { if [ -z "$VARIABLE_FILE" ]; then IP4=$(wget -4 -qO- --no-check-certificate --user-agent=Mozilla --tries=2 --timeout=3 http://ip-api.com/json/) && WAN4=$(expr "$IP4" : '.*query\":[ ]*\"\([^"]*\).*') && COUNTRY4=$(expr "$IP4" : '.*country\":[ ]*\"\([^"]*\).*') && ASNORG4=$(expr "$IP4" : '.*isp\":[ ]*\"\([^"]*\).*') && [[ "$L" = C && -n "$COUNTRY4" ]] && COUNTRY4=$(translate "$COUNTRY4") IP6=$(wget -6 -qO- --no-check-certificate --user-agent=Mozilla --tries=2 --timeout=3 https://api.ip.sb/geoip) && WAN6=$(expr "$IP6" : '.*ip\":[ ]*\"\([^"]*\).*') && COUNTRY6=$(expr "$IP6" : '.*country\":[ ]*\"\([^"]*\).*') && ASNORG6=$(expr "$IP6" : '.*isp\":[ ]*\"\([^"]*\).*') && [[ "$L" = C && -n "$COUNTRY6" ]] && COUNTRY6=$(translate "$COUNTRY6") fi } # 定义 Argo 变量 argo_variable() { [ -z "$INSTALL_NGINX" ] && reading "\n $(text 68) " INSTALL_NGINX [ "${INSTALL_NGINX,,}" != 'n' ] && check_nginx >/dev/null 2>&1 & if grep -qi 'cloudflare' <<< "$ASNORG4$ASNORG6"; then local a=6 until [ -n "$SERVER_IP" ]; do ((a--)) || true [ "$a" = 0 ] && error "\n $(text 3) \n" reading "\n $(text 54) " SERVER_IP done if [[ "$SERVER_IP" =~ : ]]; then WARP_ENDPOINT=2606:4700:d0::a29f:c101 else WARP_ENDPOINT=162.159.193.10 fi elif [ -n "$WAN4" ]; then SERVER_IP_DEFAULT=$WAN4 WARP_ENDPOINT=162.159.193.10 elif [ -n "$WAN6" ]; then SERVER_IP_DEFAULT=$WAN6 WARP_ENDPOINT=2606:4700:d0::a29f:c101 fi # 检测是否解锁 chatGPT CHAT_GPT_OUT_V4=warp-IPv4; CHAT_GPT_OUT_V6=warp-IPv4; [ "$(check_chatgpt ${DOMAIN_STRATEG: -1})" = 'unlock' ] && CHAT_GPT_OUT_V4=direct && CHAT_GPT_OUT_V6=direct # 输入服务器 IP,默认为检测到的服务器 IP,如果全部为空,则提示并退出脚本 [ -z "$SERVER_IP" ] && reading "\n $(text 59) " SERVER_IP SERVER_IP=${SERVER_IP:-"$SERVER_IP_DEFAULT"} [ -z "$SERVER_IP" ] && error " $(text 58) " # 处理可能输入的错误,去掉开头和结尾的空格,去掉最后的 : [ -z "$ARGO_DOMAIN" ] && reading "\n $(text 10) " ARGO_DOMAIN ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN") if [[ -n "$ARGO_DOMAIN" && -z "$ARGO_AUTH" ]]; then local a=5 until [[ "$ARGO_AUTH" =~ TunnelSecret || "${ARGO_AUTH,,}" =~ ^[a-z0-9=]{120,250}$ || "${ARGO_AUTH,,}" =~ .*cloudflared.*service[[:space:]]+install[[:space:]]+[a-z0-9=]{1,100} ]]; do [ "$a" = 0 ] && error "\n $(text 3) \n" || reading "\n $(text 11) " ARGO_AUTH if [[ "$ARGO_AUTH" =~ TunnelSecret ]]; then ARGO_JSON=${ARGO_AUTH//[ ]/} elif [[ "${ARGO_AUTH,,}" =~ ^[a-z0-9=]{120,250}$ ]]; then ARGO_TOKEN=$ARGO_AUTH elif [[ "{$ARGO_AUTH,,}" =~ .*cloudflared.*service[[:space:]]+install[[:space:]]+[a-z0-9=]{1,100} ]]; then ARGO_TOKEN=$(awk -F ' ' '{print $NF}' <<< "$ARGO_AUTH") else warning "\n $(text 45) \n" fi ((a--)) || true done fi } # 定义 Xray 变量 xray_variable() { local a=6 until [ -n "$REALITY_PORT" ]; do ((a--)) || true [ "$a" = 0 ] && error "\n $(text 3) \n" REALITY_PORT_DEFAULT=$(shuf -i 1000-65535 -n 1) reading "\n $(text 56) " REALITY_PORT REALITY_PORT=${REALITY_PORT:-"$REALITY_PORT_DEFAULT"} ss -nltup | grep -q ":$REALITY_PORT" && warning "\n $(text 61) \n" && unset REALITY_PORT done # 提供网上热心网友的anycast域名 if [ -z "$SERVER" ]; then echo "" for c in "${!CDN_DOMAIN[@]}"; do hint " $[c+1]. ${CDN_DOMAIN[c]} " done reading "\n $(text 42) " CUSTOM_CDN case "$CUSTOM_CDN" in [1-${#CDN_DOMAIN[@]}] ) SERVER="${CDN_DOMAIN[$((CUSTOM_CDN-1))]}" ;; ?????* ) SERVER="$CUSTOM_CDN" ;; * ) SERVER="${CDN_DOMAIN[0]}" esac fi local a=6 until [[ "${UUID,,}" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ ]]; do (( a-- )) || true [ "$a" = 0 ] && error "\n $(text 3) \n" UUID_DEFAULT=$(cat /proc/sys/kernel/random/uuid) reading "\n $(text 12) " UUID UUID=${UUID:-"$UUID_DEFAULT"} [[ ! "${UUID,,}" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ ]] && warning "\n $(text 4) " done [ -z "$WS_PATH" ] && reading "\n $(text 13) " WS_PATH local a=5 until [[ -z "$WS_PATH" || "${WS_PATH,,}" =~ ^[a-z0-9]+$ ]]; do (( a-- )) || true [ "$a" = 0 ] && error " $(text 3) " || reading " $(text 14) " WS_PATH done WS_PATH=${WS_PATH:-"$WS_PATH_DEFAULT"} # 输入节点名,以系统的 hostname 作为默认 if [ -z "$NODE_NAME" ]; then if [ $(type -p hostname) ]; then NODE_NAME_DEFAULT="$(hostname)" elif [ -s /etc/hostname ]; then NODE_NAME_DEFAULT="$(cat /etc/hostname)" else NODE_NAME_DEFAULT="ArgoX" fi reading "\n $(text 49) " NODE_NAME NODE_NAME="${NODE_NAME:-"$NODE_NAME_DEFAULT"}" fi } check_dependencies() { # 如果是 Alpine,先升级 wget ,安装 systemctl-py 版 if [ "$SYSTEM" = 'Alpine' ]; then local CHECK_WGET=$(wget 2>&1 | head -n 1) grep -qi 'busybox' <<< "$CHECK_WGET" && ${PACKAGE_INSTALL[int]} wget >/dev/null 2>&1 local DEPS_CHECK=("bash" "rc-update" "virt-what" "python3") local DEPS_INSTALL=("bash" "openrc" "virt-what" "python3") for g in ${!DEPS_CHECK[@]}; do [ ! $(type -p ${DEPS_CHECK[g]}) ] && DEPS_ALPINE+=(${DEPS_INSTALL[g]}) done if [ "${#DEPS_ALPINE[@]}" -ge 1 ]; then info "\n $(text 7) $(sed "s/ /,&/g" <<< ${DEPS_ALPINE[@]}) \n" ${PACKAGE_UPDATE[int]} >/dev/null 2>&1 ${PACKAGE_INSTALL[int]} ${DEPS_ALPINE[@]} >/dev/null 2>&1 [[ -z "$VIRT" && "${DEPS_ALPINE[@]}" =~ 'virt-what' ]] && VIRT=$(virt-what) fi [ ! $(type -p systemctl) ] && wget --no-check-certificate --quiet https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl3.py -O /bin/systemctl && chmod a+x /bin/systemctl fi # 检测 Linux 系统的依赖,升级库并重新安装依赖 local DEPS_CHECK=("wget" "systemctl" "ss" "unzip" "bash") local DEPS_INSTALL=("wget" "systemctl" "iproute2" "unzip" "bash") for g in ${!DEPS_CHECK[@]}; do [ ! $(type -p ${DEPS_CHECK[g]}) ] && DEPS+=(${DEPS_INSTALL[g]}) done if [ "${#DEPS[@]}" -ge 1 ]; then info "\n $(text 7) $(sed "s/ /,&/g" <<< ${DEPS[@]}) \n" [ "$SYSTEM" != 'CentOS' ] && ${PACKAGE_UPDATE[int]} >/dev/null 2>&1 ${PACKAGE_INSTALL[int]} ${DEPS[@]} >/dev/null 2>&1 else info "\n $(text 8) \n" fi # 不需要 nginx 原来的服务 [[ "${DEPS[@]}" =~ 'nginx' ]] && cmd_systemctl disable nginx >/dev/null 2>&1 } # 检查并安装 nginx check_nginx() { if [ ! $(type -p nginx) ]; then info "\n $(text 7) nginx \n" ${PACKAGE_INSTALL[int]} nginx >/dev/null 2>&1 # 如果新安装的 Nginx ,先停掉服务 systemctl disable --now nginx >/dev/null 2>&1 fi } # 处理防火墙规则 check_firewall_configuration() { if [[ -s /etc/selinux/config && $(type -p getenforce) && $(getenforce) = 'Enforcing' ]]; then hint "\n $(text 69) \n" setenforce 0 sed -i 's/^SELINUX=.*/# &/; /SELINUX=/a\SELINUX=disabled' /etc/selinux/config fi } # Nginx 配置文件 json_nginx() { if [ -s $WORK_DIR/*inbound*.json ]; then JSON=$(cat $WORK_DIR/*inbound*.json) WS_PATH=$(expr "$JSON" : '.*path":"/\(.*\)-vl.*') SERVER_IP=${SERVER_IP:-"$(awk -F '"' '/"SERVER_IP"/{print $4}' <<< "$JSON")"} UUID=$(awk -F '"' '/"password"/{print $4; exit}' <<< "$JSON") fi [[ "$SERVER_IP" =~ : ]] && REVERSE_IP="[$SERVER_IP]" || REVERSE_IP="$SERVER_IP" cat > $WORK_DIR/nginx.conf << EOF user root; worker_processes auto; error_log /dev/null; pid /var/run/nginx.pid; events { worker_connections 1024; } http { map \$http_user_agent \$path1 { default /; # 默认路径 ~*v2rayN|Neko /base64; # 匹配 V2rayN / NekoBox 客户端 ~*clash /clash; # 匹配 Clash 客户端 ~*ShadowRocket /shadowrocket; # 匹配 ShadowRocket 客户端 ~*SFM /sing-box-pc; # 匹配 Sing-box pc 客户端 ~*SFI|SFA /sing-box-phone; # 匹配 Sing-box phone 客户端 # ~*Chrome|Firefox|Mozilla /; # 添加更多的分流规则 } map \$http_user_agent \$path2 { default /; # 默认路径 ~*v2rayN|Neko /base64; # 匹配 V2rayN / NekoBox 客户端 ~*clash /clash2; # 匹配 Clash 客户端 ~*ShadowRocket /shadowrocket; # 匹配 ShadowRocket 客户端 ~*SFM|SFI|SFA /sing-box2; # 匹配 Sing-box pc 和 phone 客户端 # ~*Chrome|Firefox|Mozilla /; # 添加更多的分流规则 } 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"'; access_log /dev/null; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; #include /etc/nginx/conf.d/*.conf; server { listen 127.0.0.1:3006 proxy_protocol; # xray fallbacks # 来自 /auto2 的分流 location ~ ^/${UUID}/auto2 { default_type 'text/plain; charset=utf-8'; alias ${WORK_DIR}/subscribe/\$path2; } # 来自 /auto 的分流 location ~ ^/${UUID}/auto { default_type 'text/plain; charset=utf-8'; alias ${WORK_DIR}/subscribe/\$path1; } location ~ ^/${UUID}/(.*) { autoindex on; proxy_set_header X-Real-IP \$proxy_protocol_addr; default_type 'text/plain; charset=utf-8'; alias ${WORK_DIR}/subscribe/\$1; } } } EOF } # Json 生成两个配置文件 json_argo() { [ ! -s $WORK_DIR/tunnel.json ] && echo $ARGO_JSON > $WORK_DIR/tunnel.json [ ! -s $WORK_DIR/tunnel.yml ] && cat > $WORK_DIR/tunnel.yml << EOF tunnel: $(cut -d\" -f12 <<< $ARGO_JSON) credentials-file: $WORK_DIR/tunnel.json ingress: - hostname: ${ARGO_DOMAIN} service: http://localhost:8080 - service: http_status:404 EOF } install_argox() { argo_variable xray_variable [ "$SYSTEM" = 'CentOS' ] && check_firewall_configuration wait # 生成 reality 的公私钥 [[ -z "$REALITY_PRIVATE" || -z "$REALITY_PUBLIC" ]] && REALITY_KEYPAIR=$($TEMP_DIR/xray x25519) [ -z "$REALITY_PRIVATE" ] && REALITY_PRIVATE=$(awk '/Private/{print $NF}' <<< "$REALITY_KEYPAIR") [ -z "$REALITY_PUBLIC" ] && REALITY_PUBLIC=$(awk '/Public/{print $NF}' <<< "$REALITY_KEYPAIR") [ ! -d /etc/systemd/system ] && mkdir -p /etc/systemd/system mkdir -p $WORK_DIR/subscribe && echo "$L" > $WORK_DIR/language [ -s "$VARIABLE_FILE" ] && cp $VARIABLE_FILE $WORK_DIR/ wait [[ ! -s $WORK_DIR/cloudflared && -x $TEMP_DIR/cloudflared ]] && mv $TEMP_DIR/cloudflared $WORK_DIR [[ ! -s $WORK_DIR/jq && -x $TEMP_DIR/jq ]] && mv $TEMP_DIR/jq $WORK_DIR [[ "$INSTALL_NGINX" != 'n' && ! -s $WORK_DIR/qrencode && -x $TEMP_DIR/qrencode ]] && mv $TEMP_DIR/qrencode $WORK_DIR if [[ -n "${ARGO_JSON}" && -n "${ARGO_DOMAIN}" ]]; then ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto --config $WORK_DIR/tunnel.yml run" json_argo elif [[ -n "${ARGO_TOKEN}" && -n "${ARGO_DOMAIN}" ]]; then ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto run --token ${ARGO_TOKEN}" else ARGO_RUNS="$WORK_DIR/cloudflared tunnel --edge-ip-version auto --no-autoupdate --metrics 0.0.0.0:${METRICS_PORT} --url http://localhost:8080" fi # Argo 生成守护进程文件 local ARGO_SERVER="[Unit] Description=Cloudflare Tunnel After=network.target [Service] Type=simple NoNewPrivileges=yes TimeoutStartSec=0" [[ "$INSTALL_NGINX" != 'n' && "$IS_CENTOS" != 'CentOS7' ]] && ARGO_SERVER+=" ExecStartPre=$(type -p nginx) -c $WORK_DIR/nginx.conf" ARGO_SERVER+=" ExecStart=$ARGO_RUNS Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target" echo "$ARGO_SERVER" > /etc/systemd/system/argo.service # 生成配置文件及守护进程文件 local i=1 [ ! -s $WORK_DIR/xray ] && wait && while [ "$i" -le 20 ]; do [[ -s $TEMP_DIR/xray && -s $TEMP_DIR/geoip.dat && -s $TEMP_DIR/geosite.dat ]] && mv $TEMP_DIR/xray $TEMP_DIR/geo*.dat $WORK_DIR && break; ((i++)); sleep 2; done [ "$i" -ge 20 ] && local APP=Xray && error "\n $(text 48) " cat > $WORK_DIR/inbound.json << EOF // "SERVER_IP":"${SERVER_IP}" // "REALITY_PUBLIC":"${REALITY_PUBLIC}" // "SERVER":"${SERVER}" { "log":{ "access":"/dev/null", "error":"/dev/null", "loglevel":"none" }, "inbounds":[ { "tag":"${NODE_NAME} reality-vision", "protocol":"vless", "port":${REALITY_PORT}, "settings":{ "clients":[ { "id":"${UUID}", "flow":"xtls-rprx-vision" } ], "decryption":"none", "fallbacks":[ { "dest":"3001", "xver":1 } ] }, "streamSettings":{ "network":"tcp", "security":"reality", "realitySettings":{ "show":true, "dest":"${TLS_SERVER}:443", "xver":0, "serverNames":[ "${TLS_SERVER}" ], "privateKey":"${REALITY_PRIVATE}", "publicKey":"${REALITY_PUBLIC}", "maxTimeDiff":70000, "shortIds":[ "" ] } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls" ] } }, { "port":3001, "listen":"127.0.0.1", "protocol":"vless", "tag":"${NODE_NAME} reality-grpc", "settings":{ "clients":[ { "id":"${UUID}", "flow":"" } ], "decryption":"none" }, "streamSettings":{ "network":"grpc", "grpcSettings":{ "serviceName":"grpc", "multiMode":true }, "sockopt":{ "acceptProxyProtocol":true } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls" ] } }, { "listen":"127.0.0.1", "port":8080, "protocol":"vless", "settings":{ "clients":[ { "id":"${UUID}", "flow":"xtls-rprx-vision" } ], "decryption":"none", "fallbacks":[ { "path":"/${WS_PATH}-vl", "dest":3002 }, { "path":"/${WS_PATH}-vm", "dest":3003 }, { "path":"/${WS_PATH}-tr", "dest":3004 }, { "path":"/${WS_PATH}-sh", "dest":3005 }, { "dest":3006, "alpn": "", "xver": 1 } ] }, "streamSettings":{ "network":"tcp" } }, { "port":3002, "listen":"127.0.0.1", "protocol":"vless", "settings":{ "clients":[ { "id":"${UUID}", "level":0 } ], "decryption":"none" }, "streamSettings":{ "network":"ws", "security":"none", "wsSettings":{ "path":"/${WS_PATH}-vl" } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls", "quic" ], "metadataOnly":false } }, { "port":3003, "listen":"127.0.0.1", "protocol":"vmess", "settings":{ "clients":[ { "id":"${UUID}", "alterId":0 } ] }, "streamSettings":{ "network":"ws", "wsSettings":{ "path":"/${WS_PATH}-vm" } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls", "quic" ], "metadataOnly":false } }, { "port":3004, "listen":"127.0.0.1", "protocol":"trojan", "settings":{ "clients":[ { "password":"${UUID}" } ] }, "streamSettings":{ "network":"ws", "security":"none", "wsSettings":{ "path":"/${WS_PATH}-tr" } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls", "quic" ], "metadataOnly":false } }, { "port":3005, "listen":"127.0.0.1", "protocol":"shadowsocks", "settings":{ "clients":[ { "method":"chacha20-ietf-poly1305", "password":"${UUID}" } ], "decryption":"none" }, "streamSettings":{ "network":"ws", "wsSettings":{ "path":"/${WS_PATH}-sh" } }, "sniffing":{ "enabled":true, "destOverride":[ "http", "tls", "quic" ], "metadataOnly":false } } ], "dns":{ "servers":[ "https+local://8.8.8.8/dns-query" ] } } EOF cat > $WORK_DIR/outbound.json << EOF { "outbounds":[ { "protocol":"freedom", "tag":"direct" }, { "protocol":"blackhole", "settings":{ }, "tag":"block" }, { "protocol":"wireguard", "settings":{ "secretKey":"YFYOAdbw1bKTHlNNi+aEjBM3BO7unuFC5rOkMRAz9XY=", "address":[ "172.16.0.2/32", "2606:4700:110:8a36:df92:102a:9602:fa18/128" ], "peers":[ { "publicKey":"bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=", "allowedIPs":[ "0.0.0.0/0", "::/0" ], "endpoint":"${WARP_ENDPOINT}:2408" } ], "reserved":[ 78, 135, 76 ], "mtu":1280 }, "tag":"wireguard" }, { "protocol":"freedom", "settings":{ "domainStrategy":"UseIPv4" }, "proxySettings":{ "tag":"wireguard" }, "tag":"warp-IPv4" }, { "protocol":"freedom", "settings":{ "domainStrategy":"UseIPv6" }, "proxySettings":{ "tag":"wireguard" }, "tag":"warp-IPv6" } ], "routing":{ "domainStrategy":"AsIs", "rules":[ { "type":"field", "domain":[ "api.openai.com" ], "outboundTag":"$CHAT_GPT_OUT_V4" }, { "type":"field", "domain":[ "geosite:openai" ], "outboundTag":"$CHAT_GPT_OUT_V6" } ] } } EOF cat > /etc/systemd/system/xray.service << EOF [Unit] Description=Xray Service Documentation=https://github.com/XTLS/Xray-core After=network.target nss-lookup.target Wants=network-online.target [Service] Type=simple NoNewPrivileges=yes ExecStart=$WORK_DIR/xray run -confdir $WORK_DIR/ Restart=on-failure RestartPreventExitStatus=23 [Install] WantedBy=multi-user.target EOF # 生成 Nginx 配置文件 [ "$INSTALL_NGINX" != 'n' ] && json_nginx # 再次检测状态,运行 Argo 和 Xray check_install case "${STATUS[0]}" in "$(text 26)" ) warning "\n Argo $(text 28) $(text 38) \n" ;; "$(text 27)" ) cmd_systemctl enable argo && info "\n Argo $(text 28) $(text 37) \n" ;; "$(text 28)" ) info "\n Argo $(text 28) $(text 37) \n" esac case "${STATUS[0]}" in "$(text 26)" ) warning "\n Xray $(text 28) $(text 38) \n" ;; "$(text 27)" ) cmd_systemctl enable xray && info "\n Xray $(text 28) $(text 37) \n" ;; "$(text 28)" ) info "\n Xray $(text 28) $(text 37) \n" esac } # 创建快捷方式 create_shortcut() { cat > $WORK_DIR/ax.sh << EOF #!/usr/bin/env bash bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/argox/main/argox.sh) \$1 EOF chmod +x $WORK_DIR/ax.sh ln -sf $WORK_DIR/ax.sh /usr/bin/argox [ -s /usr/bin/argox ] && hint "\n $(text 62) " } export_list() { check_install #### v1.6.3 处理的 jq 和 qrencode 二进制文件代替系统依赖的问题,此处预计6月30日删除 if [ "$IS_NGINX" = 'is_nginx' ]; then [[ ! -s $WORK_DIR/jq && -s /usr/bin/jq ]] && cp /usr/bin/jq $WORK_DIR/ if [ ! -s $WORK_DIR/qrencode ]; then check_arch wget -qO $WORK_DIR/qrencode https://github.com/fscarmen/client_template/raw/main/qrencode-go/qrencode-go-linux-$QRENCODE_ARCH && chmod +x $WORK_DIR/qrencode fi fi # 没有开启 Argo 和 Xray 服务,将不输出节点信息 local APP [ "${STATUS[0]}" != "$(text 28)" ] && APP+=(Argo) [ "${STATUS[1]}" != "$(text 28)" ] && APP+=(Xray) if [ "${#APP[@]}" -gt 0 ]; then reading "\n $(text 50) " OPEN_APP if [ "${OPEN_APP,,}" = 'y' ]; then [ "${STATUS[0]}" != "$(text 28)" ] && cmd_systemctl enable argo [ "${STATUS[1]}" != "$(text 28)" ] && cmd_systemctl enable xray else exit fi fi if grep -q "^ExecStart=.*8080$" /etc/systemd/system/argo.service; then local a=5 until [[ -n "$ARGO_DOMAIN" || "$a" = 0 ]]; do sleep 2 ARGO_DOMAIN=$(wget -qO- http://localhost:$(ps -ef | awk -F '0.0.0.0:' '/cloudflared.*:8080/{print $2}' | awk 'NR==1 {print $1}')/quicktunnel | awk -F '"' '{print $4}') ((a--)) || true done else ARGO_DOMAIN=${ARGO_DOMAIN:-"$(grep -m1 '^vless.*host=.*' $WORK_DIR/list | sed "s@.*host=\(.*\)&.*@\1@g")"} fi JSON=$(cat $WORK_DIR/*inbound*.json) SERVER_IP=${SERVER_IP:-"$(awk -F '"' '/"SERVER_IP"/{print $4; exit}' <<< "$JSON")"} REALITY_PORT=${REALITY_PORT:-"$(awk -F '[:,]' '/"port"/{print $2; exit}' <<< "$JSON")"} REALITY_PUBLIC=${REALITY_PUBLIC:-"$(awk -F '"' '/"publicKey"/{print $4; exit}' <<< "$JSON")"} REALITY_PRIVATE=${REALITY_PRIVATE:-"$(awk -F '"' '/"privateKey"/{print $4; exit}' <<< "$JSON")"} TLS_SERVER=${TLS_SERVER:-"$(awk -F '"' '/"server_name"/{print $4}' <<< "$JSON")"} SERVER=${SERVER:-"$(awk -F '"' '/"SERVER"/{print $4; exit}' <<< "$JSON")"} UUID=${UUID:-"$(awk -F '"' '/"password"/{print $4; exit}' <<< "$JSON")"} WS_PATH=${WS_PATH:-"$(expr "$JSON" : '.*path":"/\(.*\)-vl.*')"} NODE_NAME=${NODE_NAME:-"$(sed -n 's/.*tag":"\(.*\) reality-vision.*/\1/gp' <<< "$JSON")"} SS_METHOD=${SS_METHOD:-"$(awk -F '"' '/"method"/{print $4; exit}' <<< "$JSON")"} # IPv6 时的 IP 处理 if [[ "$SERVER_IP" =~ : ]]; then SERVER_IP_1="[$SERVER_IP]" SERVER_IP_2="[[$SERVER_IP]]" else SERVER_IP_1="$SERVER_IP" SERVER_IP_2="$SERVER_IP" fi # 若为临时隧道,处理查询方法 grep -q 'metrics.*url' /etc/systemd/system/argo.service && QUICK_TUNNEL_URL=$(text 60) # # 生成 vmess 文件 VMESS="{ \"v\": \"2\", \"ps\": \"${NODE_NAME}-Vm\", \"add\": \"${SERVER}\", \"port\": \"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"${ARGO_DOMAIN}\", \"path\": \"/${WS_PATH}-vm?ed=2048\", \"tls\": \"tls\", \"sni\": \"${ARGO_DOMAIN}\", \"alpn\": \"\" }" # 生成各订阅文件 # 生成 Clash proxy providers 订阅文件 local CLASH_SUBSCRIBE="proxies: - {name: \"${NODE_NAME} reality-vision\", type: vless, server: ${SERVER_IP}, port: ${REALITY_PORT}, uuid: ${UUID}, network: tcp, udp: true, tls: true, servername: ${TLS_SERVER}, flow: xtls-rprx-vision, client-fingerprint: chrome, reality-opts: {public-key: ${REALITY_PUBLIC}, short-id: \"\"} } - {name: \"${NODE_NAME} reality-grpc\", type: vless, server: ${SERVER_IP}, port: ${REALITY_PORT}, uuid: ${UUID}, network: grpc, udp: true, tls: true, servername: ${TLS_SERVER}, flow: , client-fingerprint: chrome, reality-opts: {public-key: ${REALITY_PUBLIC}, short-id: \"\"}, grpc-opts: {grpc-service-name: \"grpc\"} } - {name: \"${NODE_NAME}-Vl\", type: vless, server: ${SERVER}, port: 443, uuid: ${UUID}, udp: true, tls: true, servername: ${ARGO_DOMAIN}, skip-cert-verify: false, network: ws, ws-opts: {path: \"/${WS_PATH}-vl\", headers: {Host: ${ARGO_DOMAIN}}, \"max_early_data\":2408, \"early_data_header_name\":\"Sec-WebSocket-Protocol\"} } - {name: \"${NODE_NAME}-Vm\", type: vmess, server: ${SERVER}, port: 443, uuid: ${UUID}, udp: true, alterId: 0, cipher: none, tls: true, servername: ${ARGO_DOMAIN}, skip-cert-verify: true, network: ws, ws-opts: {path: \"/${WS_PATH}-vm\", headers: {Host: ${ARGO_DOMAIN}}, \"max_early_data\":2408, \"early_data_header_name\":\"Sec-WebSocket-Protocol\"}} - {name: \"${NODE_NAME}-Tr\", type: trojan, server: ${SERVER}, port: 443, password: ${UUID}, udp: true, tls: true, servername: ${ARGO_DOMAIN}, sni: ${ARGO_DOMAIN}, skip-cert-verify: false, network: ws, ws-opts: { path: \"/${WS_PATH}-tr\", headers: {Host: ${ARGO_DOMAIN}}, \"max_early_data\":2408, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" } } - {name: \"${NODE_NAME}-Sh\", type: ss, server: ${SERVER}, port: 443, cipher: ${SS_METHOD}, password: ${UUID}, udp: true, plugin: v2ray-plugin, plugin-opts: { mode: websocket, host: ${ARGO_DOMAIN}, path: \"/${WS_PATH}-sh\", tls: true, servername: ${ARGO_DOMAIN}, skip-cert-verify: false, mux: false } }" echo -n "${CLASH_SUBSCRIBE}" > $WORK_DIR/subscribe/proxies # 生成 clash 订阅配置文件 wget --no-check-certificate -qO- --tries=3 --timeout=2 ${SUBSCRIBE_TEMPLATE}/clash | sed "s#NODE_NAME#${NODE_NAME}#g; s#PROXY_PROVIDERS_URL#http://${ARGO_DOMAIN}/${UUID}/proxies#" > $WORK_DIR/subscribe/clash fetch_subscribe clash $WORK_DIR/subscribe/proxies https://${ARGO_DOMAIN}/${UUID}/proxies > $WORK_DIR/subscribe/clash2 # 生成 Shadowrocket 订阅文件 local SHADOWROCKET_SUBSCRIBE="vless://$(echo -n "auto:${UUID}@${SERVER_IP_2}:${REALITY_PORT}" | base64 -w0)?remarks=${NODE_NAME}%20reality-vision&obfs=none&tls=1&peer=${TLS_SERVER}&xtls=2&pbk=${REALITY_PUBLIC} vless://$(echo -n "auto:${UUID}@${SERVER_IP_2}:${REALITY_PORT}" | base64 -w0)?remarks=${NODE_NAME}%20reality-grpc&path=grpc&obfs=grpc&tls=1&peer=${TLS_SERVER}&pbk=${REALITY_PUBLIC} vless://${UUID}@${SERVER}:443?encryption=none&security=tls&type=ws&host=${ARGO_DOMAIN}&path=/${WS_PATH}-vl?ed=2048&sni=${ARGO_DOMAIN}#${NODE_NAME}-Vl vmess://$(echo -n "none:${UUID}@${SERVER}:443" | base64 -w0)?remarks=${NODE_NAME}-Vm&obfsParam=${ARGO_DOMAIN}&path=/${WS_PATH}-vm?ed=2048&obfs=websocket&tls=1&peer=${ARGO_DOMAIN}&alterId=0 trojan://${UUID}@${SERVER}:443?peer=${ARGO_DOMAIN}&plugin=obfs-local;obfs=websocket;obfs-host=${ARGO_DOMAIN};obfs-uri=/${WS_PATH}-tr?ed=2048#${NODE_NAME}-Tr" echo -n "${SHADOWROCKET_SUBSCRIBE}" | base64 -w0 > $WORK_DIR/subscribe/shadowrocket # 生成 V2rayN / NekoBox 订阅文件 local V2RAYN_SUBSCRIBE="vless://${UUID}@${SERVER_IP_1}:${REALITY_PORT}?encryption=none&flow=xtls-rprx-vision&security=reality&sni=${TLS_SERVER}&fp=chrome&pbk=${REALITY_PUBLIC}&type=tcp&headerType=none#${NODE_NAME} reality-vision vless://${UUID}@${SERVER_IP_1}:${REALITY_PORT}?security=reality&sni=${TLS_SERVER}&fp=chrome&pbk=${REALITY_PUBLIC}&type=grpc&serviceName=grpc&encryption=none#${NODE_NAME} reality-grpc vless://${UUID}@${SERVER}:443?encryption=none&security=tls&sni=${ARGO_DOMAIN}&type=ws&host=${ARGO_DOMAIN}&path=%2F${WS_PATH}-vl%3Fed%3D2048#${NODE_NAME}-Vl vmess://$(echo -n "$VMESS" | base64 -w0) trojan://${UUID}@${SERVER}:443?security=tls&sni=${ARGO_DOMAIN}&type=ws&host=${ARGO_DOMAIN}&path=/${WS_PATH}-tr?ed%3D2048#${NODE_NAME}-Tr" echo -n "${V2RAYN_SUBSCRIBE}" | base64 -w0 > $WORK_DIR/subscribe/base64 # 生成 Sing-box 订阅文件 local INBOUND_REPLACE="{ \"type\":\"vless\", \"tag\":\"${NODE_NAME} reality-vision\", \"server\":\"${SERVER_IP}\", \"server_port\": ${REALITY_PORT}, \"uuid\":\"${UUID}\", \"flow\":\"xtls-rprx-vision\", \"packet_encoding\":\"xudp\", \"tls\":{ \"enabled\":true, \"server_name\":\"${TLS_SERVER}\", \"utls\":{ \"enabled\":true, \"fingerprint\":\"chrome\" }, \"reality\":{ \"enabled\":true, \"public_key\":\"${REALITY_PUBLIC}\", \"short_id\":\"\" } } }, { \"type\": \"vless\", \"tag\":\"${NODE_NAME} reality-grpc\", \"server\": \"${SERVER_IP}\", \"server_port\": ${REALITY_PORT}, \"uuid\": \"${UUID}\", \"packet_encoding\":\"xudp\", \"tls\": { \"enabled\": true, \"server_name\": \"${TLS_SERVER}\", \"utls\": { \"enabled\": true, \"fingerprint\": \"chrome\" }, \"reality\": { \"enabled\": true, \"public_key\": \"${REALITY_PUBLIC}\", \"short_id\": \"\" } }, \"transport\": { \"type\": \"grpc\", \"service_name\": \"grpc\" } }, { \"type\":\"vless\", \"tag\":\"${NODE_NAME}-Vl\", \"server\":\"${SERVER}\", \"server_port\":443, \"uuid\":\"${UUID}\", \"tls\": { \"enabled\":true, \"server_name\":\"${ARGO_DOMAIN}\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/${WS_PATH}-vl\", \"headers\": { \"Host\": \"${ARGO_DOMAIN}\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" } }, { \"type\":\"vmess\", \"tag\":\"${NODE_NAME}-Vm\", \"server\":\"${SERVER}\", \"server_port\":443, \"uuid\":\"${UUID}\", \"tls\": { \"enabled\":true, \"server_name\":\"${ARGO_DOMAIN}\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/${WS_PATH}-vm\", \"headers\": { \"Host\": \"${ARGO_DOMAIN}\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" } }, { \"type\":\"trojan\", \"tag\":\"${NODE_NAME}-Tr\", \"server\": \"${SERVER}\", \"server_port\": 443, \"password\": \"${UUID}\", \"tls\": { \"enabled\":true, \"server_name\":\"${ARGO_DOMAIN}\", \"utls\": { \"enabled\":true, \"fingerprint\":\"chrome\" } }, \"transport\": { \"type\":\"ws\", \"path\":\"/${WS_PATH}-tr\", \"headers\": { \"Host\": \"${ARGO_DOMAIN}\" }, \"max_early_data\":2048, \"early_data_header_name\":\"Sec-WebSocket-Protocol\" } }" local NODE_REPLACE="\"${NODE_NAME} reality-vision\", \"${NODE_NAME} reality-grpc\", \"${NODE_NAME}-Vl\", \"${NODE_NAME}-Vm\", \"${NODE_NAME}-Tr\"" # 模板1 local SING_BOX_JSON1=$(wget --no-check-certificate -qO- --tries=3 --timeout=2 ${SUBSCRIBE_TEMPLATE}/sing-box1) echo $SING_BOX_JSON1 | sed 's#, {[^}]\+"tun-in"[^}]\+}##' | sed "s#\"\"#$INBOUND_REPLACE#; s#\"\"#$NODE_REPLACE#g" | $WORK_DIR/jq > $WORK_DIR/subscribe/sing-box-pc echo $SING_BOX_JSON1 | sed 's# {[^}]\+"mixed"[^}]\+},##; s#, "auto_detect_interface": true##' | sed "s#\"\"#$INBOUND_REPLACE#; s#\"\"#$NODE_REPLACE#g" | $WORK_DIR/jq > $WORK_DIR/subscribe/sing-box-phone # 模板2 fetch_subscribe singbox $WORK_DIR/subscribe/proxies https://${ARGO_DOMAIN}/${UUID}/proxies | $WORK_DIR/jq > $WORK_DIR/subscribe/sing-box2 # 生成二维码 url 文件 [ "$IS_NGINX" = 'is_nginx' ] && cat > $WORK_DIR/subscribe/qr << EOF $(text 66): $(text 67) 1: https://${ARGO_DOMAIN}/${UUID}/auto $(text 67) 2: https://${ARGO_DOMAIN}/${UUID}/auto2 $(text 67) 1: $(text 64) QRcode: https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://${ARGO_DOMAIN}/${UUID}/auto $(text 67) 2: $(text 64) QRcode: https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://${ARGO_DOMAIN}/${UUID}/auto2 $(text 67) 1: $($WORK_DIR/qrencode "https://${ARGO_DOMAIN}/${UUID}/auto") $(text 67) 2: $($WORK_DIR/qrencode "https://${ARGO_DOMAIN}/${UUID}/auto2") EOF # 生成客户端配置文件 EXPORT_LIST_FILE="******************************************* ┌────────────────┐ ┌────────────────┐ │ │ │ │ │ $(warning "V2rayN") │ │ $(warning "NekoBox") │ │ │ │ │ └────────────────┘ └────────────────┘ ---------------------------- $(info "$(sed "G" <<< "${V2RAYN_SUBSCRIBE}") ss://$(echo -n "${SS_METHOD}:${UUID}" | base64 -w0)@${SERVER}:443#${NODE_NAME}-Sh 由于该软件导出的链接不全,请自行处理如下: 传输协议: WS , 伪装域名: ${ARGO_DOMAIN} , 路径: /${WS_PATH}-sh?ed=2048 , 传输层安全: tls , sni: ${ARGO_DOMAIN}") ******************************************* ┌────────────────┐ │ │ │ $(warning "Shadowrocket") │ │ │ └────────────────┘ ---------------------------- $(hint "$(sed "G" <<< "${SHADOWROCKET_SUBSCRIBE}")") ******************************************* ┌────────────────┐ │ │ │ $(warning "Clash Meta") │ │ │ └────────────────┘ ---------------------------- $(info "$(sed '1d;G' <<< "$CLASH_SUBSCRIBE")") ******************************************* ┌────────────────┐ │ │ │ $(warning "Sing-box") │ │ │ └────────────────┘ ---------------------------- $(hint "$(echo "{ \"outbounds\":[ ${INBOUND_REPLACE%,} ] }" | $WORK_DIR/jq) $(text 63)") " [ "$IS_NGINX" = 'is_nginx' ] && EXPORT_LIST_FILE+=" ******************************************* $(info "Index: https://${ARGO_DOMAIN}/${UUID}/ QR code: https://${ARGO_DOMAIN}/${UUID}/qr V2rayN / Nekoray $(text 66): https://${ARGO_DOMAIN}/${UUID}/base64") $(info "Clash $(text 66): https://${ARGO_DOMAIN}/${UUID}/clash sing-box for pc $(text 66): https://${ARGO_DOMAIN}/${UUID}/sing-box-pc sing-box for cellphone $(text 66): https://${ARGO_DOMAIN}/${UUID}/sing-box-phone Shadowrocket $(text 66): https://${ARGO_DOMAIN}/${UUID}/shadowrocket") ******************************************* $(hint " $(text 66): $(text 67) 1: https://${ARGO_DOMAIN}/${UUID}/auto $(text 67) 2: https://${ARGO_DOMAIN}/${UUID}/auto2 $(text 64) QRcode: $(text 67) 1: https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://${ARGO_DOMAIN}/${UUID}/auto $(text 67) 2: https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=https://${ARGO_DOMAIN}/${UUID}/auto2") $(hint "$(text 67) 1:") $($WORK_DIR/qrencode https://${ARGO_DOMAIN}/${UUID}/auto) $(hint "$(text 67) 2:") $($WORK_DIR/qrencode https://${ARGO_DOMAIN}/${UUID}/auto2) " EXPORT_LIST_FILE+=" $(info "\n******************************************* ${QUICK_TUNNEL_URL} ") " # 生成并显示节点信息 echo "$EXPORT_LIST_FILE" > $WORK_DIR/list cat $WORK_DIR/list # 显示脚本使用情况数据 hint "\n $(text 55) \n" } # 更换 Argo 隧道类型 change_argo() { check_install [[ ${STATUS[0]} = "$(text 26)" ]] && error " $(text 39) " case $(grep "ExecStart=" /etc/systemd/system/argo.service) in *--config* ) ARGO_TYPE='Json'; ARGO_DOMAIN="$(grep -m1 '^vless' $WORK_DIR/list | sed "s@.*host=\(.*\)&.*@\1@g")" ;; *--token* ) ARGO_TYPE='Token'; ARGO_DOMAIN="$(grep -m1 '^vless' $WORK_DIR/list | sed "s@.*host=\(.*\)&.*@\1@g")" ;; * ) ARGO_TYPE='Try'; ARGO_DOMAIN=$(wget -qO- http://localhost:$(ps -ef | awk -F '0.0.0.0:' '/cloudflared.*:8080/{print $2}' | awk 'NR==1 {print $1}')/quicktunnel | awk -F '"' '{print $4}') esac hint "\n $(text 40) \n" unset ARGO_DOMAIN hint " $(text 41) \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 --metrics 0.0.0.0:${METRICS_PORT} --url http://localhost:8080@g" /etc/systemd/system/argo.service ;; 2 ) SERVER_IP=$(awk -F '"' '/"SERVER_IP"/{print $4}' $WORK_DIR/*inbound*.json) argo_variable cmd_systemctl disable argo if [ -n "$ARGO_TOKEN" ]; then [ -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 run --token ${ARGO_TOKEN}@g" /etc/systemd/system/argo.service elif [ -n "$ARGO_JSON" ]; then [ -s $WORK_DIR/tunnel.json ] && rm -f $WORK_DIR/tunnel.{json,yml} json_argo 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 ;; * ) exit 0 esac [ "$IS_NGINX" = 'is_nginx' ] && json_nginx cmd_systemctl enable argo export_list } # 卸载 ArgoX uninstall() { if [ -d $WORK_DIR ]; then cmd_systemctl disable argo cmd_systemctl disable xray [[ -s $WORK_DIR/nginx.conf && $(ps -ef | grep 'nginx' | wc -l) -le 1 ]] && reading "\n $(text 65) " REMOVE_NGINX [ "${REMOVE_NGINX,,}" = 'y' ] && ${PACKAGE_UNINSTALL[int]} nginx >/dev/null 2>&1 rm -rf $WORK_DIR $TEMP_DIR /etc/systemd/system/{xray,argo}.service /usr/bin/argox info "\n $(text 16) \n" else error "\n $(text 15) \n" fi # 如果 Alpine 系统,删除开机自启动和python3版systemd if [ "$SYSTEM" = 'Alpine' ]; then rm -f /etc/local.d/argo.start /etc/local.d/xray.start rc-update add local >/dev/null 2>&1 [ ! $(ls /etc/systemd/system/*.service) ] && rm -f /bin/systemctl fi } # Argo 与 Xray 的最新版本 version() { # Argo 版本 local ONLINE=$(wget --no-check-certificate -qO- "https://api.github.com/repos/cloudflare/cloudflared/releases/latest" | grep "tag_name" | cut -d \" -f4) local LOCAL=$($WORK_DIR/cloudflared -v | awk '{for (i=0; i&1 | sed "s#.*/#Version: #") OPTION[1]="1. $(text 29)" if [ ${STATUS[0]} = "$(text 28)" ]; then AEGO_MEMORY="$(text 52): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$(awk '/\/etc\/argox\/cloudflared/{print $1}' <<< "$PS_LIST")/status) MB" [ "$IS_NGINX" = 'is_nginx' ] && NGINX_MEMORY="$(text 52): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$(awk '/\/etc\/argox\/nginx/{print $1}' <<< "$PS_LIST")/status) MB" OPTION[2]="2. $(text 27) Argo (argox -a)" else OPTION[2]="2. $(text 28) Argo (argox -a)" fi [ ${STATUS[1]} = "$(text 28)" ] && XRAY_MEMORY="$(text 52): $(awk '/VmRSS/{printf "%.1f\n", $2/1024}' /proc/$(awk '/\/etc\/argox\/xray.*\/etc\/argox/{print $1}' <<< "$PS_LIST")/status) MB" && OPTION[3]="3. $(text 27) Xray (argox -x)" || OPTION[3]="3. $(text 28) Xray (argox -x)" OPTION[4]="4. $(text 30)" OPTION[5]="5. $(text 31)" OPTION[6]="6. $(text 32)" OPTION[7]="7. $(text 33)" OPTION[8]="8. $(text 51)" OPTION[9]="9. $(text 57)" ACTION[1]() { export_list; exit 0; } [[ ${STATUS[0]} = "$(text 28)" ]] && ACTION[2]() { cmd_systemctl disable argo; [[ "$(systemctl is-active argo)" =~ 'inactive'|'unknown' ]] && info "\n Argo $(text 27) $(text 37)" || error " Argo $(text 27) $(text 38) "; } || ACTION[2]() { cmd_systemctl enable argo && [ "$(systemctl is-active argo)" = 'active' ] && info "\n Argo $(text 28) $(text 37)" || error " Argo $(text 28) $(text 38) "; } [[ ${STATUS[1]} = "$(text 28)" ]] && ACTION[3]() { cmd_systemctl disable xray; [[ "$(systemctl is-active xray)" =~ 'inactive'|'unknown' ]] && info "\n Xray $(text 27) $(text 37)" || error " Xray $(text 27) $(text 38) "; } || ACTION[3]() { cmd_systemctl enable xray && [ "$(systemctl is-active xray)" = 'active' ] && info "\n Xray $(text 28) $(text 37)" || error " Xray $(text 28) $(text 38) "; } ACTION[4]() { change_argo; exit; } ACTION[5]() { version; exit; } ACTION[6]() { bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit; } ACTION[7]() { uninstall; exit; } ACTION[8]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sing-box/main/sing-box.sh) -$L; exit; } ACTION[9]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } else OPTION[1]="1. $(text 34)" OPTION[2]="2. $(text 32)" OPTION[3]="3. $(text 51)" OPTION[4]="4. $(text 57)" ACTION[1]() { install_argox; export_list; 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/sing-box/main/sing-box.sh) -$L; exit; } ACTION[4]() { bash <(wget --no-check-certificate -qO- https://raw.githubusercontent.com/fscarmen/sba/main/sba.sh) -$L; exit; } fi [ "${#OPTION[@]}" -ge '10' ] && OPTION[0]="0 . $(text 35)" || OPTION[0]="0. $(text 35)" ACTION[0]() { exit; } } menu() { clear ### hint " $(text 2) " echo -e "======================================================================================================================\n" 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):$ARGO_ARCH\n\t $(text 23):$VIRT " info "\t IPv4: $WAN4 $WARPSTATUS4 $COUNTRY4 $ASNORG4 " info "\t IPv6: $WAN6 $WARPSTATUS6 $COUNTRY6 $ASNORG6 " info "\t Argo: ${STATUS[0]}\t $ARGO_VERSION\t $AEGO_MEMORY\t $ARGO_CHECKHEALTH\n\t Xray: ${STATUS[1]}\t $XRAY_VERSION\t\t $XRAY_MEMORY " [ "$IS_NGINX" = 'is_nginx' ] && info "\t Nginx: ${STATUS[0]}\t $NGINX_VERSION\t $NGINX_MEMORY " echo -e "\n======================================================================================================================\n" for ((b=1;b<${#OPTION[*]};b++)); do hint " ${OPTION[b]} "; done hint " ${OPTION[0]} " reading "\n $(text 24) " CHOOSE # 输入必须是数字且少于等于最大可选项 if grep -qE "^[0-9]$" <<< "$CHOOSE" && [ "$CHOOSE" -lt "${#OPTION[*]}" ]; then ACTION[$CHOOSE] else warning " $(text 36) [0-$((${#OPTION[*]}-1))] " && sleep 1 && menu fi } statistics_of_run-times # 传参 [[ "${*,,}" =~ -e ]] && L=E [[ "${*,,}" =~ -c ]] && L=C while getopts ":AaXxTtUuNnVvBbF:f:" OPTNAME; do case "${OPTNAME,,}" in a ) select_language; check_system_info; check_install; [ "${STATUS[0]}" = "$(text 28)" ] && { cmd_systemctl disable argo; [[ "$(systemctl is-active argo)" =~ 'inactive'|'unknown' ]] && info "\n Argo $(text 27) $(text 37)" || error " Argo $(text 27) $(text 38) "; } || { cmd_systemctl enable argo; [ "$(systemctl is-active argo)" = 'active' ] && info "\n Argo $(text 28) $(text 37)" || error " Argo $(text 28) $(text 38) "; } ; exit 0 ;; x ) select_language; check_system_info; check_install; [ "${STATUS[1]}" = "$(text 28)" ] && { cmd_systemctl disable xray; [[ "$(systemctl is-active xray)" =~ 'inactive'|'unknown' ]] && info "\n Xray $(text 27) $(text 37)" || error " Xray $(text 27) $(text 38) "; } || { cmd_systemctl enable xray; [ "$(systemctl is-active xray)" = 'active' ] && info "\n Xray $(text 28) $(text 37)" || error " Xray $(text 28) $(text 38) "; } ; exit 0 ;; t ) select_language; change_argo; exit 0 ;; u ) select_language; check_system_info; uninstall; exit 0;; n ) select_language; check_system_info; export_list; exit 0 ;; v ) select_language; check_arch; version; exit 0;; b ) select_language; bash <(wget --no-check-certificate -qO- "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh"); exit ;; f ) VARIABLE_FILE=$OPTARG; . $VARIABLE_FILE ;; esac done select_language check_root check_arch check_system_info check_dependencies check_system_ip check_install menu_setting [ -z "$VARIABLE_FILE" ] && menu || ACTION[1]