#!/bin/bash export LC_ALL=C export LANG=en_US.UTF-8 export LANGUAGE=en_US.UTF-8 export LC_COLLATE=C export LC_CTYPE=en_US.UTF-8 sudoCmd="" if [[ $(/usr/bin/id -u) -ne 0 ]]; then sudoCmd="sudo" fi uninstall() { ${sudoCmd} "$(which rm)" -rf $1 printf "File or Folder Deleted: %s\n" $1 } # fonts color red(){ echo -e "\033[31m\033[01m$1\033[0m" } green(){ echo -e "\033[32m\033[01m$1\033[0m" } yellow(){ echo -e "\033[33m\033[01m$1\033[0m" } blue(){ echo -e "\033[34m\033[01m$1\033[0m" } bold(){ echo -e "\033[1m\033[01m$1\033[0m" } function showHeaderGreen(){ echo green " ==================================================" for parameter in "$@" do if [[ -n "${parameter}" ]]; then green " ${parameter}" fi done green " ==================================================" echo } function showHeaderRed(){ echo red " ==================================================" for parameter in "$@" do if [[ -n "${parameter}" ]]; then red " ${parameter}" fi done red " ==================================================" echo } function showInfoGreen(){ echo for parameter in "$@" do if [[ -n "${parameter}" ]]; then green " ${parameter}" fi done echo } osCPU="" osArchitecture="arm" osInfo="" osRelease="" osReleaseVersion="" osReleaseVersionNo="" osReleaseVersionNoShort="" osReleaseVersionCodeName="CodeName" osSystemPackage="" osSystemMdPath="" osSystemShell="bash" function checkArchitecture(){ # https://stackoverflow.com/questions/48678152/how-to-detect-386-amd64-arm-or-arm64-os-architecture-via-shell-bash case $(uname -m) in i386) osArchitecture="386" ;; i686) osArchitecture="386" ;; x86_64) osArchitecture="amd64" ;; arm) dpkg --print-architecture | grep -q "arm64" && osArchitecture="arm64" || osArchitecture="arm" ;; aarch64) dpkg --print-architecture | grep -q "arm64" && osArchitecture="arm64" || osArchitecture="arm" ;; * ) osArchitecture="arm" ;; esac } function checkCPU(){ osCPUText=$(cat /proc/cpuinfo | grep vendor_id | uniq) if [[ $osCPUText =~ "GenuineIntel" ]]; then osCPU="intel" elif [[ $osCPUText =~ "AMD" ]]; then osCPU="amd" else echo fi # green " Status 状态显示--当前CPU是: $osCPU" } # 检测系统版本号 getLinuxOSVersion(){ if [[ -s /etc/redhat-release ]]; then osReleaseVersion=$(grep -oE '[0-9.]+' /etc/redhat-release) else osReleaseVersion=$(grep -oE '[0-9.]+' /etc/issue) fi # https://unix.stackexchange.com/questions/6345/how-can-i-get-distribution-name-and-version-number-in-a-simple-shell-script if [ -f /etc/os-release ]; then # freedesktop.org and systemd source /etc/os-release osInfo=$NAME osReleaseVersionNo=$VERSION_ID if [ -n "$VERSION_CODENAME" ]; then osReleaseVersionCodeName=$VERSION_CODENAME fi elif type lsb_release >/dev/null 2>&1; then # linuxbase.org osInfo=$(lsb_release -si) osReleaseVersionNo=$(lsb_release -sr) elif [ -f /etc/lsb-release ]; then # For some versions of Debian/Ubuntu without lsb_release command . /etc/lsb-release osInfo=$DISTRIB_ID osReleaseVersionNo=$DISTRIB_RELEASE elif [ -f /etc/debian_version ]; then # Older Debian/Ubuntu/etc. osInfo=Debian osReleaseVersion=$(cat /etc/debian_version) osReleaseVersionNo=$(sed 's/\..*//' /etc/debian_version) elif [ -f /etc/redhat-release ]; then osReleaseVersion=$(grep -oE '[0-9.]+' /etc/redhat-release) else # Fall back to uname, e.g. "Linux ", also works for BSD, etc. osInfo=$(uname -s) osReleaseVersionNo=$(uname -r) fi osReleaseVersionNoShort=$(echo $osReleaseVersionNo | sed 's/\..*//') } # 检测系统发行版代号 function getLinuxOSRelease(){ if [[ -f /etc/redhat-release ]]; then osRelease="centos" osSystemPackage="yum" osSystemMdPath="/usr/lib/systemd/system/" osReleaseVersionCodeName="" elif cat /etc/issue | grep -Eqi "debian|raspbian"; then osRelease="debian" osSystemPackage="apt-get" osSystemMdPath="/lib/systemd/system/" osReleaseVersionCodeName="buster" elif cat /etc/issue | grep -Eqi "ubuntu"; then osRelease="ubuntu" osSystemPackage="apt-get" osSystemMdPath="/lib/systemd/system/" osReleaseVersionCodeName="bionic" elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then osRelease="centos" osSystemPackage="yum" osSystemMdPath="/usr/lib/systemd/system/" osReleaseVersionCodeName="" elif cat /proc/version | grep -Eqi "debian|raspbian"; then osRelease="debian" osSystemPackage="apt-get" osSystemMdPath="/lib/systemd/system/" osReleaseVersionCodeName="buster" elif cat /proc/version | grep -Eqi "ubuntu"; then osRelease="ubuntu" osSystemPackage="apt-get" osSystemMdPath="/lib/systemd/system/" osReleaseVersionCodeName="bionic" elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then osRelease="centos" osSystemPackage="yum" osSystemMdPath="/usr/lib/systemd/system/" osReleaseVersionCodeName="" fi getLinuxOSVersion checkArchitecture checkCPU [[ -z $(echo $SHELL|grep zsh) ]] && osSystemShell="bash" || osSystemShell="zsh" green " OS info: ${osInfo}, ${osRelease}, ${osReleaseVersion}, ${osReleaseVersionNo}, ${osReleaseVersionCodeName}, ${osCPU} CPU ${osArchitecture}, ${osSystemShell}, ${osSystemPackage}, ${osSystemMdPath}" } function promptContinueOpeartion(){ read -p "是否继续操作? 直接回车默认继续操作, 请输入[Y/n]:" isContinueInput isContinueInput=${isContinueInput:-Y} if [[ $isContinueInput == [Yy] ]]; then echo "" else exit 1 fi } osPort80="" osPort443="" osSELINUXCheck="" osSELINUXCheckIsRebootInput="" function testLinuxPortUsage(){ $osSystemPackage install -y net-tools socat osPort80=$(netstat -tlpn | awk -F '[: ]+' '$1=="tcp"{print $5}' | grep -w 80) osPort443=$(netstat -tlpn | awk -F '[: ]+' '$1=="tcp"{print $5}' | grep -w 443) if [ -n "$osPort80" ]; then process80=$(netstat -tlpn | awk -F '[: ]+' '$5=="80"{print $9}') red "===========================================================" red "检测到80端口被占用,占用进程为:${process80} " red "===========================================================" promptContinueOpeartion fi if [ -n "$osPort443" ]; then process443=$(netstat -tlpn | awk -F '[: ]+' '$5=="443"{print $9}') red "=============================================================" red "检测到443端口被占用,占用进程为:${process443} " red "=============================================================" promptContinueOpeartion fi osSELINUXCheck=$(grep SELINUX= /etc/selinux/config | grep -v "#") if [ "$osSELINUXCheck" == "SELINUX=enforcing" ]; then red "=======================================================================" red "检测到SELinux为开启强制模式状态, 为防止申请证书失败 将关闭SELinux. 请先重启VPS后,再执行本脚本" red "=======================================================================" read -p "是否现在重启? 请输入 [Y/n] :" osSELINUXCheckIsRebootInput [ -z "${osSELINUXCheckIsRebootInput}" ] && osSELINUXCheckIsRebootInput="y" if [[ $osSELINUXCheckIsRebootInput == [Yy] ]]; then sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config setenforce 0 echo -e "VPS 重启中..." reboot fi exit fi if [ "$osSELINUXCheck" == "SELINUX=permissive" ]; then red "=======================================================================" red "检测到SELinux为宽容模式状态, 为防止申请证书失败, 将关闭SELinux. 请先重启VPS后,再执行本脚本" red "=======================================================================" read -p "是否现在重启? 请输入 [Y/n] :" osSELINUXCheckIsRebootInput [ -z "${osSELINUXCheckIsRebootInput}" ] && osSELINUXCheckIsRebootInput="y" if [[ $osSELINUXCheckIsRebootInput == [Yy] ]]; then sed -i 's/SELINUX=permissive/SELINUX=disabled/g' /etc/selinux/config setenforce 0 echo -e "VPS 重启中..." reboot fi exit fi if [ "$osRelease" == "centos" ]; then if [[ ${osReleaseVersionNoShort} == "6" || ${osReleaseVersionNoShort} == "5" ]]; then green " ==================================================" red " 本脚本不支持 Centos 6 或 Centos 6 更早的版本" green " ==================================================" exit fi red " 关闭防火墙 firewalld" ${sudoCmd} systemctl stop firewalld ${sudoCmd} systemctl disable firewalld elif [ "$osRelease" == "ubuntu" ]; then if [[ ${osReleaseVersionNoShort} == "14" || ${osReleaseVersionNoShort} == "12" ]]; then green " ==================================================" red " 本脚本不支持 Ubuntu 14 或 Ubuntu 14 更早的版本" green " ==================================================" exit fi red " 关闭防火墙 ufw" ${sudoCmd} systemctl stop ufw ${sudoCmd} systemctl disable ufw if ! command -v ufw &> /dev/null; then echo "ufw command could not be found" else ufw disable fi elif [ "$osRelease" == "debian" ]; then $osSystemPackage update -y fi } # 查看端口占用情况 function checkPortUsage(){ # https://stackoverflow.com/questions/2013547/assigning-default-values-to-shell-variables-with-a-single-command-in-bash portNum="${1:-80}" # check port 80 is running # http://www.letuknowit.com/post/98.html # 不过,一般像下面这样写,多一个加号表明将连续出现的记录分隔符当做一个来处理 osPort80=$(netstat -tupln | awk -F '[ ]+' '$1=="tcp"||$1=="tcp6"{print $4}' | grep -w "${portNum}") if [ -n "$osPort80" ]; then process80=$(netstat -tupln | grep -w "${portNum}" | awk -F '[ ]+' '{print $7}') showHeaderRed "检测到${portNum}端口被占用,占用进程为:${process80} " if [[ ${portNum} == "80" ]] ; then green " 如需要关闭 apache2 请运行如下命令: " green " Run following command to stop apache2: " green " ${sudoCmd} systemctl stop apache2 " green " ${sudoCmd} systemctl disable apache2 " fi promptContinueOpeartion fi } # 编辑 SSH 公钥 文件用于 免密码登录 function editLinuxLoginWithPublicKey(){ if [ ! -d "${HOME}/ssh" ]; then mkdir -p ${HOME}/.ssh fi vi ${HOME}/.ssh/authorized_keys } # 设置SSH root 登录 function setLinuxRootLogin(){ read -p "是否设置允许root登陆(ssh密钥方式 或 密码方式登陆 )? 请输入[Y/n]:" osIsRootLoginInput osIsRootLoginInput=${osIsRootLoginInput:-Y} if [[ $osIsRootLoginInput == [Yy] ]]; then if [ "$osRelease" == "centos" ] || [ "$osRelease" == "debian" ] ; then ${sudoCmd} sed -i 's/#\?PermitRootLogin \(yes\|no\|Yes\|No\|prohibit-password\)/PermitRootLogin yes/g' /etc/ssh/sshd_config fi if [ "$osRelease" == "ubuntu" ]; then ${sudoCmd} sed -i 's/#\?PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config fi green "设置允许root登陆成功!" fi read -p "是否设置允许root使用密码登陆(上一步请先设置允许root登陆才可以)? 请输入[Y/n]:" osIsRootLoginWithPasswordInput osIsRootLoginWithPasswordInput=${osIsRootLoginWithPasswordInput:-Y} if [[ $osIsRootLoginWithPasswordInput == [Yy] ]]; then sed -i 's/#\?PasswordAuthentication \(yes\|no\)/PasswordAuthentication yes/g' /etc/ssh/sshd_config green "设置允许root使用密码登陆成功!" fi ${sudoCmd} sed -i 's/#\?TCPKeepAlive yes/TCPKeepAlive yes/g' /etc/ssh/sshd_config ${sudoCmd} sed -i 's/#\?ClientAliveCountMax 3/ClientAliveCountMax 30/g' /etc/ssh/sshd_config ${sudoCmd} sed -i 's/#\?ClientAliveInterval [0-9]*/ClientAliveInterval 40/g' /etc/ssh/sshd_config if [ "$osRelease" == "centos" ] ; then ${sudoCmd} service sshd restart ${sudoCmd} systemctl restart sshd green "设置成功, 请用shell工具软件登陆vps服务器!" fi if [ "$osRelease" == "ubuntu" ] || [ "$osRelease" == "debian" ] ; then ${sudoCmd} service ssh restart ${sudoCmd} systemctl restart ssh green "设置成功, 请用shell工具软件登陆vps服务器!" fi # /etc/init.d/ssh restart } # 修改SSH 端口号 function changeLinuxSSHPort(){ green " 修改的SSH登陆的端口号, 不要使用常用的端口号. 例如 20|21|23|25|53|69|80|110|443|123!" read -p "请输入要修改的端口号(必须是纯数字并且在1024~65535之间或22):" osSSHLoginPortInput osSSHLoginPortInput=${osSSHLoginPortInput:-0} if [ $osSSHLoginPortInput -eq 22 -o $osSSHLoginPortInput -gt 1024 -a $osSSHLoginPortInput -lt 65535 ]; then sed -i "s/#\?Port [0-9]*/Port $osSSHLoginPortInput/g" /etc/ssh/sshd_config if [ "$osRelease" == "centos" ] ; then if [[ ${osReleaseVersionNoShort} == "7" ]]; then yum install -y policycoreutils-python elif [[ ${osReleaseVersionNoShort} == "8" ]]; then yum install -y policycoreutils-python-utils fi # semanage port -l if command -v semanage &> /dev/null; then semanage port -a -t ssh_port_t -p tcp ${osSSHLoginPortInput} else red "semanage command is not installed" fi if command -v firewall-cmd &> /dev/null; then firewall-cmd --permanent --zone=public --add-port=$osSSHLoginPortInput/tcp firewall-cmd --reload else red "firewall-cmd command is not installed" fi ${sudoCmd} systemctl restart sshd.service fi if [ "$osRelease" == "ubuntu" ] || [ "$osRelease" == "debian" ] ; then if ! command -v semanage &> /dev/null; then red "semanage command is not installed" else semanage port -a -t ssh_port_t -p tcp $osSSHLoginPortInput fi if ! command -v ufw &> /dev/null; then red "ufw command is not installed" else ${sudoCmd} ufw allow $osSSHLoginPortInput/tcp fi ${sudoCmd} service ssh restart ${sudoCmd} systemctl restart ssh fi green "设置成功, 请记住设置的端口号 ${osSSHLoginPortInput}!" green "登陆服务器命令: ssh -p ${osSSHLoginPortInput} root@111.111.111.your ip !" else red "输入的端口号错误! 范围: 22,1025~65534" fi } # 设置北京时区 function setLinuxDateZone(){ tempCurrentDateZone=$(date +'%z') echo if [[ ${tempCurrentDateZone} == "+0800" ]]; then yellow "当前时区已经为北京时间 $tempCurrentDateZone | $(date -R) " else green " ==================================================" yellow " 当前时区为: $tempCurrentDateZone | $(date -R) " yellow " 是否设置时区为北京时间 +0800区, 以便cron定时重启脚本按照北京时间运行." green " ==================================================" # read 默认值 https://stackoverflow.com/questions/2642585/read-a-variable-in-bash-with-a-default-value read -p "是否设置为北京时间 +0800 时区? 请输入[Y/n]:" osTimezoneInput osTimezoneInput=${osTimezoneInput:-Y} if [[ $osTimezoneInput == [Yy] ]]; then if [[ -f /etc/localtime ]] && [[ -f /usr/share/zoneinfo/Asia/Shanghai ]]; then mv /etc/localtime /etc/localtime.bak cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime yellow " 设置成功! 当前时区已设置为 $(date -R)" green " ==================================================" fi fi fi echo if [ "$osRelease" == "centos" ]; then if [[ ${osReleaseVersionNoShort} == "7" ]]; then systemctl stop chronyd systemctl disable chronyd $osSystemPackage install -y ntpdate $osSystemPackage install -y ntp ntpdate -q 0.rhel.pool.ntp.org systemctl enable ntpd systemctl restart ntpd ntpdate -u pool.ntp.org elif [[ ${osReleaseVersionNoShort} == "8" || ${osReleaseVersionNoShort} == "9" ]]; then $osSystemPackage install -y chrony systemctl enable chronyd systemctl restart chronyd if command -v firewall-cmd &> /dev/null; then firewall-cmd --permanent --add-service=ntp firewall-cmd --reload fi echo "" echo "chrony sources:" chronyc sources echo "" echo "" fi else if [[ "${osReleaseVersionNoShort}" == "12" ]]; then systemctl restart systemd-timesyncd timedatectl timesync-status else $osSystemPackage install -y ntp systemctl enable ntp systemctl restart ntp fi fi } # 软件安装 function installSoftDownload(){ if [[ "${osRelease}" == "debian" || "${osRelease}" == "ubuntu" ]]; then PACKAGE_LIST=( "wget" "curl" "git" "unzip" "apt-transport-https" "cpu-checker" "bc" "cron" ) # 检查所有软件包是否已安装 for package in "${PACKAGE_LIST[@]}"; do if ! dpkg -l | grep -qw "$package"; then # green "$package is not installed. ${osSystemPackage} Installing..." ${osSystemPackage} install -y "$package" fi done elif [[ "${osRelease}" == "centos" ]]; then if [[ ${osReleaseVersion} == "8.1.1911" || ${osReleaseVersion} == "8.2.2004" || ${osReleaseVersion} == "8.0.1905" || ${osReleaseVersion} == "8.5.2111" ]]; then # https://techglimpse.com/failed-metadata-repo-appstream-centos-8/ cd /etc/yum.repos.d/ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* yum update -y sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Linux-* sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-* ${sudoCmd} dnf install centos-release-stream -y ${sudoCmd} dnf swap centos-{linux,stream}-repos -y ${sudoCmd} dnf distro-sync -y fi PACKAGE_LIST_Centos=( "wget" "curl" "git" "unzip" "glibc-langpack-en" ) # 检查所有软件包是否已安装 for package in "${PACKAGE_LIST_Centos[@]}"; do if ! rpm -qa | grep -qw "$package"; then # green "$package is not installed. ${osSystemPackage} Installing..." ${osSystemPackage} install -y "$package" fi done fi } function installPackage(){ echo green " ==================================================" yellow " 开始安装软件" green " ==================================================" echo # sed -i '1s/^/nameserver 1.1.1.1 \n/' /etc/resolv.conf if [ "$osRelease" == "centos" ]; then # rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm rm -f /etc/yum.repos.d/nginx.repo # cat > "/etc/yum.repos.d/nginx.repo" <<-EOF # [nginx] # name=nginx repo # baseurl=https://nginx.org/packages/centos/$osReleaseVersionNoShort/\$basearch/ # gpgcheck=0 # enabled=1 # sslverify=0 # # EOF PACKAGE_LIST=("zip" "unzip" "tar" "iputils" "htop" "redhat-lsb-core" "epel-release" "bind-utils" "net-tools" "xz" "jq" "iperf3" ) # 检查所有软件包是否已安装 for package in "${PACKAGE_LIST[@]}"; do if ! rpm -qa | grep -qw "$package"; then green "$package is not installed. Installing..." ${sudoCmd} ${osSystemPackage} install -y "$package" else green "$package has been installed." fi done yum clean all ${osSystemPackage} update -y # https://www.cyberciti.biz/faq/how-to-install-and-use-nginx-on-centos-8/ if [[ ${osReleaseVersionNoShort} == "8" ]]; then ${sudoCmd} yum module -y reset nginx ${sudoCmd} yum module -y enable nginx:1.20 ${sudoCmd} yum module list nginx fi if [[ ${osReleaseVersionNoShort} == "9" ]]; then ${sudoCmd} yum module -y reset nginx ${sudoCmd} yum module -y enable nginx:1.22 ${sudoCmd} yum module list nginx fi elif [ "$osRelease" == "ubuntu" ]; then # https://joshtronic.com/2018/12/17/how-to-install-the-latest-nginx-on-debian-and-ubuntu/ # https://www.nginx.com/resources/wiki/start/topics/tutorials/install/ $osSystemPackage install -y gnupg2 curl ca-certificates lsb-release ubuntu-keyring # wget -O - https://nginx.org/keys/nginx_signing.key | ${sudoCmd} apt-key add - curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null rm -f /etc/apt/sources.list.d/nginx.list cat > "/etc/apt/sources.list.d/nginx.list" <<-EOF deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/ubuntu/ $osReleaseVersionCodeName nginx # deb [arch=amd64] https://nginx.org/packages/ubuntu/ $osReleaseVersionCodeName nginx # deb-src https://nginx.org/packages/ubuntu/ $osReleaseVersionCodeName nginx EOF echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | sudo tee /etc/apt/preferences.d/99-nginx if [[ "${osReleaseVersionNoShort}" == "22" || "${osReleaseVersionNoShort}" == "21" ]]; then echo fi ${osSystemPackage} update -y if ! dpkg -l | grep -qw iperf3; then ${sudoCmd} ${osSystemPackage} install -y software-properties-common ${osSystemPackage} install -y curl wget git unzip zip tar htop ${osSystemPackage} install -y xz-utils jq lsb-core lsb-release ${osSystemPackage} install -y iputils-ping ${osSystemPackage} install -y iperf3 ${osSystemPackage} install -y cron fi elif [ "$osRelease" == "debian" ]; then # ${sudoCmd} add-apt-repository ppa:nginx/stable -y ${osSystemPackage} update -y ${osSystemPackage} install -y gnupg2 ${osSystemPackage} install -y curl ca-certificates lsb-release wget https://nginx.org/keys/nginx_signing.key -O- | apt-key add - rm -f /etc/apt/sources.list.d/nginx.list if [[ "${osReleaseVersionNoShort}" == "12" ]]; then echo else cat > "/etc/apt/sources.list.d/nginx.list" <<-EOF deb https://nginx.org/packages/mainline/debian/ $osReleaseVersionCodeName nginx deb-src https://nginx.org/packages/mainline/debian $osReleaseVersionCodeName nginx EOF fi ${osSystemPackage} update -y if ! dpkg -l | grep -qw iperf3; then ${osSystemPackage} install -y curl wget git unzip zip tar htop ${osSystemPackage} install -y xz-utils jq lsb-core lsb-release ${osSystemPackage} install -y iputils-ping ${osSystemPackage} install -y iperf3 fi fi } function installSoftEditor(){ # 安装 micro 编辑器 if [[ ! -f "${HOME}/bin/micro" ]] ; then mkdir -p ${HOME}/bin cd ${HOME}/bin curl https://getmic.ro | bash cp ${HOME}/bin/micro /usr/local/bin green " ==================================================" green " micro 编辑器 安装成功!" green " ==================================================" fi if [ "$osRelease" == "centos" ]; then $osSystemPackage install -y xz vim-minimal vim-enhanced vim-common nano else $osSystemPackage install -y vim-gui-common vim-runtime vim nano fi # 设置vim 中文乱码 if [[ ! -d "${HOME}/.vimrc" ]] ; then cat > "${HOME}/.vimrc" <<-EOF set fileencodings=utf-8,gb2312,gb18030,gbk,ucs-bom,cp936,latin1 set enc=utf8 set fencs=utf8,gbk,gb2312,gb18030 syntax on colorscheme elflord if has('mouse') se mouse+=a set number endif EOF fi } function installSoftOhMyZsh(){ echo green " ==================================================" yellow " 开始安装 ZSH" green " ==================================================" echo if [ "$osRelease" == "centos" ]; then ${sudoCmd} $osSystemPackage install zsh -y $osSystemPackage install util-linux-user -y elif [ "$osRelease" == "ubuntu" ]; then ${sudoCmd} $osSystemPackage install zsh -y elif [ "$osRelease" == "debian" ]; then ${sudoCmd} $osSystemPackage install zsh -y fi green " ==================================================" green " ZSH 安装成功" green " ==================================================" # 安装 oh-my-zsh if [[ ! -d "${HOME}/.oh-my-zsh" ]] ; then green " ==================================================" yellow " 开始安装 oh-my-zsh" green " ==================================================" curl -Lo ${HOME}/ohmyzsh_install.sh https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh chmod +x ${HOME}/ohmyzsh_install.sh sh ${HOME}/ohmyzsh_install.sh --unattended fi if [[ ! -d "${HOME}/.oh-my-zsh/custom/plugins/zsh-autosuggestions" ]] ; then git clone "https://github.com/zsh-users/zsh-autosuggestions" "${HOME}/.oh-my-zsh/custom/plugins/zsh-autosuggestions" # 配置 zshrc 文件 zshConfig=${HOME}/.zshrc zshTheme="maran" sed -i 's/ZSH_THEME=.*/ZSH_THEME="'"${zshTheme}"'"/' $zshConfig sed -i 's/plugins=(git)/plugins=(git cp history z rsync colorize zsh-autosuggestions)/' $zshConfig zshAutosuggestionsConfig=${HOME}/.oh-my-zsh/custom/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh sed -i "s/ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'/ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=1'/" $zshAutosuggestionsConfig sed -i "s/# zstyle ':omz:update' mode disabled/zstyle ':omz:update' mode disabled/" $zshConfig # Actually change the default shell to zsh zsh=$(which zsh) if ! chsh -s "$zsh"; then red "chsh command unsuccessful. Change your default shell manually." else export SHELL="$zsh" green "===== Shell successfully changed to '$zsh'." fi echo 'alias ll="ls -ahl"' >> ${HOME}/.zshrc echo 'alias mi="micro"' >> ${HOME}/.zshrc green " ==================================================" yellow " oh-my-zsh 安装成功, 请用exit命令退出服务器后重新登陆即可!" green " ==================================================" fi } # 更新本脚本 function upgradeScript(){ wget -Nq --no-check-certificate -O ./trojan_v2ray_install.sh "https://raw.githubusercontent.com/jinwyp/one_click_script/master/trojan_v2ray_install.sh" green " Script upgrade successful. 本脚本升级成功! " chmod +x ./trojan_v2ray_install.sh sleep 2s exec "./trojan_v2ray_install.sh" } function installWireguard(){ bash <(wget -qO- https://github.com/jinwyp/one_click_script/raw/master/install_kernel.sh) # wget -N --no-check-certificate https://github.com/jinwyp/one_click_script/raw/master/install_kernel.sh && chmod +x ./install_kernel.sh && ./install_kernel.sh } # 网络测速 function vps_netflix(){ # bash <(curl -sSL https://raw.githubusercontent.com/Netflixxp/NF/main/nf.sh) # bash <(curl -sSL "https://github.com/CoiaPrant/Netflix_Unlock_Information/raw/main/netflix.sh") # bash <(curl -L -s https://raw.githubusercontent.com/lmc999/RegionRestrictionCheck/main/check.sh) # wget -N --no-check-certificate https://github.com/CoiaPrant/Netflix_Unlock_Information/raw/main/netflix.sh && chmod +x netflix.sh && ./netflix.sh # wget -N --no-check-certificate -O netflixcheck https://github.com/sjlleo/netflix-verify/releases/download/2.61/nf_2.61_linux_amd64 && chmod +x ./netflixcheck && ./netflixcheck -method full wget -N --no-check-certificate -O ./netflix.sh https://github.com/CoiaPrant/MediaUnlock_Test/raw/main/check.sh && chmod +x ./netflix.sh && ./netflix.sh } function vps_netflix2(){ wget -N --no-check-certificate -O ./netflix.sh https://github.com/lmc999/RegionRestrictionCheck/raw/main/check.sh && chmod +x ./netflix.sh && ./netflix.sh } function vps_netflix_jin(){ # wget -qN --no-check-certificate -O ./nf.sh https://raw.githubusercontent.com/jinwyp/SimpleNetflix/dev/nf.sh && chmod +x ./nf.sh wget -qN --no-check-certificate -O ./nf.sh https://raw.githubusercontent.com/jinwyp/one_click_script/master/netflix_check.sh && chmod +x ./nf.sh && ./nf.sh } function vps_netflixgo(){ wget -qN --no-check-certificate -O netflixGo https://github.com/sjlleo/netflix-verify/releases/download/v3.1.0-1/nf_linux_amd64 && chmod +x ./netflixGo && ./netflixGo # wget -qN --no-check-certificate -O netflixGo https://github.com/sjlleo/netflix-verify/releases/download/2.61/nf_2.61_linux_amd64 && chmod +x ./netflixGo && ./netflixGo -method full echo echo wget -qN --no-check-certificate -O disneyplusGo https://github.com/sjlleo/VerifyDisneyPlus/releases/download/1.01/dp_1.01_linux_amd64 && chmod +x ./disneyplusGo && ./disneyplusGo } function vps_superspeed(){ bash <(curl -Lso- https://git.io/superspeed_uxh) # bash <(curl -Lso- https://git.io/Jlkmw) # https://github.com/coolaj/sh/blob/main/speedtest.sh # bash <(curl -Lso- https://raw.githubusercontent.com/uxh/superspeed/master/superspeed.sh) # bash <(curl -Lso- https://raw.githubusercontent.com/zq/superspeed/master/superspeed.sh) # bash <(curl -Lso- https://git.io/superspeed.sh) #wget -N --no-check-certificate https://raw.githubusercontent.com/flyzy2005/superspeed/master/superspeed.sh && chmod +x superspeed.sh && ./superspeed.sh #wget -N --no-check-certificate https://raw.githubusercontent.com/zq/superspeed/master/superspeed.sh && chmod +x superspeed.sh && ./superspeed.sh # bash <(curl -Lso- https://git.io/superspeed) #wget -N --no-check-certificate https://raw.githubusercontent.com/ernisn/superspeed/master/superspeed.sh && chmod +x superspeed.sh && ./superspeed.sh #wget -N --no-check-certificate https://raw.githubusercontent.com/oooldking/script/master/superspeed.sh && chmod +x superspeed.sh && ./superspeed.sh } function vps_yabs(){ curl -sL yabs.sh | bash } function vps_bench(){ wget -N --no-check-certificate https://raw.githubusercontent.com/jinwyp/one_click_script/master/bench.sh && chmod +x bench.sh && bash bench.sh # wget -N --no-check-certificate https://raw.githubusercontent.com/teddysun/across/master/bench.sh && chmod +x bench.sh && bash bench.sh } function vps_bench_dedicated(){ # bash -c "$(wget -qO- https://github.com/Aniverse/A/raw/i/a)" wget -N --no-check-certificate -O dedicated_server_bench.sh https://raw.githubusercontent.com/Aniverse/A/i/a && chmod +x dedicated_server_bench.sh && bash dedicated_server_bench.sh } function vps_zbench(){ wget -N --no-check-certificate https://raw.githubusercontent.com/FunctionClub/ZBench/master/ZBench-CN.sh && chmod +x ZBench-CN.sh && bash ZBench-CN.sh } function vps_LemonBench(){ wget -N --no-check-certificate -O LemonBench.sh https://ilemonra.in/LemonBenchIntl && chmod +x LemonBench.sh && ./LemonBench.sh fast } function vps_testrace(){ wget -N --no-check-certificate https://raw.githubusercontent.com/nanqinlang-script/testrace/master/testrace.sh && chmod +x testrace.sh && ./testrace.sh } function vps_autoBestTrace(){ wget -N --no-check-certificate -O autoBestTrace.sh https://raw.githubusercontent.com/zq/shell/master/autoBestTrace.sh && chmod +x autoBestTrace.sh && ./autoBestTrace.sh } function vps_mtrTrace(){ curl https://raw.githubusercontent.com/zhucaidan/mtr_trace/main/mtr_trace.sh | bash } function vps_returnroute(){ # https://www.zhujizixun.com/6216.html # https://91ai.net/thread-1015693-5-1.html # https://github.com/zhucaidan/mtr_trace wget --no-check-certificate -O route https://tutu.ovh/bash/returnroute/route && chmod +x route && ./route } function vps_returnroute2(){ # curl https://raw.githubusercontent.com/zhanghanyun/backtrace/main/install.sh | sh wget -N --no-check-certificate -O routeGo.sh https://raw.githubusercontent.com/zhanghanyun/backtrace/main/install.sh && chmod +x routeGo.sh && ./routeGo.sh } function installBBR(){ wget -N --no-check-certificate -O tcp_old.sh "https://raw.githubusercontent.com/chiakge/Linux-NetSpeed/master/tcp.sh" && chmod +x tcp_old.sh && ./tcp_old.sh } function installBBR2(){ wget -N --no-check-certificate "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh" && chmod +x tcp.sh && ./tcp.sh } function installSWAP(){ bash <(wget --no-check-certificate -qO- 'https://www.moerats.com/usr/shell/swap.sh') } function installBTPanel(){ if [ "$osRelease" == "centos" ]; then yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh else # curl -sSO http://download.bt.cn/install/install_panel.sh && bash install_panel.sh wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh fi } function installBTPanelCrack(){ echo "美国节点(直接随意输入 11位数字 跟 1位 密码 就能登录)" if [ "$osRelease" == "centos" ]; then yum install -y wget && wget -O btinstall.sh http://io.yu.al/install/install_6.0.sh && sh btinstall.sh # yum install -y wget && wget -O install.sh https://download.fenhao.me/install/install_6.0.sh && sh install.sh else wget -O btinstall.sh http://io.yu.al/install/install_panel.sh && sudo bash btinstall.sh #wget -O install.sh https://download.fenhao.me/install/install-ubuntu_6.0.sh && sudo bash install.sh fi } function installBTPanelCrackHostcli(){ if [ "$osRelease" == "centos" ]; then yum install -y wget && wget -O btinstall.sh http://v7.hostcli.com/install/install_6.0.sh && sh btinstall.sh else wget -O btinstall.sh http://v7.hostcli.com/install/install-ubuntu_6.0.sh && sudo bash btinstall.sh fi } configWebsiteFatherPath="/nginxweb" configWebsitePath="${configWebsiteFatherPath}/html" nginxAccessLogFilePath="${configWebsiteFatherPath}/nginx-access.log" nginxErrorLogFilePath="${configWebsiteFatherPath}/nginx-error.log" configTrojanWindowsCliPrefixPath=$(cat /dev/urandom | head -1 | md5sum | head -c 20) configWebsiteDownloadPath="${configWebsitePath}/download/${configTrojanWindowsCliPrefixPath}" configDownloadTempPath="${HOME}/temp" versionTrojan="1.16.0" downloadFilenameTrojan="trojan-${versionTrojan}-linux-amd64.tar.xz" versionTrojanGo="0.10.6" downloadFilenameTrojanGo="trojan-go-linux-amd64.zip" versionV2ray="5.12.1" downloadFilenameV2ray="v2ray-linux-64.zip" versionXray="1.8.7" downloadFilenameXray="Xray-linux-64.zip" versionTrojanWeb="2.10.5" downloadFilenameTrojanWeb="trojan-linux-amd64" isTrojanMultiPassword="no" promptInfoTrojanName="-go" isTrojanGoSupportWebsocket="false" configTrojanGoWebSocketPath=$(cat /dev/urandom | head -1 | md5sum | head -c 8) configTrojanPasswordPrefixInputDefault=$(cat /dev/urandom | head -1 | md5sum | head -c 3) trojanInstallType="4" configTrojanPath="${HOME}/trojan" configTrojanGoPath="${HOME}/trojan-go" configTrojanBasePath="${configTrojanGoPath}" configTrojanWebPath="${HOME}/trojan-web" configTrojanLogFile="${HOME}/trojan-access.log" configTrojanBaseVersion=${versionTrojan} configTrojanWebNginxPath=$(cat /dev/urandom | head -1 | md5sum | head -c 5) configTrojanWebPort="$(($RANDOM + 10000))" configInstallNginxMode="" nginxConfigPath="/etc/nginx/nginx.conf" nginxConfigSiteConfPath="/etc/nginx/conf.d" promptInfoXrayInstall="V2ray" promptInfoXrayVersion="" promptInfoXrayName="v2ray" promptInfoXrayNameServiceName="" isXray="no" configV2rayWebSocketPath=$(cat /dev/urandom | head -1 | md5sum | head -c 8) configV2rayGRPCServiceName=$(cat /dev/urandom | head -1 | md5sum | head -c 8) configV2rayPort="$(($RANDOM + 10000))" configV2rayGRPCPort="$(($RANDOM + 10000))" configV2rayVmesWSPort="$(($RANDOM + 10000))" configV2rayVmessTCPPort="$(($RANDOM + 10000))" configV2rayPortShowInfo=$configV2rayPort configV2rayPortGRPCShowInfo=$configV2rayGRPCPort configV2rayIsTlsShowInfo="tls" configV2rayTrojanPort="$(($RANDOM + 10000))" configV2rayPath="${HOME}/v2ray" configV2rayAccessLogFilePath="${HOME}/v2ray-access.log" configV2rayErrorLogFilePath="${HOME}/v2ray-error.log" configV2rayVmessImportLinkFile1Path="${configV2rayPath}/vmess_link1.json" configV2rayVmessImportLinkFile2Path="${configV2rayPath}/vmess_link2.json" configV2rayVlessImportLinkFile1Path="${configV2rayPath}/vless_link1.json" configV2rayVlessImportLinkFile2Path="${configV2rayPath}/vless_link2.json" configV2rayProtocol="vmess" configV2rayWorkingMode="" configV2rayWorkingNotChangeMode="" configV2rayStreamSetting="" configReadme=${HOME}/readme_trojan_v2ray.txt function downloadAndUnzip(){ if [ -z $1 ]; then green " ================================================== " green " 下载文件地址为空!" green " ================================================== " exit fi if [ -z $2 ]; then green " ================================================== " green " 目标路径地址为空!" green " ================================================== " exit fi if [ -z $3 ]; then green " ================================================== " green " 下载文件的文件名为空!" green " ================================================== " exit fi mkdir -p ${configDownloadTempPath} if [[ $3 == *"tar.xz"* ]]; then green "===== 下载并解压tar文件: $3 " wget -O ${configDownloadTempPath}/$3 $1 tar xf ${configDownloadTempPath}/$3 -C ${configDownloadTempPath} mv ${configDownloadTempPath}/* $2 elif [[ $3 == *"tar.gz"* ]]; then green "===== 下载并解压tar.gz文件: $3 " wget -O ${configDownloadTempPath}/$3 $1 tar -xzvf ${configDownloadTempPath}/$3 -C ${configDownloadTempPath} mv ${configDownloadTempPath}/easymosdns/* $2 else green "===== 下载并解压zip文件: $3 " wget -O ${configDownloadTempPath}/$3 $1 unzip -d $2 ${configDownloadTempPath}/$3 fi rm -rf ${configDownloadTempPath}/* } function getGithubLatestReleaseVersion(){ # https://github.com/p4gefau1t/trojan-go/issues/63 wget --no-check-certificate -qO- https://api.github.com/repos/$1/tags | grep 'name' | cut -d\" -f4 | head -1 | cut -b 2- } function getV2rayVersion(){ # https://github.com/trojan-gfw/trojan/releases/download/v1.16.0/trojan-1.16.0-linux-amd64.tar.xz echo if [[ $1 == "v2ray" ]] ; then echo green " ================================================== " green " 请选择 V2ray 的版本, 默认直接回车为 稳定版4.45.2 (推荐)" green " 选否则安装最新版的 V2ray 5.4.1 User Preview" echo read -r -p "是否安装稳定版V2ray? 默认直接回车为稳定版4.45.2, 请输入[Y/n]:" isInstallXrayVersionInput isInstallXrayVersionInput=${isInstallXrayVersionInput:-Y} echo if [[ $isInstallXrayVersionInput == [Yy] ]]; then versionV2ray="4.45.2" else versionV2ray=$(getGithubLatestReleaseVersion "v2fly/v2ray-core") fi echo "versionV2ray: ${versionV2ray}" fi if [[ $1 == "xray" ]] ; then echo green " ================================================== " tempXrayVersionDisplayText="2" if [[ $configV2rayWorkingMode == "vlessTCPREALITY" ]]; then tempXrayVersionDisplayText="1" green " 请选择 Xray 的版本, 默认直接回车为 1.8.7 或以上的最新版本" echo green " 1. 1.8.7 或以上的最新版本 支持 REALITY 和 XTLS Vision" elif [[ $configV2rayWorkingMode == "vlessTCPVision" ]]; then tempXrayVersionDisplayText="1" green " 请选择 Xray 的版本, 默认直接回车为 1.8.7 或以上的最新版本" echo green " 1. 1.8.7 或以上的最新版本 支持 REALITY 和 XTLS Vision" green " 2. 1.7.5 支持 XTLS Vision " else green " 请选择 Xray 的版本, 默认直接回车为 1.7.5" echo if [[ $2 == "update" ]]; then red "升级 1.8.7 或以上版本可能导致 启动失败, 不兼容旧版 XTLS 配置!" echo fi if [[ $2 == "shadowsocks" ]]; then echo fi green " 1. 1.8.7 或以上的最新版本 支持 REALITY 和 XTLS Vision" green " 2. 1.7.5 支持 XTLS Vision (推荐)" green " 3. 1.6.1 (推荐)" green " 4. 1.6.0" green " 5. 1.5.5" green " 6. 1.5.4" green " 7. 1.5.3" green " 8. 1.5.2" green " 9. 1.5.1" green " 10. 1.5.0" green " 11. 1.4.5" green " 12. 1.3.1" fi echo read -r -p "请选择Xray版本? 直接回车默认选${tempXrayVersionDisplayText}, 请输入纯数字:" isXrayVersionInput isXrayVersionInput=${isXrayVersionInput:-${tempXrayVersionDisplayText}} if [[ "${isXrayVersionInput}" == "1" ]]; then versionXray=$(getGithubLatestReleaseVersion "XTLS/Xray-core") elif [[ "${isXrayVersionInput}" == "3" ]]; then versionXray="1.6.1" elif [[ "${isXrayVersionInput}" == "4" ]]; then versionXray="1.6.0" elif [[ "${isXrayVersionInput}" == "5" ]]; then versionXray="1.5.5" elif [[ "${isXrayVersionInput}" == "6" ]]; then versionXray="1.5.4" elif [[ "${isXrayVersionInput}" == "7" ]]; then versionXray="1.5.3" elif [[ "${isXrayVersionInput}" == "8" ]]; then versionXray="1.5.2" elif [[ "${isXrayVersionInput}" == "9" ]]; then versionXray="1.5.1" elif [[ "${isXrayVersionInput}" == "10" ]]; then versionXray="1.5.0" elif [[ "${isXrayVersionInput}" == "11" ]]; then versionXray="1.4.5" elif [[ "${isXrayVersionInput}" == "12" ]]; then versionXray="1.3.1" else versionXray="1.7.5" fi echo "versionXray: ${versionXray}" fi if [[ $1 == "trojan-web" ]] ; then versionTrojanWeb=$(getGithubLatestReleaseVersion "Jrohy/trojan") echo "versionTrojanWeb: ${versionTrojanWeb}" fi if [[ $1 == "wgcf" ]] ; then versionWgcf=$(getGithubLatestReleaseVersion "ViRb3/wgcf") downloadFilenameWgcf="wgcf_${versionWgcf}_linux_amd64" echo "versionWgcf: ${versionWgcf}" fi } configNetworkRealIp="" configSSLDomain="" acmeSSLRegisterEmailInput="" isDomainSSLGoogleEABKeyInput="" isDomainSSLGoogleEABIdInput="" function getHTTPSCertificateCheckEmail(){ if [ -z $2 ]; then if [[ $1 == "email" ]]; then red " 输入邮箱地址不能为空, 请重新输入!" getHTTPSCertificateInputEmail elif [[ $1 == "googleEabKey" ]]; then red " 输入EAB key 不能为空, 请重新输入!" getHTTPSCertificateInputGoogleEABKey elif [[ $1 == "googleEabId" ]]; then red " 输入EAB Id 不能为空, 请重新输入!" getHTTPSCertificateInputGoogleEABId fi fi } function getHTTPSCertificateInputEmail(){ echo read -r -p "请输入邮箱地址, 用于申请SSL证书:" acmeSSLRegisterEmailInput getHTTPSCertificateCheckEmail "email" "${acmeSSLRegisterEmailInput}" } function getHTTPSCertificateInputGoogleEABKey(){ echo read -r -p "请输入 Google EAB key :" isDomainSSLGoogleEABKeyInput getHTTPSCertificateCheckEmail "googleEabKey" "${isDomainSSLGoogleEABKeyInput}" } function getHTTPSCertificateInputGoogleEABId(){ echo read -r -p "请输入 Google EAB id :" isDomainSSLGoogleEABIdInput getHTTPSCertificateCheckEmail "googleEabId" "${isDomainSSLGoogleEABIdInput}" } acmeSSLDays="89" acmeSSLServerName="letsencrypt" acmeSSLDNSProvider="dns_cf" configRanPath="${HOME}/ran" configSSLAcmeScriptPath="${HOME}/.acme.sh" configSSLCertPath="${configWebsiteFatherPath}/cert" configSSLCertKeyFilename="server.key" configSSLCertFullchainFilename="server_fullchain.cert" function renewCertificationWithAcme(){ # https://stackoverflow.com/questions/8880603/loop-through-an-array-of-strings-in-bash # https://stackoverflow.com/questions/9954680/how-to-store-directory-files-listing-into-an-array shopt -s nullglob renewDomainArray=("${configSSLAcmeScriptPath}"/*ecc*) COUNTER1=1 if [ ${#renewDomainArray[@]} -ne 0 ]; then echo green " ================================================== " green " 检测到本机已经申请过域名证书 是否新增申请域名证书" yellow " 新安装或卸载后重新安装trojan或v2ray 请选择新增而不要选择续签" echo green " 1. 新增申请域名证书" green " 2. 续签已申请域名证书" green " 3. 删除已申请域名证书" echo read -r -p "请选择是否新增域名证书? 默认直接回车为新增, 请输入纯数字:" isAcmeSSLAddNewInput isAcmeSSLAddNewInput=${isAcmeSSLAddNewInput:-1} if [[ "$isAcmeSSLAddNewInput" == "2" || "$isAcmeSSLAddNewInput" == "3" ]]; then echo green " ================================================== " green " 请选择要续签或要删除的域名:" echo for renewDomainName in "${renewDomainArray[@]}"; do substr=${renewDomainName##*/} substr=${substr%_ecc*} renewDomainArrayFix[${COUNTER1}]="$substr" echo " ${COUNTER1}. 域名: ${substr}" COUNTER1=$((COUNTER1 +1)) done echo read -r -p "请选择域名? 请输入纯数字:" isRenewDomainSelectNumberInput isRenewDomainSelectNumberInput=${isRenewDomainSelectNumberInput:-99} if [[ "$isRenewDomainSelectNumberInput" == "99" ]]; then red " 输入错误, 请重新输入!" echo read -r -p "请选择域名? 请输入纯数字:" isRenewDomainSelectNumberInput isRenewDomainSelectNumberInput=${isRenewDomainSelectNumberInput:-99} if [[ "$isRenewDomainSelectNumberInput" == "99" ]]; then red " 输入错误, 退出!" exit else echo fi else echo fi configSSLRenewDomain=${renewDomainArrayFix[${isRenewDomainSelectNumberInput}]} if [[ -n $(${configSSLAcmeScriptPath}/acme.sh --list | grep ${configSSLRenewDomain}) ]]; then if [[ "$isAcmeSSLAddNewInput" == "2" ]]; then ${configSSLAcmeScriptPath}/acme.sh --renew -d ${configSSLRenewDomain} --force --ecc echo green " 域名 ${configSSLRenewDomain} 的证书已经成功续签!" elif [[ "$isAcmeSSLAddNewInput" == "3" ]]; then ${configSSLAcmeScriptPath}/acme.sh --revoke -d ${configSSLRenewDomain} --ecc ${configSSLAcmeScriptPath}/acme.sh --remove -d ${configSSLRenewDomain} --ecc rm -rf "${configSSLAcmeScriptPath}/${configSSLRenewDomain}_ecc" echo green " 域名 ${configSSLRenewDomain} 的证书已经删除成功!" exit fi else echo red " 您选择的域名 ${configSSLRenewDomain} 证书不存在!" fi else getHTTPSCertificateStep1 fi else getHTTPSCertificateStep1 fi } function getHTTPSCertificateWithAcme(){ # 申请https证书 mkdir -p ${configSSLCertPath} mkdir -p ${configWebsitePath} getHTTPSCertificateInputEmail curl https://get.acme.sh | sh -s email=${acmeSSLRegisterEmailInput} echo green " ================================================== " green " 请选择证书提供商, 默认通过 Letsencrypt.org 来申请证书 " green " 如果证书申请失败, 例如一天内通过 Letsencrypt.org 申请次数过多, 可选 BuyPass.com 或 ZeroSSL.com 来申请." green " 1 Letsencrypt.org " green " 2 BuyPass.com " green " 3 ZeroSSL.com " green " 4 Google Public CA " echo read -r -p "请选择证书提供商? 默认直接回车为通过 Letsencrypt.org 申请, 请输入纯数字:" isDomainSSLFromLetInput isDomainSSLFromLetInput=${isDomainSSLFromLetInput:-1} if [[ "$isDomainSSLFromLetInput" == "2" ]]; then acmeSSLDays="179" acmeSSLServerName="buypass" echo ${configSSLAcmeScriptPath}/acme.sh --register-account --accountemail ${acmeSSLRegisterEmailInput} --server buypass elif [[ "$isDomainSSLFromLetInput" == "3" ]]; then acmeSSLServerName="zerossl" echo ${configSSLAcmeScriptPath}/acme.sh --register-account -m ${acmeSSLRegisterEmailInput} --server zerossl elif [[ "$isDomainSSLFromLetInput" == "4" ]]; then green " ================================================== " yellow " 请先按照如下链接申请 google Public CA https://hostloc.com/thread-993780-1-1.html" yellow " 具体可参考 https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA" acmeSSLServerName="google" getHTTPSCertificateInputGoogleEABKey getHTTPSCertificateInputGoogleEABId ${configSSLAcmeScriptPath}/acme.sh --register-account -m ${acmeSSLRegisterEmailInput} --server google --eab-kid ${isDomainSSLGoogleEABIdInput} --eab-hmac-key ${isDomainSSLGoogleEABKeyInput} else acmeSSLServerName="letsencrypt" #${configSSLAcmeScriptPath}/acme.sh --issue -d ${configSSLDomain} --webroot ${configWebsitePath} --keylength ec-256 --days 89 --server letsencrypt fi echo green " ================================================== " green " 请选择 acme.sh 脚本申请SSL证书方式: 1 http方式, 2 dns方式 " green " 默认直接回车为 http 申请方式, 选否则为 dns 方式" echo read -r -p "请选择SSL证书申请方式 ? 默认直接回车为http方式, 选否则为 dns 方式申请证书, 请输入[Y/n]:" isAcmeSSLRequestMethodInput isAcmeSSLRequestMethodInput=${isAcmeSSLRequestMethodInput:-Y} echo if [[ $isAcmeSSLRequestMethodInput == [Yy] ]]; then acmeSSLHttpWebrootMode="" if [[ -n "${configInstallNginxMode}" ]]; then acmeDefaultValue="3" acmeDefaultText="3. webroot 并使用ran作为临时的Web服务器" acmeSSLHttpWebrootMode="webrootran" else acmeDefaultValue="1" acmeDefaultText="1. standalone 模式" acmeSSLHttpWebrootMode="standalone" fi if [ -z "$1" ]; then checkPortUsage "80" green " ================================================== " green " 请选择 http 申请证书方式: 默认直接回车为 ${acmeDefaultText} " green " 1 standalone 模式, 适合没有安装Web服务器, 如已选择不安装Nginx 请选择此模式. 请确保80端口不被占用. 注意:三个月后续签时80端口被占用会导致续签失败!" green " 2 webroot 模式, 适合已经安装Web服务器, 例如 Caddy Apache 或 Nginx, 请确保Web服务器已经运行在80端口" green " 3 webroot 模式 并使用 ran 作为临时的Web服务器, 如已选择同时安装Nginx,请使用此模式, 可以正常续签" green " 4 nginx 模式 适合已经安装 Nginx, 请确保 Nginx 已经运行" echo read -r -p "请选择http申请证书方式? 默认为 ${acmeDefaultText}, 请输入纯数字:" isAcmeSSLWebrootModeInput isAcmeSSLWebrootModeInput=${isAcmeSSLWebrootModeInput:-${acmeDefaultValue}} if [[ ${isAcmeSSLWebrootModeInput} == "1" ]]; then acmeSSLHttpWebrootMode="standalone" elif [[ ${isAcmeSSLWebrootModeInput} == "2" ]]; then acmeSSLHttpWebrootMode="webroot" elif [[ ${isAcmeSSLWebrootModeInput} == "4" ]]; then acmeSSLHttpWebrootMode="nginx" else acmeSSLHttpWebrootMode="webrootran" fi else if [[ $1 == "standalone" ]]; then acmeSSLHttpWebrootMode="standalone" elif [[ $1 == "webroot" ]]; then acmeSSLHttpWebrootMode="webroot" elif [[ $1 == "webrootran" ]] ; then acmeSSLHttpWebrootMode="webrootran" elif [[ $1 == "nginx" ]] ; then acmeSSLHttpWebrootMode="nginx" fi fi echo if [[ ${acmeSSLHttpWebrootMode} == "standalone" ]] ; then green " 开始申请证书 acme.sh 通过 http standalone mode 从 ${acmeSSLServerName} 申请, 请确保80端口不被占用 " echo ${configSSLAcmeScriptPath}/acme.sh --issue -d ${configSSLDomain} --standalone --keylength ec-256 --days ${acmeSSLDays} --server ${acmeSSLServerName} elif [[ ${acmeSSLHttpWebrootMode} == "webroot" ]] ; then green " 开始申请证书, acme.sh 通过 http webroot mode 从 ${acmeSSLServerName} 申请, 请确保web服务器 例如 nginx 已经运行在80端口 " echo read -r -p "请输入Web服务器的html网站根目录路径? 例如/usr/share/nginx/html:" isDomainSSLNginxWebrootFolderInput echo " 您输入的网站根目录路径为 ${isDomainSSLNginxWebrootFolderInput}" if [ -z ${isDomainSSLNginxWebrootFolderInput} ]; then red " 输入的Web服务器的 html网站根目录路径不能为空, 网站根目录将默认设置为 ${configWebsitePath}, 请修改你的web服务器配置后再申请证书!" else configWebsitePath="${isDomainSSLNginxWebrootFolderInput}" fi echo ${configSSLAcmeScriptPath}/acme.sh --issue -d ${configSSLDomain} --webroot ${configWebsitePath} --keylength ec-256 --days ${acmeSSLDays} --server ${acmeSSLServerName} elif [[ ${acmeSSLHttpWebrootMode} == "nginx" ]] ; then green " 开始申请证书, acme.sh 通过 http nginx mode 从 ${acmeSSLServerName} 申请, 请确保web服务器 nginx 已经运行 " echo ${configSSLAcmeScriptPath}/acme.sh --issue -d ${configSSLDomain} --nginx --keylength ec-256 --days ${acmeSSLDays} --server ${acmeSSLServerName} elif [[ ${acmeSSLHttpWebrootMode} == "webrootran" ]] ; then # https://github.com/m3ng9i/ran/issues/10 ranDownloadUrl="https://github.com/m3ng9i/ran/releases/download/v0.1.6/ran_linux_amd64.zip" ranDownloadFileName="ran_linux_amd64" if [[ "${osArchitecture}" == "arm64" || "${osArchitecture}" == "arm" ]]; then ranDownloadUrl="https://github.com/m3ng9i/ran/releases/download/v0.1.6/ran_linux_arm64.zip" ranDownloadFileName="ran_linux_arm64" fi mkdir -p ${configRanPath} if [[ -f "${configRanPath}/${ranDownloadFileName}" ]]; then green " 检测到 ran 已经下载过, 准备启动 ran 临时的web服务器 " else green " 开始下载 ran 作为临时的web服务器 " downloadAndUnzip "${ranDownloadUrl}" "${configRanPath}" "${ranDownloadFileName}" chmod +x "${configRanPath}/${ranDownloadFileName}" fi echo "nohup ${configRanPath}/${ranDownloadFileName} -l=false -g=false -sa=true -p=80 -r=${configWebsitePath} >/dev/null 2>&1 &" nohup ${configRanPath}/${ranDownloadFileName} -l=false -g=false -sa=true -p=80 -r=${configWebsitePath} >/dev/null 2>&1 & echo green " 开始申请证书, acme.sh 通过 http webroot mode 从 ${acmeSSLServerName} 申请, 并使用 ran 作为临时的web服务器 " echo ${configSSLAcmeScriptPath}/acme.sh --issue -d ${configSSLDomain} --webroot ${configWebsitePath} --keylength ec-256 --days ${acmeSSLDays} --server ${acmeSSLServerName} sleep 4 ps -C ${ranDownloadFileName} -o pid= | xargs -I {} kill {} fi else green " 开始申请证书, acme.sh 通过 dns mode 申请 " echo green "请选择 DNS provider DNS 提供商: 1 CloudFlare, 2 AliYun, 3 DNSPod(Tencent), 4 GoDaddy " red "注意 CloudFlare 针对某些免费域名例如 .tk .cf 等 不再支持使用API 申请DNS证书 " echo read -r -p "请选择 DNS 提供商 ? 默认直接回车为 1. CloudFlare, 请输入纯数字:" isAcmeSSLDNSProviderInput isAcmeSSLDNSProviderInput=${isAcmeSSLDNSProviderInput:-1} if [ "$isAcmeSSLDNSProviderInput" == "2" ]; then read -r -p "Please Input Ali Key: " Ali_Key export Ali_Key="${Ali_Key}" read -r -p "Please Input Ali Secret: " Ali_Secret export Ali_Secret="${Ali_Secret}" acmeSSLDNSProvider="dns_ali" elif [ "$isAcmeSSLDNSProviderInput" == "3" ]; then read -r -p "Please Input DNSPod API ID: " DP_Id export DP_Id="${DP_Id}" read -r -p "Please Input DNSPod API Key: " DP_Key export DP_Key="${DP_Key}" acmeSSLDNSProvider="dns_dp" elif [ "$isAcmeSSLDNSProviderInput" == "4" ]; then read -r -p "Please Input GoDaddy API Key: " gd_Key export GD_Key="${gd_Key}" read -r -p "Please Input GoDaddy API Secret: " gd_Secret export GD_Secret="${gd_Secret}" acmeSSLDNSProvider="dns_gd" else read -r -p "Please Input CloudFlare Email: " cf_email export CF_Email="${cf_email}" read -r -p "Please Input CloudFlare Global API Key: " cf_key export CF_Key="${cf_key}" acmeSSLDNSProvider="dns_cf" fi echo ${configSSLAcmeScriptPath}/acme.sh --issue -d "${configSSLDomain}" --dns ${acmeSSLDNSProvider} --force --keylength ec-256 --server ${acmeSSLServerName} --debug fi echo if [[ ${isAcmeSSLWebrootModeInput} == "1" ]]; then ${configSSLAcmeScriptPath}/acme.sh --installcert --ecc -d ${configSSLDomain} \ --key-file ${configSSLCertPath}/${configSSLCertKeyFilename} \ --fullchain-file ${configSSLCertPath}/${configSSLCertFullchainFilename} else ${configSSLAcmeScriptPath}/acme.sh --installcert --ecc -d ${configSSLDomain} \ --key-file ${configSSLCertPath}/${configSSLCertKeyFilename} \ --fullchain-file ${configSSLCertPath}/${configSSLCertFullchainFilename} \ --reloadcmd "systemctl restart nginx.service" fi green " ================================================== " } function compareRealIpWithLocalIp(){ echo green " 是否检测域名指向的IP正确 直接回车默认检测" red " 如果域名指向的IP不是本机IP, 或已开启CDN不方便关闭 或只有IPv6的VPS 可以选否不检测" read -r -p "是否检测域名指向的IP正确? 请输入[Y/n]:" isDomainValidInput isDomainValidInput=${isDomainValidInput:-Y} if [[ $isDomainValidInput == [Yy] ]]; then if [[ -n "$1" ]]; then configNetworkRealIp=$(ping $1 -c 1 | sed '1{s/[^(]*(//;s/).*//;q}') # https://unix.stackexchange.com/questions/22615/how-can-i-get-my-external-ip-address-in-a-shell-script configNetworkLocalIp1="$(curl http://whatismyip.akamai.com/)" configNetworkLocalIp2="$(curl https://checkip.amazonaws.com/)" #configNetworkLocalIp3="$(curl https://ipv4.icanhazip.com/)" #configNetworkLocalIp4="$(curl https://v4.ident.me/)" #configNetworkLocalIp5="$(curl https://api.ip.sb/ip)" #configNetworkLocalIp6="$(curl https://ipinfo.io/ip)" #configNetworkLocalIPv61="$(curl https://ipv6.icanhazip.com/)" #configNetworkLocalIPv62="$(curl https://v6.ident.me/)" green " ================================================== " green " 域名解析地址为 ${configNetworkRealIp}, 本VPS的IP为 ${configNetworkLocalIp1} " echo if [[ ${configNetworkRealIp} == "${configNetworkLocalIp1}" || ${configNetworkRealIp} == "${configNetworkLocalIp2}" ]] ; then green " 域名解析的IP正常!" green " ================================================== " true else red " 域名解析地址与本VPS的IP地址不一致!" red " 本次安装失败,请确保域名解析正常, 请检查域名和DNS是否生效!" green " ================================================== " false fi else green " ================================================== " red " 域名输入错误!" green " ================================================== " false fi else green " ================================================== " green " 不检测域名解析是否正确!" green " ================================================== " true fi } function getHTTPSCertificateStep1(){ echo green " ================================================== " green " 请输入证书要放置的路径: 默认为${configSSLCertPath} " yellow " 自定义证书路径可能会导致安装失败 仅供高手使用 " yellow " 自定义证书路径需要预先创建好, 否则会使用默认路径${configSSLCertPath} " echo read -r -p "请输入证书路径 默认直接回车为${configSSLCertPath}" configSSLFilePath configSSLFilePath=${configSSLFilePath:-${configSSLCertPath}} if [ -z "${configSSLFilePath}" ]; then configSSLFilePath="${configSSLCertPath}" red " 输入的自定义证书路径为空, 将使用默认路径${configSSLCertPath} " fi if [ ! -d "${configSSLFilePath}" ]; then configSSLFilePath="${configSSLCertPath}" red " 输入的自定义证书路径为不存在, 将使用默认路径${configSSLCertPath} " fi configSSLCertPath="${configSSLFilePath}" echo green " ================================================== " yellow " 请输入解析到本VPS的域名 例如 www.xxx.com: (此步骤请关闭CDN后和nginx后安装 避免80端口占用导致申请证书失败)" read -r -p "请输入解析到本VPS的域名:" configSSLDomain if compareRealIpWithLocalIp "${configSSLDomain}" ; then echo green " ==================================================" green " 是否申请证书? 默认直接回车为申请证书, 如第二次安装或已有证书 可以选否" green " 如果已经有SSL证书文件 请放到下面路径" red " ${configSSLDomain} 域名证书内容文件路径 ${configSSLCertPath}/${configSSLCertFullchainFilename} " red " ${configSSLDomain} 域名证书私钥文件路径 ${configSSLCertPath}/${configSSLCertKeyFilename} " echo read -r -p "是否申请证书? 默认直接回车为自动申请证书,请输入[Y/n]:" isDomainSSLRequestInput isDomainSSLRequestInput=${isDomainSSLRequestInput:-Y} if [[ $isDomainSSLRequestInput == [Yy] ]]; then getHTTPSCertificateWithAcme "" else green " ==================================================" green " 不申请域名的证书, 请把证书放到如下目录, 或自行修改trojan或v2ray配置!" green " ${configSSLDomain} 域名证书内容文件路径 ${configSSLCertPath}/${configSSLCertFullchainFilename} " green " ${configSSLDomain} 域名证书私钥文件路径 ${configSSLCertPath}/${configSSLCertKeyFilename} " green " ==================================================" fi else exit fi } wwwUsername="www-data" function createUserWWW(){ isHaveWwwUser=$(cat /etc/passwd | cut -d ":" -f 1 | grep ^${wwwUsername}$) if [ "${isHaveWwwUser}" != "${wwwUsername}" ]; then ${sudoCmd} groupadd ${wwwUsername} ${sudoCmd} useradd -s /usr/sbin/nologin -g ${wwwUsername} ${wwwUsername} --no-create-home fi } function stopServiceNginx(){ serviceNginxStatus=$(ps -aux | grep "nginx: worker" | grep -v "grep") if [[ -n "$serviceNginxStatus" ]]; then ${sudoCmd} systemctl stop nginx.service fi } function stopServiceV2ray(){ if [[ -f "${osSystemMdPath}v2ray.service" ]] || [[ -f "/etc/systemd/system/v2ray.service" ]] || [[ -f "/lib/systemd/system/v2ray.service" ]] ; then ${sudoCmd} systemctl stop v2ray.service fi if [[ -f "${osSystemMdPath}xray.service" ]] || [[ -f "/etc/systemd/system/xray.service" ]] || [[ -f "/lib/systemd/system/xray.service" ]] ; then ${sudoCmd} systemctl stop xray.service fi } function installWebServerNginx(){ echo green " ================================================== " yellow " 开始安装 Web服务器 nginx !" green " ================================================== " echo if test -s ${nginxConfigPath}; then showHeaderRed "Nginx 已存在, 是否继续安装? " "Nginx already exists. Continue the installation? " promptContinueOpeartion ${sudoCmd} systemctl stop nginx.service else stopServiceV2ray createUserWWW nginxUser="${wwwUsername} ${wwwUsername}" if [ "$osRelease" == "centos" ]; then ${osSystemPackage} install -y nginx-mod-stream else echo groupadd -r -g 4 adm apt autoremove -y apt-get remove --purge -y nginx-common apt-get remove --purge -y nginx-core apt-get remove --purge -y libnginx-mod-stream apt-get remove --purge -y libnginx-mod-http-xslt-filter libnginx-mod-http-geoip2 libnginx-mod-stream-geoip2 libnginx-mod-mail libnginx-mod-http-image-filter apt autoremove -y --purge nginx nginx-common nginx-core apt-get remove --purge -y nginx nginx-full nginx-common nginx-core #${osSystemPackage} install -y libnginx-mod-stream fi ${osSystemPackage} install -y nginx ${sudoCmd} systemctl enable nginx.service ${sudoCmd} systemctl stop nginx.service # 解决出现的nginx warning 错误 Failed to parse PID from file /run/nginx.pid: Invalid argument # https://www.kancloud.cn/tinywan/nginx_tutorial/753832 mkdir -p /etc/systemd/system/nginx.service.d printf "[Service]\nExecStartPost=/bin/sleep 0.1\n" > /etc/systemd/system/nginx.service.d/override.conf ${sudoCmd} systemctl daemon-reload fi mkdir -p ${configWebsitePath} mkdir -p "${nginxConfigSiteConfPath}" nginxConfigServerHttpInput="" nginxConfigServerHttpGrpcInput="" nginxConfigStreamConfigInput="" nginxConfigNginxModuleInput="" nginxConfigDefaultWebsiteLocation="" echo green " ==================================================" green " 是否反代指定的网站? 默认不反代网站, 使用bootstrap静态网页作为伪装网站)" green " 如需要反代网站 请输入网址 例如 www.baidu.com (不要输入https://)" echo read -r -p "是否反代指定的网站, 默认直接回车不反代, 请输入反代网址:" configNginxDefaultWebsiteInput configNginxDefaultWebsiteInput=${configNginxDefaultWebsiteInput:-} if [[ -n "${configNginxDefaultWebsiteInput}" ]]; then read -r -d '' nginxConfigDefaultWebsiteLocation << EOM location / { proxy_pass https://$configNginxDefaultWebsiteInput; } EOM fi if [[ "${configInstallNginxMode}" == "noSSL" ]]; then if [[ ${configV2rayWorkingNotChangeMode} == "true" ]]; then inputV2rayStreamSettings fi if [[ "${configV2rayStreamSetting}" == "grpc" || "${configV2rayStreamSetting}" == "wsgrpc" ]]; then read -r -d '' nginxConfigServerHttpGrpcInput << EOM location /$configV2rayGRPCServiceName { grpc_pass grpc://127.0.0.1:$configV2rayGRPCPort; grpc_connect_timeout 60s; grpc_read_timeout 720m; grpc_send_timeout 720m; grpc_set_header X-Real-IP \$remote_addr; grpc_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; } EOM fi cat > "${nginxConfigSiteConfPath}/nossl_site.conf" <<-EOF server { listen 80; server_name $configSSLDomain; root $configWebsitePath; index index.php index.html index.htm; location /$configV2rayWebSocketPath { proxy_pass http://127.0.0.1:$configV2rayPort; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host \$http_host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; } ${nginxConfigServerHttpGrpcInput} ${nginxConfigDefaultWebsiteLocation} } EOF elif [[ "${configInstallNginxMode}" == "v2raySSL" ]]; then inputV2rayStreamSettings cat > "${nginxConfigSiteConfPath}/v2rayssl_site.conf" <<-EOF server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name $configSSLDomain; ssl_certificate ${configSSLCertPath}/$configSSLCertFullchainFilename; ssl_certificate_key ${configSSLCertPath}/$configSSLCertKeyFilename; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers TLS-AES-256-GCM-SHA384:TLS-CHACHA20-POLY1305-SHA256:TLS-AES-128-GCM-SHA256:TLS-AES-128-CCM-8-SHA256:TLS-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; # Config for 0-RTT in TLSv1.3 ssl_early_data on; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security "max-age=31536000"; root $configWebsitePath; index index.php index.html index.htm; location /$configV2rayWebSocketPath { proxy_pass http://127.0.0.1:$configV2rayPort; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host \$http_host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; } location /$configV2rayGRPCServiceName { grpc_pass grpc://127.0.0.1:$configV2rayGRPCPort; grpc_connect_timeout 60s; grpc_read_timeout 720m; grpc_send_timeout 720m; grpc_set_header X-Real-IP \$remote_addr; grpc_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; } ${nginxConfigDefaultWebsiteLocation} } server { listen 80; listen [::]:80; server_name $configSSLDomain; return 301 https://$configSSLDomain\$request_uri; } EOF elif [[ "${configInstallNginxMode}" == "sni" ]]; then if [ "$osRelease" == "centos" ]; then read -r -d '' nginxConfigNginxModuleInput << EOM load_module /usr/lib64/nginx/modules/ngx_stream_module.so; EOM else read -r -d '' nginxConfigNginxModuleInput << EOM include /etc/nginx/modules-enabled/*.conf; # load_module /usr/lib/nginx/modules/ngx_stream_module.so; EOM fi nginxConfigStreamFakeWebsiteDomainInput="" nginxConfigStreamOwnWebsiteInput="" nginxConfigStreamOwnWebsiteMapInput="" if [[ "${isNginxSNIModeInput}" == "4" || "${isNginxSNIModeInput}" == "5" || "${isNginxSNIModeInput}" == "6" ]]; then read -r -d '' nginxConfigStreamOwnWebsiteInput << EOM server { listen 8000 ssl http2; listen [::]:8000 ssl http2; server_name $configNginxSNIDomainWebsite; ssl_certificate ${configNginxSNIDomainWebsiteCertPath}/$configSSLCertFullchainFilename; ssl_certificate_key ${configNginxSNIDomainWebsiteCertPath}/$configSSLCertKeyFilename; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers TLS-AES-256-GCM-SHA384:TLS-CHACHA20-POLY1305-SHA256:TLS-AES-128-GCM-SHA256:TLS-AES-128-CCM-8-SHA256:TLS-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; # Config for 0-RTT in TLSv1.3 ssl_early_data on; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security "max-age=31536000"; root $configWebsitePath; index index.php index.html index.htm; } server { listen 80; listen [::]:80; server_name $configNginxSNIDomainWebsite; return 301 https://$configNginxSNIDomainWebsite\$request_uri; } EOM read -r -d '' nginxConfigStreamOwnWebsiteMapInput << EOM ${configNginxSNIDomainWebsite} web; EOM fi nginxConfigStreamTrojanMapInput="" nginxConfigStreamTrojanUpstreamInput="" if [[ "${isNginxSNIModeInput}" == "1" || "${isNginxSNIModeInput}" == "2" || "${isNginxSNIModeInput}" == "4" || "${isNginxSNIModeInput}" == "5" ]]; then nginxConfigStreamFakeWebsiteDomainInput="${configNginxSNIDomainTrojan}" read -r -d '' nginxConfigStreamTrojanMapInput << EOM ${configNginxSNIDomainTrojan} trojan; EOM read -r -d '' nginxConfigStreamTrojanUpstreamInput << EOM upstream trojan { server 127.0.0.1:$configV2rayTrojanPort; } EOM fi nginxConfigStreamV2rayMapInput="" nginxConfigStreamV2rayUpstreamInput="" if [[ "${isNginxSNIModeInput}" == "1" || "${isNginxSNIModeInput}" == "3" || "${isNginxSNIModeInput}" == "4" || "${isNginxSNIModeInput}" == "6" ]]; then nginxConfigStreamFakeWebsiteDomainInput="${nginxConfigStreamFakeWebsiteDomainInput} ${configNginxSNIDomainV2ray}" read -r -d '' nginxConfigStreamV2rayMapInput << EOM ${configNginxSNIDomainV2ray} v2ray; EOM read -r -d '' nginxConfigStreamV2rayUpstreamInput << EOM upstream v2ray { server 127.0.0.1:$configV2rayPort; } EOM fi cat > "${nginxConfigSiteConfPath}/sni_site.conf" <<-EOF server { listen 80; server_name $nginxConfigStreamFakeWebsiteDomainInput; root $configWebsitePath; index index.php index.html index.htm; } ${nginxConfigStreamOwnWebsiteInput} EOF read -r -d '' nginxConfigStreamConfigInput << EOM stream { map \$ssl_preread_server_name \$filtered_sni_name { ${nginxConfigStreamOwnWebsiteMapInput} ${nginxConfigStreamTrojanMapInput} ${nginxConfigStreamV2rayMapInput} } ${nginxConfigStreamTrojanUpstreamInput} ${nginxConfigStreamV2rayUpstreamInput} upstream web { server 127.0.0.1:8000; } server { listen 443; listen [::]:443; resolver 8.8.8.8; ssl_preread on; proxy_pass \$filtered_sni_name; } } EOM elif [[ "${configInstallNginxMode}" == "trojanWeb" ]]; then cat > "${nginxConfigSiteConfPath}/trojanweb_site.conf" <<-EOF server { listen 80; server_name $configSSLDomain; root $configWebsitePath; index index.php index.html index.htm; location /$configTrojanWebNginxPath { proxy_pass http://127.0.0.1:$configTrojanWebPort/; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Host \$http_host; } location ~* ^/(static|common|auth|trojan)/ { proxy_pass http://127.0.0.1:$configTrojanWebPort; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host \$http_host; } # http redirect to https if ( \$remote_addr != 127.0.0.1 ){ rewrite ^/(.*)$ https://$configSSLDomain/\$1 redirect; } } EOF else echo fi cat > "${nginxConfigPath}" <<-EOF ${nginxConfigNginxModuleInput} # user ${nginxUser}; user root; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } ${nginxConfigStreamConfigInput} http { 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 $nginxAccessLogFilePath main; error_log $nginxErrorLogFilePath; sendfile on; #tcp_nopush on; keepalive_timeout 120; client_max_body_size 20m; gzip on; include ${nginxConfigSiteConfPath}/*.conf; } EOF # 下载伪装站点 并设置伪装网站 rm -rf ${configWebsitePath}/* mkdir -p ${configWebsiteDownloadPath} downloadAndUnzip "https://github.com/jinwyp/one_click_script/raw/master/download/website2.zip" "${configWebsitePath}" "website2.zip" if [ "${configInstallNginxMode}" != "trojanWeb" ] ; then wget -P "${configWebsiteDownloadPath}" "https://github.com/jinwyp/one_click_script/raw/master/download/trojan-mac.zip" wget -P "${configWebsiteDownloadPath}" "https://github.com/jinwyp/one_click_script/raw/master/download/v2ray-windows.zip" wget -P "${configWebsiteDownloadPath}" "https://github.com/jinwyp/one_click_script/raw/master/download/v2ray-mac.zip" fi # downloadAndUnzip "https://github.com/jinwyp/one_click_script/raw/master/download/trojan_client_all.zip" "${configWebsiteDownloadPath}" "trojan_client_all.zip" # downloadAndUnzip "https://github.com/jinwyp/one_click_script/raw/master/download/trojan-qt5.zip" "${configWebsiteDownloadPath}" "trojan-qt5.zip" # downloadAndUnzip "https://github.com/jinwyp/one_click_script/raw/master/download/v2ray_client_all.zip" "${configWebsiteDownloadPath}" "v2ray_client_all.zip" #wget -P "${configWebsiteDownloadPath}" "https://github.com/jinwyp/one_click_script/raw/master/download/v2ray-android.zip" # ${sudoCmd} chown -R ${wwwUsername}:${wwwUsername} ${configWebsitePath} ${sudoCmd} chmod -R 774 ${configWebsitePath} ${sudoCmd} systemctl start nginx.service green " ================================================== " green " Web服务器 nginx 安装成功!!" green " 伪装站点为 http://${configSSLDomain}" if [[ "${configInstallNginxMode}" == "trojanWeb" ]] ; then yellow " Trojan-web ${versionTrojanWeb} 可视化管理面板地址 http://${configSSLDomain}/${configTrojanWebNginxPath} " green " Trojan-web 可视化管理面板 可执行文件路径 ${configTrojanWebPath}/trojan-web" green " Trojan-web 停止命令: systemctl stop trojan-web.service 启动命令: systemctl start trojan-web.service 重启命令: systemctl restart trojan-web.service" green " Trojan 服务器端可执行文件路径 /usr/bin/trojan/trojan" green " Trojan 服务器端配置路径 /usr/local/etc/trojan/config.json " green " Trojan 停止命令: systemctl stop trojan.service 启动命令: systemctl start trojan.service 重启命令: systemctl restart trojan.service" fi green " 伪装站点的静态html内容放置在目录 ${configWebsitePath}, 可自行更换网站内容!" red " nginx 配置路径 ${nginxConfigPath} " green " nginx 访问日志 ${nginxAccessLogFilePath} " green " nginx 错误日志 ${nginxErrorLogFilePath} " green " nginx 查看日志命令: journalctl -n 50 -u nginx.service" green " nginx 启动命令: systemctl start nginx.service 停止命令: systemctl stop nginx.service 重启命令: systemctl restart nginx.service" green " nginx 查看运行状态命令: systemctl status nginx.service " green " ================================================== " cat >> ${configReadme} <<-EOF Web服务器 nginx 安装成功! 伪装站点为 ${configSSLDomain} 伪装站点的静态html内容放置在目录 ${configWebsitePath}, 可自行更换网站内容. nginx 配置路径 ${nginxConfigPath} nginx 访问日志 ${nginxAccessLogFilePath} nginx 错误日志 ${nginxErrorLogFilePath} nginx 查看日志命令: journalctl -n 50 -u nginx.service nginx 启动命令: systemctl start nginx.service nginx 停止命令: systemctl stop nginx.service nginx 重启命令: systemctl restart nginx.service nginx 查看运行状态命令: systemctl status nginx.service EOF if [[ "${configInstallNginxMode}" == "trojanWeb" ]] ; then cat >> ${configReadme} <<-EOF 安装的Trojan-web ${versionTrojanWeb} 可视化管理面板 访问地址 http://${configSSLDomain}/${configTrojanWebNginxPath} Trojan-web 停止命令: systemctl stop trojan-web.service Trojan-web 启动命令: systemctl start trojan-web.service Trojan-web 重启命令: systemctl restart trojan-web.service Trojan 服务器端配置路径 /usr/local/etc/trojan/config.json Trojan 停止命令: systemctl stop trojan.service Trojan 启动命令: systemctl start trojan.service Trojan 重启命令: systemctl restart trojan.service Trojan 查看运行状态命令: systemctl status trojan.service EOF fi } function removeNginx(){ green " ================================================== " green " Are you sure to remove Nginx ? " echo read -r -p "是否确认卸载Nginx? 直接回车默认卸载, 请输入[Y/n]:" isRemoveNginxServerInput isRemoveNginxServerInput=${isRemoveNginxServerInput:-Y} if [[ "${isRemoveNginxServerInput}" == [Yy] ]]; then echo if [[ -f "${nginxConfigPath}" ]]; then showHeaderRed "准备卸载已安装的nginx" ${sudoCmd} systemctl stop nginx.service ${sudoCmd} systemctl disable nginx.service if [ "$osRelease" == "centos" ]; then yum remove -y nginx-mod-stream yum remove -y nginx else apt autoremove -y apt-get remove --purge -y nginx-common apt-get remove --purge -y nginx-core apt-get remove --purge -y libnginx-mod-stream apt-get remove --purge -y libnginx-mod-http-xslt-filter libnginx-mod-http-geoip2 libnginx-mod-stream-geoip2 libnginx-mod-mail libnginx-mod-http-image-filter apt autoremove -y --purge nginx nginx-common nginx-core apt-get remove --purge -y nginx nginx-full nginx-common nginx-core fi rm -f ${nginxAccessLogFilePath} rm -f ${nginxErrorLogFilePath} rm -f ${nginxConfigPath} rm -rf ${nginxConfigSiteConfPath} rm -f ${configReadme} rm -rf "/etc/nginx" rm -rf ${configDownloadTempPath} echo read -r -p "是否删除证书 和 卸载acme.sh申请证书工具, 由于一天内申请证书有次数限制, 默认建议不删除证书, 请输入[y/N]:" isDomainSSLRemoveInput isDomainSSLRemoveInput=${isDomainSSLRemoveInput:-n} if [[ $isDomainSSLRemoveInput == [Yy] ]]; then shopt -s nullglob renewDomainArray=("${configSSLAcmeScriptPath}"/*ecc*) COUNTER1=1 echo green " ================================================== " green " 请选择要续签或要删除的域名:" echo for renewDomainName in "${renewDomainArray[@]}"; do substr=${renewDomainName##*/} substr=${substr%_ecc*} renewDomainArrayFix[${COUNTER1}]="$substr" echo " ${COUNTER1}. 域名: ${substr}" COUNTER1=$((COUNTER1 +1)) done echo read -r -p "请选择域名? 请输入纯数字:" isRenewDomainSelectNumberInput isRenewDomainSelectNumberInput=${isRenewDomainSelectNumberInput:-99} if [[ "$isRenewDomainSelectNumberInput" == "99" ]]; then red " 输入错误, 请重新输入!" echo read -r -p "请选择域名? 请输入纯数字:" isRenewDomainSelectNumberInput isRenewDomainSelectNumberInput=${isRenewDomainSelectNumberInput:-99} if [[ "$isRenewDomainSelectNumberInput" == "99" ]]; then red " 输入错误, 退出!" exit else echo fi else echo fi configSSLRenewDomain=${renewDomainArrayFix[${isRenewDomainSelectNumberInput}]} if [[ -n $(${configSSLAcmeScriptPath}/acme.sh --list | grep ${configSSLRenewDomain}) ]]; then ${configSSLAcmeScriptPath}/acme.sh --revoke -d ${configSSLRenewDomain} --ecc ${configSSLAcmeScriptPath}/acme.sh --remove -d ${configSSLRenewDomain} --ecc rm -rf "${configSSLAcmeScriptPath}/${configSSLRenewDomain}_ecc" echo green " 域名 ${configSSLRenewDomain} 的证书已经删除成功!" else echo red " 您选择的域名 ${configSSLRenewDomain} 证书不存在!" fi ${sudoCmd} bash ${configSSLAcmeScriptPath}/acme.sh --uninstall rm -rf ${configWebsiteFatherPath} showHeaderGreen "Nginx 卸载完毕, SSL 证书文件已删除!" else rm -rf ${configWebsitePath} showHeaderGreen "Nginx 卸载完毕, 已保留 SSL 证书文件 到 ${configSSLCertPath} " fi else showHeaderRed "系统没有安装 Nginx, 退出卸载" fi echo fi } # Regular expression to match a valid domain name ip_regex="^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$" domain_regex="^[a-zA-Z0-9]+([a-zA-Z0-9\-]*[a-zA-Z0-9]+)?(\.[a-zA-Z]+)+$" domain_regex2="^(?!:\/\/)(?=.{1,255}$)([[:alnum:]][[:alnum:]-]*[[:alnum:]]\.)+[a-z]{2,}$" configNginxSNIDomainWebsite="" configNginxSNIDomainV2ray="" configNginxSNIDomainTrojan="" configNginxSNIDomainTrojanCertPath="${configWebsiteFatherPath}/cert/nginxsni/trojan" configNginxSNIDomainV2rayCertPath="${configWebsiteFatherPath}/cert/nginxsni/v2ray" configNginxSNIDomainWebsiteCertPath="${configWebsiteFatherPath}/cert/nginxsni/web" function checkNginxSNIDomain(){ if compareRealIpWithLocalIp "$2" ; then if [ "$1" = "trojan" ]; then configNginxSNIDomainTrojan=$2 configSSLCertPath="${configNginxSNIDomainTrojanCertPath}" elif [ "$1" = "v2ray" ]; then configNginxSNIDomainV2ray=$2 configSSLCertPath="${configNginxSNIDomainV2rayCertPath}" elif [ "$1" = "website" ]; then configNginxSNIDomainWebsite=$2 configSSLCertPath="${configNginxSNIDomainWebsiteCertPath}" fi configSSLDomain="$2" mkdir -p ${configSSLCertPath} echo green " ==================================================" green " 是否申请证书? 默认直接回车为申请证书, 如第二次安装或已有证书 可以选否" green " 如果已经有SSL证书文件 请放到下面路径" red " ${configSSLDomain} 域名证书内容文件路径 ${configSSLCertPath}/${configSSLCertFullchainFilename} " red " ${configSSLDomain} 域名证书私钥文件路径 ${configSSLCertPath}/${configSSLCertKeyFilename} " echo read -p "是否申请证书? 默认直接回车为自动申请证书,请输入[Y/n]:" isDomainSSLRequestInput isDomainSSLRequestInput=${isDomainSSLRequestInput:-Y} if [[ $isDomainSSLRequestInput == [Yy] ]]; then getHTTPSCertificateWithAcme "" else green " ==================================================" green " 不申请域名的证书, 请把证书放到如下目录, 或自行修改trojan或v2ray配置!" green " ${configSSLDomain} 域名证书内容文件路径 ${configSSLCertPath}/${configSSLCertFullchainFilename} " green " ${configSSLDomain} 域名证书私钥文件路径 ${configSSLCertPath}/${configSSLCertKeyFilename} " green " ==================================================" fi else inputNginxSNIDomain $1 fi } function inputNginxSNIDomain(){ echo green " ================================================== " if [ "$1" = "trojan" ]; then yellow " 请输入解析到本VPS的域名 用于给Trojan使用, 例如 www.xxx.com: (此步骤请关闭CDN后安装)" read -p "请输入解析到本VPS的域名:" configNginxSNIDomainDefault elif [ "$1" = "v2ray" ]; then yellow " 请输入解析到本VPS的域名 用于给V2ray使用, 例如 www.xxx.com: (此步骤请关闭CDN后安装)" read -p "请输入解析到本VPS的域名:" configNginxSNIDomainDefault elif [ "$1" = "website" ]; then yellow " 请输入解析到本VPS的域名 用于给现有网站使用, 例如 www.xxx.com: (此步骤请关闭CDN后安装)" read -p "请输入解析到本VPS的域名:" configNginxSNIDomainDefault fi checkNginxSNIDomain $1 ${configNginxSNIDomainDefault} } function inputXraySystemdServiceName(){ if [[ "$1" == "v2ray_nginxOptional" || "$1" == "nginx_v2ray" || "$1" == "v2ray" ]]; then echo green " ================================================== " yellow " 请输入自定义的 V2ray 或 Xray 的Systemd服务名称后缀, 默认为空" green " 默认直接回车不输入字符 即为 v2ray.service 或 xray.service" green " 输入的字符将作为后缀 例如 v2ray-xxx.service 或 xray-xxx.service" green " 此功能用于在一台VPS上安装多个 v2ray / xray" echo read -p "请输入自定义的Xray服务名称后缀, 默认为空:" configXraySystemdServiceNameSuffix configXraySystemdServiceNameSuffix=${configXraySystemdServiceNameSuffix:-""} if [ -n "${configXraySystemdServiceNameSuffix}" ]; then promptInfoXrayNameServiceName="-${configXraySystemdServiceNameSuffix}" configSSLCertPath="${configSSLCertPath}/xray_${configXraySystemdServiceNameSuffix}" fi echo fi } function installTrojanV2rayWithNginx(){ stopServiceNginx testLinuxPortUsage # installPackage echo if [ "$1" = "v2ray" ]; then read -r -p "是否不申请域名的证书 直接使用本VPS的IP安装? 默认直接回车为不申请证书,请输入[Y/n]:" isDomainIPRequestInput isDomainIPRequestInput=${isDomainIPRequestInput:-Y} if [[ $isDomainIPRequestInput == [Yy] ]]; then echo read -r -p "请输入本VPS的IP 或 解析到本VPS的域名:" configSSLDomain installV2ray exit fi elif [ "$1" = "nginxSNI_trojan_v2ray" ]; then green " ================================================== " yellow " 请选择 Nginx SNI + Trojan + V2ray 的安装模式, 默认为1" red " 必须使用不同的2个或3个域名,并设置好DNS解析,否则无法申请SSL证书" echo green " 1. Nginx + Trojan + V2ray + 伪装网站" green " 2. Nginx + Trojan + 伪装网站" green " 3. Nginx + V2ray + 伪装网站" green " 4. Nginx + Trojan + V2ray + 已有网站共存" green " 5. Nginx + Trojan + 已有网站共存" green " 6. Nginx + V2ray + 已有网站共存" echo read -p "请选择 Nginx SNI 的安装模式 直接回车默认选1, 请输入纯数字:" isNginxSNIModeInput isNginxSNIModeInput=${isNginxSNIModeInput:-1} if [[ "${isNginxSNIModeInput}" == "1" ]]; then inputNginxSNIDomain "trojan" inputNginxSNIDomain "v2ray" installWebServerNginx installTrojanServer installV2ray elif [[ "${isNginxSNIModeInput}" == "2" ]]; then inputNginxSNIDomain "trojan" installWebServerNginx installTrojanServer elif [[ "${isNginxSNIModeInput}" == "3" ]]; then inputNginxSNIDomain "v2ray" installWebServerNginx installV2ray elif [[ "${isNginxSNIModeInput}" == "4" ]]; then inputNginxSNIDomain "trojan" inputNginxSNIDomain "v2ray" inputNginxSNIDomain "website" installWebServerNginx installTrojanServer installV2ray elif [[ "${isNginxSNIModeInput}" == "5" ]]; then inputNginxSNIDomain "trojan" inputNginxSNIDomain "website" installWebServerNginx installTrojanServer elif [[ "${isNginxSNIModeInput}" == "6" ]]; then inputNginxSNIDomain "v2ray" inputNginxSNIDomain "website" installWebServerNginx installV2ray fi exit fi inputXraySystemdServiceName "$1" if [[ "$1" == "v2ray_nginxOptional" && "$configV2rayWorkingMode" == "vlessTCPREALITY" ]]; then configNetworkLocalIp3="$(curl ipinfo.io/ip)" echo green "当前 VPS IP 地址为: ${configNetworkLocalIp3}" green "如果上面的IP不正确, 请输入正确的IP或域名. 直接回车默认为 ${configNetworkLocalIp3}" green "如果输入的是域名 将安装 Nginx 作为伪装网站" echo read -r -p "请输入本VPS的IP 或 解析到本VPS的域名:" configSSLDomain if [ -z "${configSSLDomain}" ]; then configSSLDomain="${configNetworkLocalIp3}" fi if [[ $configSSLDomain =~ $ip_regex ]]; then green "Valid ip address. 输入的 IP 格式正确 " else red "Invalid ip address. 输入的 IP 格式不正确 " if [[ $configSSLDomain =~ $domain_regex ]]; then green "Valid domain name. 输入的域名格式正确 " echo green " 是否安装 Nginx 用于提供伪装网站, 如果已有网站或搭配宝塔面板请选择N不安装" read -r -p "是否确安装Nginx伪装网站? 直接回车默认安装, 请输入[Y/n]:" isInstallNginxServerInput isInstallNginxServerInput=${isInstallNginxServerInput:-Y} if [[ "${isInstallNginxServerInput}" == [Yy] ]]; then installWebServerNginx fi else red "Invalid domain name. 输入的域名格式不正确 " green "使用 ${configNetworkLocalIp3} 作为本VPS的IP地址 " configSSLDomain="${configNetworkLocalIp3}" fi fi echo installV2ray exit else renewCertificationWithAcme "" fi echo if test -s ${configSSLCertPath}/${configSSLCertFullchainFilename}; then green " ================================================== " green " 已检测到域名 ${configSSLDomain} 的证书文件 获取成功!" green " ${configSSLDomain} 域名证书内容文件路径 ${configSSLCertPath}/${configSSLCertFullchainFilename} " green " ${configSSLDomain} 域名证书私钥文件路径 ${configSSLCertPath}/${configSSLCertKeyFilename} " green " ================================================== " echo if [ "$1" == "trojan_nginx" ]; then installWebServerNginx installTrojanServer elif [ "$1" = "trojan" ]; then installTrojanServer elif [ "$1" = "nginx_v2ray" ]; then installWebServerNginx installV2ray elif [ "$1" = "v2ray_nginxOptional" ]; then echo green " 是否安装 Nginx 用于提供伪装网站, 如果已有网站或搭配宝塔面板请选择N不安装" read -r -p "是否确安装Nginx伪装网站? 直接回车默认安装, 请输入[Y/n]:" isInstallNginxServerInput isInstallNginxServerInput=${isInstallNginxServerInput:-Y} if [[ "${isInstallNginxServerInput}" == [Yy] ]]; then installWebServerNginx fi if [[ "${configV2rayWorkingMode}" == "trojan" ]]; then installTrojanServer fi installV2ray elif [ "$1" = "v2ray" ]; then installV2ray elif [ "$1" = "trojan_nginx_v2ray" ]; then installWebServerNginx installTrojanServer installV2ray else echo fi else red " ================================================== " red " https证书没有申请成功,安装失败!" red " 请检查域名和DNS是否生效, 同一域名请不要一天内多次申请!" red " 请检查80和443端口是否开启, VPS服务商可能需要添加额外防火墙规则,例如阿里云、谷歌云等!" red " 重启VPS, 重新执行脚本, 可重新选择该项再次申请证书 ! " red " ================================================== " exit fi } function getTrojanGoVersion(){ if [[ "${isTrojanTypeInput}" == "1" ]]; then versionTrojan=$(getGithubLatestReleaseVersion "trojan-gfw/trojan") downloadFilenameTrojan="trojan-${versionTrojan}-linux-amd64.tar.xz" echo "versionTrojan: ${versionTrojan}" configTrojanBaseVersion=${versionTrojan} configTrojanBasePath="${configTrojanPath}" promptInfoTrojanName="" elif [[ "${isTrojanTypeInput}" == "2" ]]; then versionTrojanGo=$(getGithubLatestReleaseVersion "p4gefau1t/trojan-go") echo "versionTrojanGo: ${versionTrojanGo}" configTrojanBaseVersion=${versionTrojanGo} configTrojanBasePath="${configTrojanGoPath}" promptInfoTrojanName="-go" elif [[ "${isTrojanTypeInput}" == "3" ]]; then versionTrojanGo=$(getGithubLatestReleaseVersion "fregie/trojan-go") echo "versionTrojanGo: ${versionTrojanGo}" configTrojanBaseVersion=${versionTrojanGo} configTrojanBasePath="${configTrojanGoPath}" promptInfoTrojanName="-go" else # https://github.com/Potterli20/trojan-go-fork/releases/download/V2023.03.08/trojan-go-fork-linux-amd64.zip versionTrojanGo=$(getGithubLatestReleaseVersion "Potterli20/trojan-go-fork") # versionTrojanGo="V2023.03.08" echo "versionTrojanGo: ${versionTrojanGo}" configTrojanBaseVersion=${versionTrojanGo} configTrojanBasePath="${configTrojanGoPath}" promptInfoTrojanName="-go" fi } function downloadTrojanBin(){ if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameTrojanGo="trojan-go-linux-arm.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameTrojanGo="trojan-go-linux-armv8.zip" fi if [[ "${isTrojanTypeInput}" == "1" ]]; then # https://github.com/trojan-gfw/trojan/releases/download/v1.16.0/trojan-1.16.0-linux-amd64.tar.xz if [[ ${osArchitecture} == "arm" || ${osArchitecture} == "arm64" ]] ; then red "Trojan not support arm on linux! " exit fi downloadAndUnzip "https://github.com/trojan-gfw/trojan/releases/download/v${versionTrojan}/${downloadFilenameTrojan}" "${configTrojanBasePath}" "${downloadFilenameTrojan}" mv -f ${configTrojanBasePath}/trojan ${configTrojanBasePath}/trojan-temp mv -f ${configTrojanBasePath}/trojan-temp/* ${configTrojanBasePath}/ elif [[ "${isTrojanTypeInput}" == "2" ]]; then # https://github.com/p4gefau1t/trojan-go/releases/download/v0.10.6/trojan-go-linux-amd64.zip downloadAndUnzip "https://github.com/p4gefau1t/trojan-go/releases/download/v${versionTrojanGo}/${downloadFilenameTrojanGo}" "${configTrojanBasePath}" "${downloadFilenameTrojanGo}" elif [[ "${isTrojanTypeInput}" == "3" ]]; then # https://github.com/fregie/trojan-go/releases/download/v1.0.5/trojan-go-linux-amd64.zip downloadAndUnzip "https://github.com/fregie/trojan-go/releases/download/v${versionTrojanGo}/${downloadFilenameTrojanGo}" "${configTrojanBasePath}" "${downloadFilenameTrojanGo}" else downloadFilenameTrojanGo="trojan-go-fork-linux-amd64.zip" if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameTrojanGo="trojan-go-fork-linux-arm.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameTrojanGo="trojan-go-fork-linux-armv8.zip" fi # https://github.com/Potterli20/trojan-go-fork/releases/download/V2023.02.15/trojan-go-fork-linux-arm.zip # https://github.com/Potterli20/trojan-go-fork/releases/download/V2023.02.15/trojan-go-fork-linux-armv8.zip # https://github.com/Potterli20/trojan-go-fork/releases/download/V2023.03.08/trojan-go-fork-linux-amd64.zip downloadAndUnzip "https://github.com/Potterli20/trojan-go-fork/releases/download/V${versionTrojanGo}/${downloadFilenameTrojanGo}" "${configTrojanBasePath}" "${downloadFilenameTrojanGo}" mv -f ${configTrojanBasePath}/trojan-go-fork ${configTrojanBasePath}/trojan-go fi } function generateTrojanPassword(){ trojanPassword1=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword2=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword3=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword4=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword5=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword6=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword7=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword8=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword9=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword10=$(cat /dev/urandom | head -1 | md5sum | head -c 10) } function installTrojanServer(){ if [[ -f "${configTrojanPath}/trojan" ]]; then green " ==================================================" red " 已安装过 Trojan, 退出安装 !" red " Trojan already installed !" green " ==================================================" exit fi if [[ -f "${configTrojanGoPath}/trojan-go" ]]; then green " ==================================================" red " 已安装过 Trojan-go, 退出安装 !" red " Trojan-go already installed !" green " ==================================================" exit fi generateTrojanPassword echo green " ==================================================" green " 请选择安装 Trojan 或 Trojan-go ? 默认选择2 原版 Trojan-go " echo green " 1 原版 Trojan 不支持 websocket (not support websocket)" green " 2 原版 Trojan-go 支持 websocket (support websocket)" green " 3 修改版 Trojan-go 支持 websocket by fregie (support websocket)" green " 4 修改版 Trojan-go 支持模拟浏览器指纹 支持 websocket by Potterli20 (support websocket)" echo read -r -p "请选择哪种 Trojan ? 直接回车默认选2, 请输入纯数字:" isTrojanTypeInput isTrojanTypeInput=${isTrojanTypeInput:-2} if [[ "${isTrojanTypeInput}" == "1" ]]; then trojanInstallType="1" elif [[ "${isTrojanTypeInput}" == "2" ]]; then trojanInstallType="2" elif [[ "${isTrojanTypeInput}" == "3" ]]; then trojanInstallType="3" else trojanInstallType="4" fi if [[ "${trojanInstallType}" != "1" ]]; then echo green " ==================================================" green " Enable Websocket or not, default is Y" green " 是否开启 Websocket 用于CDN中转, 注意原版trojan客户端不支持 Websocket" echo read -r -p "请选择是否开启 Websocket? 直接回车默认开启, 请输入[Y/n]:" isTrojanGoWebsocketInput isTrojanGoWebsocketInput=${isTrojanGoWebsocketInput:-Y} if [[ "${isTrojanGoWebsocketInput}" == [Yy] ]]; then isTrojanGoSupportWebsocket="true" else isTrojanGoSupportWebsocket="false" fi fi echo getTrojanGoVersion echo showHeaderGreen " 开始安装 Trojan${promptInfoTrojanName} Version: ${configTrojanBaseVersion} !" echo green " ==================================================" green " Input trojan${promptInfoTrojanName} password prefix, default is ramdom char: " green " 请输入 trojan${promptInfoTrojanName} 密码的前缀? (会生成若干随机密码和带有该前缀的密码)" echo read -r -p "请输入密码的前缀, 直接回车默认随机生成前缀:" configTrojanPasswordPrefixInput configTrojanPasswordPrefixInput=${configTrojanPasswordPrefixInput:-${configTrojanPasswordPrefixInputDefault}} echo echo if [[ "$configV2rayWorkingMode" != "trojan" && "$configV2rayWorkingMode" != "sni" ]] ; then configV2rayTrojanPort=443 inputV2rayServerPort "textMainTrojanPort" configV2rayTrojanPort=${isTrojanUserPortInput} fi configV2rayTrojanReadmePort=${configV2rayTrojanPort} if [[ "$configV2rayWorkingMode" == "sni" ]] ; then configSSLCertPath="${configNginxSNIDomainTrojanCertPath}" configSSLDomain=${configNginxSNIDomainTrojan} configV2rayTrojanReadmePort=443 fi rm -rf "${configTrojanBasePath}" mkdir -p "${configTrojanBasePath}" cd "${configTrojanBasePath}" || exit echo downloadTrojanBin if [ "${isTrojanMultiPassword}" = "no" ] ; then read -r -d '' trojanConfigUserpasswordInput << EOM "${trojanPassword1}", "${trojanPassword2}", "${trojanPassword3}", "${trojanPassword4}", "${trojanPassword5}", "${trojanPassword6}", "${trojanPassword7}", "${trojanPassword8}", "${trojanPassword9}", "${trojanPassword10}", "${configTrojanPasswordPrefixInput}202201", "${configTrojanPasswordPrefixInput}202202", "${configTrojanPasswordPrefixInput}202203", "${configTrojanPasswordPrefixInput}202204", "${configTrojanPasswordPrefixInput}202205", "${configTrojanPasswordPrefixInput}202206", "${configTrojanPasswordPrefixInput}202207", "${configTrojanPasswordPrefixInput}202208", "${configTrojanPasswordPrefixInput}202209", "${configTrojanPasswordPrefixInput}202210" EOM else read -r -d '' trojanConfigUserpasswordInput << EOM "${trojanPassword1}", "${trojanPassword2}", "${trojanPassword3}", "${trojanPassword4}", "${trojanPassword5}", "${trojanPassword6}", "${trojanPassword7}", "${trojanPassword8}", "${trojanPassword9}", "${trojanPassword10}", "${configTrojanPasswordPrefixInput}202200", "${configTrojanPasswordPrefixInput}202201", "${configTrojanPasswordPrefixInput}202202", "${configTrojanPasswordPrefixInput}202203", "${configTrojanPasswordPrefixInput}202204", "${configTrojanPasswordPrefixInput}202205", "${configTrojanPasswordPrefixInput}202206", "${configTrojanPasswordPrefixInput}202207", "${configTrojanPasswordPrefixInput}202208", "${configTrojanPasswordPrefixInput}202209", "${configTrojanPasswordPrefixInput}202210", "${configTrojanPasswordPrefixInput}202211", "${configTrojanPasswordPrefixInput}202212", "${configTrojanPasswordPrefixInput}202213", "${configTrojanPasswordPrefixInput}202214", "${configTrojanPasswordPrefixInput}202215", "${configTrojanPasswordPrefixInput}202216", "${configTrojanPasswordPrefixInput}202217", "${configTrojanPasswordPrefixInput}202218", "${configTrojanPasswordPrefixInput}202219", "${configTrojanPasswordPrefixInput}202220", "${configTrojanPasswordPrefixInput}202221", "${configTrojanPasswordPrefixInput}202222", "${configTrojanPasswordPrefixInput}202223", "${configTrojanPasswordPrefixInput}202224", "${configTrojanPasswordPrefixInput}202225", "${configTrojanPasswordPrefixInput}202226", "${configTrojanPasswordPrefixInput}202227", "${configTrojanPasswordPrefixInput}202228", "${configTrojanPasswordPrefixInput}202229", "${configTrojanPasswordPrefixInput}202230", "${configTrojanPasswordPrefixInput}202231", "${configTrojanPasswordPrefixInput}202232", "${configTrojanPasswordPrefixInput}202233", "${configTrojanPasswordPrefixInput}202234", "${configTrojanPasswordPrefixInput}202235", "${configTrojanPasswordPrefixInput}202236", "${configTrojanPasswordPrefixInput}202237", "${configTrojanPasswordPrefixInput}202238", "${configTrojanPasswordPrefixInput}202239", "${configTrojanPasswordPrefixInput}202240", "${configTrojanPasswordPrefixInput}202241", "${configTrojanPasswordPrefixInput}202242", "${configTrojanPasswordPrefixInput}202243", "${configTrojanPasswordPrefixInput}202244", "${configTrojanPasswordPrefixInput}202245", "${configTrojanPasswordPrefixInput}202246", "${configTrojanPasswordPrefixInput}202247", "${configTrojanPasswordPrefixInput}202248", "${configTrojanPasswordPrefixInput}202249", "${configTrojanPasswordPrefixInput}202250", "${configTrojanPasswordPrefixInput}202251", "${configTrojanPasswordPrefixInput}202252", "${configTrojanPasswordPrefixInput}202253", "${configTrojanPasswordPrefixInput}202254", "${configTrojanPasswordPrefixInput}202255", "${configTrojanPasswordPrefixInput}202256", "${configTrojanPasswordPrefixInput}202257", "${configTrojanPasswordPrefixInput}202258", "${configTrojanPasswordPrefixInput}202259", "${configTrojanPasswordPrefixInput}202260", "${configTrojanPasswordPrefixInput}202261", "${configTrojanPasswordPrefixInput}202262", "${configTrojanPasswordPrefixInput}202263", "${configTrojanPasswordPrefixInput}202264", "${configTrojanPasswordPrefixInput}202265", "${configTrojanPasswordPrefixInput}202266", "${configTrojanPasswordPrefixInput}202267", "${configTrojanPasswordPrefixInput}202268", "${configTrojanPasswordPrefixInput}202269", "${configTrojanPasswordPrefixInput}202270", "${configTrojanPasswordPrefixInput}202271", "${configTrojanPasswordPrefixInput}202272", "${configTrojanPasswordPrefixInput}202273", "${configTrojanPasswordPrefixInput}202274", "${configTrojanPasswordPrefixInput}202275", "${configTrojanPasswordPrefixInput}202276", "${configTrojanPasswordPrefixInput}202277", "${configTrojanPasswordPrefixInput}202278", "${configTrojanPasswordPrefixInput}202279", "${configTrojanPasswordPrefixInput}202280", "${configTrojanPasswordPrefixInput}202281", "${configTrojanPasswordPrefixInput}202282", "${configTrojanPasswordPrefixInput}202283", "${configTrojanPasswordPrefixInput}202284", "${configTrojanPasswordPrefixInput}202285", "${configTrojanPasswordPrefixInput}202286", "${configTrojanPasswordPrefixInput}202287", "${configTrojanPasswordPrefixInput}202288", "${configTrojanPasswordPrefixInput}202289", "${configTrojanPasswordPrefixInput}202290", "${configTrojanPasswordPrefixInput}202291", "${configTrojanPasswordPrefixInput}202292", "${configTrojanPasswordPrefixInput}202293", "${configTrojanPasswordPrefixInput}202294", "${configTrojanPasswordPrefixInput}202295", "${configTrojanPasswordPrefixInput}202296", "${configTrojanPasswordPrefixInput}202297", "${configTrojanPasswordPrefixInput}202298", "${configTrojanPasswordPrefixInput}202299" EOM fi if [[ "${isTrojanTypeInput}" == "1" ]]; then # 增加trojan 服务器端配置 cat > ${configTrojanBasePath}/server.json <<-EOF { "run_type": "server", "local_addr": "0.0.0.0", "local_port": ${configV2rayTrojanPort}, "remote_addr": "127.0.0.1", "remote_port": 80, "password": [ ${trojanConfigUserpasswordInput} ], "log_level": 1, "ssl": { "cert": "${configSSLCertPath}/$configSSLCertFullchainFilename", "key": "${configSSLCertPath}/$configSSLCertKeyFilename", "key_password": "", "cipher_tls13":"TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384", "prefer_server_cipher": true, "alpn": [ "http/1.1" ], "reuse_session": true, "session_ticket": false, "session_timeout": 600, "plain_http_response": "", "curves": "", "dhparam": "" }, "tcp": { "no_delay": true, "keep_alive": true, "fast_open": false, "fast_open_qlen": 20 }, "mysql": { "enabled": false, "server_addr": "127.0.0.1", "server_port": 3306, "database": "trojan", "username": "trojan", "password": "" } } EOF # rm /etc/systemd/system/trojan.service # 增加启动脚本 cat > ${osSystemMdPath}trojan.service <<-EOF [Unit] Description=trojan After=network.target [Service] Type=simple PIDFile=${configTrojanBasePath}/trojan.pid ExecStart=${configTrojanBasePath}/trojan -l ${configTrojanLogFile} -c "${configTrojanBasePath}/server.json" ExecReload=/bin/kill -HUP \$MAINPID Restart=on-failure RestartSec=10 RestartPreventExitStatus=23 PrivateTmp=true [Install] WantedBy=multi-user.target EOF else # 增加trojan-go 服务器端配置 cat > ${configTrojanBasePath}/server.json <<-EOF { "run_type": "server", "local_addr": "0.0.0.0", "local_port": ${configV2rayTrojanPort}, "remote_addr": "127.0.0.1", "remote_port": 80, "password": [ ${trojanConfigUserpasswordInput} ], "log_level": 1, "log_file": "${configTrojanLogFile}", "ssl": { "verify": true, "verify_hostname": true, "cert": "${configSSLCertPath}/$configSSLCertFullchainFilename", "key": "${configSSLCertPath}/$configSSLCertKeyFilename", "sni": "${configSSLDomain}", "fallback_addr": "127.0.0.1", "fallback_port": 80, "fingerprint": "chrome" }, "websocket": { "enabled": ${isTrojanGoSupportWebsocket}, "path": "/${configTrojanGoWebSocketPath}", "host": "${configSSLDomain}" } } EOF # 增加启动脚本 cat > ${osSystemMdPath}trojan-go.service <<-EOF [Unit] Description=trojan-go After=network.target [Service] Type=simple PIDFile=${configTrojanBasePath}/trojan-go.pid ExecStart=${configTrojanBasePath}/trojan-go -config "${configTrojanBasePath}/server.json" ExecReload=/bin/kill -HUP \$MAINPID Restart=on-failure RestartSec=10 RestartPreventExitStatus=23 [Install] WantedBy=multi-user.target EOF fi ${sudoCmd} chown -R root:root ${configTrojanBasePath} ${sudoCmd} chmod -R 774 ${configTrojanBasePath} ${sudoCmd} chmod +x ${osSystemMdPath}trojan${promptInfoTrojanName}.service ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl start trojan${promptInfoTrojanName}.service ${sudoCmd} systemctl enable trojan${promptInfoTrojanName}.service # 设置 cron 定时任务 # https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job # (crontab -l 2>/dev/null | grep -v '^[a-zA-Z]'; echo "15 4 * * 0,1,2,3,4,5,6 systemctl restart trojan.service") | sort - | uniq - | crontab - (crontab -l ; echo "10 4 * * 0,1,2,3,4,5,6 systemctl restart trojan${promptInfoTrojanName}.service") | sort - | uniq - | crontab - green "======================================================================" green " Trojan${promptInfoTrojanName} Version: ${configTrojanBaseVersion} 安装成功 !" if [[ ${configInstallNginxMode} == "noSSL" ]]; then green " 伪装站点为 https://${configSSLDomain}" green " 伪装站点的静态html内容放置在目录 ${configWebsitePath}, 可自行更换网站内容!" fi red " Trojan${promptInfoTrojanName} 服务器端配置路径 ${configTrojanBasePath}/server.json " red " Trojan${promptInfoTrojanName} 运行日志文件路径: ${configTrojanLogFile} " green " Trojan${promptInfoTrojanName} 查看日志命令: journalctl -n 50 -u trojan${promptInfoTrojanName}.service " green " Trojan${promptInfoTrojanName} 停止命令: systemctl stop trojan${promptInfoTrojanName}.service 启动命令: systemctl start trojan${promptInfoTrojanName}.service 重启命令: systemctl restart trojan${promptInfoTrojanName}.service" green " Trojan${promptInfoTrojanName} 查看运行状态命令: systemctl status trojan${promptInfoTrojanName}.service " green " Trojan${promptInfoTrojanName} 服务器 每天会自动重启, 防止内存泄漏. 运行 crontab -l 命令 查看定时重启命令 !" green "======================================================================" echo yellow "Trojan${promptInfoTrojanName} 配置信息如下, 请自行复制保存, 密码任选其一 !" yellow "服务器地址: ${configSSLDomain} 端口: ${configV2rayTrojanReadmePort}" yellow "密码1: ${trojanPassword1}" yellow "密码2: ${trojanPassword2}" yellow "密码3: ${trojanPassword3}" yellow "密码4: ${trojanPassword4}" yellow "密码5: ${trojanPassword5}" yellow "密码6: ${trojanPassword6}" yellow "密码7: ${trojanPassword7}" yellow "密码8: ${trojanPassword8}" yellow "密码9: ${trojanPassword9}" yellow "密码10: ${trojanPassword10}" tempTextInfoTrojanPassword="您指定前缀的密码共100个: 从 ${configTrojanPasswordPrefixInput}202200 到 ${configTrojanPasswordPrefixInput}202299 都可以使用" if [ "${isTrojanMultiPassword}" = "no" ] ; then tempTextInfoTrojanPassword="您指定前缀的密码共10个: 从 ${configTrojanPasswordPrefixInput}202201 到 ${configTrojanPasswordPrefixInput}202220 都可以使用" fi yellow "${tempTextInfoTrojanPassword}" yellow "例如: 密码:${configTrojanPasswordPrefixInput}202202 或 密码:${configTrojanPasswordPrefixInput}202209 都可以使用" if [[ ${isTrojanGoSupportWebsocket} == "true" ]]; then yellow "Websocket path 路径为: /${configTrojanGoWebSocketPath}" # yellow "Websocket obfuscation_password 混淆密码为: ${trojanPasswordWS}" yellow "Websocket 双重TLS为: true 开启" fi echo green "======================================================================" yellow " Trojan${promptInfoTrojanName} 小火箭 Shadowrocket 链接地址" if [ "$isTrojanTypeInput" != "1" ] ; then if [[ ${isTrojanGoSupportWebsocket} == "true" ]]; then green " trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?peer=${configSSLDomain}&sni=${configSSLDomain}&plugin=obfs-local;obfs=websocket;obfs-host=${configSSLDomain};obfs-uri=/${configTrojanGoWebSocketPath}#${configSSLDomain}_trojan_go_ws" echo yellow " 二维码 Trojan${promptInfoTrojanName} " green "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayTrojanReadmePort}%3fallowInsecure%3d0%26peer%3d${configSSLDomain}%26plugin%3dobfs-local%3bobfs%3dwebsocket%3bobfs-host%3d${configSSLDomain}%3bobfs-uri%3d/${configTrojanGoWebSocketPath}%23${configSSLDomain}_trojan_go_ws" echo yellow " Trojan${promptInfoTrojanName} QV2ray 链接地址" green " trojan-go://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?sni=${configSSLDomain}&type=ws&host=${configSSLDomain}&path=%2F${configTrojanGoWebSocketPath}#${configSSLDomain}_trojan_go_ws" else green " trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?peer=${configSSLDomain}&sni=${configSSLDomain}#${configSSLDomain}_trojan_go" echo yellow " 二维码 Trojan${promptInfoTrojanName} " green "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayTrojanReadmePort}%3fpeer%3d${configSSLDomain}%26sni%3d${configSSLDomain}%23${configSSLDomain}_trojan_go" echo yellow " Trojan${promptInfoTrojanName} QV2ray 链接地址" green " trojan-go://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?sni=${configSSLDomain}&type=original&host=${configSSLDomain}#${configSSLDomain}_trojan_go" fi else green " trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?peer=${configSSLDomain}&sni=${configSSLDomain}#${configSSLDomain}_trojan" echo yellow " 二维码 Trojan${promptInfoTrojanName} " green "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayTrojanReadmePort}%3fpeer%3d${configSSLDomain}%26sni%3d${configSSLDomain}%23${configSSLDomain}_trojan" fi echo green "======================================================================" green "请下载相应的trojan客户端:" yellow "1 Windows 客户端下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/v2ray-windows.zip" #yellow " Windows 客户端另一个版本下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/trojan-Qt5-windows.zip" #yellow " Windows 客户端命令行版本下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/trojan-win-cli.zip" #yellow " Windows 客户端命令行版本需要搭配浏览器插件使用,例如switchyomega等! " yellow "2 MacOS 客户端下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/v2ray-mac.zip" yellow " MacOS 另一个客户端下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/trojan-mac.zip" #yellow " MacOS 客户端Trojan-Qt5下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/trojan-Qt5-mac.zip" yellow "3 Android 客户端下载 https://github.com/trojan-gfw/igniter/releases " yellow " Android 另一个客户端下载 https://github.com/2dust/v2rayNG/releases " yellow " Android 客户端Clash下载 https://github.com/Kr328/ClashForAndroid/releases " yellow "4 iOS 客户端 请安装小火箭 https://shadowsockshelp.github.io/ios/ " yellow " iOS 请安装小火箭另一个地址 https://lueyingpro.github.io/shadowrocket/index.html " yellow " iOS 安装小火箭遇到问题 教程 https://github.com/shadowrocketHelp/help/ " green "======================================================================" green "教程与其他资源:" green "访问 https://www.v2rayssr.com/vpn-client.html 下载 客户端 及教程" green "访问 https://westworldss.com/portal/page/download 下载 客户端 及教程" green "======================================================================" green "其他 Windows 客户端:" green "https://dl.trojan-cdn.com/trojan (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/Qv2ray/Qv2ray/releases (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/Dr-Incognito/V2Ray-Desktop/releases (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/Fndroid/clash_for_windows_pkg/releases" green "======================================================================" green "其他 Mac 客户端:" green "https://dl.trojan-cdn.com/trojan (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/Qv2ray/Qv2ray/releases (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/Dr-Incognito/V2Ray-Desktop/releases (exe为Win客户端, dmg为Mac客户端)" green "https://github.com/yichengchen/clashX/releases " green "======================================================================" cat >> ${configReadme} <<-EOF Trojan${promptInfoTrojanName} Version: ${configTrojanBaseVersion} 安装成功 ! Trojan${promptInfoTrojanName} 服务器端配置路径 ${configTrojanBasePath}/server.json Trojan${promptInfoTrojanName} 运行日志文件路径: ${configTrojanLogFile} Trojan${promptInfoTrojanName} 查看日志命令: journalctl -n 50 -u trojan${promptInfoTrojanName}.service Trojan${promptInfoTrojanName} 启动命令: systemctl start trojan${promptInfoTrojanName}.service Trojan${promptInfoTrojanName} 停止命令: systemctl stop trojan${promptInfoTrojanName}.service Trojan${promptInfoTrojanName} 重启命令: systemctl restart trojan${promptInfoTrojanName}.service Trojan${promptInfoTrojanName} 查看运行状态命令: systemctl status trojan${promptInfoTrojanName}.service Trojan${promptInfoTrojanName}服务器地址: ${configSSLDomain} 端口: ${configV2rayTrojanReadmePort} 密码1: ${trojanPassword1} 密码2: ${trojanPassword2} 密码3: ${trojanPassword3} 密码4: ${trojanPassword4} 密码5: ${trojanPassword5} 密码6: ${trojanPassword6} 密码7: ${trojanPassword7} 密码8: ${trojanPassword8} 密码9: ${trojanPassword9} 密码10: ${trojanPassword10} ${tempTextInfoTrojanPassword} 例如: 密码:${configTrojanPasswordPrefixInput}202202 或 密码:${configTrojanPasswordPrefixInput}202209 都可以使用 如果是trojan-go开启了Websocket,那么Websocket path 路径为: /${configTrojanGoWebSocketPath} 小火箭链接: trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanReadmePort}?peer=${configSSLDomain}&sni=${configSSLDomain}#${configSSLDomain}_trojan" 二维码 Trojan${promptInfoTrojanName} https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayTrojanReadmePort}%3fpeer%3d${configSSLDomain}%26sni%3d${configSSLDomain}%23${configSSLDomain}_trojan EOF } function removeTrojan(){ if [[ -f "${configTrojanGoPath}/trojan-go" ]]; then promptInfoTrojanName="-go" configTrojanBasePath="${configTrojanGoPath}" elif [[ -f "${configTrojanPath}/trojan" ]]; then promptInfoTrojanName="" configTrojanBasePath="${configTrojanPath}" else red " 系统没有安装 Trojan / Trojan-go, 退出卸载" red " Trojan or Trojan-go not install, exit" fi echo green " ================================================== " green " Are you sure to uninstall Trojan${promptInfoTrojanName} ? " echo read -r -p "是否确认卸载 Trojan${promptInfoTrojanName}? 直接回车默认卸载, 请输入[Y/n]:" isRemoveTrojanServerInput isRemoveTrojanServerInput=${isRemoveTrojanServerInput:-Y} if [[ "${isRemoveTrojanServerInput}" == [Yy] ]]; then echo green " ================================================== " red " 准备卸载已安装的 Trojan${promptInfoTrojanName}" green " ================================================== " echo ${sudoCmd} systemctl stop trojan${promptInfoTrojanName}.service ${sudoCmd} systemctl disable trojan${promptInfoTrojanName}.service rm -rf ${configTrojanBasePath} rm -f ${osSystemMdPath}trojan${promptInfoTrojanName}.service rm -f ${configTrojanLogFile} rm -f ${configReadme} crontab -l | grep -v "trojan${promptInfoTrojanName}" | crontab - echo green " ================================================== " green " Trojan${promptInfoTrojanName} 卸载完毕 ! Trojan${promptInfoTrojanName} uninstall success !" green " crontab 定时任务 删除完毕 ! crontab remove success !" green " ================================================== " fi } get_ip(){ local IP IP=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v '^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\.' | head -n 1 ) [ -z "${IP}" ] && IP=$( wget -qO- -t1 -T2 ipv4.icanhazip.com ) [ -z "${IP}" ] && IP=$( wget -qO- -t1 -T2 ipinfo.io/ip ) echo "${IP}" } get_ipv6(){ local ipv6 ipv6=$(wget -qO- -t1 -T2 ipv6.icanhazip.com) [ -z "${ipv6}" ] && return 1 || return 0 } genShadowsocksPassword(){ if [ -z "$1" ]; then shadowsocksPassword1=$(openssl rand -base64 32 | head -c 12) shadowsocksPassword2=$(openssl rand -base64 32 | head -c 12) shadowsocksPassword3=$(openssl rand -base64 32 | head -c 12) shadowsocksPassword4=$(openssl rand -base64 32 | head -c 12) shadowsocksPassword5=$(openssl rand -base64 32 | head -c 12) else PSlength=$1 shadowsocksPassword0=$(openssl rand -base64 "${PSlength}") shadowsocksPassword1=$(openssl rand -base64 "${PSlength}") shadowsocksPassword2=$(openssl rand -base64 "${PSlength}") shadowsocksPassword3=$(openssl rand -base64 "${PSlength}") shadowsocksPassword4=$(openssl rand -base64 "${PSlength}") shadowsocksPassword5=$(openssl rand -base64 "${PSlength}") fi } selectShadowsocksMethod(){ # 建议使用 AEAD (method 为 aes-256-gcm、aes-128-gcm、chacha20-poly1305 即可开启 AEAD) # 也可以使用传统的 method (method 为 aes-256-cfb、aes-128-cfb、chacha20、salsa20 等) echo green " ==================================================" yellow " 请选择 Shadowsocks 加密方式 (默认7 2022-blake3-aes-256-gcm):" yellow " Pls select Shadowsocks encryption method (default is 7 2022-blake3-aes-256-gcm):" echo green " 1. aes-256-gcm" green " 2. aes-128-gcm" green " 3. chacha20-poly1305" green " 4. chacha20-ietf-poly1305" green " 5. xchacha20-ietf-poly1305" green " 6. 2022-blake3-aes-128-gcm" green " 7. 2022-blake3-aes-256-gcm" green " 8. 2022-blake3-chacha20-poly1305" echo read -r -p "请选择加密方式? 直接回车默认选7, 请输入纯数字:" isShadowsocksMethodInput isShadowsocksMethodInput=${isShadowsocksMethodInput:-7} genShadowsocksPassword if [[ "${isShadowsocksMethodInput}" == "1" ]]; then shadowsocksMethod="aes-256-gcm" elif [[ "${isShadowsocksMethodInput}" == "2" ]]; then shadowsocksMethod="aes-128-gcm" elif [[ "${isShadowsocksMethodInput}" == "3" ]]; then shadowsocksMethod="chacha20-poly1305" elif [[ "${isShadowsocksMethodInput}" == "4" ]]; then shadowsocksMethod="chacha20-ietf-poly1305" elif [[ "${isShadowsocksMethodInput}" == "5" ]]; then shadowsocksMethod="xchacha20-ietf-poly1305" elif [[ "${isShadowsocksMethodInput}" == "6" ]]; then shadowsocksMethod="2022-blake3-aes-128-gcm" genShadowsocksPassword "16" elif [[ "${isShadowsocksMethodInput}" == "7" ]]; then shadowsocksMethod="2022-blake3-aes-256-gcm" genShadowsocksPassword "32" elif [[ "${isShadowsocksMethodInput}" == "8" ]]; then shadowsocksMethod="2022-blake3-chacha20-poly1305" genShadowsocksPassword "32" else shadowsocksMethod="aes-256-gcm" fi echo } configSSRustPath="/root/shadowsocksrust" configSSXrayPath="/root/shadowsocksxray" configSSXrayPort="$(($RANDOM + 10000))" configSSAccessLogFilePath="${HOME}/ss-access.log" configSSErrorLogFilePath="${HOME}/ss-error.log" function installShadowsocksRust(){ if [ -f "${configSSRustPath}/xray" ]; then showHeaderGreen " 已安装过 Shadowsocks Rust, 退出安装 !" \ " Shadowsocks Rust already installed, exit !" exit 0 fi showHeaderGreen " 开始安装 Shadowsocks Rust " \ " Prepare to install Shadowsocks Rust " configNetworkVPSIP=$(get_ip) echo green " ================================================== " green " Shadowsocks Rust Version, default is latest 1.15.0-alpha, choose no is 1.14.3 " green " 请选择 Shadowsocks Rust 的版本, 默认直接回车为最新版 1.15.0-alpha 选否为 1.14.3" echo read -r -p "是否安装最新版? 默认直接回车为最新版, 请输入[Y/n]:" isInstallSSRustVersionInput isInstallSSRustVersionInput=${isInstallSSRustVersionInput:-Y} echo if [[ $isInstallSSRustVersionInput == [Yy] ]]; then versionShadowsocksRust="1.15.0-alpha.9" #versionShadowsocksRust=$(getGithubLatestReleaseVersion "shadowsocks/shadowsocks-rust") else versionShadowsocksRust="1.14.3" fi echo "Version: ${versionShadowsocksRust}" echo green " 准备下载并安装 Shadowsocks Rust: ${versionXray} !" green " Prepare to download and install Shadowsocks Rust Version: ${versionXray} !" echo mkdir -p "${configSSRustPath}" cd "${configSSRustPath}" || exit rm -rf ${configSSRustPath}/* # https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.14.3/shadowsocks-v1.14.3.x86_64-unknown-linux-musl.tar.xz # https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.14.3/shadowsocks-v1.14.3.arm-unknown-linux-musleabi.tar.xz downloadFilenameShadowsocksRust="shadowsocks-v${versionShadowsocksRust}.x86_64-unknown-linux-musl.tar.xz" if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameShadowsocksRust="shadowsocks-v${versionShadowsocksRust}.arm-unknown-linux-musleabi.tar.xz" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameShadowsocksRust="shadowsocks-v${versionShadowsocksRust}.arm-unknown-linux-musleabi.tar.xz" fi downloadAndUnzip "https://github.com/shadowsocks/shadowsocks-rust/releases/download/v${versionShadowsocksRust}/${downloadFilenameShadowsocksRust}" "${configSSRustPath}" "${downloadFilenameShadowsocksRust}" selectShadowsocksMethod cat > ${configSSRustPath}/shadowsocks.json <<-EOF { "server": "0.0.0.0", "server_port": ${configSSXrayPort}, "password": "${shadowsocksPassword1}", "timeout": 300, "method": "${shadowsocksMethod}" } EOF cat > ${osSystemMdPath}shadowsocksrust.service <<-EOF [Unit] Description=ssserver service After=network.target [Service] ExecStart=${configSSRustPath}/ssserver -c ${configSSRustPath}/shadowsocks.json ExecStop=/usr/bin/killall ssserver Restart=on-failure RestartSec=30 User=root Group=root [Install] WantedBy=multi-user.target EOF ${sudoCmd} chmod +x ${configSSRustPath}/ssserver ${sudoCmd} chmod +x ${osSystemMdPath}shadowsocksrust.service ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl enable shadowsocksrust.service ${sudoCmd} systemctl restart shadowsocksrust.service (crontab -l ; echo "22 4 * * 0,1,2,3,4,5,6 systemctl restart shadowsocksrust.service") | sort - | uniq - | crontab - configShadowsocksLink=$(echo -n "${shadowsocksMethod}:${shadowsocksPassword1}@${configNetworkVPSIP}:${configSSXrayPort}" | base64 -w0) configShadowsocksLinkFull="ss://${configShadowsocksLink}" cat > ${configSSRustPath}/clientConfig.json <<-EOF =========== 客户端 Shadowsocks 配置参数 密码任选其一 ============= { 协议: Shadowsocks, 地址: IP ${configNetworkVPSIP}, 端口: ${configSSXrayPort}, 加密方式: ${shadowsocksMethod}, 密码1: ${shadowsocksPassword1} 别名:自己起个任意名称 } Shadowsocks 导入链接: ss://${shadowsocksMethod}:${configShadowsocksPasswordPrefix}${shadowsocksPassword1}@${configNetworkVPSIP}:${configSSXrayPort} 或 ${configShadowsocksLinkFull} EOF showHeaderGreen " Shadowsocks Rust 安装成功 !" red " ShadowsocksRust 服务器端配置路径 ${configSSRustPath}/shadowsocks.json !" green " ShadowsocksRust 查看日志命令: journalctl -n 50 -u shadowsocksrust.service " green " ShadowsocksRust 停止命令: systemctl stop shadowsocksrust.service 启动命令: systemctl start shadowsocksrust.service " green " ShadowsocksRust 重启命令: systemctl restart shadowsocksrust.service" green " ShadowsocksRust 查看运行状态命令: systemctl status shadowsocksrust.service " green " ShadowsocksRust 服务器 每天会自动重启, 防止内存泄漏. 运行 crontab -l 命令 查看定时重启命令 !" echo cat "${configSSRustPath}/clientConfig.json" echo } function installShadowsocks(){ if [ -f "${configSSXrayPath}/xray" ]; then showHeaderGreen " 已安装过 Shadowsocks Xray, 退出安装 !" \ " Shadowsocks Xray already installed, exit !" exit 0 fi showHeaderGreen " 开始安装 Xray Shadowsocks " \ " Prepare to install Xray Shadowsocks " configNetworkVPSIP=$(get_ip) getV2rayVersion "xray" "shadowsocks" green " 准备下载并安装 Xray Version: ${versionXray} !" green " Prepare to download and install Xray Version: ${versionXray} !" echo mkdir -p "${configSSXrayPath}" cd "${configSSXrayPath}" || exit downloadV2rayXrayBin "shadowsocks" selectShadowsocksMethod if [[ "${isShadowsocksMethodInput}" == "6" || "${isShadowsocksMethodInput}" == "7" || "${isShadowsocksMethodInput}" == "8" ]]; then read -r -d '' shadowsocksXrayConfigInboundInput << EOM "inbounds": [ { "port": ${configSSXrayPort}, "protocol": "shadowsocks", "settings": { "method": "${shadowsocksMethod}", "password": "${shadowsocksPassword0}", "network": "tcp,udp", "clients": [ { "password": "${shadowsocksPassword1}", "email": "password101@gmail.com" }, { "password": "${shadowsocksPassword2}", "email": "password102@gmail.com" }, { "password": "${shadowsocksPassword3}", "email": "password103@gmail.com" }, { "password": "${shadowsocksPassword4}", "email": "password104@gmail.com" }, { "password": "${shadowsocksPassword5}", "email": "password105@gmail.com" } ] } } ], EOM else read -r -d '' shadowsocksXrayConfigInboundInput << EOM "inbounds": [ { "port": ${configSSXrayPort}, "protocol": "shadowsocks", "settings": { "network": "tcp,udp", "clients": [ { "password": "${shadowsocksPassword1}", "method": "${shadowsocksMethod}", "email": "password101@gmail.com" }, { "password": "${shadowsocksPassword2}", "method": "${shadowsocksMethod}", "email": "password102@gmail.com" }, { "password": "${shadowsocksPassword3}", "method": "${shadowsocksMethod}", "email": "password103@gmail.com" }, { "password": "${shadowsocksPassword4}", "method": "${shadowsocksMethod}", "email": "password104@gmail.com" }, { "password": "${shadowsocksPassword5}", "method": "${shadowsocksMethod}", "email": "password105@gmail.com" } ] } } ], EOM fi echo echo green " ==================================================" yellow " 是否屏蔽中国回国流量, 根据 geosite:cn 和 geoip:cn 规则判断是否中国回国流量" yellow " 屏蔽中国回国流量, 可以有效防止GFW的检测, 如果挂代理访问中国国内网站 则很容易2次过墙而被检测" echo green " 1. 屏蔽中国回国流量" green " 2. 不屏蔽中国回国流量" green " 3. 中国回国流量走 WARP IPv6 解锁" echo green " 默认选1 屏蔽回国流量. 选择3 需要安装好 Wireguard 和 Cloudflare WARP, 可重新运行本脚本选择第一项安装WARP". red " 推荐先安装 Wireguard 与 Cloudflare WARP 后,再安装v2ray或xray. 实际上先安装v2ray或xray, 后安装Wireguard 与 Cloudflare WARP也没问题" echo read -p "请输入? 直接回车默认选1, 请输入纯数字:" isV2rayBlockChinaSiteInput isV2rayBlockChinaSiteInput=${isV2rayBlockChinaSiteInput:-1} V2rayBlockChinaSiteRuleText="blocked_out" if [[ $isV2rayBlockChinaSiteInput == "1" ]]; then V2rayBlockChinaSiteRuleText="blocked_out" elif [[ $isV2rayBlockChinaSiteInput == "2" ]]; then V2rayBlockChinaSiteRuleText="IPv4_out" else V2rayBlockChinaSiteRuleText="IPv6_out" fi cat > ${configSSXrayPath}/config.json <<-EOF { "log" : { "access": "${configSSAccessLogFilePath}", "error": "${configSSErrorLogFilePath}", "loglevel": "warning" }, ${shadowsocksXrayConfigInboundInput} "routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "type": "field", "domain": [ "geosite:cn" ], "outboundTag": "${V2rayBlockChinaSiteRuleText}" }, { "type": "field", "ip": [ "geoip:cn" ], "outboundTag": "${V2rayBlockChinaSiteRuleText}" }, { "type": "field", "outboundTag": "IPv4_out", "network": "udp,tcp" } ] }, "outbounds": [ { "tag":"IPv4_out", "protocol": "freedom", "settings": { "domainStrategy": "UseIPv4" } }, { "tag": "blocked_out", "protocol": "blackhole", "settings": { "response": { "type": "http" } } }, { "tag":"IPv6_out", "protocol": "freedom", "settings": { "domainStrategy": "UseIPv6" } } ] } EOF cat > ${osSystemMdPath}shadowsocksxray.service <<-EOF [Unit] Description=Xray Service Documentation=https://github.com/xtls After=network.target nss-lookup.target [Service] Type=simple # This service runs as root. You may consider to run it as another user for security concerns. # By uncommenting User=nobody and commenting out User=root, the service will run as user nobody. # More discussion at https://github.com/v2ray/v2ray-core/issues/1011 User=root #User=nobody #CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE NoNewPrivileges=true ExecStart=${configSSXrayPath}/xray run -config ${configSSXrayPath}/config.json Restart=on-failure RestartPreventExitStatus=23 LimitNPROC=10000 LimitNOFILE=1000000 [Install] WantedBy=multi-user.target EOF ${sudoCmd} chmod +x ${configSSXrayPath}/xray ${sudoCmd} chmod +x ${osSystemMdPath}shadowsocksxray.service ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl enable shadowsocksxray.service ${sudoCmd} systemctl restart shadowsocksxray.service # 设置 cron 定时任务 # https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job (crontab -l ; echo "10 4 * * 0,1,2,3,4,5,6 rm -f /root/ss-*") | sort - | uniq - | crontab - (crontab -l ; echo "20 4 * * 0,1,2,3,4,5,6 systemctl restart shadowsocksxray.service") | sort - | uniq - | crontab - if [[ "${isShadowsocksMethodInput}" == "6" || "${isShadowsocksMethodInput}" == "7" || "${isShadowsocksMethodInput}" == "8" ]]; then configShadowsocksPasswordPrefix="${shadowsocksPassword0}:" else configShadowsocksPasswordPrefix="" fi configShadowsocksLink=$(echo -n "${shadowsocksMethod}:${configShadowsocksPasswordPrefix}${shadowsocksPassword1}@${configNetworkVPSIP}:${configSSXrayPort}" | base64 -w0) configShadowsocksLinkFull="ss://${configShadowsocksLink}" cat > ${configSSXrayPath}/clientConfig.json <<-EOF =========== 客户端 Shadowsocks 配置参数 密码任选其一 ============= { 协议: Shadowsocks, 地址: IP ${configNetworkVPSIP}, 端口: ${configSSXrayPort}, 加密方式: ${shadowsocksMethod}, 密码1: ${configShadowsocksPasswordPrefix}${shadowsocksPassword1}, 密码2: ${configShadowsocksPasswordPrefix}${shadowsocksPassword2}, 密码3: ${configShadowsocksPasswordPrefix}${shadowsocksPassword3}, 密码4: ${configShadowsocksPasswordPrefix}${shadowsocksPassword4}, 密码5: ${configShadowsocksPasswordPrefix}${shadowsocksPassword5}, 别名:自己起个任意名称 } Shadowsocks 导入链接: ss://${shadowsocksMethod}:${configShadowsocksPasswordPrefix}${shadowsocksPassword1}@${configNetworkVPSIP}:${configSSXrayPort} 或 ${configShadowsocksLinkFull} EOF showHeaderGreen " Shadowsocks Xray ${versionXray} 安装成功 !" red " Shadowsocksxray 服务器端配置路径 ${configSSXrayPath}/config.json !" green " Shadowsocksxray 访问日志 ${configSSAccessLogFilePath} !" green " Shadowsocksxray 错误日志 ${configSSErrorLogFilePath} ! " green " Shadowsocksxray 查看日志命令: journalctl -n 50 -u shadowsocksxray.service " green " Shadowsocksxray 停止命令: systemctl stop shadowsocksxray.service 启动命令: systemctl start shadowsocksxray.service " green " Shadowsocksxray 重启命令: systemctl restart shadowsocksxray.service" green " Shadowsocksxray 查看运行状态命令: systemctl status shadowsocksxray.service " green " Shadowsocksxray 服务器 每天会自动重启, 防止内存泄漏. 运行 crontab -l 命令 查看定时重启命令 !" echo cat "${configSSXrayPath}/clientConfig.json" echo } function removeShadowsocks(){ if [[ -f "${configSSXrayPath}/xray" ]]; then echo green " ================================================== " green " Are you sure to remove Shadowsocks Xray ? " echo read -r -p "是否确认卸载 Shadowsocks Xray? 直接回车默认卸载, 请输入[Y/n]:" isRemoveShadowsocksServerInput isRemoveShadowsocksServerInput=${isRemoveShadowsocksServerInput:-Y} if [[ "${isRemoveShadowsocksServerInput}" == [Yy] ]]; then ${sudoCmd} systemctl stop shadowsocksxray.service ${sudoCmd} systemctl disable shadowsocksxray.service rm -rf ${configSSXrayPath} rm -f ${osSystemMdPath}shadowsocksxray.service rm -f ${configSSAccessLogFilePath} rm -f ${configSSErrorLogFilePath} crontab -l | grep -v "rm" | crontab - crontab -l | grep -v "shadowsocksxray" | crontab - showHeaderGreen " Shadowsocks Xray 卸载完毕 !" \ " Shadowsocks Xray uninstalled successfully !" fi else showHeaderRed " 系统没有安装 Shadowsocks Xray, 退出卸载 !" \ " Shadowsocks Xray not found, exit !" exit 0 fi if [[ -f "${configSSRustPath}/ssserver" ]]; then echo green " ================================================== " green " Are you sure to remove Shadowsocks Rust ? " echo read -r -p "是否确认卸载 Shadowsocks Rust? 直接回车默认卸载, 请输入[Y/n]:" isRemoveShadowsocksServerInput isRemoveShadowsocksServerInput=${isRemoveShadowsocksServerInput:-Y} if [[ "${isRemoveShadowsocksServerInput}" == [Yy] ]]; then ${sudoCmd} systemctl stop shadowsocksrust.service ${sudoCmd} systemctl disable shadowsocksrust.service rm -rf ${configSSRustPath} rm -f ${osSystemMdPath}shadowsocksrust.service crontab -l | grep -v "shadowsocksrust" | crontab - showHeaderGreen " Shadowsocks Rust 卸载完毕 !" \ " Shadowsocks Rust uninstalled successfully !" fi else showHeaderRed " 系统没有安装 Shadowsocks Rust, 退出卸载 !" \ " Shadowsocks Rust not found, exit !" exit 0 fi } xrayRealityX25519Key="" xrayRealityPrivateKey="" xrayRealityPublicKey="" xrayRealityShortId="" configxrayRealityKeyFilePath="${HOME}/xray_reality_key" function generateXrayRealityShortId() { # Generate random string of specified length # 0 到 f,长度为 2 的倍数,长度上限为 16 local hex_chars="0123456789abcdef" for (( i=0; i<16; i++ )); do xrayRealityShortId+=${hex_chars:$((RANDOM%16)):1} done } function generateXrayRealityPrivateKey(){ if [[ -f "${configxrayRealityKeyFilePath}" ]]; then xrayRealityX25519Key=$(cat ${configxrayRealityKeyFilePath}) xrayRealityPrivateKey=$(echo "${xrayRealityX25519Key}" | head -1 | awk '{print $3}') xrayRealityPublicKey=$(echo "${xrayRealityX25519Key}" | tail -n 1 | awk '{print $3}') fi if [[ -z "${xrayRealityPrivateKey}" ]]; then xrayRealityX25519Key=$(${configV2rayPath}/xray x25519) echo "${xrayRealityX25519Key}" > "${configxrayRealityKeyFilePath}" xrayRealityPrivateKey=$(echo "${xrayRealityX25519Key}" | head -1 | awk '{print $3}') xrayRealityPublicKey=$(echo "${xrayRealityX25519Key}" | tail -n 1 | awk '{print $3}') else echo green " 发现之前安装的 Xray Reality PublicKey 和 PrivateKey, 是否重新生成新Key?" green " 默认直接回车 重新生成新Key, 选否则使用之前生成的Key " echo read -r -p "是否重新生成新的 Reality Key, 请输入[Y/n]:" isGenerateNewXrayRealityKey isGenerateNewXrayRealityKey=${isGenerateNewXrayRealityKey:-Y} if [[ "${isGenerateNewXrayRealityKey}" == [Yy] ]]; then xrayRealityX25519Key=$(${configV2rayPath}/xray x25519) echo "${xrayRealityX25519Key}" > "${configxrayRealityKeyFilePath}" xrayRealityPrivateKey=$(echo "${xrayRealityX25519Key}" | head -1 | awk '{print $3}') xrayRealityPublicKey=$(echo "${xrayRealityX25519Key}" | tail -n 1 | awk '{print $3}') fi fi generateXrayRealityShortId } function downloadV2rayXrayBin(){ if [ -z $1 ]; then tempDownloadV2rayPath="${configV2rayPath}" elif [ "$1" = "shadowsocks" ]; then isXray="yes" tempDownloadV2rayPath="${configSSXrayPath}" else tempDownloadV2rayPath="${configV2rayPath}/upgrade/${promptInfoXrayName}" fi mkdir -p "${tempDownloadV2rayPath}" cd "${tempDownloadV2rayPath}" || exit if [ "$isXray" = "no" ] ; then # https://github.com/v2fly/v2ray-core/releases/download/v4.41.1/v2ray-linux-64.zip # https://github.com/v2fly/v2ray-core/releases/download/v4.41.1/v2ray-linux-arm32-v6.zip # https://github.com/v2fly/v2ray-core/releases/download/v4.44.0/v2ray-linux-arm64-v8a.zip if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameV2ray="v2ray-linux-arm32-v6.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameV2ray="v2ray-linux-arm64-v8a.zip" fi downloadAndUnzip "https://github.com/v2fly/v2ray-core/releases/download/v${versionV2ray}/${downloadFilenameV2ray}" "${tempDownloadV2rayPath}" "${downloadFilenameV2ray}" else # https://github.com/XTLS/Xray-core/releases/download/v1.5.0/Xray-linux-64.zip # https://github.com/XTLS/Xray-core/releases/download/v1.5.2/Xray-linux-arm32-v6.zip if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameXray="Xray-linux-arm32-v6.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameXray="Xray-linux-arm64-v8a.zip" fi downloadAndUnzip "https://github.com/XTLS/Xray-core/releases/download/v${versionXray}/${downloadFilenameXray}" "${tempDownloadV2rayPath}" "${downloadFilenameXray}" fi if [ "$1" = "upgrade" ]; then if [ "$isXray" = "no" ]; then mv -f ${configV2rayPath}/upgrade/${promptInfoXrayName}/v2ctl ${configV2rayPath} fi mv -f ${configV2rayPath}/upgrade/${promptInfoXrayName}/${promptInfoXrayName} ${configV2rayPath} mv -f ${configV2rayPath}/upgrade/${promptInfoXrayName}/geoip.dat ${configV2rayPath} mv -f ${configV2rayPath}/upgrade/${promptInfoXrayName}/geosite.dat ${configV2rayPath} fi } function inputV2rayStreamSettings(){ echo green " ==================================================" yellow " 请选择 V2ray或Xray的 StreamSettings 传输协议, 默认为3 Websocket" echo green " 1. TCP " green " 2. KCP " green " 3. WebSocket 支持CDN" green " 4. HTTP/2 (注意Nginx不支持HTTP/2的转发)" green " 5. QUIC " green " 6. gRPC 支持CDN" green " 7. WebSocket + gRPC 支持CDN" echo read -p "请选择传输协议? 直接回车默认选3 Websocket, 请输入纯数字:" isV2rayStreamSettingInput isV2rayStreamSettingInput=${isV2rayStreamSettingInput:-3} if [[ $isV2rayStreamSettingInput == 1 ]]; then configV2rayStreamSetting="tcp" elif [[ $isV2rayStreamSettingInput == 2 ]]; then configV2rayStreamSetting="kcp" inputV2rayKCPSeedPassword elif [[ $isV2rayStreamSettingInput == 4 ]]; then configV2rayStreamSetting="h2" inputV2rayWSPath "h2" elif [[ $isV2rayStreamSettingInput == 5 ]]; then configV2rayStreamSetting="quic" inputV2rayKCPSeedPassword "quic" elif [[ $isV2rayStreamSettingInput == 6 ]]; then configV2rayStreamSetting="grpc" elif [[ $isV2rayStreamSettingInput == 7 ]]; then configV2rayStreamSetting="wsgrpc" else configV2rayStreamSetting="ws" inputV2rayWSPath fi if [[ "${configInstallNginxMode}" == "v2raySSL" || ${configV2rayWorkingNotChangeMode} == "true" ]]; then if [[ "${configV2rayStreamSetting}" == "grpc" ]]; then inputV2rayGRPCPath elif [[ "${configV2rayStreamSetting}" == "wsgrpc" ]]; then inputV2rayWSPath inputV2rayGRPCPath fi else if [[ "${configV2rayStreamSetting}" == "grpc" ]]; then inputV2rayServerPort "textMainGRPCPort" configV2rayGRPCPort=${isV2rayUserPortGRPCInput} configV2rayPortGRPCShowInfo=${isV2rayUserPortGRPCInput} inputV2rayGRPCPath elif [[ "${configV2rayStreamSetting}" == "wsgrpc" ]]; then inputV2rayWSPath inputV2rayServerPort "textMainGRPCPort" configV2rayGRPCPort=${isV2rayUserPortGRPCInput} configV2rayPortGRPCShowInfo=${isV2rayUserPortGRPCInput} inputV2rayGRPCPath fi fi } function inputV2rayKCPSeedPassword(){ echo configV2rayKCPSeedPassword=$(cat /dev/urandom | head -1 | md5sum | head -c 4) configV2rayKCPQuicText="KCP的Seed 混淆密码" if [[ $1 == "quic" ]]; then configV2rayKCPQuicText="QUIC 的key密钥" fi read -p "是否自定义${promptInfoXrayName}的 ${configV2rayKCPQuicText}? 直接回车默认创建随机密码, 请输入自定义密码:" isV2rayUserKCPSeedInput isV2rayUserKCPSeedInput=${isV2rayUserKCPSeedInput:-${configV2rayKCPSeedPassword}} if [[ -z $isV2rayUserKCPSeedInput ]]; then echo else configV2rayKCPSeedPassword=${isV2rayUserKCPSeedInput} fi } function inputV2rayWSPath(){ echo configV2rayWebSocketPath=$(cat /dev/urandom | head -1 | md5sum | head -c 8) configV2rayWSH2Text="WS" if [[ $1 == "h2" ]]; then configV2rayWSH2Text="HTTP2" fi read -r -p "是否自定义${promptInfoXrayName}的 ${configV2rayWSH2Text}的Path? 直接回车默认创建随机路径, 请输入自定义路径(不要输入/):" isV2rayUserWSPathInput isV2rayUserWSPathInput=${isV2rayUserWSPathInput:-${configV2rayWebSocketPath}} if [[ -z $isV2rayUserWSPathInput ]]; then echo else configV2rayWebSocketPath=${isV2rayUserWSPathInput} fi } function inputV2rayGRPCPath(){ echo configV2rayGRPCServiceName=$(cat /dev/urandom | head -1 | md5sum | head -c 8) read -p "是否自定义${promptInfoXrayName}的 gRPC 的serviceName ? 直接回车默认创建随机路径, 请输入自定义路径(不要输入/):" isV2rayUserGRPCPathInput isV2rayUserGRPCPathInput=${isV2rayUserGRPCPathInput:-${configV2rayGRPCServiceName}} if [[ -z $isV2rayUserGRPCPathInput ]]; then echo else configV2rayGRPCServiceName=${isV2rayUserGRPCPathInput} fi } function inputV2rayServerPort(){ echo if [[ $1 == "textMainPort" ]]; then green " 是否自定义${promptInfoXrayName}的端口号? 如要支持cloudflare的CDN, 需要使用cloudflare支持的HTTPS端口号 例如 443 8443 2053 2083 2087 2096 端口" green " 具体请看cloudflare官方文档 https://developers.cloudflare.com/fundamentals/get-started/network-ports" read -p "是否自定义${promptInfoXrayName}的端口号? 直接回车默认为${configV2rayPortShowInfo}, 请输入自定义端口号[1-65535]:" isV2rayUserPortInput isV2rayUserPortInput=${isV2rayUserPortInput:-${configV2rayPortShowInfo}} checkPortInUse "${isV2rayUserPortInput}" $1 fi if [[ $1 == "textMainGRPCPort" ]]; then green " 如果使用gRPC 协议并要支持cloudflare的CDN, 需要输入 443 端口才可以" read -p "是否自定义${promptInfoXrayName} gRPC的端口号? 直接回车默认为${configV2rayPortGRPCShowInfo}, 请输入自定义端口号[1-65535]:" isV2rayUserPortGRPCInput isV2rayUserPortGRPCInput=${isV2rayUserPortGRPCInput:-${configV2rayPortGRPCShowInfo}} checkPortInUse "${isV2rayUserPortGRPCInput}" $1 fi if [[ $1 == "textAdditionalPort" ]]; then green " 是否添加一个额外监听端口, 与主端口${configV2rayPort}一起同时工作" green " 一般用于 中转机无法使用443端口 使用额外端口中转给目标主机时使用" read -p "是否给${promptInfoXrayName}添加额外的监听端口? 直接回车默认否, 请输入额外端口号[1-65535]:" isV2rayAdditionalPortInput isV2rayAdditionalPortInput=${isV2rayAdditionalPortInput:-999999} checkPortInUse "${isV2rayAdditionalPortInput}" $1 fi if [[ $1 == "textMainTrojanPort" ]]; then green "是否自定义Trojan${promptInfoTrojanName}的端口号? 直接回车默认为${configV2rayTrojanPort}" read -p "是否自定义Trojan${promptInfoTrojanName}的端口号? 直接回车默认为${configV2rayTrojanPort}, 请输入自定义端口号[1-65535]:" isTrojanUserPortInput isTrojanUserPortInput=${isTrojanUserPortInput:-${configV2rayTrojanPort}} checkPortInUse "${isTrojanUserPortInput}" $1 fi } function checkPortInUse(){ if [ $1 = "999999" ]; then echo elif [[ $1 -gt 1 && $1 -le 65535 ]]; then isPortUsed=$(netstat -tulpn | grep -e ":$1") ; if [ -z "${isPortUsed}" ]; then green "输入的端口号 $1 没有被占用, 继续安装..." else processInUsedName=$(echo "${isPortUsed}" | awk '{print $7}' | awk -F"/" '{print $2}') red "输入的端口号 $1 已被 ${processInUsedName} 占用! 请退出安装, 检查端口是否已被占用 或 重新输入!" inputV2rayServerPort $2 fi else red "输入的端口号错误! 必须是[1-65535]. 请重新输入" inputV2rayServerPort $2 fi } v2rayVmessLinkQR1="" v2rayVmessLinkQR2="" v2rayVlessLinkQR1="" v2rayVlessLinkQR2="" v2rayPassword1UrlEncoded="" function rawUrlEncode() { # https://stackoverflow.com/questions/296536/how-to-urlencode-data-for-curl-command local string="${1}" local strlen=${#string} local encoded="" local pos c o for (( pos=0 ; pos ${configV2rayVmessImportLinkFile1Path} <<-EOF { "v": "2", "ps": "${configSSLDomain}_${configV2rayProtocolDisplayName}_${configV2rayVmessLinkStreamSetting1}", "add": "${configSSLDomain}", "port": "${configV2rayPortShowInfo}", "id": "${v2rayPassword1}", "aid": "0", "net": "${configV2rayVmessLinkStreamSetting1}", "type": "none", "host": "${configV2rayVmessLinkConfigHost}", "path": "${configV2rayVmessLinkConfigPath}", "tls": "${configV2rayVmessLinkConfigTls}", "sni": "${configSSLDomain}" } EOF cat > ${configV2rayVmessImportLinkFile2Path} <<-EOF { "v": "2", "ps": "${configSSLDomain}_${configV2rayProtocolDisplayName}_${configV2rayVmessLinkStreamSetting2}", "add": "${configSSLDomain}", "port": "${configV2rayPortShowInfo}", "id": "${v2rayPassword1}", "aid": "0", "net": "${configV2rayVmessLinkStreamSetting2}", "type": "${configV2rayProtocolDisplayHeaderType}", "host": "${configV2rayVmessLinkConfigHost}", "path": "${configV2rayVmessLinkConfigPath2}", "tls": "${configV2rayVmessLinkConfigTls}", "sni": "${configSSLDomain}" } EOF v2rayVmessLinkQR1="vmess://$(cat ${configV2rayVmessImportLinkFile1Path} | base64 -w 0)" v2rayVmessLinkQR2="vmess://$(cat ${configV2rayVmessImportLinkFile2Path} | base64 -w 0)" } function generateVLessImportLink(){ # https://github.com/XTLS/Xray-core/discussions/716 generateVmessImportLink rawUrlEncode "${v2rayPassword1}" if [[ "${configV2rayStreamSetting}" == "" ]]; then configV2rayVlessXtlsFlow="tls" configV2rayVlessXtlsFlowShowInfo="空" if [[ "${configV2rayIsTlsShowInfo}" == "xtls" ]]; then configV2rayVlessXtlsFlow="xtls&flow=xtls-rprx-direct" configV2rayVlessXtlsFlowShowInfo="xtls-rprx-direct" fi if [[ "${configV2rayWorkingMode}" == "vlessTCPVision" ]]; then configV2rayVlessXtlsFlow="tls&flow=xtls-rprx-vision" configV2rayVlessXtlsFlowShowInfo="xtls-rprx-vision" fi if [[ "${configV2rayWorkingMode}" == "vlessTCPREALITY" ]]; then configV2rayVlessXtlsFlow="reality&flow=xtls-rprx-vision&fp=chrome&utls=chrome&pbk=${xrayRealityPublicKey}&sni=${configXrayRealitySni}&sid=${xrayRealityShortId}" configV2rayVlessXtlsFlowShowInfo="xtls-rprx-vision" fi if [[ "$configV2rayWorkingMode" == "vlessgRPC" ]]; then cat > ${configV2rayVlessImportLinkFile1Path} <<-EOF ${configV2rayProtocol}://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=${configV2rayVlessXtlsFlow}&type=grpc&host=${configSSLDomain}&serviceName=${configV2rayGRPCServiceName}#${configSSLDomain}+gRPC_${configV2rayIsTlsShowInfo} EOF else cat > ${configV2rayVlessImportLinkFile1Path} <<-EOF ${configV2rayProtocol}://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=${configV2rayVlessXtlsFlow}&type=tcp&host=${configSSLDomain}#${configSSLDomain}+TCP_${configV2rayIsTlsShowInfo} EOF cat > ${configV2rayVlessImportLinkFile2Path} <<-EOF ${configV2rayProtocol}://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=tls&type=ws&host=${configSSLDomain}&path=%2f${configV2rayWebSocketPath}#${configSSLDomain}+WebSocket_${configV2rayIsTlsShowInfo} EOF fi v2rayVlessLinkQR1="$(cat ${configV2rayVlessImportLinkFile1Path})" v2rayVlessLinkQR2="$(cat ${configV2rayVlessImportLinkFile2Path})" else if [[ "${configV2rayProtocol}" == "vless" ]]; then cat > ${configV2rayVlessImportLinkFile1Path} <<-EOF ${configV2rayProtocol}://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=${configV2rayIsTlsShowInfo}&type=${configV2rayVmessLinkStreamSetting1}&path=%2f${configV2rayVmessLinkConfigPath}&headerType=none&seed=${configV2rayKCPSeedPassword}&quicSecurity=none&key=${configV2rayKCPSeedPassword}&serviceName=${configV2rayVmessLinkConfigPath}#${configSSLDomain}+${configV2rayVmessLinkStreamSetting1}_${configV2rayIsTlsShowInfo} EOF cat > ${configV2rayVlessImportLinkFile2Path} <<-EOF ${configV2rayProtocol}://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=${configV2rayIsTlsShowInfo}&type=${configV2rayVmessLinkStreamSetting2}&host=${configSSLDomain}&path=%2f${configV2rayVmessLinkConfigPath2}&headerType=none&seed=${configV2rayKCPSeedPassword}&quicSecurity=none&key=${configV2rayKCPSeedPassword}&serviceName=${configV2rayVmessLinkConfigPath2}#${configSSLDomain}+${configV2rayVmessLinkStreamSetting2}_${configV2rayIsTlsShowInfo} EOF v2rayVlessLinkQR1="$(cat ${configV2rayVlessImportLinkFile1Path})" v2rayVlessLinkQR2="$(cat ${configV2rayVlessImportLinkFile2Path})" fi fi } v2rayConfigRouteGoNetflixInput="" v2rayConfigOutboundV2rayGoNetflixServerInput="" function unlockNetflixBySomebody(){ echo yellow " 某大佬提供了可以解锁Netflix非自制剧的V2ray服务器, 不保证有效" read -p "是否使用某大佬提供的Netflix解锁服务器? 直接回车默认不使用, 请输入[y/N]:" isV2rayUnlockGoNetflixInput isV2rayUnlockGoNetflixInput=${isV2rayUnlockGoNetflixInput:-n} if [[ $isV2rayUnlockGoNetflixInput == [Nn] ]]; then echo else removeString="\"geosite:netflix\"," V2rayUnlockVideoSiteRuleText=${V2rayUnlockVideoSiteRuleText/"$removeString"/} removeString2="\"geosite:disney\"," V2rayUnlockVideoSiteRuleText=${V2rayUnlockVideoSiteRuleText/"$removeString2"/} removeString3="\"geosite:netflix\"" V2rayUnlockVideoSiteRuleText=${V2rayUnlockVideoSiteRuleText/"$removeString3"/} removeString4="\"geosite:disney\"" V2rayUnlockVideoSiteRuleText=${V2rayUnlockVideoSiteRuleText/"$removeString4"/} read -r -d '' v2rayConfigRouteGoNetflixInput << EOM { "type": "field", "outboundTag": "GoNetflix", "domain": [ "geosite:netflix", "geosite:disney" ] }, EOM read -r -d '' v2rayConfigOutboundV2rayGoNetflixServerInput << EOM { "tag": "GoNetflix", "protocol": "vmess", "streamSettings": { "network": "ws", "security": "tls", "tlsSettings": { "allowInsecure": false }, "wsSettings": { "path": "ws" } }, "mux": { "enabled": true, "concurrency": 8 }, "settings": { "vnext": [{ "address": "free-sg-01.unblocknetflix.cf", "port": 443, "users": [ { "id": "402d7490-6d4b-42d4-80ed-e681b0e6f1f9", "security": "auto", "alterId": 0 } ] }] } }, EOM read -r -d '' v2rayConfigOutboundV2rayGoNetflixServerInput << EOM { "tag": "GoNetflix", "protocol": "vmess", "streamSettings": { "network": "tcp", "security": "none" }, "mux": { "enabled": true, "concurrency": 8 }, "settings": { "vnext": [{ "address": "34.84.10.251", "port": 47890, "users": [ { "id": "e85059c9-a47b-44b5-b644-4eb96dfcd4de", "security": "auto", "alterId": 0 } ] }] } }, EOM fi } isInputWARPSock5Server="" function inputUnlockWARPSock5Server(){ if [ -z "${isInputWARPSock5Server}" ]; then echo read -r -p "请输入WARP Sock5 代理服务器地址? 直接回车默认本机 127.0.0.1, 请输入:" unlockWARPServerIpInput unlockWARPServerIpInput=${unlockWARPServerIpInput:-127.0.0.1} echo read -r -p "请输入WARP Sock5 代理服务器端口号? 直接回车默认${configWARPPortLocalServerPort}, 请输入纯数字:" unlockWARPServerPortInput unlockWARPServerPortInput=${unlockWARPServerPortInput:-$configWARPPortLocalServerPort} isInputWARPSock5Server="true" fi } isInputV2rayServer="" function inputUnlockV2rayServerInfo(){ if [ -z "${isInputV2rayServer}" ]; then isInputV2rayServer="true" echo yellow " 请选择可解锁流媒体的V2ray或Xray服务器的协议 " green " 1. VLess + TCP + TLS" green " 2. VLess + TCP + XTLS (Xray 1.7 以上版本不再支持)" green " 3. VLess + TCP + XTLS Vision (Xray 1.7 以上版本才支持)" green " 4. VLess + TCP + Reality (Xray 1.8 以上版本才支持)" green " 5. VLess + WS + TLS (支持CDN)" green " 6. VMess + TCP + TLS" green " 7. VMess + WS + TLS (支持CDN)" echo read -r -p "请选择协议? 直接回车默认选3, 请输入纯数字:" isV2rayUnlockServerProtocolInput isV2rayUnlockServerProtocolInput=${isV2rayUnlockServerProtocolInput:-3} isV2rayUnlockOutboundServerProtocolText="vless" if [[ $isV2rayUnlockServerProtocolInput == "6" || $isV2rayUnlockServerProtocolInput == "7" ]]; then isV2rayUnlockOutboundServerProtocolText="vmess" fi isV2rayUnlockOutboundServerTCPText="tcp" unlockOutboundServerWebSocketSettingText="" if [[ $isV2rayUnlockServerProtocolInput == "5" || $isV2rayUnlockServerProtocolInput == "7" ]]; then isV2rayUnlockOutboundServerTCPText="ws" echo yellow " 请填写可解锁流媒体的V2ray或Xray服务器Websocket Path, 默认为/" read -r -p "请填写Websocket Path? 直接回车默认为/ , 请输入(不要包含/):" isV2rayUnlockServerWSPathInput isV2rayUnlockServerWSPathInput=${isV2rayUnlockServerWSPathInput:-""} read -r -d '' unlockOutboundServerWebSocketSettingText << EOM , "wsSettings": { "path": "/${isV2rayUnlockServerWSPathInput}" } EOM else read -r -d '' unlockOutboundServerWebSocketSettingText << EOM , "${isV2rayUnlockOutboundServerTLSText}Settings": { "serverName": "${isV2rayUnlockServerDomainInput}" } EOM fi unlockOutboundServerXTLSFlowText="" isV2rayUnlockOutboundServerTLSText="tls" if [[ $isV2rayUnlockServerProtocolInput == "2" ]]; then isV2rayUnlockOutboundServerTLSText="xtls" echo yellow " 请选择可解锁流媒体的V2ray或Xray服务器 XTLS模式下的Flow " green " 1. VLess + TCP + XTLS (xtls-rprx-direct) 推荐" green " 2. VLess + TCP + XTLS (xtls-rprx-splice) 此项可能会无法连接" read -r -p "请选择Flow 参数? 直接回车默认选1, 请输入纯数字:" isV2rayUnlockServerFlowInput isV2rayUnlockServerFlowInput=${isV2rayUnlockServerFlowInput:-1} unlockOutboundServerXTLSFlowValue="xtls-rprx-direct" if [[ $isV2rayUnlockServerFlowInput == "1" ]]; then unlockOutboundServerXTLSFlowValue="xtls-rprx-direct" else unlockOutboundServerXTLSFlowValue="xtls-rprx-splice" fi read -r -d '' unlockOutboundServerXTLSFlowText << EOM "flow": "${unlockOutboundServerXTLSFlowValue}", EOM read -r -d '' unlockOutboundServerWebSocketSettingText << EOM , "${isV2rayUnlockOutboundServerTLSText}Settings": { "serverName": "${isV2rayUnlockServerDomainInput}" } EOM elif [[ $isV2rayUnlockServerProtocolInput == "3" ]]; then read -r -d '' unlockOutboundServerXTLSFlowText << EOM "flow": "xtls-rprx-vision", EOM elif [[ $isV2rayUnlockServerProtocolInput == "4" ]]; then isV2rayUnlockOutboundServerTLSText="reality" echo green " 请输入回落域名 同时也用于serverName? 默认为www.ebay.com" read -r -p "请输入回落域名, 直接回车默认为 www.ebay.com: " configXrayRealityFallbackDomainNameInput if [ -z "${configXrayRealityFallbackDomainNameInput}" ]; then configXrayRealitySni="www.ebay.com" fi echo green " 请输入privateKey? 默认为空" read -r -p "请输入privateKey, 直接回车默认为空: " xrayRealityPrivateKey xrayRealityPrivateKey=${xrayRealityPrivateKey:-""} read -r -d '' unlockOutboundServerWebSocketSettingText << EOM , "realitySettings": { "show": false, "dest": "${configXrayRealitySni}:443", "xver": 0, "serverNames": [ "${configXrayRealitySni}", "ebay.com", "www.ebay.com", "icloud.com", "www.icloud.com", "apple.com", "www.apple.com", "mozilla.org", "addons.mozilla.org", "walmart.com", "www.walmart.com", "etsy.com", "www.etsy.com", "shopify.com", "www.shopify.com", "samsung.com", "www.samsung.com", "airbnb.com", "www.airbnb.com", "asml.com", "www.asml.com", "tsmc.com", "www.tsmc.com", "pfizer.com", "www.pfizer.com", "microsoft.com", "www.microsoft.com", "support.microsoft.com", "office.com", "www.office.com", "signup.live.com", "www.live.com", "outlook.live.com", "lovelive-anime.jp", "s0.awsstatic.com", "d1.awsstatic.com", "amazon.com", "m.media-amazon.com", "www.lovelive-anime.jp" ], "privateKey": "${xrayRealityPrivateKey}", "maxTimeDiff": 0, "shortIds": [ "" ] } EOM fi echo yellow " 请填写可解锁流媒体的V2ray或Xray服务器地址, 例如 www.example.com" read -r -p "请填写可解锁流媒体服务器地址? 直接回车默认为本机, 请输入:" isV2rayUnlockServerDomainInput isV2rayUnlockServerDomainInput=${isV2rayUnlockServerDomainInput:-127.0.0.1} echo yellow " 请填写可解锁流媒体的V2ray或Xray服务器端口号, 例如 443" read -r -p "请填写可解锁流媒体服务器地址? 直接回车默认为443, 请输入:" isV2rayUnlockServerPortInput isV2rayUnlockServerPortInput=${isV2rayUnlockServerPortInput:-443} echo yellow " 请填写可解锁流媒体的V2ray或Xray服务器的用户UUID, 例如 4aeaf80d-f89e-46a2-b3dc-bb815eae75ba" read -r -p "请填写用户UUID? 直接回车默认为111, 请输入:" isV2rayUnlockServerUserIDInput isV2rayUnlockServerUserIDInput=${isV2rayUnlockServerUserIDInput:-111} read -r -d '' v2rayConfigOutboundV2rayServerInput << EOM { "tag": "V2Ray_out", "protocol": "${isV2rayUnlockOutboundServerProtocolText}", "settings": { "vnext": [ { "address": "${isV2rayUnlockServerDomainInput}", "port": ${isV2rayUnlockServerPortInput}, "users": [ { "id": "${isV2rayUnlockServerUserIDInput}", "encryption": "none", ${unlockOutboundServerXTLSFlowText} "level": 0 } ] } ] }, "streamSettings": { "network": "${isV2rayUnlockOutboundServerTCPText}", "security": "${isV2rayUnlockOutboundServerTLSText}", ${unlockOutboundServerWebSocketSettingText} } }, EOM echo green " 可自行修改V2ray或Xray配置, 在outbounds字段中增加一个tag为 V2Ray_out 的V2ray或Xray服务器配置" echo fi } function v2rayRouteRule(){ site_LIST=("google" "openai" "twitter" "netflix" "disney" "youtube" "spotify" "pornhub" ) V2rayUnlockSiteRuleV6Text="" V2rayUnlockSiteRuleSock5Text="" V2rayUnlockSiteRuleV2rayServerText="" # 使用 for 循环遍历数组中的元素 for site in "${site_LIST[@]}"; do echo green " ==================================================" if [[ "${site}" == "google" ]]; then yellow " 请选择 避免弹出 Google reCAPTCHA 人机验证的方式" elif [[ "${site}" == "openai" ]]; then yellow " 请选择 解锁 OpenAI ChatGPT 方式" elif [[ "${site}" == "twitter" ]]; then yellow " 请选择 解锁 Twitter 方式" elif [[ "${site}" == "netflix" ]]; then yellow " 请选择 解锁 Netflix 非自制剧的方式" elif [[ "${site}" == "disney" ]]; then yellow " 请选择 解锁 Disney+ 的方式" elif [[ "${site}" == "youtube" ]]; then yellow " 请选择 解锁 Youtube 和 Youtube Premium 的方式" elif [[ "${site}" == "pornhub" ]]; then yellow " 请选择 避免出现 Pornhub 视频变成玉米的方式" elif [[ "${site}" == "spotify" ]]; then yellow " 请选择 解锁 Spotify 的方式" fi echo green " 1. 不解锁 出口使用 IPv4" green " 2. 使用 IPv6 解锁, 需要配合安装WARP 推荐使用" green " 3. 使用 WARP Sock5 代理解锁" green " 4. 通过转发到可解锁的v2ray或xray服务器解锁" echo green " 默认选1 不解锁. 选择2,3解锁需要安装好 Wireguard 与 Cloudflare WARP, 可重新运行本脚本选择第1项安装". red " 推荐先安装 Wireguard 与 Cloudflare WARP 后,再安装v2ray或xray. 实际上先安装v2ray或xray, 后安装Wireguard 与 Cloudflare WARP也没问题" red " 但如果先安装v2ray或xray,选择2和3解锁, 那么会暂时无法访问google和其他视频网站, 需要继续安装Wireguard 与 Cloudflare WARP 才能访问" echo read -r -p "请输入解锁选项? 直接回车默认选1 不解锁, 请输入纯数字:" isV2rayUnlockGoogleInput isV2rayUnlockGoogleInput=${isV2rayUnlockGoogleInput:-1} V2rayUnlockSiteRuleTempText=", \"geosite:${site}\" " if [[ "${site}" == "others" ]]; then V2rayUnlockSiteRuleTempText=", \"geosite:${site}\" " fi if [[ $isV2rayUnlockGoogleInput == "2" ]]; then V2rayUnlockSiteRuleV6Text+="${V2rayUnlockSiteRuleTempText}" elif [[ $isV2rayUnlockGoogleInput == "3" ]]; then V2rayUnlockSiteRuleSock5Text+="${V2rayUnlockSiteRuleTempText}" inputUnlockWARPSock5Server elif [[ $isV2rayUnlockGoogleInput == "4" ]]; then V2rayUnlockSiteRuleV2rayServerText+="${V2rayUnlockSiteRuleTempText}" inputUnlockV2rayServerInfo else echo "" fi done V2rayUnlockVideoSiteRuleText="" echo green " ==================================================" yellow " 是否解锁的更多的流媒体和视频网站:" echo green " 1. 不解锁" green " 2. 解锁 Hulu " green " 3. 解锁 HBO " green " 5. 同时解锁 Hulu, HBO" green " 9. 同时解锁 全部流媒体 包括 Hulu, HBO, Spotify, BBC, Fox, Niconico, DMM, Viu Pixiv 等" echo read -r -p "请输入解锁选项? 直接回车默认选1 不解锁, 请输入纯数字:" isV2rayUnlockVideoSiteInput isV2rayUnlockVideoSiteInput=${isV2rayUnlockVideoSiteInput:-1} if [[ $isV2rayUnlockVideoSiteInput == "2" ]]; then V2rayUnlockVideoSiteRuleText="\"geosite:hulu\"" elif [[ $isV2rayUnlockVideoSiteInput == "3" ]]; then V2rayUnlockVideoSiteRuleText="\"geosite:hbo\"" elif [[ $isV2rayUnlockVideoSiteInput == "4" ]]; then V2rayUnlockVideoSiteRuleText="\"geosite:bbc\"" elif [[ $isV2rayUnlockVideoSiteInput == "5" ]]; then V2rayUnlockVideoSiteRuleText="\"geosite:hulu\", \"geosite:hbo\" " elif [[ $isV2rayUnlockVideoSiteInput == "6" ]]; then V2rayUnlockVideoSiteRuleText=" \"geosite:hulu\", \"geosite:hbo\" " elif [[ $isV2rayUnlockVideoSiteInput == "7" ]]; then V2rayUnlockVideoSiteRuleText=" \"geosite:hulu\", \"geosite:hbo\" " elif [[ $isV2rayUnlockVideoSiteInput == "8" ]]; then V2rayUnlockVideoSiteRuleText=" \"geosite:hulu\", \"geosite:hbo\" " elif [[ $isV2rayUnlockVideoSiteInput == "9" ]]; then V2rayUnlockVideoSiteRuleText=" \"geosite:hulu\", \"geosite:hbo\", \"geosite:bbc\", \"geosite:4chan\", \"geosite:fox\", \"geosite:abema\", \"geosite:dmm\", \"geosite:niconico\", \"geosite:pixiv\", \"geosite:viu\"" fi if [[ $isV2rayUnlockVideoSiteInput != "1" ]]; then echo green " ==================================================" yellow " 请选择 解锁更多的流媒体和视频网站的方式" echo green " 1. 不使用解锁" green " 2. 使用 IPv6 解锁, 需要配合安装WARP 推荐使用" green " 3. 使用 WARP Sock5 代理解锁" green " 4. 通过转发到可解锁的v2ray或xray服务器解锁" echo read -r -p "请输入? 直接回车默认选1 不解锁, 请输入纯数字:" isV2rayUnlockWarpModeInput isV2rayUnlockWarpModeInput=${isV2rayUnlockWarpModeInput:-1} if [[ $isV2rayUnlockWarpModeInput == "2" ]]; then V2rayUnlockSiteRuleV6Text+=", ${V2rayUnlockVideoSiteRuleText}" elif [[ $isV2rayUnlockWarpModeInput == "3" ]]; then V2rayUnlockSiteRuleSock5Text+=", ${V2rayUnlockVideoSiteRuleText}" inputUnlockWARPSock5Server elif [[ $isV2rayUnlockWarpModeInput == "4" ]]; then V2rayUnlockSiteRuleV2rayServerText+=", ${V2rayUnlockVideoSiteRuleText}" inputUnlockV2rayServerInfo else echo "" fi fi if [ -z "$V2rayUnlockSiteRuleV6Text" ]; then V2rayUnlockSiteRuleV6Text="\"test.com\" " else V2rayUnlockSiteRuleV6TextFirstChar="${V2rayUnlockSiteRuleV6Text:0:1}" if [[ $V2rayUnlockSiteRuleV6TextFirstChar == "," ]]; then V2rayUnlockSiteRuleV6Text="${V2rayUnlockSiteRuleV6Text:1}" fi fi if [ -z "$V2rayUnlockSiteRuleSock5Text" ]; then V2rayUnlockSiteRuleSock5Text="\"test.com\" " else V2rayUnlockSiteRuleSock5TextFirstChar="${V2rayUnlockSiteRuleSock5Text:0:1}" if [[ $V2rayUnlockSiteRuleSock5TextFirstChar == "," ]]; then V2rayUnlockSiteRuleSock5Text="${V2rayUnlockSiteRuleSock5Text:1}" fi fi if [ -z "$V2rayUnlockSiteRuleV2rayServerText" ]; then V2rayUnlockSiteRuleV2rayServerText="\"test.com\" " else V2rayUnlockSiteRuleV2rayServerTextFirstChar="${V2rayUnlockSiteRuleV2rayServerText:0:1}" if [[ $V2rayUnlockSiteRuleV2rayServerTextFirstChar == "," ]]; then V2rayUnlockSiteRuleV2rayServerText="${V2rayUnlockSiteRuleV2rayServerText:1}" fi fi read -r -d '' v2rayConfigRouteInput << EOM "routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "type": "field", "outboundTag": "IPv6_out", "domain": [${V2rayUnlockSiteRuleV6Text}] }, { "type": "field", "outboundTag": "WARP_out", "domain": [${V2rayUnlockSiteRuleSock5Text}] }, { "type": "field", "outboundTag": "V2Ray_out", "domain": [${V2rayUnlockSiteRuleV2rayServerText}] }, ${v2rayConfigRouteGoNetflixInput} { "type": "field", "domain": [ "geosite:cn" ], "outboundTag": "${V2rayBlockChinaSiteRuleText}" }, { "type": "field", "ip": [ "geoip:cn" ], "outboundTag": "${V2rayBlockChinaSiteRuleText}" }, { "type": "field", "outboundTag": "IPv4_out", "network": "udp,tcp" } ] }, EOM } function installV2ray(){ v2rayPassword1=$(cat /proc/sys/kernel/random/uuid) v2rayPassword2=$(cat /proc/sys/kernel/random/uuid) v2rayPassword3=$(cat /proc/sys/kernel/random/uuid) v2rayPassword4=$(cat /proc/sys/kernel/random/uuid) v2rayPassword5=$(cat /proc/sys/kernel/random/uuid) v2rayPassword6=$(cat /proc/sys/kernel/random/uuid) v2rayPassword7=$(cat /proc/sys/kernel/random/uuid) v2rayPassword8=$(cat /proc/sys/kernel/random/uuid) v2rayPassword9=$(cat /proc/sys/kernel/random/uuid) v2rayPassword10=$(cat /proc/sys/kernel/random/uuid) echo if [ -f "${configV2rayPath}/xray" ] || [ -f "${configV2rayPath}/v2ray" ] || [ -f "/usr/local/bin/v2ray" ] || [ -f "/usr/bin/v2ray" ]; then green " ==================================================" green " 已安装过 V2ray 或 Xray, 退出安装 !" green " ==================================================" exit fi green " ==================================================" green " 开始安装 V2ray or Xray " green " ==================================================" echo if [[ ( $configV2rayWorkingMode == "trojan" ) || ( $configV2rayWorkingMode == "vlessTCPVmessWS" ) || ( $configV2rayWorkingMode == "vlessTCPWS" ) || ( $configV2rayWorkingMode == "vlessTCPWSTrojan" ) || ( $configV2rayWorkingMode == "sni" ) ]]; then echo green " 是否使用XTLS代替TLS加密, XTLS是Xray特有的加密方式, 速度更快, 默认使用TLS加密" green " 由于V2ray不支持XTLS, 如果选择XTLS加密将使用Xray内核提供服务" read -p "是否使用XTLS? 直接回车默认为TLS加密, 请输入[y/N]:" isXrayXTLSInput isXrayXTLSInput=${isXrayXTLSInput:-n} if [[ $isXrayXTLSInput == [Yy] ]]; then promptInfoXrayName="xray" isXray="yes" configV2rayIsTlsShowInfo="xtls" else echo read -p "是否使用Xray内核? 直接回车默认为V2ray内核, 请输入[y/N]:" isV2rayOrXrayCoreInput isV2rayOrXrayCoreInput=${isV2rayOrXrayCoreInput:-n} if [[ $isV2rayOrXrayCoreInput == [Yy] ]]; then promptInfoXrayName="xray" isXray="yes" fi fi elif [[ $configV2rayWorkingMode == "vlessTCPVision" ]]; then promptInfoXrayName="xray" isXray="yes" configV2rayIsTlsShowInfo="tls" elif [[ $configV2rayWorkingMode == "vlessTCPREALITY" ]]; then promptInfoXrayName="xray" isXray="yes" configV2rayIsTlsShowInfo="reality" else read -r -p "是否使用Xray内核? 直接回车默认为V2ray内核, 请输入[y/N]:" isV2rayOrXrayCoreInput isV2rayOrXrayCoreInput=${isV2rayOrXrayCoreInput:-n} if [[ $isV2rayOrXrayCoreInput == [Yy] ]]; then promptInfoXrayName="xray" isXray="yes" fi fi if [[ -n "${configV2rayWorkingMode}" ]]; then if [[ "${configV2rayWorkingMode}" != "sni" ]]; then configV2rayProtocol="vless" configV2rayPort=443 configV2rayPortShowInfo=$configV2rayPort inputV2rayServerPort "textMainPort" configV2rayPort=${isV2rayUserPortInput} configV2rayPortShowInfo=${isV2rayUserPortInput} else configV2rayProtocol="vless" configV2rayPortShowInfo=443 configV2rayPortGRPCShowInfo=443 fi else echo read -p "是否使用VLESS协议? 直接回车默认为VMess协议, 请输入[y/N]:" isV2rayUseVLessInput isV2rayUseVLessInput=${isV2rayUseVLessInput:-n} if [[ $isV2rayUseVLessInput == [Yy] ]]; then configV2rayProtocol="vless" else configV2rayProtocol="vmess" fi if [[ ${configInstallNginxMode} == "v2raySSL" ]]; then configV2rayPortShowInfo=443 configV2rayPortGRPCShowInfo=443 else if [[ ${configV2rayWorkingNotChangeMode} == "true" ]]; then configV2rayPortShowInfo=443 configV2rayPortGRPCShowInfo=443 else configV2rayIsTlsShowInfo="none" configV2rayPort="$(($RANDOM + 10000))" configV2rayPortShowInfo=$configV2rayPort inputV2rayServerPort "textMainPort" configV2rayPort=${isV2rayUserPortInput} configV2rayPortShowInfo=${isV2rayUserPortInput} inputV2rayStreamSettings fi fi fi if [[ "$configV2rayWorkingMode" == "sni" ]] ; then configSSLCertPath="${configNginxSNIDomainV2rayCertPath}" configSSLDomain=${configNginxSNIDomainV2ray} fi # 增加任意门 if [[ ${configInstallNginxMode} == "v2raySSL" ]]; then echo else inputV2rayServerPort "textAdditionalPort" if [[ $isV2rayAdditionalPortInput == "999999" ]]; then v2rayConfigAdditionalPortInput="" else read -r -d '' v2rayConfigAdditionalPortInput << EOM , { "listen": "0.0.0.0", "port": ${isV2rayAdditionalPortInput}, "protocol": "dokodemo-door", "settings": { "address": "127.0.0.1", "port": ${configV2rayPort}, "network": "tcp, udp", "followRedirect": false }, "sniffing": { "enabled": true, "destOverride": ["http", "tls"] } } EOM fi fi echo read -p "是否自定义${promptInfoXrayName}的密码? 直接回车默认创建随机密码, 请输入自定义UUID密码:" isV2rayUserPassordInput isV2rayUserPassordInput=${isV2rayUserPassordInput:-''} if [ -z "${isV2rayUserPassordInput}" ]; then isV2rayUserPassordInput="" else v2rayPassword1=${isV2rayUserPassordInput} fi echo echo green " ==================================================" yellow " 是否屏蔽中国回国流量, 根据 geosite:cn 和 geoip:cn 规则判断是否中国回国流量" yellow " 屏蔽中国回国流量, 可以有效防止GFW的检测, 如果挂代理访问中国国内网站 则很容易2次过墙而被检测" echo green " 1. 屏蔽中国回国流量" green " 2. 不屏蔽中国回国流量 中国回国流量走默认 IPv4" green " 3. 不屏蔽中国回国流量 中国回国流量走 IPv6(建议使用WARP IPv6) " echo green " 默认选1 屏蔽回国流量. 选择3 需要先安装好 Wireguard 和 Cloudflare WARP, 可重新运行本脚本选择第1项安装WARP". red " 推荐先安装 Wireguard 与 Cloudflare WARP 后,再安装v2ray或xray. 实际上先安装v2ray或xray, 后安装Wireguard 与 Cloudflare WARP也没问题" echo read -p "请输入? 直接回车默认选1, 请输入纯数字:" isV2rayBlockChinaSiteInput isV2rayBlockChinaSiteInput=${isV2rayBlockChinaSiteInput:-1} V2rayBlockChinaSiteRuleText="blocked_out" if [[ $isV2rayBlockChinaSiteInput == "2" ]]; then V2rayBlockChinaSiteRuleText="IPv4_out" elif [[ $isV2rayBlockChinaSiteInput == "3" ]]; then V2rayBlockChinaSiteRuleText="IPv6_out" else V2rayBlockChinaSiteRuleText="blocked_out" fi echo echo isV2rayUnlockWarpModeInput="1" V2rayDNSUnlockText="UseIPv4" unlockWARPServerIpInput="127.0.0.1" unlockWARPServerPortInput="40000" configWARPPortFilePath="${HOME}/wireguard/warp-port" configWARPPortLocalServerPort="40000" configWARPPortLocalServerText="" if [[ -f "${configWARPPortFilePath}" ]]; then configWARPPortLocalServerPort="$(cat ${configWARPPortFilePath})" configWARPPortLocalServerText="检测到本机已安装 WARP Sock5, 端口号 ${configWARPPortLocalServerPort}" fi echo green " ==================================================" yellow " 是否使用 DNS 解锁 Netflix HBO Disney+ 等流媒体网站" green " 如需解锁请填入 解锁 Netflix 的DNS服务器的IP地址, 例如 8.8.8.8" read -r -p "是否使用DNS解锁流媒体? 直接回车默认不解锁, 解锁请输入DNS服务器的IP地址:" isV2rayUnlockDNSInput isV2rayUnlockDNSInput=${isV2rayUnlockDNSInput:-n} V2rayDNSUnlockText="UseIPv4" v2rayConfigDNSInput="" if [[ "${isV2rayUnlockDNSInput}" == [Nn] ]]; then V2rayDNSUnlockText="UseIPv4" else V2rayDNSUnlockText="UseIP" read -r -d '' v2rayConfigDNSInput << EOM "dns": { "servers": [ { "address": "${isV2rayUnlockDNSInput}", "port": 53, "domains": [ "geosite:netflix", "geosite:youtube", "geosite:bahamut", "geosite:hulu", "geosite:hbo", "geosite:disney", "geosite:bbc", "geosite:4chan", "geosite:fox", "geosite:abema", "geosite:dmm", "geosite:niconico", "geosite:pixiv", "geosite:bilibili", "geosite:viu", "geosite:pornhub" ] }, "localhost" ] }, EOM fi v2rayRouteRule read -r -d '' v2rayConfigOutboundInput << EOM "outbounds": [ { "tag":"IPv4_out", "protocol": "freedom", "settings": { "domainStrategy": "${V2rayDNSUnlockText}" } }, { "tag": "blocked_out", "protocol": "blackhole", "settings": { "response": { "type": "http" } } }, { "tag":"IPv6_out", "protocol": "freedom", "settings": { "domainStrategy": "UseIPv6" } }, ${v2rayConfigOutboundV2rayServerInput} ${v2rayConfigOutboundV2rayGoNetflixServerInput} { "tag": "WARP_out", "protocol": "socks", "settings": { "servers": [ { "address": "${unlockWARPServerIpInput}", "port": ${unlockWARPServerPortInput} } ] }, "streamSettings": { "network": "tcp" } } ] EOM echo green " ==================================================" if [ "$isXray" = "no" ] ; then getV2rayVersion "v2ray" green " 准备下载并安装 V2ray Version: ${versionV2ray} !" promptInfoXrayInstall="V2ray" promptInfoXrayVersion=${versionV2ray} else getV2rayVersion "xray" green " 准备下载并安装 Xray Version: ${versionXray} !" promptInfoXrayInstall="Xray" promptInfoXrayVersion=${versionXray} fi echo mkdir -p "${configV2rayPath}" cd "${configV2rayPath}" || exit rm -rf ${configV2rayPath}/* downloadV2rayXrayBin if [[ "$configV2rayWorkingMode" == "vlessTCPREALITY" ]]; then generateXrayRealityPrivateKey echo green " 请输入回落域名 同时也用于serverName? 默认为www.ebay.com" read -r -p "请输入回落域名, 直接回车默认为 www.ebay.com: " configXrayRealityFallbackDomainNameInput if [ -z "${configXrayRealityFallbackDomainNameInput}" ]; then configXrayRealitySni="www.ebay.com" fi if [[ $configXrayRealityFallbackDomainNameInput =~ $domain_regex ]]; then green "Valid domain name. 输入的域名格式正确 " configXrayRealitySni="$configXrayRealityFallbackDomainNameInput" else red "Invalid domain name. 输入的域名格式不正确 " green "使用 www.ebay.com 作为回落域名 同时也用于serverName " configXrayRealitySni="www.ebay.com" fi echo echo fi # 增加 v2ray 服务器端配置 if [[ "$configV2rayWorkingMode" == "vlessTCPWSTrojan" ]]; then trojanPassword1=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword2=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword3=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword4=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword5=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword6=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword7=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword8=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword9=$(cat /dev/urandom | head -1 | md5sum | head -c 10) trojanPassword10=$(cat /dev/urandom | head -1 | md5sum | head -c 10) echo yellow " 请输入 trojan 密码的前缀? (会生成若干随机密码和带有该前缀的密码)" read -p "请输入密码的前缀, 直接回车默认随机生成前缀:" configTrojanPasswordPrefixInput configTrojanPasswordPrefixInput=${configTrojanPasswordPrefixInput:-${configTrojanPasswordPrefixInputDefault}} fi if [ "${isTrojanMultiPassword}" = "no" ] ; then read -r -d '' v2rayConfigUserpasswordTrojanInput << EOM { "password": "${trojanPassword1}", "level": 0, "email": "password111@gmail.com" }, { "password": "${trojanPassword2}", "level": 0, "email": "password112@gmail.com" }, { "password": "${trojanPassword3}", "level": 0, "email": "password113@gmail.com" }, { "password": "${trojanPassword4}", "level": 0, "email": "password114@gmail.com" }, { "password": "${trojanPassword5}", "level": 0, "email": "password115@gmail.com" }, { "password": "${trojanPassword6}", "level": 0, "email": "password116@gmail.com" }, { "password": "${trojanPassword7}", "level": 0, "email": "password117@gmail.com" }, { "password": "${trojanPassword8}", "level": 0, "email": "password118@gmail.com" }, { "password": "${trojanPassword9}", "level": 0, "email": "password119@gmail.com" }, { "password": "${trojanPassword10}", "level": 0, "email": "password120@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202201", "level": 0, "email": "password201@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202202", "level": 0, "email": "password202@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202203", "level": 0, "email": "password203@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202204", "level": 0, "email": "password204@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202205", "level": 0, "email": "password205@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202206", "level": 0, "email": "password206@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202207", "level": 0, "email": "password207@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202208", "level": 0, "email": "password208@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202209", "level": 0, "email": "password209@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202210", "level": 0, "email": "password210@gmail.com" } EOM else read -r -d '' v2rayConfigUserpasswordTrojanInput << EOM { "password": "${trojanPassword1}", "level": 0, "email": "password111@gmail.com" }, { "password": "${trojanPassword2}", "level": 0, "email": "password112@gmail.com" }, { "password": "${trojanPassword3}", "level": 0, "email": "password113@gmail.com" }, { "password": "${trojanPassword4}", "level": 0, "email": "password114@gmail.com" }, { "password": "${trojanPassword5}", "level": 0, "email": "password115@gmail.com" }, { "password": "${trojanPassword6}", "level": 0, "email": "password116@gmail.com" }, { "password": "${trojanPassword7}", "level": 0, "email": "password117@gmail.com" }, { "password": "${trojanPassword8}", "level": 0, "email": "password118@gmail.com" }, { "password": "${trojanPassword9}", "level": 0, "email": "password119@gmail.com" }, { "password": "${trojanPassword10}", "level": 0, "email": "password120@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202200", "level": 0, "email": "password200@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202201", "level": 0, "email": "password201@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202202", "level": 0, "email": "password202@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202203", "level": 0, "email": "password203@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202204", "level": 0, "email": "password204@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202205", "level": 0, "email": "password205@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202206", "level": 0, "email": "password206@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202207", "level": 0, "email": "password207@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202208", "level": 0, "email": "password208@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202209", "level": 0, "email": "password209@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202210", "level": 0, "email": "password210@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202211", "level": 0, "email": "password211@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202212", "level": 0, "email": "password212@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202213", "level": 0, "email": "password213@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202214", "level": 0, "email": "password214@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202215", "level": 0, "email": "password215@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202216", "level": 0, "email": "password216@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202217", "level": 0, "email": "password217@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202218", "level": 0, "email": "password218@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202219", "level": 0, "email": "password219@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202220", "level": 0, "email": "password220@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202221", "level": 0, "email": "password221@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202222", "level": 0, "email": "password222@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202223", "level": 0, "email": "password223@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202224", "level": 0, "email": "password224@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202225", "level": 0, "email": "password225@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202226", "level": 0, "email": "password226@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202227", "level": 0, "email": "password227@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202228", "level": 0, "email": "password228@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202229", "level": 0, "email": "password229@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202230", "level": 0, "email": "password230@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202231", "level": 0, "email": "password231@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202232", "level": 0, "email": "password232@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202233", "level": 0, "email": "password233@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202234", "level": 0, "email": "password234@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202235", "level": 0, "email": "password235@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202236", "level": 0, "email": "password236@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202237", "level": 0, "email": "password237@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202238", "level": 0, "email": "password238@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202239", "level": 0, "email": "password239@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202240", "level": 0, "email": "password240@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202241", "level": 0, "email": "password241@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202242", "level": 0, "email": "password242@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202243", "level": 0, "email": "password243@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202244", "level": 0, "email": "password244@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202245", "level": 0, "email": "password245@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202246", "level": 0, "email": "password246@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202247", "level": 0, "email": "password247@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202248", "level": 0, "email": "password248@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202249", "level": 0, "email": "password249@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202250", "level": 0, "email": "password250@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202251", "level": 0, "email": "password251@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202252", "level": 0, "email": "password252@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202253", "level": 0, "email": "password253@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202254", "level": 0, "email": "password254@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202255", "level": 0, "email": "password255@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202256", "level": 0, "email": "password256@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202257", "level": 0, "email": "password257@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202258", "level": 0, "email": "password258@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202259", "level": 0, "email": "password259@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202260", "level": 0, "email": "password260@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202261", "level": 0, "email": "password261@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202262", "level": 0, "email": "password262@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202263", "level": 0, "email": "password263@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202264", "level": 0, "email": "password264@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202265", "level": 0, "email": "password265@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202266", "level": 0, "email": "password266@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202267", "level": 0, "email": "password267@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202268", "level": 0, "email": "password268@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202269", "level": 0, "email": "password269@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202270", "level": 0, "email": "password270@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202271", "level": 0, "email": "password271@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202272", "level": 0, "email": "password272@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202273", "level": 0, "email": "password273@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202274", "level": 0, "email": "password274@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202275", "level": 0, "email": "password275@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202276", "level": 0, "email": "password276@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202277", "level": 0, "email": "password277@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202278", "level": 0, "email": "password278@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202279", "level": 0, "email": "password279@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202280", "level": 0, "email": "password280@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202281", "level": 0, "email": "password281@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202282", "level": 0, "email": "password282@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202283", "level": 0, "email": "password283@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202284", "level": 0, "email": "password284@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202285", "level": 0, "email": "password285@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202286", "level": 0, "email": "password286@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202287", "level": 0, "email": "password287@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202288", "level": 0, "email": "password288@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202289", "level": 0, "email": "password289@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202290", "level": 0, "email": "password290@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202291", "level": 0, "email": "password291@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202292", "level": 0, "email": "password292@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202293", "level": 0, "email": "password293@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202294", "level": 0, "email": "password294@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202295", "level": 0, "email": "password295@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202296", "level": 0, "email": "password296@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202297", "level": 0, "email": "password297@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202298", "level": 0, "email": "password298@gmail.com" }, { "password": "${configTrojanPasswordPrefixInput}202299", "level": 0, "email": "password299@gmail.com" } EOM fi if [[ "${configV2rayIsTlsShowInfo}" == "xtls" ]]; then read -r -d '' v2rayConfigUserpasswordInput << EOM { "id": "${v2rayPassword1}", "flow": "xtls-rprx-direct", "level": 0, "email": "password11@gmail.com" }, { "id": "${v2rayPassword2}", "flow": "xtls-rprx-direct", "level": 0, "email": "password12@gmail.com" }, { "id": "${v2rayPassword3}", "flow": "xtls-rprx-direct", "level": 0, "email": "password13@gmail.com" }, { "id": "${v2rayPassword4}", "flow": "xtls-rprx-direct", "level": 0, "email": "password14@gmail.com" }, { "id": "${v2rayPassword5}", "flow": "xtls-rprx-direct", "level": 0, "email": "password15@gmail.com" }, { "id": "${v2rayPassword6}", "flow": "xtls-rprx-direct", "level": 0, "email": "password16@gmail.com" }, { "id": "${v2rayPassword7}", "flow": "xtls-rprx-direct", "level": 0, "email": "password17@gmail.com" }, { "id": "${v2rayPassword8}", "flow": "xtls-rprx-direct", "level": 0, "email": "password18@gmail.com" }, { "id": "${v2rayPassword9}", "flow": "xtls-rprx-direct", "level": 0, "email": "password19@gmail.com" }, { "id": "${v2rayPassword10}", "flow": "xtls-rprx-direct", "level": 0, "email": "password20@gmail.com" } EOM elif [[ "${configV2rayWorkingMode}" == "vlessTCPVision" || "${configV2rayWorkingMode}" == "vlessTCPREALITY" ]]; then read -r -d '' v2rayConfigUserpasswordInput << EOM { "id": "${v2rayPassword1}", "flow": "xtls-rprx-vision", "level": 0, "email": "password11@gmail.com" }, { "id": "${v2rayPassword2}", "flow": "xtls-rprx-vision", "level": 0, "email": "password12@gmail.com" }, { "id": "${v2rayPassword3}", "flow": "xtls-rprx-vision", "level": 0, "email": "password13@gmail.com" }, { "id": "${v2rayPassword4}", "flow": "xtls-rprx-vision", "level": 0, "email": "password14@gmail.com" }, { "id": "${v2rayPassword5}", "flow": "xtls-rprx-vision", "level": 0, "email": "password15@gmail.com" }, { "id": "${v2rayPassword6}", "flow": "xtls-rprx-vision", "level": 0, "email": "password16@gmail.com" }, { "id": "${v2rayPassword7}", "flow": "xtls-rprx-vision", "level": 0, "email": "password17@gmail.com" }, { "id": "${v2rayPassword8}", "flow": "xtls-rprx-vision", "level": 0, "email": "password18@gmail.com" }, { "id": "${v2rayPassword9}", "flow": "xtls-rprx-vision", "level": 0, "email": "password19@gmail.com" }, { "id": "${v2rayPassword10}", "flow": "xtls-rprx-vision", "level": 0, "email": "password20@gmail.com" } EOM else read -r -d '' v2rayConfigUserpasswordInput << EOM { "id": "${v2rayPassword1}", "level": 0, "email": "password11@gmail.com" }, { "id": "${v2rayPassword2}", "level": 0, "email": "password12@gmail.com" }, { "id": "${v2rayPassword3}", "level": 0, "email": "password13@gmail.com" }, { "id": "${v2rayPassword4}", "level": 0, "email": "password14@gmail.com" }, { "id": "${v2rayPassword5}", "level": 0, "email": "password15@gmail.com" }, { "id": "${v2rayPassword6}", "level": 0, "email": "password16@gmail.com" }, { "id": "${v2rayPassword7}", "level": 0, "email": "password17@gmail.com" }, { "id": "${v2rayPassword8}", "level": 0, "email": "password18@gmail.com" }, { "id": "${v2rayPassword9}", "level": 0, "email": "password19@gmail.com" }, { "id": "${v2rayPassword10}", "level": 0, "email": "password20@gmail.com" } EOM fi v2rayConfigInboundInput="" if [[ "${configV2rayStreamSetting}" == "grpc" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayGRPCPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "grpc", "security": "none", "grpcSettings": { "serviceName": "${configV2rayGRPCServiceName}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "ws" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "path": "/${configV2rayWebSocketPath}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "wsgrpc" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "path": "/${configV2rayWebSocketPath}" } } }, { "port": ${configV2rayGRPCPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "grpc", "security": "none", "grpcSettings": { "serviceName": "${configV2rayGRPCServiceName}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "tcp" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "tcp", "security": "none", "tcpSettings": { "acceptProxyProtocol": false, "header": { "type": "none" } } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "kcp" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "kcp", "security": "none", "kcpSettings": { "seed": "${configV2rayKCPSeedPassword}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "h2" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "h2", "security": "none", "httpSettings": { "path": "/${configV2rayWebSocketPath}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "${configV2rayStreamSetting}" == "quic" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "quic", "security": "none", "quicSettings": { "security": "aes-128-gcm", "key": "${configV2rayKCPSeedPassword}", "header": { "type": "none" } } } } ${v2rayConfigAdditionalPortInput} ], EOM fi if [[ "$configV2rayWorkingMode" == "vlessTCPVmessWS" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 }, { "path": "/${configV2rayWebSocketPath}", "dest": ${configV2rayVmesWSPort}, "xver": 1 }, { "path": "/tcp${configV2rayWebSocketPath}", "dest": ${configV2rayVmessTCPPort}, "xver": 1 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "alpn": [ "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } } }, { "port": ${configV2rayVmesWSPort}, "listen": "127.0.0.1", "protocol": "vmess", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ] }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "acceptProxyProtocol": true, "path": "/${configV2rayWebSocketPath}" } } }, { "port": ${configV2rayVmessTCPPort}, "listen": "127.0.0.1", "protocol": "vmess", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ] }, "streamSettings": { "network": "tcp", "security": "none", "tcpSettings": { "acceptProxyProtocol": true, "header": { "type": "http", "request": { "path": [ "/tcp${configV2rayWebSocketPath}" ] } } } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "$configV2rayWorkingMode" == "vlessgRPC" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 } ] }, "streamSettings": { "network": "grpc", "security": "tls", "tlsSettings": { "alpn": [ "h2", "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] }, "grpcSettings": { "serviceName": "${configV2rayGRPCServiceName}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ $configV2rayWorkingMode == "vlessTCPWS" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 }, { "path": "/${configV2rayWebSocketPath}", "dest": ${configV2rayVmesWSPort}, "xver": 1 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "alpn": [ "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } } }, { "port": ${configV2rayVmesWSPort}, "listen": "127.0.0.1", "protocol": "vless", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "acceptProxyProtocol": true, "path": "/${configV2rayWebSocketPath}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "$configV2rayWorkingMode" == "vlessTCPVision" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "rejectUnknownSni": true, "minVersion": "1.2", "alpn": [ "http/1.1", "h2" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } } ${v2rayConfigAdditionalPortInput} ], "policy": { "levels": { "0": { "handshake": 5, "connIdle": 310 } } }, EOM elif [[ "$configV2rayWorkingMode" == "vlessTCPREALITY" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "show": false, "dest": "${configXrayRealitySni}:443", "xver": 0, "serverNames": [ "${configXrayRealitySni}", "icloud.com", "www.icloud.com", "apple.com", "www.apple.com", "mozilla.org", "addons.mozilla.org", "ebay.com", "www.ebay.com", "walmart.com", "www.walmart.com", "etsy.com", "www.etsy.com", "shopify.com", "www.shopify.com", "samsung.com", "www.samsung.com", "airbnb.com", "www.airbnb.com", "asml.com", "www.asml.com", "tsmc.com", "www.tsmc.com", "pfizer.com", "www.pfizer.com", "microsoft.com", "www.microsoft.com", "support.microsoft.com", "office.com", "www.office.com", "signup.live.com", "www.live.com", "outlook.live.com", "lovelive-anime.jp", "s0.awsstatic.com", "d1.awsstatic.com", "amazon.com", "m.media-amazon.com" ], "privateKey": "${xrayRealityPrivateKey}", "maxTimeDiff": 0, "shortIds": [ "", "${xrayRealityShortId}" ] } }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ "$configV2rayWorkingMode" == "sni" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 }, { "path": "/${configV2rayWebSocketPath}", "dest": ${configV2rayVmesWSPort}, "xver": 1 }, { "path": "/${configV2rayGRPCServiceName}", "dest": ${configV2rayGRPCPort}, "xver": 1 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "alpn": [ "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } } }, { "port": ${configV2rayVmesWSPort}, "listen": "127.0.0.1", "protocol": "vless", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "acceptProxyProtocol": true, "path": "/${configV2rayWebSocketPath}" } } }, { "port": ${configV2rayGRPCPort}, "protocol": "vless", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "grpc", "security": "none", "grpcSettings": { "serviceName": "${configV2rayGRPCServiceName}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ $configV2rayWorkingMode == "vlessTCPWSTrojan" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": ${configV2rayTrojanPort}, "xver": 1 }, { "path": "/${configV2rayWebSocketPath}", "dest": ${configV2rayVmesWSPort}, "xver": 1 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "alpn": [ "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } } }, { "port": ${configV2rayTrojanPort}, "listen": "127.0.0.1", "protocol": "trojan", "settings": { "clients": [ ${v2rayConfigUserpasswordTrojanInput} ], "fallbacks": [ { "dest": 80 } ] }, "streamSettings": { "network": "tcp", "security": "none", "tcpSettings": { "acceptProxyProtocol": true } } }, { "port": ${configV2rayVmesWSPort}, "listen": "127.0.0.1", "protocol": "vless", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "acceptProxyProtocol": true, "path": "/${configV2rayWebSocketPath}" } } } ${v2rayConfigAdditionalPortInput} ], EOM elif [[ $configV2rayWorkingMode == "trojan" ]]; then read -r -d '' v2rayConfigInboundInput << EOM "inbounds": [ { "port": ${configV2rayPort}, "protocol": "${configV2rayProtocol}", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none", "fallbacks": [ { "dest": 80 }, { "path": "/${configTrojanGoWebSocketPath}", "dest": ${configV2rayTrojanPort}, "xver": 1 }, { "path": "/${configV2rayWebSocketPath}", "dest": ${configV2rayVmesWSPort}, "xver": 1 } ] }, "streamSettings": { "network": "tcp", "security": "${configV2rayIsTlsShowInfo}", "${configV2rayIsTlsShowInfo}Settings": { "alpn": [ "http/1.1" ], "certificates": [ { "certificateFile": "${configSSLCertPath}/$configSSLCertFullchainFilename", "keyFile": "${configSSLCertPath}/$configSSLCertKeyFilename" } ] } } }, { "port": ${configV2rayVmesWSPort}, "listen": "127.0.0.1", "protocol": "vless", "settings": { "clients": [ ${v2rayConfigUserpasswordInput} ], "decryption": "none" }, "streamSettings": { "network": "ws", "security": "none", "wsSettings": { "acceptProxyProtocol": true, "path": "/${configV2rayWebSocketPath}" } } } ${v2rayConfigAdditionalPortInput} ], EOM fi cat > ${configV2rayPath}/config.json <<-EOF { "log" : { "access": "${configV2rayAccessLogFilePath}", "error": "${configV2rayErrorLogFilePath}", "loglevel": "warning" }, ${v2rayConfigDNSInput} ${v2rayConfigInboundInput} ${v2rayConfigRouteInput} ${v2rayConfigOutboundInput} } EOF systemmdServiceFixV2ray5="run" if [[ $versionV2ray == "4.45.2" ]]; then systemmdServiceFixV2ray5="" fi # 增加 V2ray启动脚本 if [ "$isXray" = "no" ] ; then cat > ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service <<-EOF [Unit] Description=V2Ray Documentation=https://www.v2fly.org/ After=network.target nss-lookup.target [Service] Type=simple # This service runs as root. You may consider to run it as another user for security concerns. # By uncommenting User=nobody and commenting out User=root, the service will run as user nobody. # More discussion at https://github.com/v2ray/v2ray-core/issues/1011 User=root #User=nobody #CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE NoNewPrivileges=true ExecStart=${configV2rayPath}/v2ray ${systemmdServiceFixV2ray5} -config ${configV2rayPath}/config.json Restart=on-failure RestartPreventExitStatus=23 [Install] WantedBy=multi-user.target EOF else cat > ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service <<-EOF [Unit] Description=Xray Documentation=https://xtls.github.io/ After=network.target nss-lookup.target [Service] Type=simple # This service runs as root. You may consider to run it as another user for security concerns. # By uncommenting User=nobody and commenting out User=root, the service will run as user nobody. # More discussion at https://github.com/v2ray/v2ray-core/issues/1011 User=root #User=nobody #CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE NoNewPrivileges=true ExecStart=${configV2rayPath}/xray run -config ${configV2rayPath}/config.json Restart=on-failure RestartPreventExitStatus=23 [Install] WantedBy=multi-user.target EOF fi ${sudoCmd} chmod +x ${configV2rayPath}/${promptInfoXrayName} ${sudoCmd} chmod +x ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl enable ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${sudoCmd} systemctl restart ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service generateVLessImportLink if [[ "${configV2rayStreamSetting}" == "tcp" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: tcp, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "${configV2rayStreamSetting}" == "kcp" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: kcp, 底层传输协议: ${configV2rayIsTlsShowInfo}, seed 混淆密码: "${configV2rayKCPSeedPassword}", 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "${configV2rayStreamSetting}" == "h2" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: h2, 底层传输协议: ${configV2rayIsTlsShowInfo}, path路径:/${configV2rayWebSocketPath}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "${configV2rayStreamSetting}" == "quic" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: quic, 底层传输协议: ${configV2rayIsTlsShowInfo}, Quic security: none, key 加密时所用的密钥: "${configV2rayKCPSeedPassword}", 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "${configV2rayStreamSetting}" == "grpc" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortGRPCShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: gRPC, gRPC serviceName: ${configV2rayGRPCServiceName}, // serviceName 不能有/ 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "${configV2rayStreamSetting}" == "wsgrpc" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall} 客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall} gRPC 客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortGRPCShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: gRPC, gRPC serviceName: ${configV2rayGRPCServiceName}, // serviceName 不能有/ 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR2} 导入链接 Vless 格式: ${v2rayVlessLinkQR2} EOF elif [[ "${configV2rayStreamSetting}" == "ws" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端配置参数 ============= { 协议: ${configV2rayProtocol}, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id/AlterID: 0, // AlterID, Vmess 请填0, 如果是Vless协议则不需要该项 加密方式: aes-128-gcm, // 如果是Vless协议则为none 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF fi if [[ "$configV2rayWorkingMode" == "vlessTCPVmessWS" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-TLS) + (VMess-TCP-TLS) + (VMess-WS-TLS) 支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-TLS 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, // 如果是Vless协议则为none 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VMess-WS-TLS 配置参数 支持CDN ============= { 协议: VMess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 加密方式: auto, // 如果是Vless协议则为none 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VMess-TCP-TLS 配置参数 支持CDN ============= { 协议: VMess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 加密方式: auto, // 如果是Vless协议则为none 传输协议: tcp, 伪装类型: http, 路径:/tcp${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接 Vmess Base64 格式: ${v2rayVmessLinkQR2} EOF elif [[ "$configV2rayWorkingMode" == "vlessgRPC" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-gRPC-TLS) 支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-gRPC-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: gRPC, gRPC serviceName: ${configV2rayGRPCServiceName}, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "$configV2rayWorkingMode" == "vlessTCPWS" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-TLS) + (VLess-WS-TLS) 支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-TLS 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VLess-WS-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接 Vless 格式: vless://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=tls&type=ws&host=${configSSLDomain}&path=%2f${configV2rayWebSocketPath}#${configSSLDomain}+WebSocket_tls EOF elif [[ "$configV2rayWorkingMode" == "vlessTCPVision" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-XTLS Vision) 不支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-XTLS Vision 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, fingerprint: chrome, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "$configV2rayWorkingMode" == "vlessTCPREALITY" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-REALITY XTLS Vision) 不支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-REALITY XTLS Vision 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: tcp, websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, fingerprint: chrome, serverNames: ${configXrayRealitySni}, publicKey: ${xrayRealityPublicKey}, shortId: ${xrayRealityShortId}, 别名:自己起个任意名称 } serverNames 还可以填入以下任意一个网站: icloud.com www.icloud.com apple.com www.apple.com mozilla.org addons.mozilla.org ebay.com www.ebay.com walmart.com www.walmart.com etsy.com www.etsy.com shopify.com www.shopify.com samsung.com www.samsung.com airbnb.com www.airbnb.com asml.com www.asml.com tsmc.com www.tsmc.com pfizer.com www.pfizer.com microsoft.com www.microsoft.com support.microsoft.com office.com www.office.com signup.live.com www.live.com outlook.live.com lovelive-anime.jp s0.awsstatic.com d1.awsstatic.com amazon.com m.media-amazon.com 导入链接 Vless 格式: ${v2rayVlessLinkQR1} EOF elif [[ "$configV2rayWorkingMode" == "sni" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-TLS) + (VLess-WS-TLS) + (VLess-gRPC-TLS)支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-TLS 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: 空 加密方式: none, 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VLess-WS-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接 Vless 格式: vless://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=tls&type=ws&host=${configSSLDomain}&path=%2f${configV2rayWebSocketPath}#${configSSLDomain}+WebSocket_tls =========== ${promptInfoXrayInstall}客户端 VLess-gRPC-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPortShowInfo}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: 空, 加密方式: none, 传输协议: gRPC, gRPC serviceName: ${configV2rayGRPCServiceName}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接 Vless 格式: vless://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPortShowInfo}?encryption=none&security=tls&type=grpc&serviceName=${configV2rayGRPCServiceName}&host=${configSSLDomain}#${configSSLDomain}+gRPC_tls EOF elif [[ "$configV2rayWorkingMode" == "vlessTCPWSTrojan" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF VLess运行在${configV2rayPortShowInfo}端口 (VLess-TCP-TLS) + (VLess-WS-TLS) + (Trojan)支持CDN =========== ${promptInfoXrayInstall}客户端 VLess-TCP-TLS 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: xtls-rprx-direct 加密方式: none, 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VLess-WS-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接: vless://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPort}?encryption=none&security=tls&type=ws&host=${configSSLDomain}&path=%2f${configV2rayWebSocketPath}#${configSSLDomain}+WebSocket_tls =========== Trojan${promptInfoTrojanName}服务器地址: ${configSSLDomain} 端口: $configV2rayPort 密码1: ${trojanPassword1} 密码2: ${trojanPassword2} 密码3: ${trojanPassword3} 密码4: ${trojanPassword4} 密码5: ${trojanPassword5} 密码6: ${trojanPassword6} 密码7: ${trojanPassword7} 密码8: ${trojanPassword8} 密码9: ${trojanPassword9} 密码10: ${trojanPassword10} 您指定前缀的密码共10个: 从 ${configTrojanPasswordPrefixInput}202201 到 ${configTrojanPasswordPrefixInput}202210 都可以使用 例如: 密码:${configTrojanPasswordPrefixInput}202202 或 密码:${configTrojanPasswordPrefixInput}202209 都可以使用 小火箭链接: trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayPort}?peer=${configSSLDomain}&sni=${configSSLDomain}#${configSSLDomain}_trojan 二维码 Trojan${promptInfoTrojanName} https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayPort}%3fpeer%3d${configSSLDomain}%26sni%3d${configSSLDomain}%23${configSSLDomain}_trojan EOF elif [[ "$configV2rayWorkingMode" == "trojan" ]]; then cat > ${configV2rayPath}/clientConfig.json <<-EOF =========== ${promptInfoXrayInstall}客户端 VLess-TCP-TLS 配置参数 ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: xtls-rprx-direct 加密方式: none, 传输协议: tcp , websocket路径:无, 底层传输协议: ${configV2rayIsTlsShowInfo}, 别名:自己起个任意名称 } 导入链接 Vless 格式: ${v2rayVlessLinkQR1} =========== ${promptInfoXrayInstall}客户端 VLess-WS-TLS 配置参数 支持CDN ============= { 协议: VLess, 地址: ${configSSLDomain}, 端口: ${configV2rayPort}, uuid: ${v2rayPassword1}, 额外id: 0, // AlterID 如果是Vless协议则不需要该项 流控flow: ${configV2rayVlessXtlsFlowShowInfo}, 加密方式: none, 传输协议: websocket, websocket路径:/${configV2rayWebSocketPath}, 底层传输协议:tls, 别名:自己起个任意名称 } 导入链接: vless://${v2rayPassword1UrlEncoded}@${configSSLDomain}:${configV2rayPort}?encryption=none&security=tls&type=ws&host=${configSSLDomain}&path=%2f${configV2rayWebSocketPath}#${configSSLDomain}+WebSocket_tls =========== Trojan${promptInfoTrojanName}服务器地址: ${configSSLDomain} 端口: $configV2rayTrojanPort 密码1: ${trojanPassword1} 密码2: ${trojanPassword2} 密码3: ${trojanPassword3} 密码4: ${trojanPassword4} 密码5: ${trojanPassword5} 密码6: ${trojanPassword6} 密码7: ${trojanPassword7} 密码8: ${trojanPassword8} 密码9: ${trojanPassword9} 密码10: ${trojanPassword10} 您指定前缀的密码共10个: 从 ${configTrojanPasswordPrefixInput}202201 到 ${configTrojanPasswordPrefixInput}202210 都可以使用 例如: 密码:${configTrojanPasswordPrefixInput}202202 或 密码:${configTrojanPasswordPrefixInput}202209 都可以使用 小火箭链接: trojan://${trojanPassword1}@${configSSLDomain}:${configV2rayTrojanPort}?peer=${configSSLDomain}&sni=${configSSLDomain}#${configSSLDomain}_trojan 二维码 Trojan${promptInfoTrojanName} https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=trojan%3a%2f%2f${trojanPassword1}%40${configSSLDomain}%3a${configV2rayTrojanPort}%3fpeer%3d${configSSLDomain}%26sni%3d${configSSLDomain}%23${configSSLDomain}_trojan EOF fi # 设置 cron 定时任务 # https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job (crontab -l ; echo "10 4 * * 0,1,2,3,4,5,6 rm -f /root/v2ray-*") | sort - | uniq - | crontab - (crontab -l ; echo "20 4 * * 0,1,2,3,4,5,6 systemctl restart ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service") | sort - | uniq - | crontab - green "======================================================================" green " ${promptInfoXrayInstall} Version: ${promptInfoXrayVersion} 安装成功 !" if [[ -n ${configInstallNginxMode} ]]; then green " 伪装站点为 https://${configSSLDomain}!" green " 伪装站点的静态html内容放置在目录 ${configWebsitePath}, 可自行更换网站内容!" fi red " ${promptInfoXrayInstall} 服务器端配置路径 ${configV2rayPath}/config.json !" green " ${promptInfoXrayInstall} 访问日志 ${configV2rayAccessLogFilePath} !" green " ${promptInfoXrayInstall} 错误日志 ${configV2rayErrorLogFilePath} ! " green " ${promptInfoXrayInstall} 查看日志命令: journalctl -n 50 -u ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service " green " ${promptInfoXrayInstall} 停止命令: systemctl stop ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service 启动命令: systemctl start ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service " green " ${promptInfoXrayInstall} 重启命令: systemctl restart ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service" green " ${promptInfoXrayInstall} 查看运行状态命令: systemctl status ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service " green " ${promptInfoXrayInstall} 服务器 每天会自动重启, 防止内存泄漏. 运行 crontab -l 命令 查看定时重启命令 !" green "======================================================================" echo "" yellow "${promptInfoXrayInstall} 配置信息如下, 请自行复制保存, 密码任选其一 (密码即用户ID或UUID) !!" yellow "服务器地址: ${configSSLDomain} 端口: ${configV2rayPortShowInfo}" yellow "用户ID或密码1: ${v2rayPassword1}" yellow "用户ID或密码2: ${v2rayPassword2}" yellow "用户ID或密码3: ${v2rayPassword3}" yellow "用户ID或密码4: ${v2rayPassword4}" yellow "用户ID或密码5: ${v2rayPassword5}" yellow "用户ID或密码6: ${v2rayPassword6}" yellow "用户ID或密码7: ${v2rayPassword7}" yellow "用户ID或密码8: ${v2rayPassword8}" yellow "用户ID或密码9: ${v2rayPassword9}" yellow "用户ID或密码10: ${v2rayPassword10}" echo "" cat "${configV2rayPath}/clientConfig.json" echo "" green "======================================================================" green "请下载相应的 ${promptInfoXrayName} 客户端:" yellow "1 Windows 客户端V2rayN下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/v2ray-windows.zip" yellow "2 MacOS 客户端下载:http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/v2ray-mac.zip" yellow "3 Android 客户端下载 https://github.com/2dust/v2rayNG/releases" #yellow "3 Android 客户端下载 http://${configSSLDomain}/download/${configTrojanWindowsCliPrefixPath}/v2ray-android.zip" yellow "4 iOS 客户端 请安装小火箭 https://shadowsockshelp.github.io/ios/ " yellow " iOS 请安装小火箭另一个地址 https://lueyingpro.github.io/shadowrocket/index.html " yellow " iOS 安装小火箭遇到问题 教程 https://github.com/shadowrocketHelp/help/ " yellow "全平台客户端程序汇总 https://tlanyan.pp.ua/v2ray-clients-download/ " yellow "其他客户端程序请看 https://www.v2fly.org/awesome/tools.html " green "======================================================================" cat >> ${configReadme} <<-EOF ${promptInfoXrayInstall} Version: ${promptInfoXrayVersion} 安装成功 ! ${promptInfoXrayInstall} 服务器端配置路径 ${configV2rayPath}/config.json ${promptInfoXrayInstall} 访问日志 ${configV2rayAccessLogFilePath} ${promptInfoXrayInstall} 错误日志 ${configV2rayErrorLogFilePath} ${promptInfoXrayInstall} 查看日志命令: journalctl -n 50 -u ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${promptInfoXrayInstall} 启动命令: systemctl start ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${promptInfoXrayInstall} 停止命令: systemctl stop ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${promptInfoXrayInstall} 重启命令: systemctl restart ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${promptInfoXrayInstall} 查看运行状态命令: systemctl status ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${promptInfoXrayInstall} 配置信息如下, 请自行复制保存, 密码任选其一 (密码即用户ID或UUID) ! 服务器地址: ${configSSLDomain} 端口: ${configV2rayPortShowInfo} 用户ID或密码1: ${v2rayPassword1} 用户ID或密码2: ${v2rayPassword2} 用户ID或密码3: ${v2rayPassword3} 用户ID或密码4: ${v2rayPassword4} 用户ID或密码5: ${v2rayPassword5} 用户ID或密码6: ${v2rayPassword6} 用户ID或密码7: ${v2rayPassword7} 用户ID或密码8: ${v2rayPassword8} 用户ID或密码9: ${v2rayPassword9} 用户ID或密码10: ${v2rayPassword10} EOF cat "${configV2rayPath}/clientConfig.json" >> ${configReadme} } function removeV2ray(){ green " ================================================== " green " Are you sure to remove V2ray or Xray ? " echo read -r -p "是否确认卸载 V2ray 或 Xray? 直接回车默认卸载, 请输入[Y/n]:" isRemoveV2rayServerInput isRemoveV2rayServerInput=${isRemoveV2rayServerInput:-Y} if [[ "${isRemoveV2rayServerInput}" == [Yy] ]]; then if [[ -f "${configV2rayPath}/xray" || -f "${configV2rayPath}/v2ray" ]]; then tempIsXrayService=$(ls ${osSystemMdPath} | grep v2ray- ) if [ -f "${configV2rayPath}/xray" ]; then promptInfoXrayName="xray" isXray="yes" tempIsXrayService=$(ls ${osSystemMdPath} | grep xray- ) fi if [[ -z "${tempIsXrayService}" ]]; then promptInfoXrayNameServiceName="" else if [ -f "${osSystemMdPath}${promptInfoXrayName}-jin.service" ]; then promptInfoXrayNameServiceName="-jin" else tempFilelist=$(ls /usr/lib/systemd/system | grep ${promptInfoXrayName} | awk -F '-' '{ print $2 }' ) promptInfoXrayNameServiceName="-${tempFilelist%.*}" fi fi showHeaderRed "准备卸载已安装 ${promptInfoXrayName}${promptInfoXrayNameServiceName} " ${sudoCmd} systemctl stop ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service ${sudoCmd} systemctl disable ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service rm -rf ${configV2rayPath} rm -f ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service rm -f ${configV2rayAccessLogFilePath} rm -f ${configV2rayErrorLogFilePath} crontab -l | grep -v "rm" | crontab - crontab -l | grep -v "${promptInfoXrayName}${promptInfoXrayNameServiceName}" | crontab - showHeaderGreen " ${promptInfoXrayName}${promptInfoXrayNameServiceName} 卸载完毕 !" else showHeaderRed " 系统没有安装 ${promptInfoXrayName}${promptInfoXrayNameServiceName}, 退出卸载" fi echo fi } function upgradeV2ray(){ if [[ -f "${configV2rayPath}/xray" || -f "${configV2rayPath}/v2ray" ]]; then tempIsXrayService=$(ls ${osSystemMdPath} | grep v2ray- ) if [ -f "${configV2rayPath}/xray" ]; then promptInfoXrayName="xray" isXray="yes" tempIsXrayService=$(ls ${osSystemMdPath} | grep xray- ) fi if [[ -z "${tempIsXrayService}" ]]; then promptInfoXrayNameServiceName="" else if [ -f "${osSystemMdPath}${promptInfoXrayName}-jin.service" ]; then promptInfoXrayNameServiceName="-jin" else tempFilelist=$(ls /usr/lib/systemd/system | grep ${promptInfoXrayName} | awk -F '-' '{ print $2 }' ) promptInfoXrayNameServiceName="-${tempFilelist%.*}" fi fi if [ "$isXray" = "no" ] ; then getV2rayVersion "v2ray" green " ==================================================" green " 开始升级 V2ray Version: ${versionV2ray} !" green " ==================================================" else getV2rayVersion "xray" "update" green " ==================================================" green " 开始升级 Xray Version: ${versionXray} !" green " ==================================================" fi ${sudoCmd} systemctl stop ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service mkdir -p ${configDownloadTempPath}/upgrade/${promptInfoXrayName} downloadV2rayXrayBin "upgrade" ${sudoCmd} chmod +x ${configV2rayPath}/${promptInfoXrayName} systemmdServiceFixV2ray5="run" if [[ $versionV2ray == "4.45.2" ]]; then systemmdServiceFixV2ray5="" sed -i 's/run -config/-config/g' ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service else sed -i 's/run -config/-config/g' ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service sed -i 's/-config/run -config/g' ${osSystemMdPath}${promptInfoXrayName}${promptInfoXrayNameServiceName}.service fi ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl start ${promptInfoXrayName}${promptInfoXrayNameServiceName}.service if [ "$isXray" = "no" ] ; then green " ================================================== " green " 升级成功 V2ray Version: ${versionV2ray} !" green " ================================================== " else green " ==================================================" green " 升级成功 Xray Version: ${versionXray} !" green " ==================================================" fi else red " 系统没有安装 ${promptInfoXrayName}${promptInfoXrayNameServiceName}, 退出卸载" fi echo } function downloadTrojanWebBin(){ # https://github.com/Jrohy/trojan/releases/download/v2.12.2/trojan-linux-amd64 # https://github.com/Jrohy/trojan/releases/download/v2.12.2/trojan-linux-arm64 if [[ ${osArchitecture} == "arm" || ${osArchitecture} == "arm64" ]] ; then downloadFilenameTrojanWeb="trojan-linux-arm64" fi if [ -z $1 ]; then wget -O ${configTrojanWebPath}/trojan-web --no-check-certificate "https://github.com/Jrohy/trojan/releases/download/v${versionTrojanWeb}/${downloadFilenameTrojanWeb}" else wget -O ${configDownloadTempPath}/upgrade/trojan-web/trojan-web "https://github.com/Jrohy/trojan/releases/download/v${versionTrojanWeb}/${downloadFilenameTrojanWeb}" fi } function installTrojanWeb(){ # wget -O trojan-web_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/Jrohy/trojan/master/install.sh" && chmod +x trojan-web_install.sh && ./trojan-web_install.sh if [ -f "${configTrojanWebPath}/trojan-web" ] ; then green " ==================================================" green " 已安装过 Trojan-web 可视化管理面板, 退出安装 !" green " ==================================================" exit fi stopServiceNginx testLinuxPortUsage installPackage green " ================================================== " yellow " 请输入绑定到本VPS的域名 例如www.xxx.com: (此步骤请关闭CDN后安装)" green " ================================================== " read configSSLDomain if compareRealIpWithLocalIp "${configSSLDomain}" ; then getV2rayVersion "trojan-web" green " ==================================================" green " 开始安装 Trojan-web 可视化管理面板: ${versionTrojanWeb} !" green " ==================================================" mkdir -p ${configTrojanWebPath} downloadTrojanWebBin chmod +x ${configTrojanWebPath}/trojan-web # 增加启动脚本 cat > ${osSystemMdPath}trojan-web.service <<-EOF [Unit] Description=trojan-web Documentation=https://github.com/Jrohy/trojan After=network.target network-online.target nss-lookup.target mysql.service mariadb.service mysqld.service docker.service [Service] Type=simple StandardError=journal ExecStart=${configTrojanWebPath}/trojan-web web -p ${configTrojanWebPort} ExecReload=/bin/kill -HUP \$MAINPID Restart=on-failure RestartSec=3s [Install] WantedBy=multi-user.target EOF ${sudoCmd} systemctl daemon-reload ${sudoCmd} systemctl enable trojan-web.service ${sudoCmd} systemctl start trojan-web.service green " ==================================================" green " Trojan-web 可视化管理面板: ${versionTrojanWeb} 安装成功!" green " Trojan可视化管理面板地址 https://${configSSLDomain}/${configTrojanWebNginxPath}" green " 开始运行命令 ${configTrojanWebPath}/trojan-web 进行初始化设置." echo red " 后续安装步骤: " green " 根据提示选择 1. Let's Encrypt 证书, 申请SSL证书 " green " 证书申请成功后. 继续根据提示 再选择 1.安装docker版mysql(mariadb)." green " mysql(mariadb)启动成功后, 继续根据提示 输入第一个trojan用户的账号密码, 回车后出现 '欢迎使用trojan管理程序' " green " 出现 '欢迎使用trojan管理程序'后 需要不输入数字直接按回车, 这样就会继续安装 nginx 直到完成 " echo green " nginx 安装成功会显示可视化管理面板网址, 请保存下来. 如果没有显示管理面板网址则表明安装失败. " green " ==================================================" read -r -p "按回车继续安装. Press enter to continue" ${configTrojanWebPath}/trojan-web installWebServerNginx # 命令补全环境变量 echo "export PATH=$PATH:${configTrojanWebPath}" >> ${HOME}/.${osSystemShell}rc # (crontab -l ; echo '25 0 * * * "${configSSLAcmeScriptPath}"/acme.sh --cron --home "${configSSLAcmeScriptPath}" > /dev/null') | sort - | uniq - | crontab - (crontab -l ; echo "30 4 * * 0,1,2,3,4,5,6 systemctl restart trojan-web.service") | sort - | uniq - | crontab - else exit fi } function upgradeTrojanWeb(){ getV2rayVersion "trojan-web" green " ==================================================" green " 开始升级 Trojan-web 可视化管理面板: ${versionTrojanWeb} !" green " ==================================================" ${sudoCmd} systemctl stop trojan-web.service mkdir -p ${configDownloadTempPath}/upgrade/trojan-web downloadTrojanWebBin "upgrade" mv -f ${configDownloadTempPath}/upgrade/trojan-web/trojan-web ${configTrojanWebPath} chmod +x ${configTrojanWebPath}/trojan-web ${sudoCmd} systemctl start trojan-web.service ${sudoCmd} systemctl restart trojan.service green " ================================================== " green " 升级成功 Trojan-web 可视化管理面板: ${versionTrojanWeb} !" green " ================================================== " } function removeTrojanWeb(){ # wget -O trojan-web_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/Jrohy/trojan/master/install.sh" && chmod +x trojan-web_install.sh && ./trojan-web_install.sh --remove green " ================================================== " red " 准备卸载已安装 Trojan-web " green " ================================================== " ${sudoCmd} systemctl stop trojan.service ${sudoCmd} systemctl stop trojan-web.service ${sudoCmd} systemctl disable trojan-web.service # 移除trojan rm -rf /usr/bin/trojan rm -rf /usr/local/etc/trojan rm -f ${osSystemMdPath}trojan.service rm -f /etc/systemd/system/trojan.service rm -f /usr/local/etc/trojan/config.json # 移除trojan web 管理程序 # rm -f /usr/local/bin/trojan rm -rf ${configTrojanWebPath} rm -f ${osSystemMdPath}trojan-web.service rm -rf /var/lib/trojan-manager ${sudoCmd} systemctl daemon-reload # 移除trojan的专用数据库 docker rm -f trojan-mysql docker rm -f trojan-mariadb rm -rf /home/mysql rm -rf /home/mariadb # 移除环境变量 sed -i '/trojan/d' ${HOME}/.${osSystemShell}rc # source ${HOME}/.${osSystemShell}rc crontab -l | grep -v "trojan-web" | crontab - green " ================================================== " green " Trojan-web 卸载完毕 !" green " ================================================== " } function runTrojanWebGetSSL(){ ${sudoCmd} systemctl stop trojan-web.service ${sudoCmd} systemctl stop nginx.service ${sudoCmd} systemctl stop trojan.service ${configTrojanWebPath}/trojan-web tls ${sudoCmd} systemctl start trojan-web.service ${sudoCmd} systemctl start nginx.service ${sudoCmd} systemctl restart trojan.service } function runTrojanWebCommand(){ ${configTrojanWebPath}/trojan-web } function installXUI(){ stopServiceNginx testLinuxPortUsage installPackage green " ================================================== " yellow " 请输入绑定到本VPS的域名 例如www.xxx.com: (此步骤请关闭CDN后安装)" green " ================================================== " read -r configSSLDomain if compareRealIpWithLocalIp "${configSSLDomain}" ; then green " ==================================================" green " 开始安装 X-UI 可视化管理面板 !" green " ==================================================" # wget -O x_ui_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/sprov065/x-ui/master/install.sh" && chmod +x x_ui_install.sh && ./x_ui_install.sh wget -O x_ui_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/vaxilu/x-ui/master/install.sh" && chmod +x x_ui_install.sh && ./x_ui_install.sh green "X-UI 可视化管理面板地址 http://${configSSLDomain}:54321" green " 请确保 54321 端口已经放行, 例如检查linux防火墙或VPS防火墙 54321 端口是否开启" green "X-UI 可视化管理面板 默认管理员用户 admin 密码 admin, 为保证安全,请登陆后尽快修改默认密码 " green " ==================================================" else exit fi } function removeXUI(){ green " ==================================================" /usr/bin/x-ui } function installV2rayUI(){ stopServiceNginx testLinuxPortUsage installPackage green " ================================================== " yellow " 请输入绑定到本VPS的域名 例如www.xxx.com: (此步骤请关闭CDN后安装)" green " ================================================== " read -r configSSLDomain if compareRealIpWithLocalIp "${configSSLDomain}" ; then green " ==================================================" green " 开始安装 V2ray-UI 可视化管理面板 !" green " ==================================================" bash <(curl -Ls https://raw.githubusercontent.com/tszho-t/v2ui/master/v2-ui.sh) # wget -O v2_ui_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/sprov065/v2-ui/master/install.sh" && chmod +x v2_ui_install.sh && ./v2_ui_install.sh # wget -O v2_ui_install.sh -N --no-check-certificate "https://raw.githubusercontent.com/tszho-t/v2-ui/master/install.sh" && chmod +x v2_ui_install.sh && ./v2_ui_install.sh green " V2ray-UI 可视化管理面板地址 http://${configSSLDomain}:65432" green " 请确保 65432 端口已经放行, 例如检查linux防火墙或VPS防火墙 65432 端口是否开启" green " V2ray-UI 可视化管理面板 默认管理员用户 admin 密码 admin, 为保证安全,请登陆后尽快修改默认密码 " green " ==================================================" else exit fi } function removeV2rayUI(){ green " ==================================================" /usr/bin/v2-ui } function upgradeV2rayUI(){ green " ==================================================" /usr/bin/v2-ui } configMosdnsBinPath="/usr/local/bin/mosdns" configMosdnsPath="/etc/mosdns" isInstallMosdns="true" isinstallMosdnsName="mosdns" downloadFilenameMosdns="mosdns-linux-amd64.zip" downloadFilenameMosdnsCn="mosdns-cn-linux-amd64.zip" isUseEasyMosdnsConfig="false" function downloadMosdns(){ rm -rf "${configMosdnsBinPath}" mkdir -p "${configMosdnsBinPath}" cd ${configMosdnsBinPath} || exit if [[ "${isInstallMosdns}" == "true" ]]; then versionMosdns=$(getGithubLatestReleaseVersion "IrineSistiana/mosdns") downloadFilenameMosdns="mosdns-linux-amd64.zip" # https://github.com/IrineSistiana/mosdns/releases/download/v3.8.0/mosdns-linux-amd64.zip # https://github.com/IrineSistiana/mosdns/releases/download/v3.8.0/mosdns-linux-arm64.zip # https://github.com/IrineSistiana/mosdns/releases/download/v3.8.0/mosdns-linux-arm-7.zip if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameMosdns="mosdns-linux-arm-7.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameMosdns="mosdns-linux-arm64.zip" fi downloadAndUnzip "https://github.com/IrineSistiana/mosdns/releases/download/v${versionMosdns}/${downloadFilenameMosdns}" "${configMosdnsBinPath}" "${downloadFilenameMosdns}" ${sudoCmd} chmod +x "${configMosdnsBinPath}/mosdns" else versionMosdnsCn=$(getGithubLatestReleaseVersion "IrineSistiana/mosdns-cn") downloadFilenameMosdnsCn="mosdns-cn-linux-amd64.zip" # https://github.com/IrineSistiana/mosdns-cn/releases/download/v1.2.3/mosdns-cn-linux-amd64.zip # https://github.com/IrineSistiana/mosdns-cn/releases/download/v1.2.3/mosdns-cn-linux-arm64.zip # https://github.com/IrineSistiana/mosdns-cn/releases/download/v1.2.3/mosdns-cn-linux-arm-7.zip if [[ ${osArchitecture} == "arm" ]] ; then downloadFilenameMosdnsCn="mosdns-cn-linux-arm-7.zip" fi if [[ ${osArchitecture} == "arm64" ]] ; then downloadFilenameMosdnsCn="mosdns-cn-linux-arm64.zip" fi downloadAndUnzip "https://github.com/IrineSistiana/mosdns-cn/releases/download/v${versionMosdnsCn}/${downloadFilenameMosdnsCn}" "${configMosdnsBinPath}" "${downloadFilenameMosdnsCn}" ${sudoCmd} chmod +x "${configMosdnsBinPath}/mosdns-cn" fi if [ ! -f "${configMosdnsBinPath}/${isinstallMosdnsName}" ]; then echo red "下载失败, 请检查网络是否可以正常访问 gitHub.com" red "请检查网络后, 重新运行本脚本!" echo exit 1 fi rm -rf "${configMosdnsPath}" mkdir -p "${configMosdnsPath}/rule" cd ${configMosdnsPath} || exit if [[ "${isUseEasyMosdnsConfig}" == "false" ]]; then echo green " Downloading files: cn.dat, geosite.dat, geoip.dat. " green " 开始下载文件: cn.dat, geosite.dat, geoip.dat 等相关文件" echo # versionV2rayRulesDat=$(getGithubLatestReleaseVersion "Loyalsoldier/v2ray-rules-dat") # geositeUrl="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/202205162212/geosite.dat" # geoipeUrl="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/202205162212/geoip.dat" # cnipUrl="https://github.com/Loyalsoldier/geoip/releases/download/202205120123/cn.dat" geositeFilename="geosite.dat" geoipFilename="geoip.dat" cnipFilename="cn.dat" geositeUrl="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" geoipeUrl="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" cnipUrl="https://raw.githubusercontent.com/Loyalsoldier/geoip/release/cn.dat" privateUrl="https://raw.githubusercontent.com/Loyalsoldier/domain-list-custom/release/private.txt" wget -O ${configMosdnsPath}/rule/${geositeFilename} ${geositeUrl} wget -O ${configMosdnsPath}/rule/${geoipFilename} ${geoipeUrl} wget -O ${configMosdnsPath}/rule/${cnipFilename} ${cnipUrl} wget -O ${configMosdnsPath}/rule/private.txt ${privateUrl} hostsUrl="https://raw.githubusercontent.com/Journalist-HK/mosdns-config/main/rule/hosts.txt" china_domain_listUrl="https://raw.githubusercontent.com/pmkol/easymosdns/main/rules/china_domain_list.txt" china_ip_listUrl="https://raw.githubusercontent.com/pmkol/easymosdns/main/rules/china_ip_list.txt" white_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/master/white_list.txt" block_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/master/block_list.txt" grey_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/master/grey_list.txt" ipv6_domain_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/master/ipv6_domain_list.txt" original_domain_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/main/original_domain_list.txt" akamai_domain_listUrl="https://raw.githubusercontent.com/Journalist-HK/Rules/master/akamai_domain_list.txt" cdn_domain_listUrl="https://raw.githubusercontent.com/pmkol/easymosdns/rules/cdn_domain_list.txt" wget -O ${configMosdnsPath}/rule/hosts.txt ${hostsUrl} wget -O ${configMosdnsPath}/rule/china_domain_list.txt ${china_domain_listUrl} wget -O ${configMosdnsPath}/rule/china_ip_list.txt ${china_ip_listUrl} wget -O ${configMosdnsPath}/rule/white_list.txt ${white_listUrl} wget -O ${configMosdnsPath}/rule/block_list.txt ${block_listUrl} wget -O ${configMosdnsPath}/rule/grey_list.txt ${grey_listUrl} wget -O ${configMosdnsPath}/rule/ipv6_domain_list.txt ${ipv6_domain_listUrl} wget -O ${configMosdnsPath}/rule/original_domain_list.txt ${original_domain_listUrl} wget -O ${configMosdnsPath}/rule/akamai_domain_list.txt ${akamai_domain_listUrl} wget -O ${configMosdnsPath}/rule/cdn_domain_list.txt ${cdn_domain_listUrl} wget -O ${configMosdnsPath}/rule/gfw.txt "https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/gfw.txt" wget -O ${configMosdnsPath}/rule/greatfire.txt "https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/greatfire.txt" wget -O ${configMosdnsPath}/rule/custom_list.txt "https://raw.githubusercontent.com/Journalist-HK/Rules/master/custom_list.txt" wget -O ${configMosdnsPath}/rule/gfw_ip_list.txt "https://raw.githubusercontent.com/pmkol/easymosdns/rules/gfw_ip_list.txt" wget -O ${configMosdnsPath}/rule/facebook.txt "https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/facebook.txt" wget -O ${configMosdnsPath}/rule/twitter.txt "https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/twitter.txt" wget -O ${configMosdnsPath}/rule/ip.txt "https://raw.githubusercontent.com/XIU2/CloudflareSpeedTest/master/ip.txt" wget -O ${configMosdnsPath}/rule/ipv6.txt "https://raw.githubusercontent.com/XIU2/CloudflareSpeedTest/master/ipv6.txt" wget -O ${configMosdnsPath}/rule/cloudfront.txt "https://raw.githubusercontent.com/Journalist-HK/Rules/master/cloudfront.txt" wget -O ${configMosdnsPath}/rule/cloudfront_ipv6.txt "https://raw.githubusercontent.com/Journalist-HK/Rules/master/cloudfront_ipv6.txt" wget -O ${configMosdnsPath}/rule/fastly.txt "https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/fastly.txt" fi } function installMosdns(){ if [ "${osInfo}" = "OpenWrt" ]; then echo " ================================================== " echo " For Openwrt X86, please use the script below: " echo " 针对 OpenWrt X86 系统, 请使用如下脚本安装: " echo " wget --no-check-certificate https://raw.githubusercontent.com/jinwyp/one_click_script/master/dsm/openwrt.sh && chmod +x ./openwrt.sh && ./openwrt.sh " echo exit fi # https://askubuntu.com/questions/27213/what-is-the-linux-equivalent-to-windows-program-files if [ -f "${configMosdnsBinPath}/mosdns" ]; then echo green " ==================================================" green " 检测到 mosdns 已安装, 退出安装! " echo exit 1 fi if [ -f "${configMosdnsBinPath}/mosdns-cn" ]; then echo green " ==================================================" green " 检测到 mosdns-cn 已安装, 退出安装! " echo exit 1 fi echo green " ==================================================" green " 请选择安装 Mosdns 还是 Mosdns-cn DNS 服务器:" echo green " 1. Mosdns 配置规则比较复杂 推荐使用" green " 2. Mosdns-cn, 容易配置, 相当于Mosdns配置简化版 " echo read -r -p "请选择Mosdns还是Mosdns-cn, 默认直接回车安装Mosdns-cn, 请输入纯数字:" isInstallMosdnsServerInput isInstallMosdnsServerInput=${isInstallMosdnsServerInput:-1} echo if [[ "${isInstallMosdnsServerInput}" == "1" ]]; then isInstallMosdns="true" isinstallMosdnsName="mosdns" echo green " ==================================================" green " 是否使用 easymosdns 的配置, 该配置更复杂 效果更好" green " https://github.com/pmkol/easymosdns" echo read -r -p "是否使用easymosdns, 默认直接回车不使用, 请输入[y/N]:" isUseEasyConfigInput isUseEasyConfigInput=${isUseEasyConfigInput:-n} if [[ "$isUseEasyConfigInput" == [Nn] ]]; then isUseEasyMosdnsConfig="false" else isUseEasyMosdnsConfig="true" fi else isInstallMosdns="false" isinstallMosdnsName="mosdns-cn" fi echo green " ================================================== " green " 开始安装 ${isinstallMosdnsName} !" green " ================================================== " echo echo green " ================================================== " green " 请填写mosdns运行的端口号 默认端口号为5335" green " DNS服务器常用为53端口, 推荐输入53" yellow " 软路由一般内置DNS服务器, 如果在软路由安装 为避免冲突 默认为5335" echo read -r -p "请填写mosdns运行的端口号? 默认直接回车为5335, 请输入纯数字:" isMosDNSServerPortInput isMosDNSServerPortInput=${isMosDNSServerPortInput:-5335} mosDNSServerPort="5335" reNumber='^[0-9]+$' if [[ "${isMosDNSServerPortInput}" =~ ${reNumber} ]] ; then mosDNSServerPort="${isMosDNSServerPortInput}" fi echo green " ================================================== " green " 是否添加本地运营商的DNS服务器, 默认直接回车不添加, 建议添加" green " 选y是 添加本地运营商DNS服务器, 请通过光猫或路由器查看DNS的IP" echo read -r -p "是否添加运营商的DNS服务器? 默认直接回车为不添加, 请输入[y/N]:" isAddNewDNSServerInput isAddNewDNSServerInput=${isAddNewDNSServerInput:-n} if [[ "$isAddNewDNSServerInput" == [Nn] ]]; then echo chinaDNSServerIPInput="218.2.2.2" else echo green " ================================================== " green " 请输入本地运营商DNS服务器IP 格式例如 1.1.1.1" green " 请保证端口53 提供DNS解析服务, 如果是非53端口请填写端口号, 格式例如 1.1.1.1:8053" green " 请通过光猫或路由器查看DNS的IP 直接回车默认 218.2.2.2 江苏电信" green " 全国DNS列表 https://github.com/easonjim/dns-server-list" echo read -r -p "请输入DNS服务器IP地址:" chinaDNSServerIPInput chinaDNSServerIPInput=${chinaDNSServerIPInput:-218.2.2.2} fi echo downloadMosdns if [[ "${isInstallMosdns}" == "true" ]]; then rm -f "${configMosdnsPath}/config.yaml" if [[ "${isUseEasyMosdnsConfig}" == "true" ]]; then downloadAndUnzip "https://mirror.apad.pro/dns/easymosdns.tar.gz" "${configMosdnsPath}" "easymosdns.tar.gz" ${sudoCmd} chmod +x ${configMosdnsPath}/tools/* sed -i "s/0\.0\.0\.0:53/0\.0\.0\.0:${mosDNSServerPort}/g" ${configMosdnsPath}/config.yaml cd ${configMosdnsBinPath} || exit export PATH="$PATH:${configMosdnsBinPath}" ${configMosdnsPath}/tools/config-reset else cat > "${configMosdnsPath}/config.yaml" <<-EOF log: level: info file: "${configMosdnsPath}/mosdns.log" # []string, 从其他配置文件载入 plugins 插件设置。 # include 的插件会比本配置文件中的插件先初始化。 plugins: # - tag: ecs_cn # type: ecs_handler # args: # forward: false # preset: 58.208.0.0 # 电信,请针对不同的运营商自行修改 # send: false # mask4: 12 # mask6: 28 - tag: ecs_tw type: ecs_handler args: forward: false preset: 168.95.0.0 send: false mask4: 16 # mask6: 40 - tag: ecs_us type: ecs_handler args: forward: false preset: 38.94.109.0 send: false mask4: 24 # mask6: 40 # 不应处理本地 DNS 请求,防止死循环。正确顺序应该是 dnsmasq --> OpenClash(可选)--> mosdns。 # - tag: "forward_lan" # type: forward # args: # concurrent: 1 # upstream: # - addr: "192.168.1.1" - tag: "forward_local" type: forward args: concurrent: 2 upstreams: - addr: "${chinaDNSServerIPInput}" # 江苏电信 DNS,自行修改 - addr: "218.4.4.4" # 江苏电信 DNS,自行修改 - addr: "210.22.70.3" # 上海联通 DNS,自行修改 - tag: "forward_alidns" type: forward args: concurrent: 1 upstreams: - addr: "quic://223.6.6.6:853" - addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" enable_http3: false - tag: "forward_easy" type: "forward" args: concurrent: 1 upstreams: - addr: "https://doh.apad.pro/dns-query" bootstrap: "218.2.2.2" enable_http3: false - tag: "forward_remote" type: "forward" args: concurrent: 1 # 并发数。每次请求随机选取 concurrent 个 upstreams 发送请求。 # 取最快返回的应答。超过 3 最多选 3 个。默认 1。 upstreams: - addr: "https://162.159.36.1/dns-query" enable_http3: false # socks5: "127.0.0.1:1080" # 目前暂不支持用户名密码认证,只支持基于 TCP 的协议 - addr: "https://162.159.46.1/dns-query" enable_http3: false # - addr: "https://doh.opendns.com/dns-query" # dial_addr: "146.112.41.2" # enable_http3: false # - addr: "https://public.dns.iij.jp/dns-query" # dial_addr: 103.2.57.5 # enable_http3: false # - addr: "tcp://208.67.220.220:5353" # CISCO OpenDNS # enable_pipeline: true - tag: remote_sequence type: sequence args: - exec: prefer_ipv4 - exec: \$ecs_tw - exec: \$forward_remote - exec: return - tag: "fallback" type: "fallback" args: primary: forward_easy # easy secondary: forward_remote # remote threshold: 360 # 无响应回滚阈值。单位毫秒。默认 500 。 always_standby: true # 副可执行插件始终待命。 - tag: fallback_sequence type: sequence args: - exec: prefer_ipv4 - exec: \$ecs_tw - exec: \$fallback - exec: return - tag: fallback_sequence_ipv6 type: sequence args: - exec: prefer_ipv6 - exec: \$fallback - exec: return - tag: has_resp_sequence type: sequence args: - matches: - has_resp exec: accept - tag: "hosts" type: "hosts" args: # entries: # - "google.com 108.177.122.113" files: - "/etc/mosdns/rule/hosts.txt" - tag: geosite_cn # 国内域名 type: domain_set args: files: - "/etc/mosdns/rule/china_domain_list.txt" # https://raw.githubusercontent.com/pmkol/easymosdns/rules/china_domain_list.txt - tag: geoip_cn # 国内 IP type: ip_set args: files: - "/etc/mosdns/rule/china_ip_list.txt" # https://raw.githubusercontent.com/pmkol/easymosdns/rules/china_ip_list.txt - tag: privatelist # 内网域名 type: domain_set args: files: - "/etc/mosdns/rule/private.txt" # https://raw.githubusercontent.com/Loyalsoldier/domain-list-custom/release/private.txt - tag: whitelist type: domain_set args: files: - "/etc/mosdns/rule/white_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/white_list.txt - tag: blocklist type: domain_set args: files: - "/etc/mosdns/rule/block_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/block_list.txt - tag: greylist # 用来存放被污染的域名。 type: domain_set args: files: - "/etc/mosdns/rule/grey_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/grey_list.txt - tag: ipv6list # 用来存放优先走 ipv6 的域名。 type: domain_set args: files: - "/etc/mosdns/rule/ipv6_domain_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/ipv6_domain_list.txt - tag: originallist # 用来存放优不进行 IP 优选的域名。 type: domain_set args: files: - "/etc/mosdns/rule/original_domain_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/original_domain_list.txt - tag: akamailist type: domain_set args: files: - "/etc/mosdns/rule/akamai_domain_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/akamai_domain_list.txt - tag: cdnlist type: domain_set args: exps: - "cloudflare.com" - "cloudfront.net" - "ghproxy.com" - "microsoft.com" - "playstation.com" - "playstation.net" - "redhat.com" - "samsung.com" - "ubi.com" - "ubisoft.com" - "xboxlive.com" files: - "/etc/mosdns/rule/cdn_domain_list.txt" # https://raw.githubusercontent.com/pmkol/easymosdns/rules/cdn_domain_list.txt - tag: gfwlist type: domain_set args: files: - "/etc/mosdns/rule/gfw.txt" # https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/gfw.txt - "/etc/mosdns/rule/greatfire.txt" # https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/greatfire.txt - "/etc/mosdns/rule/custom_list.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/custom_list.txt - tag: banned_ip type: ip_set args: ips: - "0.0.0.0/32" - "2001::/32" files: - "/etc/mosdns/rule/gfw_ip_list.txt" # https://raw.githubusercontent.com/pmkol/easymosdns/rules/gfw_ip_list.txt - "/etc/mosdns/rule/facebook.txt" # https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/facebook.txt # - "/etc/mosdns/rule/telegram.txt" # https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/telegram.txt - "/etc/mosdns/rule/twitter.txt" # https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/twitter.txt - tag: cloudflare_ip type: ip_set args: files: - "/etc/mosdns/rule/ip.txt" # https://raw.githubusercontent.com/XIU2/CloudflareSpeedTest/master/ip.txt - tag: cloudflare_ipv6 type: ip_set args: files: - "/etc/mosdns/rule/ipv6.txt" # https://raw.githubusercontent.com/XIU2/CloudflareSpeedTest/master/ipv6.txt - tag: cloudfront_ip type: ip_set args: files: - "/etc/mosdns/rule/cloudfront.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/cloudfront.txt - tag: cloudfront_ipv6 type: ip_set args: files: - "/etc/mosdns/rule/cloudfront_ipv6.txt" # https://raw.githubusercontent.com/Journalist-HK/Rules/master/cloudfront_ipv6.txt - tag: fastly_ip type: ip_set args: files: - "/etc/mosdns/rule/fastly.txt" # https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/fastly.txt - tag: "cache_0" type: "cache" args: size: 8192 # 默认: 1024。 # lazy_cache_ttl > 0 会启用 lazy cache。 # 所有应答都会在缓存中存留 lazy_cache_ttl 秒,但自身的 TTL 仍然有效。如果命中过期的应答, # 则缓存会立即返回 TTL 为 5 的应答,然后自动在后台发送请求更新数据。 lazy_cache_ttl: 259200 # 默认: 0(禁用 lazy cache)。 # 建议值 86400(1天)~ 259200(3天) dump_file: /usr/share/mosdns/cache.dump # (实验性) 自动保存间隔。单位秒。默认 600。 # 如果距离上次 dump 有 1024 次更新,则自动保存。 dump_interval: 7200 # IP 优选,需要定期修改,最好填写 2 - 4 个 - tag: blackhole_akamai # 替换部分 AKAMAI 域名 IP,详见 https://github.com/IrineSistiana/mosdns/discussions/489 type: sequence args: - exec: black_hole 119.149.188.15 202.142.229.59 223.44.51.33 # best_akamai_ip - exec: ttl 3600-0 - exec: accept # 运行 black_hole 之后接受请求,不再进行后续判断 - tag: blackhole_akamai_ipv6 type: sequence args: - exec: black_hole 2600:140b:1000::1730:d5ab 2600:140b:1000::1730:d5ce # best_akamai_ipv6 - exec: ttl 3600-0 - exec: accept - tag: blackhole_cloudflare type: sequence args: - exec: black_hole 104.17.7.198 104.17.61.114 162.159.0.195 162.159.7.75 # best_cloudflare_ip - exec: ttl 3600-0 - exec: accept - tag: blackhole_cloudflare_ipv6 type: sequence args: - exec: black_hole 2a06:98c1:310f::e0c0:131c:2cb3 2a06:98c1:310f::ee3c:1d43:fc2e:6f6c # best_cloudflare_ipv6 - exec: ttl 3600-0 - exec: accept - tag: blackhole_cloudfront type: sequence args: - exec: black_hole 18.172.26.139 18.172.28.94 52.84.151.126 52.84.228.48 # best_cloudfront_ip - exec: ttl 3600-0 - exec: accept - tag: blackhole_cloudfront_ipv6 type: sequence args: - exec: black_hole 2600:9000:20e9:1edf:3560:977b:c990:1f75 2600:9000:20e9:1edf:35c0:29ed:b6ac:7b3b # best_cloudfront_ipv6 - exec: ttl 3600-0 - exec: accept - tag: remote_sequence_us # 使用 US ECS 请求上游 type: sequence args: - exec: prefer_ipv4 - exec: \$ecs_us - exec: \$forward_remote - exec: jump has_resp_sequence - tag: fallback_sequence_us # 使用 US ECS 请求上游 type: sequence args: - exec: prefer_ipv4 - exec: \$ecs_us - exec: \$fallback - exec: jump has_resp_sequence - tag: change_cdn_ip_akamai type: sequence args: - matches: - cname akamai.net - qtype 1 - has_wanted_ans # 防止纯 IPV6 域名被替换 exec: jump blackhole_akamai - matches: - cname akamai.net - qtype 28 - has_wanted_ans exec: jump blackhole_akamai_ipv6 # 如果不需要对纯 IPV6 域名优选可以去掉这一段 - exec: return - tag: change_cdn_ip_cf # https://github.com/XIU2/CloudflareSpeedTest/discussions/317 type: sequence args: - matches: - qtype 1 - has_wanted_ans - resp_ip \$cloudflare_ip exec: jump blackhole_cloudflare - matches: - qtype 1 - has_wanted_ans - resp_ip \$cloudfront_ip exec: jump blackhole_cloudfront - matches: - qtype 28 - has_wanted_ans - resp_ip \$cloudflare_ipv6 exec: jump blackhole_cloudflare_ipv6 - matches: - qtype 28 - has_wanted_ans - resp_ip \$cloudfront_ipv6 exec: jump blackhole_cloudfront_ipv6 - exec: return - tag: reforward_fastly_remote # 使用 US ECS 再次查询优化 Fastly CDN 结果 type: sequence args: - matches: - resp_ip \$fastly_ip exec: jump remote_sequence_us - exec: return - tag: reforward_fastly_fallback # 使用 US ECS 再次查询优化 Fastly CDN 结果 type: sequence args: - matches: - resp_ip \$fastly_ip exec: jump fallback_sequence_us - exec: return - tag: gfw_sequence # 处理 GFW 域名 type: sequence args: - exec: jump remote_sequence - exec: jump change_cdn_ip_akamai - exec: jump change_cdn_ip_cf - exec: jump reforward_fastly_remote - exec: accept # 查询失败也会停止,防止后续查询回落到国内上游 - tag: default_sequence # 默认使用 fallback type: sequence args: - exec: jump fallback_sequence - exec: jump change_cdn_ip_akamai - exec: jump change_cdn_ip_cf - exec: jump reforward_fastly_fallback - exec: accept # 查询失败也会停止,防止后续查询回落到国内上游 - tag: default_sequence_original # 使用 fallback,不替换 CDN IP type: sequence args: - exec: jump fallback_sequence - exec: jump has_resp_sequence - tag: default_sequence_ipv6 # 使用 fallback,但不替换 CDN IP,IPV6 优先 type: sequence args: - exec: jump fallback_sequence_ipv6 - exec: jump has_resp_sequence - tag: ali_sequence type: sequence args: # - exec: prefer_ipv4 - exec: \$forward_alidns - exec: jump change_cdn_ip_akamai - exec: jump change_cdn_ip_cf - exec: jump reforward_fastly_fallback - exec: accept # 查询失败也会停止,防止后续查询其他上游 - tag: ali_sequence_ipv4 type: sequence args: - exec: prefer_ipv4 - exec: \$forward_alidns - exec: jump change_cdn_ip_akamai - exec: jump change_cdn_ip_cf - exec: jump reforward_fastly_fallback - exec: accept # 查询失败也会停止,防止后续查询其他上游 # - tag: reforward_banned_ip # type: sequence # args: # - exec: debug_print "DNS poisoning detected" # - exec: jump fallback_sequence # - exec: return - tag: main type: sequence args: - matches: - qtype 65 exec: reject 3 # 屏蔽 QTYPE 65 - exec: \$hosts - exec: jump has_resp_sequence - matches: - qname \$privatelist #内网域名 exec: reject 5 # 屏蔽内网域名 # exec: \$forward_lan # 查询内网 DNS # - exec: jump has_resp_sequence - matches: - qname \$whitelist # DDNS 和 其他白名单 exec: \$forward_local - exec: ttl 5-180 - exec: jump has_resp_sequence - matches: - qname \$blocklist # 黑名单,可添加去广告列表 exec: reject 5 - exec: \$cache_0 # 下面的请求结果均进入缓存 - matches: - qname \$ipv6list exec: jump default_sequence_ipv6 # IPV6 域名请求 EASY DNS - matches: - qname \$originallist # 不进行 IP 替换的域名,通常是游戏等使用非常用端口的域名 exec: jump default_sequence_original - matches: - qname \$greylist exec: jump default_sequence # 污染域名请求 EASY DNS - matches: - qname \$geosite_cn # 国内域名走阿里 DNS,也可以走运营商 DNS exec: jump ali_sequence # 如果使用策略 1,可以考虑去掉这一段。去掉后,当阿里 DNS 查询失败后会查询可信上游。 - matches: - qname \$cdnlist apple.com icloud.com edgesuite.net msftconnecttest.com trafficmanager.net exec: jump ali_sequence_ipv4 # 我这里用阿里 DNS 请求 AKAMAI 域名返回东京电信的概率较高,可以替换成其他。 - matches: - qname \$gfwlist exec: jump gfw_sequence # GFW 域名直接请求海外 DNS - matches: - qname \$akamailist exec: jump ali_sequence_ipv4 # 我这里用阿里 DNS 请求 AKAMAI 域名返回东京电信的概率较高,可以替换成其他。 # 策略 1:默认查询国内上游,入返回境外 IP,再次将域名交给可信 DNS 查询。 - exec: \$forward_alidns # 默认使用阿里 DNS,如果担心 DNS 泄露,可以调换顺序,把 fallback 放在前面,代价是延迟会变高。这种情况下可以使用前面的 cdnlist 域名先做判断。 - matches: - resp_ip \$banned_ip # 记录被污染域名,日后加入 gerylist。可以去掉。 exec: debug_print "DNS poisoning detected" - matches: - "resp_ip \$geoip_cn" exec: accept # 返回国内 IP 直接接受 - exec: jump change_cdn_ip_akamai - matches: # 有些 AKAMAI 的域名不能直接替换 IP(没有绑定全证书),此处多加一次判断,接受所有 AKAMAI CDN 的 IP。 - cname \$akamailist exec: accept - exec: jump change_cdn_ip_cf - exec: jump reforward_fastly_fallback # 策略 2:注释上方策略 1 的配置,默认查询可信 DNS,可以避免“DNS 泄露”,对上游稳定性要求更高 - exec: jump default_sequence # 其余域名使用可信 DNS - tag: udp_server type: udp_server args: entry: main listen: ":${mosDNSServerPort}" - tag: tcp_server type: tcp_server args: entry: main listen: ":${mosDNSServerPort}" # cert: "/etc/nginx/conf.d/_lan.crt" # 配置 cert 和 key 后会启用 TLS (DoT)。 # key: "/etc/nginx/conf.d/_lan.key" idle_timeout: 10 # 空连接超时。单位秒。默认 10。 EOF fi ${configMosdnsBinPath}/mosdns service install -c "${configMosdnsPath}/config.yaml" -d "${configMosdnsPath}" ${configMosdnsBinPath}/mosdns service start else rm -f "${configMosdnsPath}/config_mosdns_cn.yaml" cat > "${configMosdnsPath}/config_mosdns_cn.yaml" <<-EOF server_addr: ":${mosDNSServerPort}" cache_size: 2048 lazy_cache_ttl: 86400 lazy_cache_reply_ttl: 30 redis_cache: "" min_ttl: 300 max_ttl: 3600 hosts: [] arbitrary: [] blacklist_domain: [] insecure: false ca: [] debug: false log_file: "${configMosdnsPath}/mosdns-cn.log" upstream: [] local_upstream: ["udp://223.5.5.5", "udp://119.29.29.29"] local_ip: ["${configMosdnsPath}/rule/${geoipFilename}:cn"] local_domain: [] local_latency: 50 remote_upstream: [ "udp://1.0.0.1", "udp://208.67.222.222", "tls://8.8.4.4:853", "udp://5.2.75.231", "udp://172.105.216.54"] remote_domain: ["${configMosdnsPath}/rule/${geositeFilename}:geolocation-!cn"] working_dir: "${configMosdnsPath}" cd2exe: false EOF ${configMosdnsBinPath}/mosdns-cn --service install --config "${configMosdnsPath}/config_mosdns_cn.yaml" --dir "${configMosdnsPath}" ${configMosdnsBinPath}/mosdns-cn --service start fi echo green " ==================================================" green " ${isinstallMosdnsName} 安装成功! 运行端口: ${mosDNSServerPort}" echo green " 启动: systemctl start ${isinstallMosdnsName} 停止: systemctl stop ${isinstallMosdnsName}" green " 重启: systemctl restart ${isinstallMosdnsName}" green " 查看状态: systemctl status ${isinstallMosdnsName} " green " 查看log: journalctl -n 50 -u ${isinstallMosdnsName} " green " 查看访问日志: cat ${configMosdnsPath}/${isinstallMosdnsName}.log" # green " 启动命令: ${configMosdnsBinPath}/${isinstallMosdnsName} -s start -dir ${configMosdnsPath} " # green " 停止命令: ${configMosdnsBinPath}/${isinstallMosdnsName} -s stop -dir ${configMosdnsPath} " # green " 重启命令: ${configMosdnsBinPath}/${isinstallMosdnsName} -s restart -dir ${configMosdnsPath} " green " ==================================================" } function removeMosdns(){ if [[ -f "${configMosdnsBinPath}/mosdns" || -f "${configMosdnsBinPath}/mosdns-cn" ]]; then if [[ -f "${configMosdnsBinPath}/mosdns" ]]; then isInstallMosdns="true" isinstallMosdnsName="mosdns" fi if [ -f "${configMosdnsBinPath}/mosdns-cn" ]; then isInstallMosdns="false" isinstallMosdnsName="mosdns-cn" fi echo green " ==================================================" green " 准备卸载已安装的 ${isinstallMosdnsName} " green " ==================================================" echo if [[ "${isInstallMosdns}" == "true" ]]; then ${configMosdnsBinPath}/${isinstallMosdnsName} service stop ${configMosdnsBinPath}/${isinstallMosdnsName} service uninstall else ${configMosdnsBinPath}/mosdns-cn --service stop ${configMosdnsBinPath}/mosdns-cn --service uninstall fi rm -rf "${configMosdnsBinPath}" rm -rf "${configMosdnsPath}" echo green " ================================================== " green " ${isinstallMosdnsName} 卸载完毕 !" green " ================================================== " else echo red " 系统没有安装 mosdns, 退出卸载" echo fi } configAdGuardPath="/opt/AdGuardHome" # DNS server function installAdGuardHome(){ wget -qN --no-check-certificate -O ./ad_guard_install.sh https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh && chmod +x ./ad_guard_install.sh && ./ad_guard_install.sh -v echo if [[ ${configLanguage} == "cn" ]] ; then green " 如要卸载删除AdGuard Home 请运行命令 ./ad_guard_install.sh -u" green " 请打开网址 http://yourip:3000 完成初始化配置 " green " 完成初始化后, 请重新运行本脚本 选择29 获取SSL 证书. 开启DOH和DOT " else green " Remove AdGuardHome, pls run ./ad_guard_install.sh -u " green " Please open http://yourip:3000 and complete the initialization " green " After the initialization, pls rerun this script and choose 29 to get SSL certificate " fi echo } function getAdGuardHomeSSLCertification(){ if [ -f "${configAdGuardPath}/AdGuardHome" ]; then echo green " ==================================================" green " 检测到 AdGuard Home 已安装" green " Found AdGuard Home have already installed" echo green " 是否继续 申请SSL证书, Continue to get Free SSL certificate ?" read -p "是否申请SSL证书, 请输入[Y/n]:" isGetAdGuardSSLCertificateInput isGetAdGuardSSLCertificateInput=${isGetAdGuardSSLCertificateInput:-Y} if [[ "${isGetAdGuardSSLCertificateInput}" == [Yy] ]]; then ${configAdGuardPath}/AdGuardHome -s stop configSSLCertPath="${configSSLCertPath}/adguardhome" renewCertificationWithAcme "" replaceAdGuardConfig fi fi } function replaceAdGuardConfig(){ if [ -f "${configAdGuardPath}/AdGuardHome" ]; then if [ -f "${configAdGuardPath}/AdGuardHome.yaml" ]; then echo yellow " 准备把已申请到的SSL证书填入 AdGuardHome 配置文件" yellow " prepare to get SSL certificate and replace AdGuardHome config" # https://stackoverflow.com/questions/4396974/sed-or-awk-delete-n-lines-following-a-pattern sed -i -e '/^tls:/{n;d}' ${configAdGuardPath}/AdGuardHome.yaml sed -i "/^tls:/a \ enabled: true" ${configAdGuardPath}/AdGuardHome.yaml # sed -i 's/enabled: false/enabled: true/g' ${configAdGuardPath}/AdGuardHome.yaml sed -i "s/server_name: .*/server_name: ${configSSLDomain}/g" ${configAdGuardPath}/AdGuardHome.yaml sed -i "s|certificate_path: .*|certificate_path: ${configSSLCertPath}/${configSSLCertFullchainFilename}|g" ${configAdGuardPath}/AdGuardHome.yaml sed -i "s|private_key_path: .*|private_key_path: ${configSSLCertPath}/${configSSLCertKeyFilename}|g" ${configAdGuardPath}/AdGuardHome.yaml # 开启DNS并行查询 加速 sed -i 's/all_servers: false/all_servers: true/g' ${configAdGuardPath}/AdGuardHome.yaml read -r -d '' adGuardConfigUpstreamDns << EOM - 1.0.0.1 - https://dns.cloudflare.com/dns-query - 8.8.8.8 - https://dns.google/dns-query - tls://dns.google - 9.9.9.9 - https://dns.quad9.net/dns-query - tls://dns.quad9.net - 208.67.222.222 - https://doh.opendns.com/dns-query EOM TEST1="${adGuardConfigUpstreamDns//\\/\\\\}" TEST1="${TEST1//\//\\/}" TEST1="${TEST1//&/\\&}" TEST1="${TEST1//$'\n'/\\n}" sed -i "/upstream_dns:/a \ ${TEST1}" ${configAdGuardPath}/AdGuardHome.yaml read -r -d '' adGuardConfigBootstrapDns << EOM - 1.0.0.1 - 8.8.8.8 - 8.8.4.4 EOM TEST2="${adGuardConfigBootstrapDns//\\/\\\\}" TEST2="${TEST2//\//\\/}" TEST2="${TEST2//&/\\&}" TEST2="${TEST2//$'\n'/\\n}" sed -i "/bootstrap_dns:/a \ ${TEST2}" ${configAdGuardPath}/AdGuardHome.yaml read -r -d '' adGuardConfigFilters << EOM - enabled: true url: https://anti-ad.net/easylist.txt name: 'CHN: anti-AD' id: 1652375944 - enabled: true url: https://easylist-downloads.adblockplus.org/easylistchina.txt name: EasyList China id: 1652375945 EOM # https://fabianlee.org/2018/10/28/linux-using-sed-to-insert-lines-before-or-after-a-match/ TEST3="${adGuardConfigFilters//\\/\\\\}" TEST3="${TEST3//\//\\/}" TEST3="${TEST3//&/\\&}" TEST3="${TEST3//$'\n'/\\n}" sed -i "/id: 2/a ${TEST3}" ${configAdGuardPath}/AdGuardHome.yaml echo green " AdGuard Home config updated success: ${configAdGuardPath}/AdGuardHome.yaml " green " AdGuard Home 配置文件更新成功: ${configAdGuardPath}/AdGuardHome.yaml " echo ${configAdGuardPath}/AdGuardHome -s restart else red " 未检测到AdGuardHome配置文件 ${configAdGuardPath}/AdGuardHome.yaml, 请先完成AdGuardHome初始化配置" red " ${configAdGuardPath}/AdGuardHome.yaml not found, pls complete the AdGuardHome initialization first!" fi else red "AdGuard Home not found, Please install AdGuard Home first !" fi } function firewallForbiden(){ # firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -p tcp -m tcp --dport=25 -j ACCEPT # firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 1 -p tcp -m tcp --dport=25 -j REJECT # firewall-cmd --reload firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -p tcp -m tcp --dport=25 -j DROP firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 1 -j ACCEPT firewall-cmd --reload # iptables -A OUTPUT -p tcp --dport 25 -j DROP # iptables -A INPUT -p tcp -s 0/0 -d 0/0 --dport 80 -j DROP # iptables -A INPUT -p all -j ACCEPT # iptables -A OUTPUT -p all -j ACCEPT } function startMenuOther(){ clear if [[ ${configLanguage} == "cn" ]] ; then green " ==================================================" red " 安装下面3个可视化管理面板 之前不能用本脚本或其他脚本安装过trojan或v2ray! " red " 如果已安装过 trojan 或 v2ray 请先卸载或重做干净系统! 3个管理面板无法同时安装" echo green " 1. 安装 trojan-web (trojan 和 trojan-go 可视化管理面板) 和 nginx 伪装网站" green " 2. 升级 trojan-web 到最新版本" green " 3. 重新申请证书" green " 4. 查看日志, 管理用户, 查看配置等功能" red " 5. 卸载 trojan-web 和 nginx " echo green " 6. 安装 V2ray 可视化管理面板V2-UI, 可以同时支持trojan" green " 7. 升级 V2-UI 到最新版本" red " 8. 卸载 V2-UI" echo green " 9. 安装 Xray 可视化管理面板 X-UI, 可以同时支持trojan" red " 10. 升级 或 卸载 X-UI" echo green " ==================================================" red " 以下是 VPS 测网速工具, 脚本测速会消耗大量 VPS 流量,请悉知!" green " 41. superspeed 三网纯测速 (全国各地三大运营商部分节点全面测速)推荐使用 " green " 42. yet-another-bench-script 综合测试 (包含 CPU IO 测试 国际多个数据节点网速测试)推荐使用" green " 43. 由teddysun 编写的Bench 综合测试 (包含系统信息 IO 测试 国内多个数据节点网速测试)" green " 44. LemonBench 快速全方位测试 (包含CPU内存性能、回程、节点测速) " green " 45. ZBench 综合网速测试 (包含节点测速, Ping 以及 路由测试)" green " 46. testrace 回程路由测试 by nanqinlang (四网路由 上海电信 厦门电信 浙江杭州联通 浙江杭州移动 北京教育网)" green " 47. autoBestTrace 回程路由测试 (广州电信 上海电信 厦门电信 重庆联通 成都联通 上海移动 成都移动 成都教育网)" green " 48. 回程路由测试 推荐使用 (北京电信/联通/移动 上海电信/联通/移动 广州电信/联通/移动 )" green " 49. 三网回程路由测试 Go 语言开发 by zhanghanyun " green " 50. 独立服务器测试 包括系统信息和I/O测试" echo green " ==================================================" green " 51. 测试VPS 是否支持 Netflix 非自制剧解锁 支持 WARP sock5 测试, 推荐使用 " green " 52. 测试VPS 是否支持 Netflix, Go语言版本 推荐使用 by sjlleo, 推荐使用" green " 53. 测试VPS 是否支持 Netflix, Disney, Hulu 等等更多流媒体平台, 新版 by lmc999" #green " 54. 测试VPS 是否支持 Netflix, 检测IP解锁范围及对应所在的地区, 原版 by CoiaPrant" echo green " 61. 安装 官方宝塔面板" green " 62. 安装 宝塔面板纯净版 by hostcli.com" green " 63. 安装 宝塔面板破解版 7.9 by yu.al" echo green " 99. 返回上级菜单" green " 0. 退出脚本" else green " ==================================================" red " Install 3 UI admin panel below require clean VPS system. Cannot install if VPS already installed trojan or v2ray " red " Pls remove trojan or v2ray if installed. Prefer using clean system to install UI admin panel. " red " Trojan and v2ray UI admin panel cannot install at the same time." echo green " 1. install trojan-web (trojan/trojan-go UI admin panel) with nginx" green " 2. upgrade trojan-web to latest version" green " 3. redo to request SSL certificate if you got problem with SSL" green " 4. Show log and config, manage users, etc." red " 5. remove trojan-web and nginx" echo green " 6. install V2-UI admin panel, support trojan protocal" green " 7. upgrade V2-UI to latest version" red " 8. remove V2-UI" echo green " 9. install X-UI admin panel, support trojan protocal" red " 10. upgrade or remove X-UI" echo green " ==================================================" red " VPS speedtest tools. Pay attention that speed tests will consume lots of traffic." green " 41. superspeed. ( China telecom / China unicom / China mobile node speed test ) " green " 42. yet-another-bench-script ( CPU IO Memory Network speed test)" green " 43. Bench by teddysun" green " 44. LemonBench ( CPU IO Memory Network Traceroute test) " green " 45. ZBench " green " 46. testrace by nanqinlang (四网路由 上海电信 厦门电信 浙江杭州联通 浙江杭州移动 北京教育网)" green " 47. autoBestTrace (Traceroute test 广州电信 上海电信 厦门电信 重庆联通 成都联通 上海移动 成都移动 成都教育网)" green " 48. returnroute test (北京电信/联通/移动 上海电信/联通/移动 广州电信/联通/移动 )" green " 49. returnroute test by zhanghanyun powered by Go (三网回程路由测试 ) " green " 50. A bench script for dedicated servers " echo green " ==================================================" green " 51. Netflix region and non-self produced drama unlock test, support WARP SOCKS5 proxy and IPv6" green " 52. Netflix region and non-self produced drama unlock test by sjlleo using go language." green " 53. Netflix, Disney, Hulu etc unlock test by by lmc999" #green " 54. Netflix region and non-self produced drama unlock test by CoiaPrant" echo green " 61. install official bt panel (aa panel)" green " 62. install modified bt panel (aa panel) by hostcli.com" green " 63. install modified bt panel (aa panel) 7.9 by yu.al" echo green " 99. Back to main menu" green " 0. exit" fi echo read -p "Please input number:" menuNumberInput case "$menuNumberInput" in 1 ) setLinuxDateZone configInstallNginxMode="trojanWeb" installTrojanWeb ;; 2 ) upgradeTrojanWeb ;; 3 ) runTrojanWebGetSSL ;; 4 ) runTrojanWebCommand ;; 5 ) removeNginx removeTrojanWeb ;; 6 ) setLinuxDateZone installV2rayUI ;; 7 ) upgradeV2rayUI ;; 8 ) removeV2rayUI ;; 9 ) setLinuxDateZone installXUI ;; 10 ) removeXUI ;; 41 ) vps_superspeed ;; 42 ) vps_yabs ;; 43 ) vps_bench ;; 44 ) vps_LemonBench ;; 45 ) vps_zbench ;; 46 ) vps_testrace ;; 47 ) vps_autoBestTrace ;; 48 ) vps_returnroute vps_returnroute2 ;; 49 ) vps_returnroute2 ;; 50 ) vps_bench_dedicated ;; 51 ) vps_netflix_jin ;; 52 ) vps_netflixgo ;; 53 ) vps_netflix2 ;; 54 ) vps_netflix2 ;; 61 ) installBTPanel ;; 62 ) installBTPanelCrackHostcli ;; 63 ) installBTPanelCrack ;; 81 ) installBBR ;; 82 ) installBBR2 ;; 99) start_menu ;; 0 ) exit 1 ;; * ) clear red "请输入正确数字 !" sleep 2s startMenuOther ;; esac } function start_menu(){ clear if [[ $1 == "first" ]] ; then getLinuxOSRelease installSoftDownload fi if [[ ${configLanguage} == "cn" ]] ; then green " ====================================================================================================" green " Trojan-go V2ray Xray 一键安装脚本 | 2024-3-13 | 系统支持:centos7+ / debian9+ / ubuntu16.04+" green " ====================================================================================================" green " 1. 安装linux内核 bbr plus, 安装WireGuard, 用于解锁 Netflix 限制和避免弹出 Google reCAPTCHA 人机验证" echo green " 2. 安装 trojan/trojan-go 和 nginx, 支持CDN 开启websocket, trojan-go 运行在443端口" green " 3. 只安装 trojan/trojan-go 运行在443或自定义端口, 不安装nginx, 方便与现有网站或宝塔面板集成" red " 4. 卸载 trojan/trojan-go 和 nginx" echo green " 6. 安装 Shadowsocks Rust 支持 Shadowsocks 2022 加密方式, 运行在随机端口" green " 7. 安装 Xray Shadowsocks 支持 Shadowsocks 2022 加密方式, 运行在随机端口" red " 8. 卸载 Shadowsocks Rust 或 Xray " echo green " 11. 安装 v2ray或xray 和 nginx ([Vmess/Vless]-[TCP/WS/gRPC/H2/QUIC]-TLS), 支持CDN, nginx 运行在443端口" green " 12. 只安装 v2ray或xray ([Vmess/Vless]-[TCP/WS/gRPC/H2/QUIC]), 无TLS加密, 方便与现有网站或宝塔面板集成" echo green " 13. 安装 v2ray或xray (VLess-TCP-[TLS/XTLS])+(VMess-TCP-TLS)+(VMess-WS-TLS) 支持CDN, 可选安装nginx, VLess运行在443端口" green " 14. 安装 v2ray或xray (VLess-gRPC-TLS) 支持CDN, 可选安装nginx, VLess运行在443端口" green " 15. 安装 v2ray或xray (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS) 支持CDN, 可选安装nginx, VLess运行在443端口" green " 16. 安装 v2ray或xray (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS)+xray自带的trojan, 支持CDN, 可选安装nginx, VLess运行在443端口" green " 17. 安装 v2ray或xray (VLess-TCP-XTLS Vision)) 不支持CDN, 可选安装nginx, VLess运行在443端口" green " 18. 安装 v2ray或xray (VLess-TCP-REALITY XTLS Vision)) 不支持CDN, 可选安装nginx, VLess运行在443端口" green " 19. 升级 v2ray或xray 到最新版本" red " 20. 卸载 v2ray或xray 和 nginx" echo green " 21. 同时安装 v2ray或xray 和 trojan-go (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS)+Trojan, 支持CDN, 可选安装nginx, VLess运行在443端口" green " 22. 同时安装 nginx, v2ray或xray 和 trojan-go (VLess/Vmess-WS-TLS)+Trojan, 支持CDN, trojan-go运行在443端口" green " 23. 同时安装 nginx, v2ray或xray 和 trojan-go, 通过 nginx SNI 分流, 支持CDN, 支持与现有网站共存, nginx 运行在443端口 " red " 24. 卸载 trojan-go, v2ray或xray 和 nginx" echo green " 25. 查看已安装的配置和用户密码等信息" green " 26. 申请免费的SSL证书" green " 30. 子菜单 安装 trojan 和 v2ray 可视化管理面板, VPS测速工具, Netflix测试解锁工具, 安装宝塔面板等" green " ==================================================" green " 31. 安装DNS服务器 AdGuardHome 支持去广告" green " 32. 给 AdGuardHome 申请免费的SSL证书, 并开启DOH与DOT" green " 33. 安装DNS国内国外分流服务器 mosdns 或 mosdns-cn" red " 34. 卸载 mosdns 或 mosdns-cn DNS服务器 " echo green " 41. 安装OhMyZsh与插件zsh-autosuggestions, Micro编辑器 等软件" green " 42. 开启root用户SSH登陆, 如谷歌云默认关闭root登录,可以通过此项开启" green " 43. 修改SSH 登陆端口号" green " 44. 设置时区为北京时间" green " 45. 用 VI 编辑 authorized_keys 文件 填入公钥, 用于SSH免密码登录 增加安全性" echo green " 88. 升级脚本" green " 0. 退出脚本" else green " ====================================================================================================" green " Trojan-go V2ray Xray Installation | 2024-3-13 | OS support: centos7+ / debian9+ / ubuntu16.04+" green " ====================================================================================================" green " 1. Install linux kernel, bbr plus kernel, WireGuard and Cloudflare WARP. Unlock Netflix geo restriction and avoid Google reCAPTCHA" echo green " 2. Install trojan/trojan-go with nginx, enable websocket, support CDN acceleration, trojan-go running at 443 port serve TLS" green " 3. Install trojan/trojan-go only, trojan-go running at 443(can customize port) serve TLS. Easy integration with existing website" red " 4. Remove trojan/trojan-go and nginx" echo green " 6. Install Shadowsocks Rust" green " 7. Install Xray Shadowsocks" red " 8. Remove Shadowsocks Rust or Xray" echo green " 11. Install v2ray/xray with nginx, ([Vmess/Vless]-[TCP/WS/gRPC/H2/QUIC]-TLS), support CDN acceleration, nginx running at 443 port serve TLS" green " 12. Install v2ray/xray only. ([Vmess/Vless]-[TCP/WS/gRPC/H2/QUIC]), no TLS encryption. Easy integration with existing website" echo green " 13. Install v2ray/xray (VLess-TCP-[TLS/XTLS])+(VMess-TCP-TLS)+(VMess-WS-TLS), support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 14. Install v2ray/xray (VLess-gRPC-TLS) support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 15. Install v2ray/xray (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS) support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 16. Install v2ray/xray (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS)+(xray's trojan), support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 17. Install v2ray/xray (VLess-TCP-XTLS Vision) not support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 18. Install v2ray/xray (VLess-TCP-REALITY XTLS Vision) not support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 19. Upgrade v2ray/xray to latest version" red " 20. Remove v2ray/xray and nginx" echo green " 21. Install both v2ray/xray and trojan-go (VLess-TCP-[TLS/XTLS])+(VLess-WS-TLS)+Trojan, support CDN, nginx is optional, VLess running at 443 port serve TLS" green " 22. Install both v2ray/xray and trojan-go with nginx, (VLess/Vmess-WS-TLS)+Trojan, support CDN, trojan-go running at 443 port serve TLS" green " 23. Install both v2ray/xray and trojan-go with nginx. Using nginx SNI distinguish traffic by different domain name, support CDN. Easy integration with existing website. nginx SNI running at 443 port" red " 24. Remove trojan-go, v2ray/xray and nginx" echo green " 25. Show info and password for installed trojan-go and v2ray" green " 26. Get a free SSL certificate for one or multiple domains" green " 30. Submenu. install trojan and v2ray UI admin panel, VPS speedtest tools, Netflix unlock tools. Miscellaneous tools" green " ==================================================" green " 31. Install AdGuardHome, ads & trackers blocking DNS server " green " 32. Get free SSL certificate for AdGuardHome and enable DOH/DOT " green " 33. Install DNS server MosDNS/MosDNS-cn" red " 34. Remove DNS server MosDNS/MosDNS-cn" echo green " 41. Install Oh My Zsh and zsh-autosuggestions plugin, Micro editor" green " 42. Enable root user login SSH, Some VPS disable root login as default, use this option to enable" green " 43. Modify SSH login port number. Secure your VPS" green " 44. Set timezone to Beijing time" green " 45. Using VI open authorized_keys file, enter your public key. Then save file. In order to login VPS without Password" echo green " 88. upgrade this script to latest version" green " 0. exit" fi echo read -p "Please input number:" menuNumberInput case "$menuNumberInput" in 1 ) installWireguard ;; 2 ) configInstallNginxMode="noSSL" isTrojanGoSupportWebsocket="true" installTrojanV2rayWithNginx "trojan_nginx" ;; 3 ) installTrojanV2rayWithNginx "trojan" ;; 4 ) removeTrojan removeNginx ;; 6 ) installShadowsocksRust ;; 7 ) installShadowsocks ;; 8 ) removeShadowsocks ;; 11 ) configInstallNginxMode="v2raySSL" configV2rayWorkingMode="" installTrojanV2rayWithNginx "nginx_v2ray" ;; 12 ) configInstallNginxMode="" configV2rayWorkingMode="" installTrojanV2rayWithNginx "v2ray" ;; 13 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessTCPVmessWS" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 14 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessgRPC" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 15 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessTCPWS" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 16 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessTCPWSTrojan" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 17 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessTCPVision" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 18 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="vlessTCPREALITY" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 19) upgradeV2ray ;; 20 ) removeV2ray removeNginx ;; 21 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="trojan" installTrojanV2rayWithNginx "v2ray_nginxOptional" ;; 22 ) configInstallNginxMode="noSSL" configV2rayWorkingMode="" configV2rayWorkingNotChangeMode="true" installTrojanV2rayWithNginx "trojan_nginx_v2ray" ;; 23 ) configInstallNginxMode="sni" configV2rayWorkingMode="sni" installTrojanV2rayWithNginx "nginxSNI_trojan_v2ray" ;; 24 ) removeV2ray removeTrojan removeNginx ;; 25 ) cat "${configReadme}" ;; 26 ) installTrojanV2rayWithNginx ;; 30 ) startMenuOther ;; 31 ) installAdGuardHome ;; 32 ) getAdGuardHomeSSLCertification "$@" ;; 33 ) installMosdns ;; 34 ) removeMosdns ;; 41 ) setLinuxDateZone installPackage installSoftEditor installSoftOhMyZsh ;; 42 ) setLinuxRootLogin sleep 4s start_menu ;; 43 ) changeLinuxSSHPort sleep 10s start_menu ;; 44 ) setLinuxDateZone sleep 4s start_menu ;; 45 ) editLinuxLoginWithPublicKey ;; 66 ) isTrojanMultiPassword="yes" echo "isTrojanMultiPassword: yes" sleep 3s start_menu ;; 76 ) vps_returnroute vps_returnroute2 ;; 77 ) vps_netflixgo vps_netflix2 ;; 80 ) installPackage ;; 81 ) installBBR ;; 82 ) installBBR2 ;; 83 ) installSWAP ;; 84 ) firewallForbiden ;; 88 ) upgradeScript ;; 89 ) generateXrayRealityPrivateKey ;; 99 ) getV2rayVersion "wgcf" ;; 0 ) exit 1 ;; * ) clear red "请输入正确数字 !" sleep 2s start_menu ;; esac } function setLanguage(){ echo green " ==================================================" green " Please choose your language" green " 1. English" green " 2. 中文" echo read -r -p "Please input your language:" languageInput case "${languageInput}" in 1 ) echo "en" > ${configLanguageFilePath} showMenu ;; 2 ) echo "cn" > ${configLanguageFilePath} showMenu ;; * ) red " Please input the correct number !" setLanguage ;; esac } configLanguageFilePath="${HOME}/language_setting_v2ray_trojan.md" configLanguage="cn" function showMenu(){ if [ -f "${configLanguageFilePath}" ]; then configLanguage=$(cat ${configLanguageFilePath}) case "${configLanguage}" in cn ) start_menu "first" ;; en ) start_menu "first" ;; * ) setLanguage ;; esac else installPackage setLanguage fi } showMenu