#!/bin/bash WORKDIR=$(dirname $(readlink -f $0)) cd $WORKDIR SYSTEM_ARCH=$(uname -m) SYSTEM_PYTHON=$(which python3 || which python) IS_DOCKER=$( [ -f /.dockerenv ] && echo "true" || echo "false" ) PID_FILE=$WORKDIR/pid/pid_mtproxy CONFIG_PATH=$WORKDIR/config URL_MTG="https://github.com/ellermister/mtproxy/releases/download/v0.04/$(uname -m)-mtg" URL_MTPROTO="https://github.com/ellermister/mtproxy/releases/download/v0.04/mtproto-proxy" URL_PY_MTPROTOPROXY="https://github.com/alexbers/mtprotoproxy/archive/refs/heads/master.zip" BINARY_MTG_PATH=$WORKDIR/bin/mtg BINARY_MTPROTO_PROXY_PATH=$WORKDIR/bin/mtproto-proxy BINARY_PY_MTPROTOPROXY_PATH=$WORKDIR/bin/mtprotoproxy.py PUBLIC_IP="" check_sys() { local checkType=$1 local value=$2 local release='' local systemPackage='' if [[ -f /etc/redhat-release ]]; then release="centos" systemPackage="yum" elif grep -Eqi "debian|raspbian" /etc/issue; then release="debian" systemPackage="apt" elif grep -Eqi "ubuntu" /etc/issue; then release="ubuntu" systemPackage="apt" elif grep -Eqi "centos|red hat|redhat" /etc/issue; then release="centos" systemPackage="yum" elif grep -Eqi "debian|raspbian" /proc/version; then release="debian" systemPackage="apt" elif grep -Eqi "ubuntu" /proc/version; then release="ubuntu" systemPackage="apt" elif grep -Eqi "centos|red hat|redhat" /proc/version; then release="centos" systemPackage="yum" fi if [[ "${checkType}" == "sysRelease" ]]; then if [ "${value}" == "${release}" ]; then return 0 else return 1 fi elif [[ "${checkType}" == "packageManager" ]]; then if [ "${value}" == "${systemPackage}" ]; then return 0 else return 1 fi fi } function abs() { echo ${1#-}; } function get_ip_public() { local public_ip="" # 尝试 Cloudflare trace API if [ -z "$public_ip" ]; then public_ip=$(curl -4 -s --connect-timeout 5 --max-time 10 https://1.1.1.1/cdn-cgi/trace -A Mozilla 2>/dev/null | grep "^ip=" | cut -d'=' -f2) fi # 尝试 ip.sb API获取公网IP if [ -z "$public_ip" ]; then public_ip=$(curl -s --connect-timeout 5 --max-time 10 https://api.ip.sb/ip -A Mozilla --ipv4 2>/dev/null) fi # 尝试 ipinfo.io API if [ -z "$public_ip" ]; then public_ip=$(curl -s --connect-timeout 5 --max-time 10 https://ipinfo.io/ip -A Mozilla --ipv4 2>/dev/null) fi # 如果所有API都失败,退出 if [ -z "$public_ip" ]; then print_error_exit "Failed to get public IP address. Please check your network connection." fi echo "$public_ip" } function get_ip_private() { echo $(ip a | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | cut -d "/" -f1 | awk 'NR==1 {print $1}') } function get_local_ip(){ ip a | grep inet | grep 127.0.0.1 > /dev/null 2>&1 if [[ $? -eq 1 ]];then echo $(get_ip_private) else echo "127.0.0.1" fi } function get_nat_ip_param() { nat_ip=$(get_ip_private) nat_info="" if [[ $nat_ip != $PUBLIC_IP ]]; then nat_info="--nat-info ${nat_ip}:${PUBLIC_IP}" fi echo $nat_info } function get_cpu_core() { echo $(cat /proc/cpuinfo | grep "processor" | wc -l) } function get_architecture() { local architecture="" case $(uname -m) in i386) architecture="386" ;; i686) architecture="386" ;; x86_64) architecture="amd64" ;; arm | aarch64 | aarch) dpkg --print-architecture | grep -q "arm64" && architecture="arm64" || architecture="armv6l" ;; *) echo "Unsupported system architecture "$(uname -m) && exit 1 ;; esac echo $architecture } function build_mtproto() { cd $WORKDIR local platform=$(uname -m) if [[ -z "$1" ]]; then print_error_exit "缺少参数" fi do_install_build_dep rm -rf build mkdir build && cd build if [[ "1" == "$1" ]]; then if [ -d 'MTProxy' ]; then rm -rf 'MTProxy' fi git clone https://github.com/ellermister/MTProxyC --depth=1 MTProxy cd MTProxy && make && cd objs/bin && chmod +x mtproto-proxy if [ ! -f "./mtproto-proxy" ]; then print_error_exit "mtproto-proxy 编译失败" fi cp -f mtproto-proxy $WORKDIR # clean rm -rf 'MTProxy' elif [[ "2" == "$1" ]]; then # golang local arch=$(get_architecture) # https://go.dev/dl/go1.18.4.linux-amd64.tar.gz local golang_url="https://go.dev/dl/go1.18.4.linux-$arch.tar.gz" wget $golang_url -O golang.tar.gz rm -rf go && tar -C . -xzf golang.tar.gz export PATH=$PATH:$(pwd)/go/bin go version if [[ $? != 0 ]]; then local uname_m=$(uname -m) local architecture_origin=$(dpkg --print-architecture) print_error_exit "golang download failed, please check!!! arch: $arch, platform: $platform, uname: $uname_m, architecture_origin: $architecture_origin download url: $golang_url" fi rm -rf build-mtg git clone https://github.com/9seconds/mtg.git -b v1 build-mtg cd build-mtg && git reset --hard 9d67414db633dded5f11d549eb80617dc6abb2c3 && make static if [[ ! -f "./mtg" ]]; then print_error_exit "Build fail for mtg, please check!!! $arch" fi cp -f mtg $WORKDIR && chmod +x $WORKDIR/mtg fi # clean cd $WORKDIR rm -rf build } function get_mtg_provider() { source $CONFIG_PATH local arch=$(get_architecture) if [[ "$arch" != "amd64" && $provider -eq 1 ]]; then provider=2 fi if [ $provider -eq 1 ]; then echo "official-MTProxy" elif [ $provider -eq 2 ]; then echo "mtg" elif [ $provider -eq 3 ]; then echo "python-mtprotoproxy" else print_error_exit "Invalid configuration, please reinstall" fi } function is_installed() { if [ ! -f "$CONFIG_PATH" ]; then return 1 fi return 0 } function kill_process_by_port() { pids=$(get_pids_by_port $1) if [ -n "$pids" ]; then kill -9 $pids fi } function get_pids_by_port() { echo $(netstat -tulpn 2>/dev/null | grep ":$1 " | awk '{print $7}' | sed 's|/.*||') } function is_port_open() { pids=$(get_pids_by_port $1) if [ -n "$pids" ]; then return 0 else return 1 fi } function is_running_mtp() { if [ -f $PID_FILE ]; then if is_pid_exists $(cat $PID_FILE); then return 0 fi fi return 1 } function is_pid_exists() { # check_ps_not_install_to_install local exists=$(ps aux | awk '{print $2}' | grep -w $1) if [[ ! $exists ]]; then return 1 else return 0 fi } do_install_proxy() { local mtg_provider=$1 if [ ! -d "$WORKDIR/bin" ]; then mkdir -p $WORKDIR/bin fi if [[ "$mtg_provider" == "mtg" ]]; then wget $URL_MTG -O $BINARY_MTG_PATH -q chmod +x $BINARY_MTG_PATH $BINARY_MTG_PATH exit_code=$? if [ $exit_code -ne 0 ]; then print_error_exit "Install mtg failed" fi print_info "Installed for mtg" elif [[ "$mtg_provider" == "official-MTProxy" ]]; then wget $URL_MTPROTO -O $BINARY_MTPROTO_PROXY_PATH -q chmod +x $BINARY_MTPROTO_PROXY_PATH $BINARY_MTPROTO_PROXY_PATH exit_code=$? if [ $exit_code -ne 0 ] && [ $exit_code -ne 2 ]; then print_error_exit "Install mtproto-proxy failed" fi print_info "Installed for mtproto-proxy" elif [[ "$mtg_provider" == "python-mtprotoproxy" ]]; then wget $URL_PY_MTPROTOPROXY -O mtprotoproxy-master.zip unzip mtprotoproxy-master.zip cp -rf mtprotoproxy-master/*.py mtprotoproxy-master/pyaes $WORKDIR/bin/ rm -rf mtprotoproxy-master mtprotoproxy-master.zip print_info "Installed for mtprotoproxy" fi } do_install() { cd $WORKDIR mtg_provider=$(get_mtg_provider) do_install_proxy $mtg_provider if [ ! -d "./pid" ]; then mkdir "./pid" fi } print_line() { echo -e "=========================================" } print_error_exit() { print_line echo -e "[\033[95mERROR\033[0m] $1" print_line exit 1 } print_warning() { echo -e "[\033[33mWARNING\033[0m] $1" } print_info() { echo -e "[\033[32mINFO\033[0m] $1" } print_subject() { echo -e "\n\033[32m> $1\033[0m" } do_kill_process() { cd $WORKDIR if [ ! -f "$CONFIG_PATH" ]; then print_error_exit "配置文件不存在,请重新安装" fi source $CONFIG_PATH if is_port_open $port; then print_info "Detected port $port is occupied, preparing to kill process!" kill_process_by_port $port fi if is_port_open $statport; then print_info "Detected port $statport is occupied, preparing to kill process!" kill_process_by_port $statport fi } do_check_system_datetime_and_update() { dateFromLocal=$(date +%s) dateFromServer=$(date -d "$(curl -v --silent ip.sb 2>&1 | grep Date | sed -e 's/< Date: //')" +%s) offset=$(abs $(( "$dateFromServer" - "$dateFromLocal"))) tolerance=60 if [ "$offset" -gt "$tolerance" ];then print_info "Detected system time is not synchronized with world time, preparing to update" ntpdate -u time.google.com if [ $? -ne 0 ]; then if [[ "$IS_DOCKER" == "true" ]]; then print_warning "Update system time failed, please manually update the system time" else print_error_exit "Update system time failed, please manually update the system time" fi fi fi } do_install_basic_dep() { print_info "Checking and installing basic dependencies..." if check_sys packageManager yum; then yum update && yum install -y iproute curl wget procps-ng.x86_64 net-tools ntp elif check_sys packageManager apt; then apt update # 先安装必需的包 apt install -y iproute2 curl wget procps net-tools unzip || true # 尝试安装时间同步工具(可选,允许失败) apt install -y ntpsec-ntpdate 2>/dev/null || apt install -y ntpdate 2>/dev/null || true fi return 0 } do_install_build_dep() { print_info "Checking and installing build dependencies..." if check_sys packageManager yum; then yum install -y git openssl-devel zlib-devel yum groupinstall -y "Development Tools" elif check_sys packageManager apt; then apt install -y git curl build-essential libssl-dev zlib1g-dev fi return 0 } do_config_mtp() { cd $WORKDIR while true; do default_provider=1 print_subject "请输入要安装的程序版本" echo "" if [ "$SYSTEM_ARCH" == "x86_64" ]; then echo -e " \033[36m1.\033[0m MTProxy (TelegramMessenger)" echo -e " └─ Telegram官方版本,只支持 x86_64, 存在很多问题" else echo -e " \033[90m1.\033[0mMTProxy (TelegramMessenger) \033[33m[不支持当前架构]\033[0m" echo -e " └─ Telegram官方版本,只支持 x86_64, 存在很多问题" fi echo -e " \033[36m2.\033[0m mtg (9seconds)" echo -e " └─ Golang 版本, 兼容性强, 推荐使用" echo -e " \033[36m3.\033[0m mtprotoproxy (alexbers)" echo -e " └─ Python 版本, 兼容性强" echo "" [ "$SYSTEM_ARCH" != "x86_64" ] && default_provider=2 read -p "(默认版本: ${default_provider}):" input_provider [ -z "${input_provider}" ] && input_provider=${default_provider} expr ${input_provider} + 1 &>/dev/null if [ $? -eq 0 ]; then [ "$SYSTEM_ARCH" != "x86_64" ] && [ ${input_provider} -eq 1 ] && print_warning "你的系统不支持该版本, 请重新输入" && continue if [ ${input_provider} -ge 1 ] && [ ${input_provider} -le 3 ] && [ ${input_provider:0:1} != 0 ]; then echo echo "---------------------------" echo "provider = ${input_provider}" echo "---------------------------" echo break fi fi print_warning "请重新输入程序版本 [1-3]" done while true; do default_port=443 print_subject "请输入一个客户端连接端口 [1-65535]" read -p "(默认端口: ${default_port}):" input_port [ -z "${input_port}" ] && input_port=${default_port} expr ${input_port} + 1 &>/dev/null if [ $? -eq 0 ]; then if [ ${input_port} -ge 1 ] && [ ${input_port} -le 65535 ] && [ ${input_port:0:1} != 0 ]; then echo echo "---------------------------" echo "port = ${input_port}" echo "---------------------------" echo break fi fi print_warning "请重新输入一个客户端连接端口 [1-65535]" done # 管理端口 while true; do default_manage=8888 print_subject "请输入一个管理端口 [1-65535]" echo -e "管理端口仅用于查看一些统计数据, 只监听本地网卡不会对外暴露" read -p "(默认端口: ${default_manage}):" input_manage_port [ -z "${input_manage_port}" ] && input_manage_port=${default_manage} expr ${input_manage_port} + 1 &>/dev/null if [ $? -eq 0 ] && [ $input_manage_port -ne $input_port ]; then if [ ${input_manage_port} -ge 1 ] && [ ${input_manage_port} -le 65535 ] && [ ${input_manage_port:0:1} != 0 ]; then echo echo "---------------------------" echo "manage port = ${input_manage_port}" echo "---------------------------" echo break fi fi print_warning "请重新输入一个管理端口 [1-65535]" done # domain while true; do default_domain="azure.microsoft.com" print_subject "请输入一个需要伪装的域名:" read -p "(默认域名: ${default_domain}):" input_domain [ -z "${input_domain}" ] && input_domain=${default_domain} http_code=$(curl -I -m 10 -o /dev/null -s -w %{http_code} $input_domain) if [ $http_code -eq "200" ] || [ $http_code -eq "302" ] || [ $http_code -eq "301" ]; then echo echo "---------------------------" echo "伪装域名 = ${input_domain}" echo "---------------------------" echo break fi print_warning "域名无法访问,请重新输入或更换域名!" done # config info secret=$(gen_rand_hex 32) # proxy tag while true; do default_tag="" print_subject "请输入你需要推广的TAG:" echo -e "若没有,请联系 @MTProxybot 进一步创建你的TAG, 可能需要信息如下:" echo -e "IP: ${PUBLIC_IP}" echo -e "PORT: ${input_port}" echo -e "SECRET(可以随便填): ${secret}" read -p "(留空则跳过):" input_tag [ -z "${input_tag}" ] && input_tag=${default_tag} if [ -z "$input_tag" ] || [[ "$input_tag" =~ ^[A-Za-z0-9]{32}$ ]]; then echo echo "---------------------------" echo "PROXY TAG = ${input_tag}" echo "---------------------------" echo break fi print_warning "TAG格式不正确!" done cat >$CONFIG_PATH </dev/null 2>&1 & [[ -f "$BINARY_MTG_PATH" ]] || (print_warning "MTProxy 代理程序不存在请重新安装!" && exit 1) echo "$BINARY_MTG_PATH run $client_secret $adtag -b 0.0.0.0:$port --multiplex-per-connection 500 --prefer-ip=ipv4 -t $local_ip:$statport" -4 "$PUBLIC_IP:$port" elif [[ "$mtg_provider" == "python-mtprotoproxy" ]]; then cat >$WORKDIR/bin/config.py </dev/null 2>&1 & echo $! >$PID_FILE sleep 2 info_mtp fi } daemon_mtp() { cd $WORKDIR if is_running_mtp; then print_warning "MTProxy已经运行,请勿重复运行!" else do_kill_process do_check_system_datetime_and_update local command=$(get_run_command) echo $command while true do { sleep 2 info_mtp "ingore" } & $command >/dev/null print_warning "进程检测到被关闭,正在重启中!!!" sleep 2 done fi } debug_mtp() { cd $WORKDIR print_info "当前正在运行调试模式:" print_warning "\t你随时可以通过 Ctrl+C 进行取消操作" do_kill_process do_check_system_datetime_and_update local command=$(get_run_command) echo $command $command } stop_mtp() { local pid=$(cat $PID_FILE) kill -9 $pid if is_pid_exists $pid; then print_warning "停止任务失败" fi } reinstall_mtp() { cd $WORKDIR if [ -f "$CONFIG_PATH" ]; then while true; do default_keep_config="y" print_subject "是否保留配置文件? " read -p "y: 保留 , n: 不保留 (默认: ${default_keep_config}):" input_keep_config [ -z "${input_keep_config}" ] && input_keep_config=${default_keep_config} if [[ "$input_keep_config" == "y" ]] || [[ "$input_keep_config" == "n" ]]; then if [[ "$input_keep_config" == "n" ]]; then rm -f $CONFIG_PATH fi break fi print_warning "输入错误, 请输入 y / n" done fi if [ ! -f "$CONFIG_PATH" ]; then do_install_basic_dep do_config_mtp fi do_install run_mtp } param=$1 if [ -z "$PUBLIC_IP" ]; then PUBLIC_IP=$(get_ip_public) || print_error_exit "Failed to get public IP address. Please check your network connection." fi if [[ "start" == $param ]]; then print_info "即将:启动脚本" run_mtp elif [[ "daemon" == $param ]]; then print_info "即将:启动脚本(守护进程)" daemon_mtp elif [[ "stop" == $param ]]; then print_info "即将:停止脚本" stop_mtp elif [[ "debug" == $param ]]; then print_info "即将:调试运行" debug_mtp elif [[ "restart" == $param ]]; then stop_mtp run_mtp elif [[ "reinstall" == $param ]]; then reinstall_mtp elif [[ "build" == $param ]]; then arch=$(get_architecture) if [[ "$arch" == "amd64" ]]; then # build_mtproto 1 do_install_proxy "official-MTProxy" fi # build_mtproto 2 do_install_proxy "mtg" do_install_proxy "python-mtprotoproxy" else if ! is_installed; then echo "MTProxyTLS一键安装运行绿色脚本" print_line print_warning "检测到您的配置文件不存在, 为您指引生成!" && print_line do_install_basic_dep do_config_mtp do_install run_mtp else [ ! -f "$CONFIG_PATH" ] && do_config_mtp echo "MTProxyTLS一键安装运行绿色脚本" print_line info_mtp print_line echo -e "脚本源码:https://github.com/ellermister/mtproxy" echo -e "配置文件: $CONFIG_PATH" echo -e "卸载方式:直接删除当前目录下文件即可" echo "使用方式:" echo -e "\t启动服务\t bash $0 start" echo -e "\t调试运行\t bash $0 debug" echo -e "\t停止服务\t bash $0 stop" echo -e "\t重启服务\t bash $0 restart" echo -e "\t重新安装代理程序 bash $0 reinstall" fi fi