4011 lines
166 KiB
Bash
4011 lines
166 KiB
Bash
#!/bin/bash
|
|
|
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
|
export PATH
|
|
#stty erase ^?
|
|
|
|
cd "$(
|
|
cd "$(dirname "$0")" || exit
|
|
pwd
|
|
)" || exit
|
|
|
|
#=====================================================
|
|
# System Request: Debian 9+/Ubuntu 18.04+/Centos 7+
|
|
# Author: hello-yunshu
|
|
# Dscription: Xray Onekey Management
|
|
# Version: 2.0
|
|
# email: admin@idleleo.com
|
|
# Official document: hey.run
|
|
#=====================================================
|
|
|
|
#fonts color
|
|
Green="\033[32m"
|
|
Red="\033[31m"
|
|
GreenW="\033[1;32m"
|
|
RedW="\033[1;31m"
|
|
#Yellow="\033[33m"
|
|
GreenBG="\033[42;30m"
|
|
RedBG="\033[41;30m"
|
|
YellowBG="\033[43;30m"
|
|
Font="\033[0m"
|
|
|
|
#notification information
|
|
Info="${Green}[$(gettext "提醒")]${Font}"
|
|
OK="${Green}[OK]${Font}"
|
|
Error="${RedW}[$(gettext "错误")]${Font}"
|
|
Warning="${RedW}[$(gettext "警告")]${Font}"
|
|
|
|
shell_version="2.5.6"
|
|
shell_mode="$(gettext "未安装")"
|
|
tls_mode="None"
|
|
ws_grpc_mode="None"
|
|
local_bin="/usr/local"
|
|
idleleo_dir="/etc/idleleo"
|
|
idleleo="${idleleo_dir}/install.sh"
|
|
idleleo_conf_dir="${idleleo_dir}/conf"
|
|
log_dir="${idleleo_dir}/logs"
|
|
xray_bin_dir="${local_bin}/bin"
|
|
xray_conf_dir="${idleleo_conf_dir}/xray"
|
|
nginx_conf_dir="${idleleo_conf_dir}/nginx"
|
|
xray_conf="${xray_conf_dir}/config.json"
|
|
xray_status_conf="${xray_conf_dir}/status_config.json"
|
|
xray_default_conf="${local_bin}/etc/xray/config.json"
|
|
nginx_conf="${nginx_conf_dir}/00-xray.conf"
|
|
nginx_ssl_conf="${nginx_conf_dir}/01-xray-80.conf"
|
|
nginx_upstream_conf="${nginx_conf_dir}/02-xray-server.conf"
|
|
idleleo_commend_file="/usr/bin/idleleo"
|
|
ssl_chainpath="${idleleo_dir}/cert"
|
|
nginx_dir="${local_bin}/nginx"
|
|
xray_info_file="${idleleo_dir}/info/xray_info.inf"
|
|
xray_qr_config_file="${idleleo_dir}/info/vless_qr.json"
|
|
nginx_systemd_file="/etc/systemd/system/nginx.service"
|
|
xray_systemd_file="/etc/systemd/system/xray.service"
|
|
xray_access_log="/var/log/xray/access.log"
|
|
xray_error_log="/var/log/xray/error.log"
|
|
amce_sh_file="/root/.acme.sh/acme.sh"
|
|
auto_update_file="${idleleo_dir}/auto_update.sh"
|
|
ssl_update_file="${idleleo_dir}/ssl_update.sh"
|
|
myemali="my@example.com"
|
|
shell_version_tmp="${idleleo_dir}/tmp/shell_version.tmp"
|
|
get_versions_all=$(curl -s https://www.idleleo.com/api/xray_shell_versions)
|
|
read_config_status=1
|
|
reality_add_more="off"
|
|
reality_add_nginx="off"
|
|
old_config_status="off"
|
|
old_tls_mode="NULL"
|
|
random_num=$((RANDOM % 12 + 4))
|
|
[[ -f "${xray_qr_config_file}" ]] && info_extraction_all=$(jq -rc . ${xray_qr_config_file})
|
|
|
|
[[ ! -d ${log_dir} ]] && mkdir -p ${log_dir}
|
|
[[ ! -f "${log_dir}/install.log" ]] && touch ${log_dir}/install.log
|
|
LOG_FILE="${log_dir}/install.log"
|
|
LOG_MAX_SIZE=$((3 * 1024 * 1024)) # 3 MB
|
|
MAX_ARCHIVES=5
|
|
|
|
log() {
|
|
if [ $(stat -c%s "$LOG_FILE" 2>/dev/null) -gt $LOG_MAX_SIZE ]; then
|
|
log_rotate
|
|
fi
|
|
|
|
local message=$(echo -e "$1" | sed 's/\x1B\[\([0-9]\(;[0-9]\)*\)*m//g' | tr -d '\n')
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" | tee -a $LOG_FILE >/dev/null
|
|
}
|
|
|
|
log_rotate() {
|
|
local timestamp=$(date +%Y%m%d%H%M%S)
|
|
local archived_log="${LOG_FILE}.${timestamp}.gz"
|
|
|
|
if ! gzip -c "$LOG_FILE" > "$archived_log"; then
|
|
log_echo "${Error} ${RedBG} $(gettext "日志文件归档失败") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
if ! :> "$LOG_FILE"; then
|
|
log_echo "${Error} ${RedBG} $(gettext "清空日志文件失败") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
log "$(gettext "日志文件已轮转并归档为") $archived_log"
|
|
|
|
rotate_archives
|
|
}
|
|
|
|
rotate_archives() {
|
|
local archives=($(ls ${LOG_FILE}.*.gz 2>/dev/null))
|
|
while [ ${#archives[@]} -gt $MAX_ARCHIVES ]; do
|
|
oldest_archive=${archives[0]}
|
|
rm "$oldest_archive"
|
|
archives=($(ls ${LOG_FILE}.*.gz 2>/dev/null))
|
|
done
|
|
}
|
|
|
|
log_echo() {
|
|
local message=$(printf "%b" "$@")
|
|
echo -e "$message"
|
|
log "$message"
|
|
}
|
|
|
|
##兼容代码, 未来删除
|
|
[[ ! -d "${idleleo_dir}/tmp" ]] && mkdir -p ${idleleo_dir}/tmp
|
|
|
|
source '/etc/os-release'
|
|
|
|
VERSION=$(echo "${VERSION}" | awk -F "[()]" '{print $2}')
|
|
|
|
check_system() {
|
|
if [[ "${ID}" == "centos" && ${VERSION_ID} -ge 7 ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "当前系统为") Centos ${VERSION_ID} ${VERSION} ${Font}"
|
|
INS="yum"
|
|
[[ ! -f "${xray_qr_config_file}" ]] && $INS update || true
|
|
elif [[ "${ID}" == "debian" && ${VERSION_ID} -ge 8 ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "当前系统为") Debian ${VERSION_ID} ${VERSION} ${Font}"
|
|
INS="apt"
|
|
[[ ! -f "${xray_qr_config_file}" ]] && $INS update || true
|
|
elif [[ "${ID}" == "ubuntu" && $(echo "${VERSION_ID}" | cut -d '.' -f1) -ge 16 ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "当前系统为") Ubuntu ${VERSION_ID} ${UBUNTU_CODENAME} ${Font}"
|
|
INS="apt"
|
|
if [[ ! -f "${xray_qr_config_file}" ]]; then
|
|
rm /var/lib/dpkg/lock || true
|
|
dpkg --configure -a || true
|
|
rm /var/lib/apt/lists/lock || true
|
|
rm /var/cache/apt/archives/lock || true
|
|
$INS update || true
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前系统为") ${ID} ${VERSION_ID} $(gettext "不在支持的系统列表内, 安装中断")! ${Font}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
is_root() {
|
|
if [[ 0 == $UID ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "当前用户是 root 用户, 进入安装流程") ${Font}"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前用户不是 root 用户, 请切换到 root 用户后重新执行脚本")! ${Font}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_and_create_user_group() {
|
|
if ! getent group nogroup > /dev/null; then
|
|
groupadd nogroup
|
|
fi
|
|
|
|
if ! id nobody > /dev/null 2>&1; then
|
|
useradd -r -g nogroup -s /sbin/nologin -c "Unprivileged User" nobody
|
|
fi
|
|
}
|
|
|
|
check_language_update() {
|
|
local lang_code="$1"
|
|
local local_file="${idleleo_dir}/languages/${lang_code}/LC_MESSAGES/xray_install.mo"
|
|
local version_file_url="https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/refs/heads/main/languages/${lang_code}/LC_MESSAGES/version"
|
|
|
|
[[ ! -f "${local_file}" ]] && return 0
|
|
|
|
local remote_version
|
|
remote_version=$(curl -s "${version_file_url}" || echo "")
|
|
|
|
if [ -z "$remote_version" ]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "无法获取远程语言文件信息") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
local local_version
|
|
local_version=$(cat "${idleleo_dir}/languages/${lang_code}/LC_MESSAGES/version" 2>/dev/null || echo "")
|
|
|
|
[ "$remote_version" != "$local_version" ]
|
|
}
|
|
|
|
update_language_file() {
|
|
local lang_code="$1"
|
|
local mo_file="${idleleo_dir}/languages/${lang_code}/LC_MESSAGES/xray_install.mo"
|
|
local version_file="${idleleo_dir}/languages/${lang_code}/LC_MESSAGES/version"
|
|
local github_url="https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/languages"
|
|
|
|
mkdir -p "${idleleo_dir}/languages/${lang_code}/LC_MESSAGES"
|
|
|
|
log_echo "${Info} ${Green} $(gettext "正在更新语言文件")... ${Font}"
|
|
|
|
if ! curl -s -o "${mo_file}" "${github_url}/${lang_code}/LC_MESSAGES/xray_install.mo"; then
|
|
log_echo "${Error} ${RedBG} $(gettext "语言文件更新失败") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -s "${mo_file}" ]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "语言文件无效") ${Font}"
|
|
rm -f "${mo_file}"
|
|
return 1
|
|
fi
|
|
|
|
if ! curl -s -o "${version_file}" "${github_url}/${lang_code}/LC_MESSAGES/version"; then
|
|
log_echo "${Error} ${RedBG} $(gettext "版本文件更新失败") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
find "${idleleo_dir}/languages" -type d -exec chmod 755 {} \;
|
|
find "${idleleo_dir}/languages" -type f -exec chmod 644 {} \;
|
|
|
|
log_echo "${OK} ${Green} $(gettext "语言文件更新完成") ${Font}"
|
|
}
|
|
|
|
init_language() {
|
|
if ! command -v gettext >/dev/null 2>&1; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "正在安装") gettext... ${Font}"
|
|
pkg_install "gettext"
|
|
if [ $? -ne 0 ]; then
|
|
log_echo "${Error} ${RedBG} gettext $(gettext "安装失败"), $(gettext "将使用默认语言") ${Font}"
|
|
export LANG=zh_CN.UTF-8
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
local gettext_paths=(
|
|
"/usr/share/gettext/gettext.sh"
|
|
"/usr/local/share/gettext/gettext.sh"
|
|
"/usr/bin/gettext.sh"
|
|
"/usr/local/bin/gettext.sh"
|
|
"/usr/share/gettext-"*/gettext.sh
|
|
)
|
|
|
|
local gettext_sh=""
|
|
for path in "${gettext_paths[@]}"; do
|
|
if [ -f "$path" ]; then
|
|
gettext_sh="$path"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -z "$gettext_sh" ]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "未找到") gettext.sh, $(gettext "将使用默认语言") ${Font}"
|
|
export LANG=zh_CN.UTF-8
|
|
return 1
|
|
fi
|
|
|
|
[ -d "${idleleo_dir}/languages" ] || mkdir "${idleleo_dir}/languages"
|
|
export TEXTDOMAIN="xray_install"
|
|
export TEXTDOMAINDIR="${idleleo_dir}/languages"
|
|
. "$gettext_sh"
|
|
|
|
if [ -f "${idleleo_dir}/language.conf" ]; then
|
|
source "${idleleo_dir}/language.conf"
|
|
|
|
if [[ "${LANG%.*}" != "zh_CN" ]]; then
|
|
local lang_code
|
|
case "${LANG%.*}" in
|
|
"en_US") lang_code="en" ;;
|
|
"fa_IR") lang_code="fa" ;;
|
|
"ru_RU") lang_code="ru" ;;
|
|
"ko_KR") lang_code="ko" ;;
|
|
*)
|
|
log_echo "${Warning} ${YellowBG} $(gettext "不支持的语言"):${LANG%.*}, $(gettext "将使用默认语言") ${Font}"
|
|
export LANG=zh_CN.UTF-8
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
local lang_file="${TEXTDOMAINDIR}/${lang_code}/LC_MESSAGES/${TEXTDOMAIN}.mo"
|
|
if [ ! -f "$lang_file" ]; then
|
|
if ! update_language_file "$lang_code"; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "语言文件更新失败"), $(gettext "将使用默认语言") ${Font}"
|
|
export LANG=zh_CN.UTF-8
|
|
return 0
|
|
fi
|
|
elif check_language_update "$lang_code"; then
|
|
log_echo "${Info} ${Green} $(gettext "发现语言文件更新") ${Font}"
|
|
if update_language_file "$lang_code"; then
|
|
. "$gettext_sh"
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
export LANG=zh_CN.UTF-8
|
|
fi
|
|
}
|
|
|
|
judge() {
|
|
if [[ 0 -eq $? ]]; then
|
|
log_echo "${OK} ${GreenBG} $1 $(gettext "完成") ${Font}"
|
|
sleep 0.5
|
|
else
|
|
log_echo "${Error} ${RedBG} $1 $(gettext "失败") ${Font}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_version() {
|
|
echo ${get_versions_all} | jq -rc ".$1"
|
|
[[ 0 -ne $? ]] && log_echo "${Error} ${RedBG} $(gettext "在线版本检测失败, 请稍后再试")! ${Font}" && exit 1
|
|
}
|
|
|
|
pkg_install_judge() {
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
yum list installed | grep -iw "^$1"
|
|
else
|
|
dpkg --get-selections | grep -iw "^$1" | grep -ivw "deinstall"
|
|
fi
|
|
}
|
|
|
|
pkg_install() {
|
|
install_array=(${1//,/ })
|
|
install_status=1
|
|
if [[ ${#install_array[@]} -gt 1 ]]; then
|
|
for install_var in ${install_array[@]}; do
|
|
if [[ -z $(pkg_install_judge "${install_var}") ]]; then
|
|
${INS} -y install ${install_var}
|
|
install_status=0
|
|
fi
|
|
done
|
|
if [[ ${install_status} == 0 ]]; then
|
|
judge "$(gettext "安装") ${1//,/ }"
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "已安装") ${1//,/ } ${Font}"
|
|
sleep 0.5
|
|
fi
|
|
else
|
|
if [[ -z $(pkg_install_judge "$1") ]]; then
|
|
${INS} -y install $1
|
|
judge "$(gettext "安装") $1"
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "已安装") $1 ${Font}"
|
|
sleep 0.5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
dependency_install() {
|
|
pkg_install "bc,curl,dbus,git,jq,lsof,python3,qrencode,wget"
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
pkg_install "crontabs"
|
|
else
|
|
pkg_install "cron"
|
|
fi
|
|
if [[ ! -f "/var/spool/cron/root" ]] && [[ ! -f "/var/spool/cron/crontabs/root" ]]; then
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
touch /var/spool/cron/root && chmod 600 /var/spool/cron/root
|
|
systemctl start crond && systemctl enable crond >/dev/null 2>&1
|
|
judge "crontab $(gettext "自启动配置")"
|
|
else
|
|
touch /var/spool/cron/crontabs/root && chmod 600 /var/spool/cron/crontabs/root
|
|
systemctl start cron && systemctl enable cron >/dev/null 2>&1
|
|
judge "crontab $(gettext "自启动配置")"
|
|
fi
|
|
fi
|
|
if [[ ${tls_mode} != "None" ]]; then
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
pkg_install "epel-release,iputils,pcre,pcre-devel,zlib-devel,perl-IPC-Cmd"
|
|
else
|
|
pkg_install "iputils-ping,libpcre3,libpcre3-dev,zlib1g-dev"
|
|
fi
|
|
judge "Nginx $(gettext "链接库安装")"
|
|
fi
|
|
}
|
|
|
|
read_optimize() {
|
|
local prompt="$1" var_name="$2" default_value="${3:-NULL}" min_value="${4:-}" max_value="${5:-}" error_msg="${6:-$(gettext "值为空或超出范围, 请重新输入")!}"
|
|
local user_input
|
|
|
|
read -rp "$prompt" user_input
|
|
|
|
if [[ -z $user_input ]]; then
|
|
if [[ $default_value != "NULL" ]]; then
|
|
user_input=$default_value
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "值为空, 请重新输入")! ${Font}"
|
|
read_optimize "$prompt" "$var_name" "$default_value" "$min_value" "$max_value" "$error_msg"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
printf -v "$var_name" "%s" "$user_input"
|
|
|
|
if [[ -n $min_value ]] && [[ -n $max_value ]]; then
|
|
if (( user_input < min_value )) || (( user_input > max_value )); then
|
|
log_echo "${Error} ${RedBG} $error_msg ${Font}"
|
|
read_optimize "$prompt" "$var_name" "$default_value" "$min_value" "$max_value" "$error_msg"
|
|
return
|
|
fi
|
|
fi
|
|
}
|
|
|
|
basic_optimization() {
|
|
sed -i '/^\*\ *soft\ *nofile\ *[[:digit:]]*/d' /etc/security/limits.conf
|
|
sed -i '/^\*\ *hard\ *nofile\ *[[:digit:]]*/d' /etc/security/limits.conf
|
|
echo '* soft nofile 65536' >>/etc/security/limits.conf
|
|
echo '* hard nofile 65536' >>/etc/security/limits.conf
|
|
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
|
|
setenforce 0
|
|
fi
|
|
|
|
}
|
|
|
|
create_directory() {
|
|
if [[ ${tls_mode} != "None" ]]; then
|
|
[[ ! -d "${nginx_conf_dir}" ]] && mkdir -p ${nginx_conf_dir}
|
|
fi
|
|
[[ ! -d "${ssl_chainpath}" ]] && mkdir -p ${ssl_chainpath}
|
|
[[ ! -d "${xray_conf_dir}" ]] && mkdir -p ${xray_conf_dir}
|
|
[[ ! -d "${idleleo_dir}/info" ]] && mkdir -p ${idleleo_dir}/info
|
|
}
|
|
|
|
port_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "确定端口") ${Font}"
|
|
read_optimize "$(gettext "请输入端口") ($(gettext "默认值"):443):" "port" 443 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
if [[ ${port} -eq 9443 || ${port} -eq 9403 ]] && [[ ${tls_mode} == "Reality" ]]; then
|
|
echo -e "${Error} ${RedBG} $(gettext "端口不允许使用, 请重新输入")! ${Font}"
|
|
read_optimize "$(gettext "请输入端口") ($(gettext "默认值"):443):" "port" 443 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ws_grpc_choose() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "请选择安装协议") ws/gRPC ${Font}"
|
|
echo -e "${Red}1${Font}: ws ($(gettext "默认"))"
|
|
echo "2: gRPC"
|
|
echo "3: ws+gRPC"
|
|
local choose_network
|
|
read_optimize "$(gettext "请输入"): " "choose_network" 1 1 3 "$(gettext "请输入有效的数字")"
|
|
if [[ $choose_network == 2 ]]; then
|
|
[[ ${shell_mode} == "Nginx+ws+TLS" ]] && shell_mode="Nginx+gRPC+TLS"
|
|
[[ ${shell_mode} == "Reality" ]] && shell_mode="Reality+gRPC"
|
|
[[ ${shell_mode} == "ws ONLY" ]] && shell_mode="gRPC ONLY"
|
|
ws_grpc_mode="onlygRPC"
|
|
elif [[ $choose_network == 3 ]]; then
|
|
[[ ${shell_mode} == "Nginx+ws+TLS" ]] && shell_mode="Nginx+ws+gRPC+TLS"
|
|
[[ ${shell_mode} == "Reality" ]] && shell_mode="Reality+ws+gRPC"
|
|
[[ ${shell_mode} == "ws ONLY" ]] && shell_mode="ws+gRPC ONLY"
|
|
ws_grpc_mode="all"
|
|
else
|
|
[[ ${shell_mode} == "Reality" ]] && shell_mode="Reality+ws"
|
|
ws_grpc_mode="onlyws"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
xray_reality_add_more_choose() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否添加简单 ws/gRPC 协议 用于负载均衡") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
echo -e "${Warning} ${YellowBG} $(gettext "如不清楚具体用途, 请勿选择")! ${Font}"
|
|
read -r reality_add_more_fq
|
|
case $reality_add_more_fq in
|
|
[yY][eE][sS] | [yY])
|
|
reality_add_more="on"
|
|
ws_grpc_choose
|
|
ws_inbound_port_set
|
|
grpc_inbound_port_set
|
|
ws_path_set
|
|
grpc_path_set
|
|
port_exist_check "${xport}"
|
|
port_exist_check "${gport}"
|
|
;;
|
|
*)
|
|
reality_add_more="off"
|
|
ws_inbound_port_set
|
|
grpc_inbound_port_set
|
|
ws_path_set
|
|
grpc_path_set
|
|
log_echo "${OK} ${GreenBG} $(gettext "已跳过添加简单 ws/gRPC 协议") ${Font}"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
ws_grpc_qr() {
|
|
artpath="None"
|
|
artxport="None"
|
|
artserviceName="None"
|
|
artgport="None"
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
artxport=${xport}
|
|
artpath=${path}
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
artgport=${gport}
|
|
artserviceName=${serviceName}
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
artxport=${xport}
|
|
artpath=${path}
|
|
artgport=${gport}
|
|
artserviceName=${serviceName}
|
|
fi
|
|
}
|
|
|
|
ws_inbound_port_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义") ws inbound_port [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r inbound_port_modify_fq
|
|
case $inbound_port_modify_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入自定义") ws inbound_port ($(gettext "请勿与其他端口相同")!): " "xport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
;;
|
|
*)
|
|
xport=$((RANDOM % 1000 + 10000))
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
;;
|
|
esac
|
|
else
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
fi
|
|
fi
|
|
}
|
|
|
|
grpc_inbound_port_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlygRPC" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义") gRPC inbound_port [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r inbound_port_modify_fq
|
|
case $inbound_port_modify_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入自定义") gRPC inbound_port ($(gettext "请勿与其他端口相同")!): " "gport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
;;
|
|
*)
|
|
gport=$((RANDOM % 1000 + 10000))
|
|
[[ ${gport} == ${xport} ]] && gport=$((RANDOM % 1000 + 10000))
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
;;
|
|
esac
|
|
else
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
fi
|
|
fi
|
|
}
|
|
|
|
firewall_set() {
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要设置防火墙") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r firewall_set_fq
|
|
case $firewall_set_fq in
|
|
[yY][eE][sS] | [yY])
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
pkg_install "iptables-services"
|
|
else
|
|
pkg_install "iptables-persistent"
|
|
fi
|
|
iptables -A INPUT -i lo -j ACCEPT
|
|
iptables -A OUTPUT -o lo -j ACCEPT
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
iptables -I INPUT -p tcp -m multiport --dport 53,80,${port} -j ACCEPT
|
|
iptables -I INPUT -p udp -m multiport --dport 53,80,${port} -j ACCEPT
|
|
iptables -I OUTPUT -p tcp -m multiport --sport 53,80,${port} -j ACCEPT
|
|
iptables -I OUTPUT -p udp -m multiport --sport 53,80,${port} -j ACCEPT
|
|
iptables -I INPUT -p udp --dport 1024:65535 -j ACCEPT
|
|
fi
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
iptables -I INPUT -p tcp -m multiport --dport 53,${xport} -j ACCEPT
|
|
iptables -I INPUT -p udp -m multiport --dport 53,${xport} -j ACCEPT
|
|
iptables -I OUTPUT -p tcp -m multiport --sport 53,${xport} -j ACCEPT
|
|
iptables -I OUTPUT -p udp -m multiport --sport 53,${xport} -j ACCEPT
|
|
iptables -I INPUT -p udp --dport 1024:65535 -j ACCEPT
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
iptables -I INPUT -p tcp -m multiport --dport 53,${gport} -j ACCEPT
|
|
iptables -I INPUT -p udp -m multiport --dport 53,${gport} -j ACCEPT
|
|
iptables -I OUTPUT -p tcp -m multiport --sport 53,${gport} -j ACCEPT
|
|
iptables -I OUTPUT -p udp -m multiport --sport 53,${gport} -j ACCEPT
|
|
iptables -I INPUT -p udp --dport 1024:65535 -j ACCEPT
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
iptables -I INPUT -p tcp -m multiport --dport 53,${xport},${gport} -j ACCEPT
|
|
iptables -I INPUT -p udp -m multiport --dport 53,${xport},${gport} -j ACCEPT
|
|
iptables -I OUTPUT -p tcp -m multiport --sport 53,${xport},${gport} -j ACCEPT
|
|
iptables -I OUTPUT -p udp -m multiport --sport 53,${xport},${gport} -j ACCEPT
|
|
iptables -I INPUT -p udp --dport 1024:65535 -j ACCEPT
|
|
fi
|
|
if [[ "${ID}" == "centos" && ${VERSION_ID} -ge 7 ]]; then
|
|
service iptables save
|
|
service iptables restart
|
|
log_echo "${OK} ${GreenBG} $(gettext "防火墙") $(gettext "重启完成") ${Font}"
|
|
else
|
|
netfilter-persistent save
|
|
systemctl restart iptables
|
|
log_echo "${OK} ${GreenBG} $(gettext "防火墙") $(gettext "重启完成") ${Font}"
|
|
fi
|
|
log_echo "${OK} ${GreenBG} $(gettext "开放防火墙相关端口") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "若修改配置, 请注意关闭防火墙相关端口") ${Font}"
|
|
log_echo "${OK} ${GreenBG} $(gettext "配置") Xray FullCone ${Font}"
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${GreenBG} $(gettext "跳过防火墙设置") ${Font}"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
ws_path_set() {
|
|
if [[ "on" != ${old_config_status} ]] || [[ ${change_ws_path} == "yes" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义") ws $(gettext "伪装路径") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r path_modify_fq
|
|
case $path_modify_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入自定义") ws $(gettext "伪装路径") ($(gettext "不需要")"/"):" "path" "NULL"
|
|
log_echo "${Green} ws $(gettext "伪装路径"): ${path} ${Font}"
|
|
;;
|
|
*)
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
log_echo "${Green} ws $(gettext "伪装路径"): ${path} ${Font}"
|
|
;;
|
|
esac
|
|
else
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
fi
|
|
elif [[ ${ws_grpc_mode} == "onlyws" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要修改") ws $(gettext "伪装路径") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r change_ws_path_fq
|
|
case $change_ws_path_fq in
|
|
[yY][eE][sS] | [yY])
|
|
change_ws_path="yes"
|
|
ws_path_set
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
grpc_path_set() {
|
|
if [[ "on" != ${old_config_status} ]] || [[ ${change_grpc_path} == "yes" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlygRPC" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义") gRPC $(gettext "伪装路径") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r path_modify_fq
|
|
case $path_modify_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入自定义") gRPC $(gettext "伪装路径") ($(gettext "不需要")"/"):" "serviceName" "NULL"
|
|
log_echo "${Green} gRPC $(gettext "伪装路径"): ${serviceName} ${Font}"
|
|
;;
|
|
*)
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
log_echo "${Green} gRPC $(gettext "伪装路径"): ${serviceName} ${Font}"
|
|
;;
|
|
esac
|
|
else
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
fi
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]] || [[ ${ws_grpc_mode} == "all" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要修改") gRPC $(gettext "伪装路径") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r change_grpc_path_fq
|
|
case $change_grpc_path_fq in
|
|
[yY][eE][sS] | [yY])
|
|
change_grpc_path="yes"
|
|
grpc_path_set
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
email_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义") Xray $(gettext "用户名") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r custom_email_fq
|
|
case $custom_email_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入正确的 email") (e.g. me@idleleo.com): " "custom_email" "NULL"
|
|
;;
|
|
*)
|
|
custom_email="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})@idleleo.com"
|
|
;;
|
|
esac
|
|
log_echo "${Green} Xray $(gettext "用户名") (email): ${custom_email} ${Font}"
|
|
fi
|
|
}
|
|
|
|
UUID_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要自定义字符串映射") (UUIDv5) [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r need_UUID5
|
|
case $need_UUID5 in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入自定义字符串") ($(gettext "最多30字符")):" "UUID5_char" "NULL"
|
|
UUID="$(UUIDv5_tranc ${UUID5_char})"
|
|
log_echo "${Green} $(gettext "自定义字符串"): ${UUID5_char} ${Font}"
|
|
log_echo "${Green} UUIDv5: ${UUID} ${Font}"
|
|
echo
|
|
;;
|
|
*)
|
|
UUID5_char="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
UUID="$(UUIDv5_tranc ${UUID5_char})"
|
|
log_echo "${Green} UUID $(gettext "映射字符串"): ${UUID5_char} ${Font}"
|
|
log_echo "${Green} UUID: ${UUID} ${Font}"
|
|
echo
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
target_set() {
|
|
if [[ "on" == ${old_config_status} ]] && [[ $(info_extraction target) != null ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "检测到 target 域名已配置, 是否保留") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r old_host_fq
|
|
case $old_host_fq in
|
|
[nN][oO] | [nN])
|
|
target_reset=1
|
|
nginx_reality_serverNames_del
|
|
;;
|
|
*)
|
|
target_reset=0
|
|
;;
|
|
esac
|
|
fi
|
|
if [[ ${target_reset} == 1 ]] || [[ "on" != ${old_config_status} ]]; then
|
|
local domain
|
|
local output
|
|
local curl_output
|
|
pkg_install "nmap"
|
|
|
|
while true; do
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "请输入一个域名") (e.g. bing.com)${Font}"
|
|
log_echo "${Green}$(gettext "域名要求支持 TLSv1.3、X25519 与 H2 以及域名非跳转用")${Font}"
|
|
read_optimize "$(gettext "确认域名符合要求后请输入"): " "domain" "NULL"
|
|
log_echo "${Green}$(gettext "正在检测域名请等待")...${Font}"
|
|
|
|
output=$(nmap --script ssl-enum-ciphers -p 443 "${domain}")
|
|
curl_output=$(curl -I -k -m 5 "https://${domain}" 2>&1)
|
|
|
|
# 检测TLSv1.3支持
|
|
if ! echo "$output" | grep -q "TLSv1.3"; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "该域名不支持") TLSv1.3 ${YellowBG}${Font}"
|
|
fi
|
|
|
|
# 检测X25519支持
|
|
if ! echo "$output" | grep -q "x25519"; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "该域名不支持") X25519 ${YellowBG}${Font}"
|
|
fi
|
|
|
|
# 检测HTTP/2支持
|
|
if ! echo "$curl_output" | grep -q "HTTP/2"; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "该域名不支持") HTTP/2 ${YellowBG}${Font}"
|
|
fi
|
|
|
|
# 检测是否跳转
|
|
if echo "$curl_output" | grep -i -q 'location:'; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "该域名发生了跳转") ${YellowBG}${Font}"
|
|
fi
|
|
|
|
if ! echo "$output" | grep -q "TLSv1.3" || \
|
|
! echo "$output" | grep -q "x25519" || \
|
|
! echo "$curl_output" | grep -q "HTTP/2" || \
|
|
echo "$curl_output" | grep -i -q 'location:'; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "该域名可能不满足所有要求") ${YellowBG}${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否仍要设置此域名") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r force_set_fq
|
|
case $force_set_fq in
|
|
[yY][eE][sS] | [yY])
|
|
target=$domain
|
|
break
|
|
;;
|
|
*)
|
|
continue
|
|
;;
|
|
esac
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "域名") ${domain} $(gettext "满足所有要求") ${Font}"
|
|
target=$domain
|
|
break
|
|
fi
|
|
done
|
|
log_echo "${Green} target $(gettext "域名"): ${target} ${Font}"
|
|
fi
|
|
}
|
|
|
|
serverNames_set() {
|
|
if [[ ${target_reset} == 1 ]] || [[ "on" != ${old_config_status} ]]; then
|
|
local custom_serverNames_fq
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要修改") ${target} $(gettext "域名的") serverNames [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
echo -e "${Green} $(gettext "默认为") ${target} $(gettext "域名本身")${Font}"
|
|
echo -e "${Warning} ${YellowBG} $(gettext "如不清楚具体用途, 请勿继续")! ${Font}"
|
|
read -r custom_serverNames_fq
|
|
case $custom_serverNames_fq in
|
|
[yY][eE][sS] | [yY])
|
|
read_optimize "$(gettext "请输入"): " "serverNames" "NULL"
|
|
;;
|
|
*)
|
|
serverNames=$target
|
|
;;
|
|
esac
|
|
log_echo "${Green} serverNames: ${serverNames} ${Font}"
|
|
echo
|
|
fi
|
|
}
|
|
|
|
keys_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
local keys
|
|
keys=$(${xray_bin_dir}/xray x25519 | tr '\n' ' ')
|
|
privateKey=$(echo "${keys}" | awk -F"Private key: " '{print $2}' | awk '{print $1}')
|
|
publicKey=$(echo "${keys}" | awk -F"Public key: " '{print $2}' | awk '{print $1}')
|
|
log_echo "${Green} privateKey: ${privateKey} ${Font}"
|
|
log_echo "${Green} publicKey: ${publicKey} ${Font}"
|
|
fi
|
|
}
|
|
|
|
shortIds_set() {
|
|
if [[ "on" != ${old_config_status} ]]; then
|
|
pkg_install "openssl"
|
|
shortIds=$(openssl rand -hex 4)
|
|
log_echo "${Green} shortIds: ${shortIds} ${Font}"
|
|
fi
|
|
}
|
|
|
|
nginx_upstream_server_set() {
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否变更") Nginx $(gettext "负载均衡") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
echo -e "${Warning} ${YellowBG} $(gettext "如不清楚具体用途, 请勿继续")! ${Font}"
|
|
read -r nginx_upstream_server_fq
|
|
case $nginx_upstream_server_fq in
|
|
[yY][eE][sS] | [yY])
|
|
echo -e "\n${GreenBG} $(gettext "请选择协议为 ws 或 gRPC") ${Font}"
|
|
echo "1: ws"
|
|
echo "2: gRPC"
|
|
echo "3: $(gettext "返回")"
|
|
local upstream_choose
|
|
read_optimize "$(gettext "请输入"): " "upstream_choose" "NULL" 1 3 "$(gettext "请重新输入正确的数字")"
|
|
|
|
fm_remote_url="https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/file_manager.sh"
|
|
fm_file_path=${nginx_conf_dir}
|
|
if [ ! -f "${idleleo_dir}/file_manager.sh" ]; then
|
|
log_echo "${Info} ${Green} $(gettext "本地文件 file_manager.sh 不存在, 正在下载")... ${Font}"
|
|
curl -sL "$fm_remote_url" -o "${idleleo_dir}/file_manager.sh"
|
|
if [ $? -ne 0 ]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "下载失败, 请手动下载并安装新版本") ${Font}"
|
|
return 1
|
|
fi
|
|
chmod +x "${idleleo_dir}/file_manager.sh"
|
|
fi
|
|
case $upstream_choose in
|
|
1) source "${idleleo_dir}/file_manager.sh" wsServers ${fm_file_path} ;;
|
|
2) source "${idleleo_dir}/file_manager.sh" grpcServers ${fm_file_path} ;;
|
|
3) ;;
|
|
*)
|
|
log_echo "${Error} ${RedBG} $(gettext "无效选项 请重试") ${Font}"
|
|
nginx_upstream_server_set
|
|
;;
|
|
esac
|
|
;;
|
|
*) ;;
|
|
esac
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前模式不支持此操作")! ${Font}"
|
|
fi
|
|
}
|
|
|
|
nginx_servernames_server_set() {
|
|
if [[ ${tls_mode} == "Reality" ]] && [[ ${reality_add_nginx} == "on" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否变更") Nginx serverNames [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
echo -e "${Warning} ${YellowBG} $(gettext "如不清楚具体用途, 请勿继续")! ${Font}"
|
|
echo -e "${Info} ${GreenBG} $(gettext "配置用途可以参考文章"): https://hey.run/archives/use-reality ${Font}"
|
|
read -r nginx_servernames_server_fq
|
|
case $nginx_servernames_server_fq in
|
|
[yY][eE][sS] | [yY])
|
|
fm_remote_url="https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/file_manager.sh"
|
|
fm_file_path=${nginx_conf_dir}
|
|
if [ ! -f "${idleleo_dir}/file_manager.sh" ]; then
|
|
log_echo "${Info} ${Green} $(gettext "本地文件 file_manager.sh 不存在, 正在下载")... ${Font}"
|
|
curl -sL "$fm_remote_url" -o "${idleleo_dir}/file_manager.sh"
|
|
if [ $? -ne 0 ]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "下载失败, 请手动下载并安装新版本") ${Font}"
|
|
return 1
|
|
fi
|
|
chmod +x "${idleleo_dir}/file_manager.sh"
|
|
fi
|
|
source "${idleleo_dir}/file_manager.sh" serverNames ${fm_file_path}
|
|
;;
|
|
*) ;;
|
|
esac
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前模式不支持此操作")! ${Font}"
|
|
fi
|
|
}
|
|
|
|
UUIDv5_tranc() {
|
|
[[ $# = 0 ]] && return
|
|
echo "import uuid;UUID_NAMESPACE=uuid.UUID('00000000-0000-0000-0000-000000000000');print(uuid.uuid5(UUID_NAMESPACE,'$1'));" | python3
|
|
}
|
|
|
|
modify_listen_address() {
|
|
local modifynum modifynum2
|
|
if [[ ${tls_mode} == "Reality" ]]; then
|
|
modifynum=1
|
|
modifynum2=2
|
|
else
|
|
modifynum=0
|
|
modifynum2=1
|
|
fi
|
|
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
jq --argjson modifynum "$modifynum" \
|
|
'.inbounds[$modifynum].listen = "0.0.0.0"' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray listen address $(gettext "修改")"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
jq --argjson modifynum2 "$modifynum2" \
|
|
'.inbounds[$modifynum2].listen = "0.0.0.0"' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray listen address $(gettext "修改")"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
jq --argjson modifynum "$modifynum" --argjson modifynum2 "$modifynum2" \
|
|
'.inbounds[$modifynum].listen = "0.0.0.0" | .inbounds[$modifynum2].listen = "0.0.0.0"' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray listen address $(gettext "修改")"
|
|
fi
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
}
|
|
|
|
modify_inbound_port() {
|
|
if [[ ${tls_mode} == "Reality" ]]; then
|
|
if [[ ${reality_add_nginx} == "off" ]]; then
|
|
jq --argjson port "${port}" --argjson xport "${xport}" --argjson gport "${gport}" \
|
|
'.inbounds[0].port = $port |
|
|
.inbounds[1].port = $xport |
|
|
.inbounds[2].port = $gport' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray inbound port $(gettext "修改")"
|
|
else
|
|
jq --argjson xport "${xport}" --argjson gport "${gport}" \
|
|
'.inbounds[1].port = $xport |
|
|
.inbounds[2].port = $gport' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray inbound port $(gettext "修改")"
|
|
fi
|
|
else
|
|
jq --argjson xport "${xport}" --argjson gport "${gport}" \
|
|
'.inbounds[0].port = $xport |
|
|
.inbounds[1].port = $gport' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "Xray inbound port $(gettext "修改")"
|
|
fi
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
}
|
|
|
|
modify_nginx_origin_conf() {
|
|
sed -i "s/worker_processes 1;/worker_processes auto;/" ${nginx_dir}/conf/nginx.conf
|
|
sed -i "s/^\( *\)worker_connections 1024;.*/\1worker_connections 4096;/" ${nginx_dir}/conf/nginx.conf
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
sed -i "\$i include ${nginx_conf_dir}/*.conf;" ${nginx_dir}/conf/nginx.conf
|
|
elif [[ ${tls_mode} == "Reality" ]] && [[ ${reality_add_nginx} == "on" ]]; then
|
|
sed -i "\$a include ${nginx_conf_dir}/*.conf;" ${nginx_dir}/conf/nginx.conf
|
|
fi
|
|
sed -i "/http\( *\){/a \\\tserver_tokens off;" ${nginx_dir}/conf/nginx.conf
|
|
sed -i "/error_page.*504/i \\\t\\tif (\$host = '${local_ip}') {\\n\\t\\t\\treturn 403;\\n\\t\\t}" ${nginx_dir}/conf/nginx.conf
|
|
}
|
|
|
|
modify_nginx_port() {
|
|
if [[ ${tls_mode} == "Reality" ]] && [[ ${reality_add_nginx} == "on" ]]; then
|
|
sed -i "s/^\( *\)listen.*so_keepalive=on.*/\1listen ${port} reuseport so_keepalive=on backlog=65535;/" ${nginx_conf}
|
|
judge "Nginx port $(gettext "修改")"
|
|
elif [[ ${tls_mode} == "TLS" ]]; then
|
|
sed -i "2s/^\( *\).*ssl reuseport;$/\1listen ${port} ssl reuseport;/" ${nginx_conf}
|
|
sed -i "3s/^\( *\).*ssl reuseport;$/\1listen [::]:${port} ssl reuseport;/" ${nginx_conf}
|
|
sed -i "4s/^\( *\).*quic reuseport;$/\1listen ${port} quic reuseport;/" ${nginx_conf}
|
|
sed -i "5s/^\( *\).*quic reuseport;$/\1listen [::]:${port} quic reuseport;/" ${nginx_conf}
|
|
judge "Xray port $(gettext "修改")"
|
|
fi
|
|
[[ "on" != ${old_config_status} ]] && log_echo "${Green} $(gettext "端口"): ${port} ${Font}"
|
|
}
|
|
|
|
modify_nginx_ssl_other() {
|
|
if [[ -f "${nginx_dir}/conf/nginx.conf" ]] && [[ $(grep -c "server_tokens off;" ${nginx_dir}/conf/nginx.conf) -eq '0' ]] && [[ ${save_originconf} != "Yes" ]]; then
|
|
modify_nginx_origin_conf
|
|
fi
|
|
sed -i "s/^\( *\)server_name\( *\).*/\1server_name\2${domain};/g" ${nginx_ssl_conf}
|
|
sed -i "s/^\( *\)return 301.*/\1return 301 https:\/\/${domain}\$request_uri;/" ${nginx_ssl_conf}
|
|
}
|
|
|
|
modify_nginx_other() {
|
|
if [[ -f "${nginx_dir}/conf/nginx.conf" ]] && [[ $(grep -c "server_tokens off;" ${nginx_dir}/conf/nginx.conf) -eq '0' ]] && [[ ${save_originconf} != "Yes" ]]; then
|
|
modify_nginx_origin_conf
|
|
fi
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
sed -i "s/^\( *\)server_name\( *\).*/\1server_name\2${domain};/g" ${nginx_conf}
|
|
sed -i "s/^\( *\)location ws$/\1location \/${path}/" ${nginx_conf}
|
|
sed -i "s/^\( *\)location grpc$/\1location \/${serviceName}/" ${nginx_conf}
|
|
sed -i "s/^\( *\)return 301.*/\1return 301 https:\/\/${domain}\$request_uri;/" ${nginx_conf}
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
sed -i "s/^\( *\)#proxy_pass\(.*\)/\1proxy_pass\2/" ${nginx_conf}
|
|
sed -i "s/^\( *\)#proxy_redirect default;/\1proxy_redirect default;/" ${nginx_conf}
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
sed -i "s/^\( *\)#grpc_pass\(.*\)/\1grpc_pass\2/" ${nginx_conf}
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
sed -i "s/^\( *\)#proxy_pass\(.*\)/\1proxy_pass\2/" ${nginx_conf}
|
|
sed -i "s/^\( *\)#proxy_redirect default;/\1proxy_redirect default;/" ${nginx_conf}
|
|
sed -i "s/^\( *\)#grpc_pass\(.*\)/\1grpc_pass\2/" ${nginx_conf}
|
|
fi
|
|
fi
|
|
}
|
|
|
|
nginx_servers_add() {
|
|
touch ${nginx_conf_dir}/127.0.0.1.wsServers
|
|
cat >${nginx_conf_dir}/127.0.0.1.wsServers <<EOF
|
|
server 127.0.0.1:${xport} weight=50 max_fails=2 fail_timeout=10;
|
|
EOF
|
|
touch ${nginx_conf_dir}/127.0.0.1.grpcServers
|
|
cat >${nginx_conf_dir}/127.0.0.1.grpcServers<<EOF
|
|
server 127.0.0.1:${gport} weight=50 max_fails=2 fail_timeout=10;
|
|
EOF
|
|
}
|
|
|
|
modify_path() {
|
|
sed -i "s/^\( *\)\"path\".*/\1\"path\": \"\/${path}\"/" ${xray_conf}
|
|
sed -i "s/^\( *\)\"serviceName\".*/\1\"serviceName\": \"${serviceName}\",/" ${xray_conf}
|
|
if [[ ${tls_mode} != "Reality" ]] || [[ "$reality_add_more" == "off" ]]; then
|
|
judge "Xray $(gettext "伪装路径") $(gettext "修改")"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} Reality $(gettext "不支持") path ${Font}"
|
|
fi
|
|
}
|
|
|
|
modify_email_address() {
|
|
if [[ $(jq -r '.inbounds[0].settings.clients|length' ${xray_conf}) == 1 ]] && [[ $(jq -r '.inbounds[1].settings.clients|length' ${xray_conf}) == 1 ]]; then
|
|
sed -i "s/^\( *\)\"email\".*/\1\"email\": \"${custom_email}\"/g" ${xray_conf}
|
|
judge "Xray $(gettext "用户名修改")"
|
|
else
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先删除多余的用户") ${Font}"
|
|
fi
|
|
}
|
|
|
|
modify_UUID() {
|
|
if [[ $(jq -r '.inbounds[0].settings.clients|length' ${xray_conf}) == 1 ]] && [[ $(jq -r '.inbounds[1].settings.clients|length' ${xray_conf}) == 1 ]]; then
|
|
sed -i "s/^\( *\)\"id\".*/\1\"id\": \"${UUID}\",/g" ${xray_conf}
|
|
judge "Xray UUID $(gettext "修改")"
|
|
else
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先删除多余的用户") ${Font}"
|
|
fi
|
|
}
|
|
|
|
modify_target_serverNames() {
|
|
jq --arg target "${target}:443" --arg serverNames "${serverNames}" '
|
|
.inbounds[0].streamSettings.realitySettings.target = $target |
|
|
.inbounds[0].streamSettings.realitySettings.serverNames = [$serverNames]' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "target serverNames $(gettext "配置修改")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
}
|
|
|
|
modify_privateKey_shortIds() {
|
|
jq --arg privateKey "${privateKey}" --arg shortIds "${shortIds}" '
|
|
.inbounds[0].streamSettings.realitySettings.privateKey = $privateKey |
|
|
.inbounds[0].streamSettings.realitySettings.shortIds = [$shortIds]' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "privateKey shortIds $(gettext "配置修改")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
}
|
|
|
|
modify_reality_listen_address () {
|
|
jq '.inbounds[0].listen = "127.0.0.1"' "${xray_conf}" > "${xray_conf}.tmp"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
judge "Xray reality listen address $(gettext "配置修改")"
|
|
}
|
|
|
|
xray_privilege_escalation() {
|
|
if [[ -n "$(grep "User=nobody" ${xray_systemd_file})" ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "检测到 Xray 的权限控制, 启动修改程序") ${Font}"
|
|
chmod -fR a+rw /var/log/xray/
|
|
chown -fR nobody:nogroup /var/log/xray/
|
|
[[ -f "${ssl_chainpath}/xray.key" ]] && chown -fR nobody:nogroup ${ssl_chainpath}/*
|
|
fi
|
|
log_echo "${OK} ${GreenBG} Xray $(gettext "修改完成") ${Font}"
|
|
}
|
|
|
|
xray_install() {
|
|
if [[ $(xray version) == "" ]] || [[ ! -f "${xray_conf}" ]]; then
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_online_version}
|
|
judge "$(gettext "安装") Xray"
|
|
systemctl daemon-reload
|
|
xray_privilege_escalation
|
|
[[ -f "${xray_default_conf}" ]] && rm -rf ${xray_default_conf}
|
|
ln -s ${xray_conf} ${xray_default_conf}
|
|
xray_version=${xray_online_version}
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "已安装") Xray ${Font}"
|
|
xray_version=$(info_extraction xray_version)
|
|
fi
|
|
}
|
|
|
|
xray_update() {
|
|
[[ ! -d "${local_bin}/etc/xray" ]] && log_echo "${GreenBG} $(gettext "若更新无效, 建议直接卸载再安装")! ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "部分新功能需要重新安装才可生效") ${Font}"
|
|
## xray_online_version=$(check_version xray_online_pre_version)
|
|
## if [[ $(info_extraction xray_version) != ${xray_online_version} ]] && [[ ${xray_version} != ${xray_online_version} ]]; then
|
|
if [[ $(info_extraction xray_version) != ${xray_online_version} ]]; then
|
|
if [[ ${auto_update} != "YES" ]]; then
|
|
log_echo "${Warning} ${GreenBG} $(gettext "检测到存在最新版") ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "脚本可能未兼容此版本") ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "是否更新") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r xray_test_fq
|
|
case $xray_test_fq in
|
|
[yY][eE][sS] | [yY])
|
|
log_echo "${OK} ${GreenBG} $(gettext "升级") Xray ! ${Font}"
|
|
systemctl stop xray
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_online_version}
|
|
if ! ${xray_bin_dir}/xray -version &> /dev/null; then
|
|
log_echo "${Error} ${RedBG} Xray $(gettext "启动失败")! ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "是否回滚到之前的版本") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r rollback_fq
|
|
case $rollback_fq in
|
|
[nN][oO] | [nN])
|
|
log_echo "${Info} ${YellowBG} $(gettext "未执行回滚操作")! ${Font}"
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${GreenBG} $(gettext "正在回滚")... ${Font}"
|
|
xray_version=$(info_extraction xray_version)
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_version}
|
|
if ${xray_bin_dir}/xray -version &> /dev/null; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "已成功回滚到之前的") Xray $(gettext "版本")! ${Font}"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "回滚失败")! ${Font}"
|
|
fi
|
|
;;
|
|
esac
|
|
else
|
|
judge "Xray $(gettext "升级")"
|
|
xray_version=${xray_online_version}
|
|
fi
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
else
|
|
systemctl stop xray
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_online_version}
|
|
if ! ${xray_bin_dir}/xray -version &> /dev/null; then
|
|
xray_version=$(info_extraction xray_version)
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_version}
|
|
fi
|
|
fi
|
|
else
|
|
timeout "$(gettext "重装") Xray !"
|
|
systemctl stop xray
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -f --version v${xray_online_version}
|
|
judge "Xray $(gettext "重装")"
|
|
fi
|
|
xray_privilege_escalation
|
|
[[ -f "${xray_default_conf}" ]] && rm -rf ${xray_default_conf}
|
|
ln -s ${xray_conf} ${xray_default_conf}
|
|
jq --arg xray_version "${xray_version}" '.xray_version = $xray_version' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
systemctl daemon-reload
|
|
systemctl start xray
|
|
}
|
|
|
|
reality_nginx_add_fq() {
|
|
echo
|
|
log_echo "${Warning} ${Green} $(gettext "Reality 协议有流量偷跑的风险") ${Font}"
|
|
log_echo "${Warning} ${Green} $(gettext "该风险在 target 网址被 cdn 加速时存在") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否额外安装 nginx 前置保护(推荐)") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r reality_nginx_add_fq
|
|
case $reality_nginx_add_fq in
|
|
[nN][oO] | [nN])
|
|
log_echo "${OK} ${GreenBG} $(gettext "已跳过安装") nginx ${Font}"
|
|
;;
|
|
*)
|
|
reality_add_nginx="on"
|
|
nginx_exist_check
|
|
nginx_systemd
|
|
nginx_reality_conf_add
|
|
nginx_reality_serverNames_add
|
|
;;
|
|
|
|
esac
|
|
}
|
|
|
|
nginx_exist_check() {
|
|
if [[ -f "${nginx_dir}/sbin/nginx" ]] && [[ "$(info_extraction nginx_build_version)" != "null" ]]; then
|
|
if [[ -d "${nginx_conf_dir}" ]]; then
|
|
rm -rf ${nginx_conf_dir}/*.conf
|
|
if [[ -f "${nginx_conf_dir}/nginx.default" ]]; then
|
|
cp -fp ${nginx_conf_dir}/nginx.default ${nginx_dir}/conf/nginx.conf
|
|
elif [[ -f "${nginx_dir}/conf/nginx.conf.default" ]]; then
|
|
cp -fp ${nginx_dir}/conf/nginx.conf.default ${nginx_dir}/conf/nginx.conf
|
|
else
|
|
sed -i "/if \(.*\) {$/,+2d" ${nginx_dir}/conf/nginx.conf
|
|
sed -i "/^include.*\*\.conf;$/d" ${nginx_dir}/conf/nginx.conf
|
|
fi
|
|
else
|
|
sed -i "/if \(.*\) {$/,+2d" ${nginx_dir}/conf/nginx.conf
|
|
sed -i "/^include.*\*\.conf;$/d" ${nginx_dir}/conf/nginx.conf
|
|
fi
|
|
modify_nginx_origin_conf
|
|
nginx_build_version=$(info_extraction nginx_build_version)
|
|
log_echo "${OK} ${GreenBG} Nginx $(gettext "已存在, 跳过编译安装过程") ${Font}"
|
|
#兼容代码, 下个大版本删除
|
|
elif [[ -d "/etc/nginx" ]] && [[ "$(info_extraction nginx_version)" == "null" ]]; then
|
|
log_echo "${Error} ${GreenBG} $(gettext "检测到旧版本安装的") nginx ! ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "请先做好备份") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否需要删除 (请删除)") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r remove_nginx_fq
|
|
case $remove_nginx_fq in
|
|
[nN][oO] | [nN])
|
|
log_echo "${OK} ${GreenBG} $(gettext "已跳过删除") nginx ${Font}"
|
|
source "$idleleo"
|
|
;;
|
|
*)
|
|
rm -rf /etc/nginx/
|
|
[[ -f "${nginx_systemd_file}" ]] && rm -rf ${nginx_systemd_file}
|
|
[[ -d "${nginx_conf_dir}" ]] && rm -rf ${nginx_conf_dir}/*.conf
|
|
log_echo "${Warning} ${GreenBG} $(gettext "日志目录已更改, 日志清除需要重新设置")! ${Font}"
|
|
nginx_install
|
|
;;
|
|
esac
|
|
#兼容代码结束
|
|
elif [[ -d "/etc/nginx" ]] && [[ "$(info_extraction nginx_version)" == "null" ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "检测到其他套件安装的 Nginx, 继续安装会造成冲突, 请处理后安装")! ${Font}"
|
|
exit 1
|
|
else
|
|
nginx_install
|
|
fi
|
|
}
|
|
|
|
nginx_install() {
|
|
local temp_dir=$(mktemp -d)
|
|
local current_dir=$(pwd)
|
|
|
|
cd "$temp_dir" || exit
|
|
|
|
log_echo "${OK} ${GreenBG} $(gettext "即将下载已编译的") Nginx ${Font}"
|
|
local nginx_filename
|
|
case $(uname -m) in
|
|
x86_64)
|
|
nginx_filename="xray-nginx-custom-x86.tar.gz"
|
|
;;
|
|
armv7l|armv8l|aarch64)
|
|
nginx_filename="xray-nginx-custom-arm.tar.gz"
|
|
;;
|
|
*)
|
|
log_echo "${Error} ${RedBG} $(gettext "不支持的系统架构"): $(uname -m) ${Font}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
local url="https://github.com/hello-yunshu/Xray_bash_onekey_Nginx/releases/download/v${nginx_build_version}/${nginx_filename}"
|
|
wget -q --show-progress --progress=bar:force:noscroll "$url" -O "$nginx_filename"
|
|
tar -xzvf "$nginx_filename" -C ./
|
|
[[ -d ${nginx_dir} ]] && rm -rf "${nginx_dir}"
|
|
mv ./nginx "${nginx_dir}"
|
|
|
|
cp -fp ${nginx_dir}/conf/nginx.conf ${nginx_conf_dir}/nginx.default
|
|
|
|
# 修改基本配置
|
|
#sed -i 's/#user nobody;/user root;/' ${nginx_dir}/conf/nginx.conf
|
|
modify_nginx_origin_conf
|
|
|
|
# 删除临时文件
|
|
cd "$current_dir" && rm -rf "$temp_dir"
|
|
chown -fR nobody:nogroup "${nginx_dir}"
|
|
chmod -fR 755 "${nginx_dir}"
|
|
}
|
|
|
|
nginx_update() {
|
|
if [[ -f "${nginx_dir}/sbin/nginx" ]]; then
|
|
current_nginx_build_version=$(info_extraction nginx_build_version)
|
|
if [[ ${nginx_build_version} != ${current_nginx_build_version} ]]; then
|
|
ip_check
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
domain=$(info_extraction host)
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
port=$(info_extraction port)
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
[[ ${gport} == ${xport} ]] && gport=$((RANDOM % 1000 + 30000))
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
fi
|
|
if [[ 0 -eq ${read_config_status} ]]; then
|
|
[[ ${auto_update} == "YES" ]] && echo "Nginx $(gettext "配置文件不完整, 退出升级")!" && exit 1
|
|
log_echo "${Error} ${RedBG} $(gettext "配置文件不完整, 退出升级")! ${Font}"
|
|
return 1
|
|
fi
|
|
elif [[ ${tls_mode} == "Reality" ]] && [[ ${reality_add_nginx} == "on" ]]; then
|
|
port=$(info_extraction port)
|
|
serverNames=$(info_extraction serverNames)
|
|
if [[ 0 -eq ${read_config_status} ]]; then
|
|
[[ ${auto_update} == "YES" ]] && echo "Nginx $(gettext "配置文件不完整, 退出升级")!" && exit 1
|
|
log_echo "${Error} ${RedBG} $(gettext "配置文件不完整, 退出升级")! ${Font}"
|
|
return 1
|
|
fi
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
[[ ${auto_update} == "YES" ]] && echo "$(gettext "当前安装模式不需要") Nginx !" && exit 1
|
|
log_echo "${Error} ${RedBG} $(gettext "当前安装模式不需要") Nginx ! ${Font}"
|
|
return 1
|
|
fi
|
|
else
|
|
[[ ${auto_update} == "YES" ]] && echo "Nginx $(gettext "配置文件不存在, 退出升级")!" && exit 1
|
|
log_echo "${Error} ${RedBG} $(gettext "配置文件不存在, 退出升级")! ${Font}"
|
|
return 1
|
|
fi
|
|
service_stop
|
|
backup_nginx_dir="${nginx_dir}_backup_${current_nginx_build_version}"
|
|
cp -r ${nginx_dir} ${backup_nginx_dir}
|
|
judge "$(gettext "备份旧版") Nginx"
|
|
timeout "$(gettext "删除旧版") Nginx !"
|
|
rm -rf ${nginx_dir}
|
|
if [[ ${auto_update} != "YES" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否保留原 Nginx 配置文件") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r save_originconf_fq
|
|
else
|
|
save_originconf_fq=1
|
|
fi
|
|
case $save_originconf_fq in
|
|
[nN][oO] | [nN])
|
|
rm -rf ${nginx_conf_dir}/*.conf
|
|
log_echo "${OK} ${GreenBG} $(gettext "原配置文件已删除")! ${Font}"
|
|
;;
|
|
*)
|
|
save_originconf="Yes"
|
|
log_echo "${OK} ${GreenBG} $(gettext "原配置文件已保留")! ${Font}"
|
|
;;
|
|
esac
|
|
nginx_install
|
|
if [[ ${tls_mode} == "TLS" ]] && [[ ${save_originconf} != "Yes" ]]; then
|
|
nginx_ssl_conf_add
|
|
nginx_conf_add
|
|
nginx_servers_conf_add
|
|
elif [[ ${tls_mode} == "Reality" ]] && [[ ${reality_add_nginx} == "on" ]] && [[ ${save_originconf} != "Yes" ]]; then
|
|
nginx_reality_conf_add
|
|
fi
|
|
service_start
|
|
sleep 1
|
|
if ! systemctl -q is-active nginx; then
|
|
log_echo "${Error} ${RedBG} Nginx $(gettext "启动失败")! ${Font}"
|
|
if [[ ${auto_update} != "YES" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否回滚到之前的版本") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r rollback_fq
|
|
else
|
|
service_stop
|
|
rm -rf ${nginx_dir}
|
|
mv ${backup_nginx_dir} ${nginx_dir}
|
|
service_start
|
|
fi
|
|
case $rollback_fq in
|
|
[nN][oO] | [nN])
|
|
log_echo "${Info} ${YellowBG} $(gettext "未执行回滚操作")! ${Font}"
|
|
exit 1
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${GreenBG} $(gettext "正在回滚")... ${Font}"
|
|
service_stop
|
|
rm -rf ${nginx_dir}
|
|
mv ${backup_nginx_dir} ${nginx_dir}
|
|
service_start
|
|
sleep 1
|
|
if systemctl -q is-active nginx; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "已成功回滚到之前的") Nginx $(gettext "版本")! ${Font}"
|
|
jq --arg nginx_build_version "${current_nginx_build_version}" '.nginx_build_version = $nginx_build_version' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
rm -rf ${backup_nginx_dir}
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "回滚失败")! ${Font}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
else
|
|
jq --arg nginx_build_version "${nginx_build_version}" '.nginx_build_version = $nginx_build_version' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
judge "Nginx $(gettext "升级")"
|
|
rm -rf ${backup_nginx_dir}
|
|
judge "$(gettext "删除") Nginx $(gettext "备份")"
|
|
fi
|
|
else
|
|
log_echo "${OK} ${GreenBG} Nginx $(gettext "已为最新版") ${Font}"
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} Nginx $(gettext "未安装") ${Font}"
|
|
fi
|
|
}
|
|
|
|
auto_update() {
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
crontab_file="/var/spool/cron/root"
|
|
else
|
|
crontab_file="/var/spool/cron/crontabs/root"
|
|
fi
|
|
if [[ ! -f "${auto_update_file}" ]] || [[ $(crontab -l | grep -c "auto_update.sh") -lt 1 ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "设置后台定时自动更新程序 (包含: 脚本/Xray/Nginx)") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "可能自动更新后有兼容问题, 谨慎开启") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否开启") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r auto_update_fq
|
|
case $auto_update_fq in
|
|
[yY][eE][sS] | [yY])
|
|
wget -N -P ${idleleo_dir} --no-check-certificate https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/auto_update.sh && chmod +x ${auto_update_file}
|
|
echo "0 1 15 * * bash ${auto_update_file}" >>${crontab_file}
|
|
judge "$(gettext "设置自动更新")"
|
|
;;
|
|
*) ;;
|
|
esac
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "已设置自动更新") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否关闭") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r auto_update_close_fq
|
|
case $auto_update_fq in
|
|
[yY][eE][sS] | [yY])
|
|
sed -i "/auto_update.sh/d" ${crontab_file}
|
|
rm -rf ${auto_update_file}
|
|
judge "$(gettext "删除自动更新")"
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
ssl_install() {
|
|
pkg_install "socat"
|
|
judge "$(gettext "安装 SSL 证书生成脚本依赖")"
|
|
curl https://get.acme.sh | sh -s email=${custom_email}
|
|
judge "$(gettext "安装 SSL 证书生成脚本")"
|
|
}
|
|
|
|
domain_check() {
|
|
if [[ "on" == ${old_config_status} ]] && [[ $(info_extraction host) != null ]] && [[ $(info_extraction ip_version) != null ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "检测到原域名配置存在, 是否跳过域名设置") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r old_host_fq
|
|
case $old_host_fq in
|
|
[nN][oO] | [nN]) ;;
|
|
*)
|
|
domain=$(info_extraction host)
|
|
ip_version=$(info_extraction ip_version)
|
|
if [[ ${ip_version} == "IPv4" ]]; then
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
elif [[ ${ip_version} == "IPv6" ]]; then
|
|
local_ip=$(curl -6 ip.me 2>/dev/null || curl -6 ip.im)
|
|
else
|
|
local_ip=${ip_version}
|
|
fi
|
|
if [[ -z ${local_ip} ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "无法获取公网IP地址"), $(gettext "安装终止")! ${Font}"
|
|
return 1
|
|
fi
|
|
log_echo "${OK} ${GreenBG} $(gettext "已跳过域名设置") ${Font}"
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "确定域名信息") ${Font}"
|
|
read_optimize "$(gettext "请输入你的域名信息") (e.g. www.idleleo.com):" "domain" "NULL"
|
|
echo -e "\n${GreenBG} $(gettext "请选择公网IP(IPv4/IPv6)或手动输入域名") ${Font}"
|
|
echo -e "${Red}1${Font}: IPv4 ($(gettext "默认"))"
|
|
echo "2: IPv6 ($(gettext "不推荐"))"
|
|
echo "3: $(gettext "域名")"
|
|
local ip_version_fq
|
|
read_optimize "$(gettext "请输入"): " "ip_version_fq" 1 1 3 "$(gettext "请输入有效的数字")"
|
|
log_echo "${OK} ${GreenBG} $(gettext "正在获取公网IP信息, 请耐心等待") ${Font}"
|
|
if [[ ${ip_version_fq} == 1 ]]; then
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
domain_ip=$(ping -4 "${domain}" -c 1 | sed '1{s/[^(]*(//;s/).*//;q}')
|
|
ip_version="IPv4"
|
|
elif [[ ${ip_version_fq} == 2 ]]; then
|
|
local_ip=$(curl -6 ip.me 2>/dev/null || curl -6 ip.im)
|
|
domain_ip=$(ping -6 "${domain}" -c 1 | sed '2{s/[^(]*(//;s/).*//;q}' | tail -n +2)
|
|
ip_version="IPv6"
|
|
elif [[ ${ip_version_fq} == 3 ]]; then
|
|
log_echo "${Warning} ${GreenBG} $(gettext "此选项用于服务器商仅提供域名访问服务器") ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "注意服务器商域名添加 CNAME 记录") ${Font}"
|
|
read_optimize "$(gettext "请输入"): " "local_ip" "NULL"
|
|
ip_version=${local_ip}
|
|
else
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
domain_ip=$(ping -4 "${domain}" -c 1 | sed '1{s/[^(]*(//;s/).*//;q}')
|
|
ip_version="IPv4"
|
|
fi
|
|
if [[ -z ${local_ip} ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "无法获取公网IP地址"), $(gettext "安装终止")! ${Font}"
|
|
return 1
|
|
fi
|
|
log_echo "$(gettext "域名DNS解析IP"): ${domain_ip}"
|
|
log_echo "$(gettext "公网IP/域名"): ${local_ip}"
|
|
if [[ ${ip_version_fq} != 3 ]] && [[ ${local_ip} == ${domain_ip} ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "域名DNS解析IP与公网IP匹配") ${Font}"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请确保域名添加了正确的 A/AAAA 记录, 否则将无法正常使用 Xray") ${Font}"
|
|
log_echo "${Error} ${RedBG} $(gettext "域名DNS解析IP与公网IP不匹配, 请选择"): ${Font}"
|
|
echo "1: $(gettext "继续安装")"
|
|
echo "2: $(gettext "重新输入")"
|
|
log_echo "${Red}3${Font}: $(gettext "终止安装") ($(gettext "默认"))"
|
|
local install
|
|
read_optimize "$(gettext "请输入"): " "install" 3 1 3 "$(gettext "请输入有效的数字")"
|
|
case $install in
|
|
1)
|
|
log_echo "${OK} ${GreenBG} $(gettext "继续安装") ${Font}"
|
|
;;
|
|
2)
|
|
domain_check
|
|
;;
|
|
*)
|
|
log_echo "${Error} ${RedBG} $(gettext "安装终止") ${Font}"
|
|
exit 2
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
ip_check() {
|
|
if [[ "on" == ${old_config_status} || ${auto_update} == "YES" ]] && [[ $(info_extraction host) != null ]] && [[ $(info_extraction ip_version) != null ]]; then
|
|
if [[ ${auto_update} != "YES" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "检测到原IP配置存在, 是否跳过IP设置") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r old_host_fq
|
|
else
|
|
old_host_fq=1
|
|
fi
|
|
case $old_host_fq in
|
|
[nN][oO] | [nN]) ;;
|
|
*)
|
|
ip_version=$(info_extraction ip_version)
|
|
if [[ ${ip_version} == "IPv4" ]]; then
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
elif [[ ${ip_version} == "IPv6" ]]; then
|
|
local_ip=$(curl -6 ip.me 2>/dev/null || curl -6 ip.im)
|
|
else
|
|
local_ip=${ip_version}
|
|
fi
|
|
if [[ -z ${local_ip} ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "无法获取公网IP地址"), $(gettext "安装终止")! ${Font}"
|
|
return 1
|
|
fi
|
|
echo
|
|
log_echo "${OK} ${GreenBG} $(gettext "已跳过IP设置") ${Font}"
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "确定公网IP信息") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "请选择公网IP为IPv4或IPv6") ${Font}"
|
|
echo -e "${Red}1${Font}: IPv4 ($(gettext "默认"))"
|
|
echo "2: IPv6 ($(gettext "不推荐"))"
|
|
echo "3: $(gettext "手动输入")"
|
|
local ip_version_fq
|
|
read_optimize "$(gettext "请输入"): " "ip_version_fq" 1 1 3 "$(gettext "请输入有效的数字")"
|
|
[[ -z ${ip_version_fq} ]] && ip_version=1
|
|
log_echo "${OK} ${GreenBG} $(gettext "正在获取公网IP信息, 请耐心等待") ${Font}"
|
|
if [[ ${ip_version_fq} == 1 ]]; then
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
ip_version="IPv4"
|
|
elif [[ ${ip_version_fq} == 2 ]]; then
|
|
local_ip=$(curl -6 ip.me 2>/dev/null || curl -6 ip.im)
|
|
ip_version="IPv6"
|
|
elif [[ ${ip_version_fq} == 3 ]]; then
|
|
read_optimize "$(gettext "请输入"): " "local_ip" "NULL"
|
|
ip_version=${local_ip}
|
|
else
|
|
local_ip=$(curl -4 ip.me 2>/dev/null || curl -4 ip.im)
|
|
ip_version="IPv4"
|
|
fi
|
|
if [[ -z ${local_ip} ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "无法获取公网IP地址"), $(gettext "安装终止")! ${Font}"
|
|
return 1
|
|
fi
|
|
log_echo "$(gettext "公网IP/域名"): ${local_ip}"
|
|
}
|
|
|
|
port_exist_check() {
|
|
if [[ 0 -eq $(lsof -i:"$1" | grep -i -c "listen") ]]; then
|
|
log_echo "${OK} ${GreenBG} $1 $(gettext "端口未被占用") ${Font}"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "检测到") $1 $(gettext "端口被占用"), $(gettext "以下为") $1 $(gettext "端口占用信息") ${Font}"
|
|
lsof -i:"$1"
|
|
timeout "$(gettext "尝试终止占用的进程")!"
|
|
lsof -i:"$1" | awk '{print $2}' | grep -v "PID" | xargs kill -9
|
|
log_echo "${OK} ${GreenBG} kill $(gettext "完成") ${Font}"
|
|
fi
|
|
}
|
|
|
|
acme() {
|
|
systemctl restart nginx
|
|
#暂时解决ca问题
|
|
if "$HOME"/.acme.sh/acme.sh --issue -d ${domain} -w ${idleleo_conf_dir} --server letsencrypt --keylength ec-256 --force --test; then
|
|
#if "$HOME"/.acme.sh/acme.sh --issue -d ${domain} -w ${idleleo_conf_dir} --keylength ec-256 --force --test; then
|
|
log_echo "${OK} ${GreenBG} SSL $(gettext "证书测试签发成功, 开始正式签发") ${Font}"
|
|
rm -rf "$HOME/.acme.sh/${domain}_ecc"
|
|
else
|
|
log_echo "${Error} ${RedBG} SSL $(gettext "证书测试签发失败") ${Font}"
|
|
rm -rf "$HOME/.acme.sh/${domain}_ecc"
|
|
exit 1
|
|
fi
|
|
|
|
if "$HOME"/.acme.sh/acme.sh --issue -d ${domain} -w ${idleleo_conf_dir} --server letsencrypt --keylength ec-256 --force; then
|
|
#if "$HOME"/.acme.sh/acme.sh --issue -d ${domain} -w ${idleleo_conf_dir} --keylength ec-256 --force; then
|
|
log_echo "${OK} ${GreenBG} SSL $(gettext "证书生成成功") ${Font}"
|
|
mkdir -p ${ssl_chainpath}
|
|
if "$HOME"/.acme.sh/acme.sh --installcert -d ${domain} --fullchainpath ${ssl_chainpath}/xray.crt --keypath ${ssl_chainpath}/xray.key --ecc --force; then
|
|
chmod -f a+rw ${ssl_chainpath}/xray.crt
|
|
chmod -f a+rw ${ssl_chainpath}/xray.key
|
|
chown -fR nobody:nogroup ${ssl_chainpath}/*
|
|
log_echo "${OK} ${GreenBG} SSL $(gettext "证书配置成功") ${Font}"
|
|
systemctl stop nginx
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} SSL $(gettext "证书生成失败") ${Font}"
|
|
rm -rf "$HOME/.acme.sh/${domain}_ecc"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
xray_conf_add() {
|
|
if [[ $(info_extraction multi_user) != "yes" ]]; then
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
wget --no-check-certificate https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/VLESS_tls/config.json -O ${xray_conf}
|
|
modify_listen_address
|
|
modify_path
|
|
modify_inbound_port
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
wget --no-check-certificate https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/VLESS_reality/config.json -O ${xray_conf}
|
|
modify_target_serverNames
|
|
modify_privateKey_shortIds
|
|
xray_reality_add_more
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
wget --no-check-certificate https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/VLESS_tls/config.json -O ${xray_conf}
|
|
modify_listen_address
|
|
modify_path
|
|
modify_inbound_port
|
|
fi
|
|
modify_email_address
|
|
modify_UUID
|
|
else
|
|
echo
|
|
log_echo "${Warning} ${GreenBG} $(gettext "检测到 Xray 配置过多用户") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否保留原 Xray 配置文件") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r save_originxray_fq
|
|
case $save_originxray_fq in
|
|
[nN][oO] | [nN])
|
|
rm -rf ${xray_conf}
|
|
log_echo "${OK} ${GreenBG} $(gettext "原配置文件已删除")! ${Font}"
|
|
xray_conf_add
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
xray_reality_add_more() {
|
|
if [[ ${reality_add_more} == "on" ]]; then
|
|
modify_path
|
|
modify_listen_address
|
|
modify_inbound_port
|
|
judge "$(gettext "添加简单 ws/gRPC 协议")"
|
|
else
|
|
modify_path
|
|
modify_inbound_port
|
|
fi
|
|
|
|
if [[ ${reality_add_nginx} == "on" ]]; then
|
|
modify_reality_listen_address
|
|
fi
|
|
}
|
|
|
|
old_config_exist_check() {
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
if [[ ${old_tls_mode} == ${tls_mode} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "检测到配置文件, 是否读取配置文件") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r old_config_fq
|
|
case $old_config_fq in
|
|
[nN][oO] | [nN])
|
|
rm -rf ${xray_qr_config_file}
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除配置文件") ${Font}"
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${GreenBG} $(gettext "已保留配置文件") ${Font}"
|
|
old_config_status="on"
|
|
old_config_input
|
|
;;
|
|
esac
|
|
else
|
|
echo
|
|
log_echo "${Warning} ${GreenBG} $(gettext "检测到当前安装模式与配置文件的安装模式不一致") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否保留配置文件 (强烈不建议)") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r old_config_fq
|
|
case $old_config_fq in
|
|
[yY][eE][sS] | [yY])
|
|
log_echo "${Warning} ${GreenBG} $(gettext "请务必确保配置文件正确") ${Font}"
|
|
log_echo "${OK} ${GreenBG} $(gettext "已保留配置文件") ${Font}"
|
|
menu
|
|
;;
|
|
*)
|
|
rm -rf ${xray_qr_config_file}
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除配置文件") ${Font}"
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
}
|
|
|
|
old_config_input() {
|
|
info_extraction_all=$(jq -rc . ${xray_qr_config_file})
|
|
custom_email=$(info_extraction email)
|
|
UUID5_char=$(info_extraction idc)
|
|
UUID=$(info_extraction id)
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
port=$(info_extraction port)
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
[[ ${gport} == ${xport} ]] && gport=$((RANDOM % 1000 + 30000))
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
[[ ${gport} == ${xport} ]] && xport=$((RANDOM % 1000 + 20000))
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
fi
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
port=$(info_extraction port)
|
|
target=$(info_extraction target)
|
|
serverNames=$(info_extraction serverNames)
|
|
privateKey=$(info_extraction privateKey)
|
|
publicKey=$(info_extraction publicKey)
|
|
shortIds=$(info_extraction shortIds)
|
|
if [[ ${reality_add_more} == "on" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction ws_path)
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
[[ ${gport} == ${xport} ]] && gport=$((RANDOM % 1000 + 30000))
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction grpc_serviceName)
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
[[ ${gport} == ${xport} ]] && xport=$((RANDOM % 1000 + 20000))
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction ws_path)
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction grpc_serviceName)
|
|
fi
|
|
else
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
fi
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
[[ ${gport} == ${xport} ]] && gport=$((RANDOM % 1000 + 30000))
|
|
serviceName="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
[[ ${gport} == ${xport} ]] && xport=$((RANDOM % 1000 + 20000))
|
|
path="$(head -n 10 /dev/urandom | md5sum | head -c ${random_num})"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
xport=$(info_extraction ws_port)
|
|
path=$(info_extraction path)
|
|
gport=$(info_extraction grpc_port)
|
|
serviceName=$(info_extraction serviceName)
|
|
fi
|
|
fi
|
|
if [[ 0 -eq ${read_config_status} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "检测到配置文件不完整, 是否保留配置文件") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r old_config_input_fq
|
|
case $old_config_input_fq in
|
|
[yY][eE][sS] | [yY])
|
|
old_config_status="off"
|
|
log_echo "${OK} ${GreenBG} $(gettext "已保留配置文件") ${Font}"
|
|
;;
|
|
*)
|
|
rm -rf ${xray_qr_config_file}
|
|
old_config_status="off"
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除配置文件") ${Font}"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
nginx_ssl_conf_add() {
|
|
touch ${nginx_ssl_conf}
|
|
cat >${nginx_ssl_conf} <<EOF
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name serveraddr.com;
|
|
|
|
location ^~ /.well-known/acme-challenge/ {
|
|
root ${idleleo_dir}/conf;
|
|
default_type "text/plain";
|
|
allow all;
|
|
}
|
|
location = /.well-known/acme-challenge/ {
|
|
return 404;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://www.idleleo.com\$request_uri;
|
|
}
|
|
}
|
|
EOF
|
|
modify_nginx_ssl_other
|
|
judge "Nginx SSL $(gettext "配置修改")"
|
|
}
|
|
|
|
nginx_conf_add() {
|
|
touch ${nginx_conf}
|
|
cat >${nginx_conf} <<EOF
|
|
server {
|
|
listen 443 ssl reuseport;
|
|
listen [::]:443 ssl reuseport;
|
|
listen 443 quic reuseport;
|
|
listen [::]:443 quic reuseport;
|
|
|
|
http2 on;
|
|
set_real_ip_from 127.0.0.1;
|
|
real_ip_header X-Forwarded-For;
|
|
real_ip_recursive on;
|
|
ssl_certificate ${idleleo_dir}/cert/xray.crt;
|
|
ssl_certificate_key ${idleleo_dir}/cert/xray.key;
|
|
ssl_protocols TLSv1.3;
|
|
ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA;
|
|
server_name serveraddr.com;
|
|
index index.html index.htm;
|
|
root /403.html;
|
|
error_page 403 https://www.idleleo.com/helloworld;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 1d;
|
|
ssl_session_tickets off;
|
|
ssl_early_data on;
|
|
ssl_stapling on;
|
|
ssl_stapling_verify on;
|
|
ssl_prefer_server_ciphers on;
|
|
add_header Strict-Transport-Security "max-age=31536000";
|
|
|
|
location grpc
|
|
{
|
|
#grpc_pass grpc://xray-grpc-server;
|
|
grpc_connect_timeout 60s;
|
|
grpc_read_timeout 720m;
|
|
grpc_send_timeout 720m;
|
|
client_max_body_size 0;
|
|
grpc_set_header X-Real-IP \$remote_addr;
|
|
grpc_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
grpc_set_header Early-Data \$ssl_early_data;
|
|
}
|
|
|
|
location ws
|
|
{
|
|
#proxy_pass http://xray-ws-server;
|
|
proxy_redirect off;
|
|
proxy_http_version 1.1;
|
|
proxy_connect_timeout 60s;
|
|
proxy_send_timeout 720m;
|
|
proxy_read_timeout 720m;
|
|
proxy_buffering off;
|
|
client_max_body_size 0;
|
|
proxy_set_header X-Real-IP \$remote_addr;
|
|
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
|
proxy_set_header Upgrade \$http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host \$http_host;
|
|
}
|
|
|
|
location /
|
|
{
|
|
return 403;
|
|
}
|
|
}
|
|
EOF
|
|
modify_nginx_port
|
|
modify_nginx_other
|
|
judge "Nginx $(gettext "配置修改")"
|
|
}
|
|
|
|
nginx_reality_conf_add() {
|
|
touch ${nginx_conf}
|
|
cat >${nginx_conf} <<EOF
|
|
|
|
stream {
|
|
map \$ssl_preread_protocol \$is_valid_protocol {
|
|
TLSv1.2 1;
|
|
TLSv1.3 1;
|
|
default 0;
|
|
}
|
|
|
|
map \$ssl_preread_server_name \$sni_upstream {
|
|
include ${nginx_conf_dir}/*.serverNames;
|
|
default deny;
|
|
}
|
|
|
|
map "\$sni_upstream:\$is_valid_protocol" \$final_upstream {
|
|
# 格式:上游名称:协议标记 => 最终上游
|
|
~^reality:1\$ reality;
|
|
default deny;
|
|
}
|
|
|
|
map \$final_upstream \$is_abnormal {
|
|
deny 1;
|
|
default 0;
|
|
}
|
|
|
|
upstream reality {
|
|
server 127.0.0.1:9443;
|
|
}
|
|
|
|
upstream deny {
|
|
server 127.0.0.1:9403;
|
|
}
|
|
|
|
log_format sni_log_abnormal '\$remote_addr [\$time_local] "\$ssl_preread_server_name" '
|
|
'\$ssl_preread_protocol \$status';
|
|
|
|
server {
|
|
listen 443 reuseport so_keepalive=on backlog=65535;
|
|
proxy_pass \$final_upstream;
|
|
ssl_preread on;
|
|
proxy_connect_timeout 5s;
|
|
proxy_timeout 300s;
|
|
access_log ${nginx_dir}/logs/sni_abnormal.log sni_log_abnormal if=\$is_abnormal;
|
|
}
|
|
|
|
server {
|
|
listen 127.0.0.1:9403 reuseport;
|
|
#ssl_preread on;
|
|
ssl_reject_handshake on;
|
|
return 444;
|
|
access_log off;
|
|
error_log /dev/null;
|
|
}
|
|
}
|
|
EOF
|
|
modify_nginx_port
|
|
modify_nginx_other
|
|
judge "Nginx $(gettext "配置修改")"
|
|
}
|
|
|
|
nginx_reality_serverNames_add () {
|
|
touch ${nginx_conf_dir}/${serverNames}.serverNames
|
|
cat >${nginx_conf_dir}/${serverNames}.serverNames <<EOF
|
|
${serverNames} reality;
|
|
EOF
|
|
# modify_nginx_reality_serverNames
|
|
judge "Nginx serverNames $(gettext "配置修改")"
|
|
|
|
}
|
|
|
|
nginx_reality_serverNames_del () {
|
|
[[ -f "${nginx_conf_dir}/${serverNames}.serverNames" ]] && rm -f "${nginx_conf_dir}/${serverNames}.serverNames"
|
|
# modify_nginx_reality_serverNames
|
|
judge "Nginx serverNames $(gettext "配置删除")"
|
|
|
|
}
|
|
|
|
nginx_servers_conf_add() {
|
|
touch ${nginx_upstream_conf}
|
|
cat >${nginx_upstream_conf} <<EOF
|
|
upstream xray-ws-server {
|
|
include ${nginx_conf_dir}/*.wsServers;
|
|
}
|
|
|
|
upstream xray-grpc-server {
|
|
include ${nginx_conf_dir}/*.grpcServers;
|
|
}
|
|
EOF
|
|
nginx_servers_add
|
|
judge "Nginx servers $(gettext "配置修改")"
|
|
}
|
|
|
|
enable_process_systemd() {
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl enable nginx && judge "$(gettext "设置 Nginx 开机自启")"
|
|
fi
|
|
systemctl enable xray
|
|
judge "$(gettext "设置") Xray $(gettext "开机自启")"
|
|
}
|
|
|
|
disable_process_systemd() {
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl stop nginx && systemctl disable nginx && judge "$(gettext "关闭 Nginx 开机自启")"
|
|
fi
|
|
systemctl disable xray
|
|
judge "$(gettext "关闭") Xray $(gettext "开机自启")"
|
|
}
|
|
|
|
stop_service_all() {
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl stop nginx && systemctl disable nginx
|
|
systemctl stop xray
|
|
systemctl disable xray
|
|
log_echo "${OK} ${GreenBG} $(gettext "停止已有服务") ${Font}"
|
|
}
|
|
|
|
service_restart() {
|
|
systemctl daemon-reload
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl restart nginx && judge "Nginx $(gettext "重启")"
|
|
fi
|
|
systemctl restart xray
|
|
judge "Xray $(gettext "重启")"
|
|
}
|
|
|
|
service_start() {
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl start nginx && judge "Nginx $(gettext "启动")"
|
|
fi
|
|
systemctl start xray
|
|
judge "Xray $(gettext "启动")"
|
|
}
|
|
|
|
service_stop() {
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl stop nginx && judge "Nginx $(gettext "停止")"
|
|
fi
|
|
systemctl stop xray
|
|
judge "Xray $(gettext "停止")"
|
|
}
|
|
|
|
acme_cron_update() {
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
local crontab_file
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
crontab_file="/var/spool/cron/root"
|
|
else
|
|
crontab_file="/var/spool/cron/crontabs/root"
|
|
fi
|
|
if [[ -f "${ssl_update_file}" ]] && [[ $(crontab -l | grep -c "ssl_update.sh") == "1" ]]; then
|
|
echo
|
|
log_echo "${Warning} ${GreenBG} $(gettext "新版本已自动设置证书自动更新") ${Font}"
|
|
log_echo "${Warning} ${GreenBG} $(gettext "老版本请及时删除 废弃的 改版证书自动更新")! ${Font}"
|
|
log_echo "${GreenBG} $(gettext "已设置改版证书自动更新") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否需要删除改版证书自动更新 (请删除)") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r remove_acme_cron_update_fq
|
|
case $remove_acme_cron_update_fq in
|
|
[nN][oO] | [nN]) ;;
|
|
*)
|
|
sed -i "/ssl_update.sh/d" ${crontab_file}
|
|
rm -rf ${ssl_update_file}
|
|
judge "$(gettext "删除改版证书自动更新")"
|
|
;;
|
|
|
|
esac
|
|
else
|
|
echo
|
|
log_echo "${OK} ${GreenBG} $(gettext "新版本已自动设置证书自动更新") ${Font}"
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前模式不支持此操作")! ${Font}"
|
|
fi
|
|
}
|
|
|
|
check_cert_status() {
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
host="$(info_extraction host)"
|
|
if [[ -d "$HOME/.acme.sh/${host}_ecc" ]] && [[ -f "$HOME/.acme.sh/${host}_ecc/${host}.key" ]] && [[ -f "$HOME/.acme.sh/${host}_ecc/${host}.cer" ]]; then
|
|
modifyTime=$(stat "$HOME/.acme.sh/${host}_ecc/${host}.cer" | sed -n '7,6p' | awk '{print $2" "$3" "$4" "$5}')
|
|
modifyTime=$(date +%s -d "${modifyTime}")
|
|
currentTime=$(date +%s)
|
|
((stampDiff = currentTime - modifyTime))
|
|
((days = stampDiff / 86400))
|
|
((remainingDays = 90 - days))
|
|
tlsStatus=${remainingDays}
|
|
[[ ${remainingDays} -le 0 ]] && tlsStatus="${Red}$(gettext "已过期")${Font}"
|
|
echo
|
|
log_echo "${Green}$(gettext "证书生成日期"): $(date -d "@${modifyTime}" +"%F %H:%M:%S")${Font}"
|
|
log_echo "${Green}$(gettext "证书生成天数"): ${days}${Font}"
|
|
log_echo "${Green}$(gettext "证书剩余天数"): ${tlsStatus}${Font}"
|
|
echo
|
|
if [[ ${remainingDays} -le 0 ]]; then
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "是否立即更新证书") [Y/${Red}N${Font}${YellowBG}]? ${Font}"
|
|
read -r cert_update_manuel_fq
|
|
case $cert_update_manuel_fq in
|
|
[yY][eE][sS] | [yY])
|
|
systemctl stop xray
|
|
judge "Xray $(gettext "停止")"
|
|
cert_update_manuel
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "证书签发工具不存在, 请确认是否证书为脚本签发")! ${Font}"
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前模式不支持此操作")! ${Font}"
|
|
fi
|
|
}
|
|
|
|
cert_update_manuel() {
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
if [[ -f "${amce_sh_file}" ]]; then
|
|
"/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "证书签发工具不存在, 请确认是否证书为脚本签发")! ${Font}"
|
|
fi
|
|
host="$(info_extraction host)"
|
|
"$HOME"/.acme.sh/acme.sh --installcert -d "${host}" --fullchainpath ${ssl_chainpath}/xray.crt --keypath ${ssl_chainpath}/xray.key --ecc
|
|
judge "$(gettext "证书更新")"
|
|
service_restart
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "当前模式不支持此操作")! ${Font}"
|
|
fi
|
|
}
|
|
|
|
set_fail2ban() {
|
|
mf_remote_url="https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/fail2ban_manager.sh"
|
|
if [ ! -f "${idleleo_dir}/fail2ban_manager.sh" ]; then
|
|
log_echo "${Info} ${Green} $(gettext "本地文件 fail2ban_manager.sh 不存在, 正在下载")... ${Font}"
|
|
curl -sL "$mf_remote_url" -o "${idleleo_dir}/fail2ban_manager.sh"
|
|
if [ $? -ne 0 ]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "下载失败, 请手动下载并安装新版本") ${Font}"
|
|
return 1
|
|
fi
|
|
chmod +x "${idleleo_dir}/fail2ban_manager.sh"
|
|
fi
|
|
source "${idleleo_dir}/fail2ban_manager.sh"
|
|
}
|
|
|
|
clean_logs() {
|
|
local cron_file logrotate_config
|
|
echo
|
|
log_echo "${Green} $(gettext "检测到日志文件大小如下:") ${Font}"
|
|
log_echo "${Green}$(du -sh /var/log/xray ${nginx_dir}/logs)${Font}"
|
|
timeout "$(gettext "即将清除")!"
|
|
for i in $(find /var/log/xray/ ${nginx_dir}/logs -name "*.log"); do cat /dev/null >"$i"; done
|
|
judge "$(gettext "日志清理")"
|
|
|
|
#以下为兼容代码, 1个大版本后删除
|
|
if [[ "${ID}" == "centos" ]]; then
|
|
cron_file="/var/spool/cron/root"
|
|
else
|
|
cron_file="/var/spool/cron/crontabs/root"
|
|
fi
|
|
|
|
if [[ $(grep -c "find /var/log/xray/ /etc/nginx/logs -name" "$cron_file") -ne '0' ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "已设置旧版自动清理日志任务") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否需要删除旧版自动清理日志任务") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r delete_task
|
|
case $delete_task in
|
|
[nN][oO] | [nN])
|
|
log_echo "${OK} ${Green} $(gettext "保留现有自动清理日志任务") ${Font}"
|
|
return
|
|
;;
|
|
*)
|
|
sed -i "/find \/var\/log\/xray\/ \/etc\/nginx\/logs -name/d" "$cron_file"
|
|
judge "$(gettext "删除旧版自动清理日志任务")"
|
|
;;
|
|
esac
|
|
fi
|
|
#兼容代码结束
|
|
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否需要设置自动清理日志") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r auto_clean_logs_fq
|
|
case $auto_clean_logs_fq in
|
|
[nN][oO] | [nN])
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${Green} $(gettext "将在 每周三 04:00 自动清空日志") ${Font}"
|
|
|
|
logrotate_config="/etc/logrotate.d/xray_log_cleanup"
|
|
|
|
if [[ -f "$logrotate_config" ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "已设置自动清理日志任务") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否需要删除现有自动清理日志任务") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r delete_task
|
|
case $delete_task in
|
|
[yY][eE][sS] | [yY])
|
|
rm -f "$logrotate_config"
|
|
judge "$(gettext "删除自动清理日志任务")"
|
|
;;
|
|
*)
|
|
log_echo "${OK} ${Green} $(gettext "保留现有自动清理日志任务") ${Font}"
|
|
return
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
echo "/var/log/xray/*.log ${nginx_dir}/logs/*.log {" > "$logrotate_config"
|
|
echo " weekly" >> "$logrotate_config"
|
|
echo " rotate 3" >> "$logrotate_config"
|
|
echo " compress" >> "$logrotate_config"
|
|
echo " missingok" >> "$logrotate_config"
|
|
echo " notifempty" >> "$logrotate_config"
|
|
echo " create 640 nobody nogroup" >> "$logrotate_config"
|
|
echo "}" >> "$logrotate_config"
|
|
|
|
judge "$(gettext "设置自动清理日志")"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
vless_qr_config_tls_ws() {
|
|
cat >${xray_qr_config_file} <<-EOF
|
|
{
|
|
"shell_mode": "${shell_mode}",
|
|
"ws_grpc_mode": "${ws_grpc_mode}",
|
|
"host": "${domain}",
|
|
"ip_version": "${ip_version}",
|
|
"port": ${port},
|
|
"ws_port": "${artxport}",
|
|
"grpc_port": "${artgport}",
|
|
"tls": "TLS",
|
|
"email": "${custom_email}",
|
|
"idc": "${UUID5_char}",
|
|
"id": "${UUID}",
|
|
"net": "ws/gRPC",
|
|
"path": "${artpath}",
|
|
"serviceName": "${artserviceName}",
|
|
"shell_version": "${shell_version}",
|
|
"xray_version": "${xray_version}",
|
|
"nginx_build_version": "${nginx_build_version}"
|
|
}
|
|
EOF
|
|
info_extraction_all=$(jq -rc . ${xray_qr_config_file})
|
|
}
|
|
|
|
vless_qr_config_reality() {
|
|
cat >${xray_qr_config_file} <<-EOF
|
|
{
|
|
"shell_mode": "${shell_mode}",
|
|
"ws_grpc_mode": "${ws_grpc_mode}",
|
|
"host": "${local_ip}",
|
|
"ip_version": "${ip_version}",
|
|
"port": ${port},
|
|
"email": "${custom_email}",
|
|
"idc": "${UUID5_char}",
|
|
"id": "${UUID}",
|
|
"net": "raw",
|
|
"tls": "Reality",
|
|
"target": "${target}",
|
|
"serverNames":"${serverNames}",
|
|
"privateKey":"${privateKey}",
|
|
"publicKey":"${publicKey}",
|
|
"shortIds":"${shortIds}",
|
|
"reality_add_nginx": "${reality_add_nginx}",
|
|
"reality_add_more": "${reality_add_more}",
|
|
"ws_port": "${artxport}",
|
|
"grpc_port": "${artgport}",
|
|
"ws_path": "${artpath}",
|
|
"grpc_serviceName": "${artserviceName}",
|
|
"shell_version": "${shell_version}",
|
|
"xray_version": "${xray_version}"
|
|
}
|
|
EOF
|
|
if [[ ${reality_add_nginx} == "on" ]]; then
|
|
jq --arg nginx_build_version "${nginx_build_version}" '. + {"nginx_build_version": $nginx_build_version}' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
fi
|
|
info_extraction_all=$(jq -rc . ${xray_qr_config_file})
|
|
}
|
|
|
|
vless_qr_config_ws_only() {
|
|
cat >${xray_qr_config_file} <<-EOF
|
|
{
|
|
"shell_mode": "${shell_mode}",
|
|
"ws_grpc_mode": "${ws_grpc_mode}",
|
|
"host": "${local_ip}",
|
|
"ip_version": "${ip_version}",
|
|
"ws_port": "${artxport}",
|
|
"grpc_port": "${artgport}",
|
|
"tls": "None",
|
|
"email": "${custom_email}",
|
|
"idc": "${UUID5_char}",
|
|
"id": "${UUID}",
|
|
"net": "ws/gRPC",
|
|
"path": "${artpath}",
|
|
"serviceName": "${artserviceName}",
|
|
"shell_version": "${shell_version}",
|
|
"xray_version": "${xray_version}"
|
|
}
|
|
EOF
|
|
info_extraction_all=$(jq -rc . ${xray_qr_config_file})
|
|
}
|
|
|
|
vless_urlquote() {
|
|
[[ $# = 0 ]] && return 1
|
|
echo "import urllib.request;print(urllib.request.quote('$1'));" | python3
|
|
}
|
|
|
|
vless_qr_link_image() {
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=ws#$(vless_urlquote $(info_extraction host))+ws%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=grpc#$(vless_urlquote $(info_extraction host))+gRPC%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=ws#$(vless_urlquote $(info_extraction host))+ws%E5%8D%8F%E8%AE%AE"
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=grpc#$(vless_urlquote $(info_extraction host))+gRPC%E5%8D%8F%E8%AE%AE"
|
|
fi
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
vless_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?security=reality&flow=xtls-rprx-vision&fp=chrome&pbk=$(info_extraction publicKey)&sni=$(info_extraction serverNames)&target=$(info_extraction target)&sid=$(info_extraction shortIds)#$(vless_urlquote $(info_extraction host))+Reality%E5%8D%8F%E8%AE%AE"
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction ws_port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&encryption=none&type=ws#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADws%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction grpc_port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&encryption=none&type=grpc#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADgrpc%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction ws_port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&encryption=none&type=ws#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADws%E5%8D%8F%E8%AE%AE"
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction grpc_port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&encryption=none&type=grpc#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADgrpc%E5%8D%8F%E8%AE%AE"
|
|
fi
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction ws_port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&encryption=none&type=ws#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADws%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction grpc_port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&encryption=none&type=grpc#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADgrpc%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
vless_ws_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction ws_port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&encryption=none&type=ws#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADws%E5%8D%8F%E8%AE%AE"
|
|
vless_grpc_link="vless://$(info_extraction id)@$(vless_urlquote $(info_extraction host)):$(info_extraction grpc_port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&encryption=none&type=grpc#$(vless_urlquote $(info_extraction host))+%E5%8D%95%E7%8B%ADgrpc%E5%8D%8F%E8%AE%AE"
|
|
fi
|
|
fi
|
|
{
|
|
echo
|
|
log_echo "${Red} —————————————— Xray $(gettext "配置分享") —————————————— ${Font}"
|
|
if [[ ${tls_mode} == "Reality" ]]; then
|
|
log_echo "${Red} URL $(gettext "分享链接"):${Font} ${vless_link}"
|
|
log_echo "${Red} $(gettext "二维码"): ${Font}"
|
|
echo -n "${vless_link}" | qrencode -o - -t utf8
|
|
echo
|
|
fi
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
log_echo "${Red} ws URL $(gettext "分享链接"):${Font} ${vless_ws_link}"
|
|
log_echo "${Red} $(gettext "二维码"): ${Font}"
|
|
echo -n "${vless_ws_link}" | qrencode -o - -t utf8
|
|
echo
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
log_echo "${Red} gRPC URL $(gettext "分享链接"):${Font} ${vless_grpc_link}"
|
|
log_echo "${Red} $(gettext "二维码"): ${Font}"
|
|
echo -n "${vless_grpc_link}" | qrencode -o - -t utf8
|
|
echo
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
log_echo "${Red} ws URL $(gettext "分享链接"):${Font} ${vless_ws_link}"
|
|
log_echo "${Red} $(gettext "二维码"): ${Font}"
|
|
echo -n "${vless_ws_link}" | qrencode -o - -t utf8
|
|
echo
|
|
log_echo "${Red} gRPC URL $(gettext "分享链接"):${Font} ${vless_grpc_link}"
|
|
log_echo "${Red} $(gettext "二维码"): ${Font}"
|
|
echo -n "${vless_grpc_link}" | qrencode -o - -t utf8
|
|
echo
|
|
fi
|
|
} >>"${xray_info_file}"
|
|
}
|
|
|
|
vless_link_image_choice() {
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "生成分享链接"): ${Font}"
|
|
vless_qr_link_image
|
|
}
|
|
|
|
info_extraction() {
|
|
echo ${info_extraction_all} | jq -r ".$1"
|
|
[[ 0 -ne $? ]] && read_config_status=0
|
|
}
|
|
|
|
basic_information() {
|
|
{
|
|
echo
|
|
case ${shell_mode} in
|
|
Nginx+ws+TLS)
|
|
log_echo "${OK} ${GreenBG} Xray+Nginx+ws+TLS $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Nginx+gRPC+TLS)
|
|
log_echo "${OK} ${GreenBG} Xray+Nginx+grpc+TLS $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Nginx+ws+gRPC+TLS)
|
|
log_echo "${OK} ${GreenBG} Xray+Nginx+ws+gRPC+TLS $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Reality)
|
|
log_echo "${OK} ${GreenBG} Xray+Reality $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Reality+ws)
|
|
log_echo "${OK} ${GreenBG} Xray+Reality+ws $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Reality+gRPC)
|
|
log_echo "${OK} ${GreenBG} Xray+Reality+gRPC $(gettext "安装成功") ${Font}"
|
|
;;
|
|
Reality+ws+gRPC)
|
|
log_echo "${OK} ${GreenBG} Xray+Reality+ws+gRPC $(gettext "安装成功") ${Font}"
|
|
;;
|
|
ws\ ONLY)
|
|
log_echo "${OK} ${GreenBG} ws ONLY $(gettext "安装成功") ${Font}"
|
|
;;
|
|
gRPC\ ONLY)
|
|
log_echo "${OK} ${GreenBG} gRPC ONLY $(gettext "安装成功") ${Font}"
|
|
;;
|
|
ws+gRPC\ ONLY)
|
|
log_echo "${OK} ${GreenBG} ws+gRPC ONLY $(gettext "安装成功") ${Font}"
|
|
;;
|
|
esac
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} VLESS $(gettext "目前分享链接规范为实验阶段, 请自行判断是否适用") ${Font}"
|
|
echo
|
|
log_echo "${Red} —————————————— Xray $(gettext "配置信息") —————————————— ${Font}"
|
|
log_echo "${Red} $(gettext "主机") (host):${Font} $(info_extraction host) "
|
|
if [[ ${tls_mode} == "None" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
log_echo "${Red} ws $(gettext "端口") (port):${Font} $(info_extraction ws_port) "
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
log_echo "${Red} gRPC $(gettext "端口") (port):${Font} $(info_extraction grpc_port) "
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
log_echo "${Red} ws $(gettext "端口") (port):${Font} $(info_extraction ws_port) "
|
|
log_echo "${Red} gRPC $(gettext "端口") (port):${Font} $(info_extraction grpc_port) "
|
|
fi
|
|
else
|
|
log_echo "${Red} $(gettext "端口") (port):${Font} $(info_extraction port) "
|
|
fi
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
log_echo "${Red} Xray ws $(gettext "端口") (inbound_port):${Font} $(info_extraction ws_port) "
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
log_echo "${Red} Xray gRPC $(gettext "端口") (inbound_port):${Font} $(info_extraction grpc_port) "
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
log_echo "${Red} Xray ws $(gettext "端口") (inbound_port):${Font} $(info_extraction ws_port) "
|
|
log_echo "${Red} Xray gRPC $(gettext "端口") (inbound_port):${Font} $(info_extraction grpc_port) "
|
|
fi
|
|
fi
|
|
log_echo "${Red} UUIDv5 $(gettext "映射字符串"):${Font} $(info_extraction idc)"
|
|
log_echo "${Red} $(gettext "用户id") (UUID):${Font} $(info_extraction id)"
|
|
|
|
log_echo "${Red} $(gettext "加密") (encryption):${Font} None "
|
|
log_echo "${Red} $(gettext "传输协议") (network):${Font} $(info_extraction net) "
|
|
log_echo "${Red} $(gettext "底层传输安全") (tls):${Font} $(info_extraction tls) "
|
|
if [[ ${tls_mode} != "Reality" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
log_echo "${Red} $(gettext "路径") (path $(gettext "不要落下")/):${Font} /$(info_extraction path) "
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
log_echo "${Red} serviceName ($(gettext "不需要加")/):${Font} $(info_extraction serviceName) "
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
log_echo "${Red} $(gettext "路径") (path $(gettext "不要落下")/):${Font} /$(info_extraction path) "
|
|
log_echo "${Red} serviceName ($(gettext "不需要加")/):${Font} $(info_extraction serviceName) "
|
|
fi
|
|
else
|
|
log_echo "${Red} $(gettext "流控") (flow):${Font} xtls-rprx-vision "
|
|
log_echo "${Red} target:${Font} $(info_extraction target) "
|
|
log_echo "${Red} serverNames:${Font} $(info_extraction serverNames) "
|
|
log_echo "${Red} privateKey:${Font} $(info_extraction privateKey) "
|
|
log_echo "${Red} publicKey:${Font} $(info_extraction publicKey) "
|
|
log_echo "${Red} shortIds:${Font} $(info_extraction shortIds) "
|
|
if [[ "$reality_add_more" == "on" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
log_echo "${Red} ws $(gettext "端口") (port):${Font} $(info_extraction ws_port) "
|
|
log_echo "${Red} ws $(gettext "路径") ($(gettext "不要落下")/):${Font} /$(info_extraction ws_path) "
|
|
elif [[ ${ws_grpc_mode} == "onlygRPC" ]]; then
|
|
log_echo "${Red} gRPC $(gettext "端口") (port):${Font} $(info_extraction grpc_port) "
|
|
log_echo "${Red} gRPC serviceName ($(gettext "不需要加")/):${Font} $(info_extraction grpc_serviceName) "
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
log_echo "${Red} ws $(gettext "端口") (port):${Font} $(info_extraction ws_port) "
|
|
log_echo "${Red} ws $(gettext "路径") ($(gettext "不要落下")/):${Font} /$(info_extraction ws_path) "
|
|
log_echo "${Red} gRPC $(gettext "端口") (port):${Font} $(info_extraction grpc_port) "
|
|
log_echo "${Red} gRPC serviceName ($(gettext "不需要加")/):${Font} $(info_extraction grpc_serviceName) "
|
|
fi
|
|
fi
|
|
fi
|
|
} >"${xray_info_file}"
|
|
}
|
|
|
|
show_information() {
|
|
cat "${xray_info_file}"
|
|
}
|
|
|
|
ssl_judge_and_install() {
|
|
cd $HOME
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "即将申请证书, 支持使用自定义证书") ${Font}"
|
|
log_echo "${Green} $(gettext "如需使用自定义证书, 请按如下步骤:") ${Font}"
|
|
log_echo " $(gettext "1. 将证书文件重命名: 私钥(xray.key)、证书(xray.crt)")"
|
|
log_echo " $(gettext "2. 将重命名后的证书文件放入") ${ssl_chainpath} $(gettext "目录后再运行脚本")"
|
|
log_echo " $(gettext "3. 重新运行脚本")"
|
|
log_echo "${GreenBG} $(gettext "是否继续") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r ssl_continue
|
|
case $ssl_continue in
|
|
[nN][oO] | [nN])
|
|
exit 0
|
|
;;
|
|
*)
|
|
if [[ -f "${ssl_chainpath}/xray.key" && -f "${ssl_chainpath}/xray.crt" ]] && [[ -f "$HOME/.acme.sh/${domain}_ecc/${domain}.key" && -f "$HOME/.acme.sh/${domain}_ecc/${domain}.cer" ]]; then
|
|
log_echo "${GreenBG} $(gettext "所有证书文件均已存在, 是否保留") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r ssl_delete_1
|
|
case $ssl_delete_1 in
|
|
[nN][oO] | [nN])
|
|
delete_tls_key_and_crt
|
|
rm -rf ${ssl_chainpath}/*
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除") ${Font}"
|
|
ssl_install
|
|
acme
|
|
;;
|
|
*)
|
|
chown -fR nobody:nogroup ${ssl_chainpath}/*
|
|
judge "$(gettext "证书应用")"
|
|
;;
|
|
esac
|
|
elif [[ -f "${ssl_chainpath}/xray.key" || -f "${ssl_chainpath}/xray.crt" ]] && [[ ! -f "$HOME/.acme.sh/${domain}_ecc/${domain}.key" && ! -f "$HOME/.acme.sh/${domain}_ecc/${domain}.cer" ]]; then
|
|
log_echo "${GreenBG} $(gettext "证书文件已存在, 是否保留") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r ssl_delete_2
|
|
case $ssl_delete_2 in
|
|
[nN][oO] | [nN])
|
|
rm -rf ${ssl_chainpath}/*
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除") ${Font}"
|
|
ssl_install
|
|
acme
|
|
;;
|
|
*)
|
|
chown -fR nobody:nogroup ${ssl_chainpath}/*
|
|
judge "$(gettext "证书应用")"
|
|
ssl_self="on"
|
|
;;
|
|
esac
|
|
elif [[ -f "$HOME/.acme.sh/${domain}_ecc/${domain}.key" && -f "$HOME/.acme.sh/${domain}_ecc/${domain}.cer" ]] && [[ ! -f "${ssl_chainpath}/xray.key" || ! -f "${ssl_chainpath}/xray.crt" ]]; then
|
|
log_echo "${GreenBG} $(gettext "证书签发残留文件已存在, 是否保留") [${Red}Y${Font}${GreenBG}/N]? ${Font}"
|
|
read -r ssl_delete_3
|
|
case $ssl_delete_3 in
|
|
[nN][oO] | [nN])
|
|
delete_tls_key_and_crt
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除") ${Font}"
|
|
ssl_install
|
|
acme
|
|
;;
|
|
*)
|
|
"$HOME"/.acme.sh/acme.sh --installcert -d "${domain}" --fullchainpath ${ssl_chainpath}/xray.crt --keypath ${ssl_chainpath}/xray.key --ecc
|
|
chown -fR nobody:nogroup ${ssl_chainpath}/*
|
|
judge "$(gettext "证书应用")"
|
|
;;
|
|
esac
|
|
else
|
|
ssl_install
|
|
acme
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
nginx_systemd() {
|
|
cat >${nginx_systemd_file} <<EOF
|
|
[Unit]
|
|
Description=The NGINX HTTP and reverse proxy server
|
|
After=syslog.target network.target remote-fs.target nss-lookup.target
|
|
|
|
[Service]
|
|
Type=forking
|
|
PIDFile=${nginx_dir}/logs/nginx.pid
|
|
ExecStartPre=${nginx_dir}/sbin/nginx -t
|
|
ExecStart=${nginx_dir}/sbin/nginx -c ${nginx_dir}/conf/nginx.conf
|
|
ExecReload=${nginx_dir}/sbin/nginx -s reload
|
|
ExecStop=/bin/kill -s QUIT \$MAINPID
|
|
PrivateTmp=true
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
judge "Nginx systemd ServerFile $(gettext "添加")"
|
|
systemctl daemon-reload
|
|
}
|
|
|
|
tls_type() {
|
|
if [[ -f "${nginx_conf}" ]] && [[ ${tls_mode} == "TLS" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "请选择支持的 TLS 版本") (default:2): ${Font}"
|
|
log_echo "${GreenBG} $(gettext "建议选择 TLS1.3 only (安全模式)") ${Font}"
|
|
echo -e "1: TLS1.2 and TLS1.3 ($(gettext "兼容模式"))"
|
|
echo -e "${Red}2${Font}: TLS1.3 only ($(gettext "安全模式"))"
|
|
local choose_tls
|
|
read_optimize "$(gettext "请输入"): " "choose_tls" 2 1 2 "$(gettext "请输入有效的数字")"
|
|
if [[ ${choose_tls} == 1 ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "由于 h3 仅支持 TLS1.3, 只支持 TLS1.3 only (安全模式)")! ${Font}"
|
|
tls_type
|
|
else
|
|
sed -i "s/^\( *\)ssl_protocols\( *\).*/\1ssl_protocols\2TLSv1.3;/" $nginx_conf
|
|
log_echo "${OK} ${GreenBG} $(gettext "已切换至") TLS1.3 only ${Font}"
|
|
fi
|
|
[[ -f "${nginx_systemd_file}" ]] && systemctl restart nginx && judge "Nginx $(gettext "重启")"
|
|
systemctl restart xray
|
|
judge "Xray $(gettext "重启")"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "Nginx/配置文件不存在 或 当前模式不支持") ${Font}"
|
|
fi
|
|
}
|
|
|
|
reset_vless_qr_config() {
|
|
basic_information
|
|
vless_qr_link_image
|
|
show_information
|
|
}
|
|
|
|
reset_UUID() {
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]]; then
|
|
UUID_set
|
|
modify_UUID
|
|
jq --arg uuid "${UUID}" \
|
|
--arg uuid5_char "${UUID5_char}" \
|
|
'.id = $uuid | .idc = $uuid5_char' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
service_restart
|
|
reset_vless_qr_config
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
reset_port() {
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]]; then
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
port_set
|
|
modify_nginx_port
|
|
jq --argjson port "${port}" '.port = $port' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
log_echo "${Green} $(gettext "端口"): ${port} ${Font}"
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
port_set
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
read_optimize "$(gettext "请输入") ws inbound_port:" "xport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${xport}"
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
elif [[ ${ws_grpc_mode} == "onlygrpc" ]]; then
|
|
read_optimize "$(gettext "请输入") gRPC inbound_port:" "gport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${gport}"
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
read_optimize "$(gettext "请输入") ws inbound_port:" "xport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
read_optimize "$(gettext "请输入") gRPC inbound_port:" "gport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${xport}"
|
|
port_exist_check "${gport}"
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
fi
|
|
jq --argjson port "$port" \
|
|
--argjson ws_port "$xport" \
|
|
--argjson grpc_port "$gport" \
|
|
'.port = $port | .ws_port = $ws_port | .grpc_port = $grpc_port' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
modify_inbound_port
|
|
[[ ${reality_add_nginx} == "on" ]] && modify_nginx_port
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
if [[ ${ws_grpc_mode} == "onlyws" ]]; then
|
|
read_optimize "$(gettext "请输入") ws inbound_port:" "xport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${xport}"
|
|
gport=$((RANDOM % 1000 + 30000))
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
elif [[ ${ws_grpc_mode} == "onlygrpc" ]]; then
|
|
read_optimize "$(gettext "请输入") gRPC inbound_port:" "gport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${gport}"
|
|
xport=$((RANDOM % 1000 + 20000))
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
elif [[ ${ws_grpc_mode} == "all" ]]; then
|
|
read_optimize "$(gettext "请输入") ws inbound_port:" "xport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
read_optimize "$(gettext "请输入") gRPC inbound_port:" "gport" "NULL" 0 65535 "$(gettext "请输入 0-65535 之间的值")!"
|
|
port_exist_check "${xport}"
|
|
port_exist_check "${gport}"
|
|
log_echo "${Green} ws inbound_port: ${xport} ${Font}"
|
|
log_echo "${Green} gRPC inbound_port: ${gport} ${Font}"
|
|
fi
|
|
jq --argjson ws_port "$xport" \
|
|
--argjson grpc_port "$gport" \
|
|
'.ws_port = ($ws_port | .grpc_port = $grpc_port' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
modify_inbound_port
|
|
fi
|
|
firewall_set
|
|
service_restart
|
|
reset_vless_qr_config
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
reset_target() {
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]] && [[ ${tls_mode} == "Reality" ]]; then
|
|
target_reset=1
|
|
serverNames=$(info_extraction serverNames)
|
|
nginx_reality_serverNames_del
|
|
target_set
|
|
serverNames_set
|
|
modify_target_serverNames
|
|
if [[ ${reality_add_nginx} == "on" ]]; then
|
|
nginx_reality_serverNames_add
|
|
fi
|
|
jq --arg target "${target}" \
|
|
--arg serverNames "${serverNames}" \
|
|
'.target = $target | .serverNames = $serverNames' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
service_restart
|
|
reset_vless_qr_config
|
|
elif [[ ${tls_mode} != "Reality" ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式不支持修改") target ! ${Font}"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
show_user() {
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]] && [[ ${tls_mode} != "None" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "即将显示用户, 一次仅能显示一个") ${Font}"
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
log_echo "${GreenBG} $(gettext "请选择显示用户使用的协议") ws/gRPC ${Font}"
|
|
echo -e "${Red}1${Font}: ws ($(gettext "默认"))"
|
|
echo "2: gRPC"
|
|
local choose_user_prot
|
|
read_optimize "$(gettext "请输入"): " "choose_user_prot" 1 1 2 "$(gettext "请输入有效的数字")"
|
|
choose_user_prot=$((choose_user_prot - 1))
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
choose_user_prot=0
|
|
fi
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "请选择要显示的用户编号"): ${Font}"
|
|
jq -r -c .inbounds[${choose_user_prot}].settings.clients[].email ${xray_conf} | awk '{print NR""": "$0}'
|
|
local show_user_index
|
|
read_optimize "$(gettext "请输入"): " "show_user_index" "NULL"
|
|
if [[ $(jq -r '.inbounds['${choose_user_prot}'].settings.clients|length' ${xray_conf}) -lt ${show_user_index} ]] || [[ ${show_user_index} == 0 ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "选择错误")! ${Font}"
|
|
show_user
|
|
elif [[ ${show_user_index} == 1 ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "请直接在主菜单选择 [查看 Xray 配置信息] 显示主用户") ${Font}"
|
|
echo
|
|
elif [[ ${show_user_index} -gt 1 ]]; then
|
|
show_user_index=$((show_user_index - 1))
|
|
user_email=$(jq -r -c '.inbounds['${choose_user_prot}'].settings.clients['${show_user_index}'].email' ${xray_conf})
|
|
user_id=$(jq -r -c '.inbounds['${choose_user_prot}'].settings.clients['${show_user_index}'].id' ${xray_conf})
|
|
elif [[ ! -z $(echo ${show_user_index} | sed 's/[0-9]//g') ]] || [[ ${show_user_index} == '' ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "选择错误")! ${Font}"
|
|
show_user
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先检测 Xray 是否正确安装")! ${Font}"
|
|
fi
|
|
if [[ ! -z ${user_email} ]] && [[ ! -z ${user_id} ]]; then
|
|
log_echo "${Green} $(gettext "用户名"): ${user_email} ${Font}"
|
|
log_echo "${Green} UUID: ${user_id} ${Font}"
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
if [[ ${choose_user_prot} == 0 ]]; then
|
|
user_vless_link="vless://${user_id}@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?path=%2f$(vless_urlquote $(info_extraction path))%3Fed%3D2048&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=ws#$(vless_urlquote $(info_extraction host))+ws%E5%8D%8F%E8%AE%AE"
|
|
elif [[ ${choose_user_prot} == 1 ]]; then
|
|
user_vless_link="vless://${user_id}@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?serviceName=$(vless_urlquote $(info_extraction serviceName))&security=tls&encryption=none&host=$(vless_urlquote $(info_extraction host))&type=grpc#$(vless_urlquote $(info_extraction host))+gRPC%E5%8D%8F%E8%AE%AE"
|
|
fi
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
user_vless_link="vless://${user_id}@$(vless_urlquote $(info_extraction host)):$(info_extraction port)?security=tls&encryption=none&headerType=none&type=raw&flow=xtls-rprx-vision#$(vless_urlquote $(info_extraction host))+reality%E5%8D%8F%E8%AE%AE"
|
|
fi
|
|
log_echo "${Red} URL $(gettext "分享链接"):${Font} ${user_vless_link}"
|
|
echo -n "${user_vless_link}" | qrencode -o - -t utf8
|
|
fi
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否继续显示用户") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r show_user_continue
|
|
case $show_user_continue in
|
|
[yY][eE][sS] | [yY])
|
|
show_user
|
|
;;
|
|
*) ;;
|
|
esac
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式不支持删除用户")! ${Font}"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
add_user() {
|
|
local choose_user_prot reality_user_more
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]] && [[ ${tls_mode} != "None" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "即将添加用户, 一次仅能添加一个") ${Font}"
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
log_echo "${GreenBG} $(gettext "请选择添加用户使用的协议") ws/gRPC ${Font}"
|
|
echo -e "${Red}1${Font}: ws ($(gettext "默认"))"
|
|
echo "2: gRPC"
|
|
local choose_user_prot
|
|
read_optimize "$(gettext "请输入"): " "choose_user_prot" 1 1 2 "$(gettext "请输入有效的数字")"
|
|
choose_user_prot=$((choose_user_prot - 1))
|
|
reality_user_more="{}"
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
choose_user_prot=0
|
|
reality_user_more='{"flow":"xtls-rprx-vision"}'
|
|
fi
|
|
email_set
|
|
UUID_set
|
|
jq --argjson choose_user_prot "${choose_user_prot}" \
|
|
--arg UUID "${UUID}" \
|
|
--argjson reality_user_more "${reality_user_more}" \
|
|
--arg custom_email "${custom_email}" \
|
|
'.inbounds[$choose_user_prot].settings.clients += [
|
|
{"id": $UUID} +
|
|
($reality_user_more // {}) +
|
|
{"level": 0, "email": $custom_email}
|
|
]' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "$(gettext "添加用户")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
jq ". += {\"multi_user\": \"yes\"}" ${xray_qr_config_file} > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否继续添加用户") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r add_user_continue
|
|
case $add_user_continue in
|
|
[yY][eE][sS] | [yY])
|
|
add_user
|
|
;;
|
|
*) ;;
|
|
esac
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式不支持添加用户")! ${Font}"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
remove_user() {
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]] && [[ ${tls_mode} != "None" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "即将删除用户, 一次仅能删除一个") ${Font}"
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
log_echo "${GreenBG} $(gettext "请选择删除用户使用的协议") ws/gRPC ${Font}"
|
|
echo -e "${Red}1${Font}: ws ($(gettext "默认"))"
|
|
echo "2: gRPC"
|
|
local choose_user_prot
|
|
read_optimize "$(gettext "请输入"): " "choose_user_prot" 1 1 2 "$(gettext "请输入有效的数字")"
|
|
choose_user_prot=$((choose_user_prot - 1))
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
choose_user_prot=0
|
|
fi
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "请选择要删除的用户编号") ${Font}"
|
|
jq -r -c .inbounds[${choose_user_prot}].settings.clients[].email ${xray_conf} | awk '{print NR""": "$0}'
|
|
local del_user_index
|
|
read_optimize "$(gettext "请输入"): " "del_user_index" "NULL"
|
|
if [[ $(jq -r '.inbounds['${choose_user_prot}'].settings.clients|length' ${xray_conf}) -lt ${del_user_index} ]] || [[ ${del_user_index} == 0 ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "选择错误")! ${Font}"
|
|
remove_user
|
|
elif [[ ${del_user_index} == 1 ]]; then
|
|
echo
|
|
log_echo "${Error} ${RedBG} $(gettext "主用户无法删除")! ${Font}"
|
|
echo
|
|
elif [[ ${del_user_index} -gt 1 ]]; then
|
|
del_user_index=$((del_user_index - 1))
|
|
jq --argjson choose_user_prot "${choose_user_prot}" --argjson del_user_index "${del_user_index}" \
|
|
'del(.inbounds[$choose_user_prot].settings.clients[$del_user_index])' ${xray_conf} > "${xray_conf}.tmp"
|
|
judge "$(gettext "删除用户")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "是否继续删除用户") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r remove_user_continue
|
|
case $remove_user_continue in
|
|
[yY][eE][sS] | [yY])
|
|
remove_user
|
|
;;
|
|
*) ;;
|
|
esac
|
|
elif [[ ! -z $(echo ${del_user_index} | sed 's/[0-9]//g') ]] || [[ ${del_user_index} == '' ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "选择错误")! ${Font}"
|
|
remove_user
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先检测 Xray 是否正确安装")! ${Font}"
|
|
fi
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式不支持删除用户")! ${Font}"
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
show_access_log() {
|
|
[[ -f "${xray_access_log}" ]] && tail -f ${xray_access_log} || log_echo "${Error} ${RedBG} log $(gettext "文件不存在")! ${Font}"
|
|
}
|
|
|
|
show_error_log() {
|
|
[[ -f "${xray_error_log}" ]] && tail -f ${xray_error_log} || log_echo "${Error} ${RedBG} log $(gettext "文件不存在")! ${Font}"
|
|
}
|
|
|
|
xray_status_add() {
|
|
if [[ -f "${xray_conf}" ]]; then
|
|
if [[ $(jq -r .stats ${xray_conf}) != null ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "已配置 Xray 流量统计") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否需要关闭此功能") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r xray_status_add_fq
|
|
case $xray_status_add_fq in
|
|
[yY][eE][sS] | [yY])
|
|
service_stop
|
|
jq "del(.api)|del(.stats)|del(.policy)" ${xray_conf} > "${xray_conf}.tmp"
|
|
judge "$(gettext "关闭 Xray 流量统计")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
service_start
|
|
[[ -f "${xray_status_conf}" ]] && rm -rf ${xray_status_conf}
|
|
;;
|
|
*) ;;
|
|
esac
|
|
else
|
|
echo
|
|
log_echo "${GreenBG} Xray $(gettext "流量统计需要使用") api ${Font}"
|
|
log_echo "${GreenBG} $(gettext "可能会影响 Xray 性能") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "是否继续") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r xray_status_add_fq
|
|
case $xray_status_add_fq in
|
|
[yY][eE][sS] | [yY])
|
|
service_stop
|
|
wget -nc --no-check-certificate "https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/status_config.json" -O ${xray_status_conf}
|
|
local status_config
|
|
status_config=$(jq -c . "${xray_status_conf}")
|
|
jq --argjson status_config "${status_config}" \
|
|
'. += $status_config' "${xray_conf}" > "${xray_conf}.tmp"
|
|
judge "$(gettext "设置 Xray 流量统计")"
|
|
mv "${xray_conf}.tmp" "${xray_conf}"
|
|
service_start
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
else
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请先安装") Xray ! ${Font}"
|
|
fi
|
|
}
|
|
|
|
bbr_boost_sh() {
|
|
if [[ -f "${idleleo_dir}/tcp.sh" ]]; then
|
|
cd ${idleleo_dir} && chmod +x ./tcp.sh && ./tcp.sh
|
|
else
|
|
wget -N --no-check-certificate -P ${idleleo_dir} "https://raw.githubusercontent.com/ylx2016/Linux-NetSpeed/master/tcp.sh" && chmod +x ${idleleo_dir}/tcp.sh && ${idleleo_dir}/tcp.sh
|
|
fi
|
|
}
|
|
|
|
uninstall_all() {
|
|
stop_service_all
|
|
if [[ -f "${xray_bin_dir}/xray" ]]; then
|
|
systemctl disable xray
|
|
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
|
|
[[ -d "${xray_conf_dir}" ]] && rm -rf ${xray_conf_dir}
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
jq -r 'del(.xray_version)' ${xray_qr_config_file} > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
fi
|
|
log_echo "${OK} ${GreenBG} $(gettext "已卸载") Xray ${Font}"
|
|
fi
|
|
if [[ -d "${nginx_dir}" ]]; then
|
|
log_echo "${GreenBG} $(gettext "是否卸载") Nginx [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r uninstall_nginx
|
|
case $uninstall_nginx in
|
|
[yY][eE][sS] | [yY])
|
|
systemctl disable nginx
|
|
rm -rf ${nginx_dir}
|
|
rm -rf ${nginx_conf_dir}/*
|
|
[[ -f "${nginx_systemd_file}" ]] && rm -rf ${nginx_systemd_file}
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
jq 'del(.nginx_build_version)' ${xray_qr_config_file} > "${xray_qr_config_file}.tmp"
|
|
mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
fi
|
|
log_echo "${OK} ${GreenBG} $(gettext "已卸载") Nginx ${Font}"
|
|
;;
|
|
*) ;;
|
|
esac
|
|
fi
|
|
log_echo "${GreenBG} $(gettext "是否删除所有脚本文件") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r remove_all_idleleo_file_fq
|
|
case $remove_all_idleleo_file_fq in
|
|
[yY][eE][sS] | [yY])
|
|
rm -rf ${idleleo_commend_file}
|
|
rm -rf ${idleleo_dir}
|
|
systemctl daemon-reload
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除所有文件") ${Font}"
|
|
log_echo "${GreenBG} $(gettext "ヾ( ̄▽ ̄) 拜拜~") ${Font}"
|
|
exit 0
|
|
;;
|
|
*)
|
|
systemctl daemon-reload
|
|
log_echo "${OK} ${GreenBG} $(gettext "已保留脚本文件 (包含 SSL 证书等)") ${Font}"
|
|
;;
|
|
esac
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
log_echo "${GreenBG} $(gettext "是否保留配置文件") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
read -r remove_config_fq
|
|
case $remove_config_fq in
|
|
[yY][eE][sS] | [yY])
|
|
log_echo "${OK} ${GreenBG} $(gettext "已保留配置文件") ${Font}"
|
|
;;
|
|
*)
|
|
rm -rf ${xray_qr_config_file}
|
|
log_echo "${OK} ${GreenBG} $(gettext "已删除配置文件") ${Font}"
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
delete_tls_key_and_crt() {
|
|
[[ -f "$HOME/.acme.sh/acme.sh" ]] && /root/.acme.sh/acme.sh uninstall >/dev/null 2>&1
|
|
[[ -d "$HOME/.acme.sh" ]] && rm -rf "$HOME/.acme.sh"
|
|
log_echo "${OK} ${GreenBG} $(gettext "已清空证书遗留文件") ${Font}"
|
|
}
|
|
|
|
timeout() {
|
|
timeout=0
|
|
timeout_str=""
|
|
while [[ ${timeout} -le 30 ]]; do
|
|
let timeout++
|
|
timeout_str+="#"
|
|
done
|
|
let timeout=timeout+5
|
|
while [[ ${timeout} -gt 0 ]]; do
|
|
let timeout--
|
|
if [[ ${timeout} -gt 25 ]]; then
|
|
let timeout_color=32
|
|
let timeout_bg=42
|
|
timeout_index="3"
|
|
elif [[ ${timeout} -gt 15 ]]; then
|
|
let timeout_color=33
|
|
let timeout_bg=43
|
|
timeout_index="2"
|
|
elif [[ ${timeout} -gt 5 ]]; then
|
|
let timeout_color=31
|
|
let timeout_bg=41
|
|
timeout_index="1"
|
|
else
|
|
timeout_index="0"
|
|
fi
|
|
printf "${Warning} ${GreenBG} %d%s%s ${Font} \033[%d;%dm%-s\033[0m \033[%dm%d\033[0m \r" \
|
|
"$timeout_index" \
|
|
" $(gettext "秒后") " \
|
|
"$1" \
|
|
"$timeout_color" \
|
|
"$timeout_bg" \
|
|
"$timeout_str" \
|
|
"$timeout_color" \
|
|
"$timeout_index"
|
|
sleep 0.1
|
|
timeout_str=${timeout_str%?}
|
|
[[ ${timeout} -eq 0 ]] && printf "\n"
|
|
done
|
|
}
|
|
|
|
judge_mode() {
|
|
local ws_grpc_mode_add
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
ws_grpc_mode=$(info_extraction ws_grpc_mode)
|
|
tls_mode=$(info_extraction tls)
|
|
|
|
case ${ws_grpc_mode} in
|
|
onlyws) ws_grpc_mode_add="ws";;
|
|
onlygRPC) ws_grpc_mode_add="gRPC";;
|
|
all) ws_grpc_mode_add="ws+gRPC";;
|
|
*);;
|
|
esac
|
|
|
|
case ${tls_mode} in
|
|
TLS)
|
|
shell_mode="Nginx+${ws_grpc_mode_add}+TLS"
|
|
;;
|
|
Reality)
|
|
reality_add_more=$(info_extraction reality_add_more)
|
|
reality_add_nginx=$(info_extraction reality_add_nginx)
|
|
|
|
if [[ ${reality_add_more} == "on" && ${reality_add_nginx} == "off" ]]; then
|
|
shell_mode="Reality+${ws_grpc_mode_add}"
|
|
elif [[ ${reality_add_nginx} == "on" && ${reality_add_more} == "on" ]]; then
|
|
shell_mode="Nginx+Reality+${ws_grpc_mode_add}"
|
|
elif [[ ${reality_add_nginx} == "on" && ${reality_add_more} == "off" ]]; then
|
|
shell_mode="Nginx+Reality"
|
|
else
|
|
shell_mode="Reality"
|
|
fi
|
|
;;
|
|
None)
|
|
shell_mode="${ws_grpc_mode_add} ONLY"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
old_tls_mode=${tls_mode}
|
|
fi
|
|
}
|
|
|
|
install_xray_ws_tls() {
|
|
is_root
|
|
check_and_create_user_group
|
|
check_system
|
|
dependency_install
|
|
basic_optimization
|
|
create_directory
|
|
old_config_exist_check
|
|
domain_check
|
|
ws_grpc_choose
|
|
port_set
|
|
ws_inbound_port_set
|
|
grpc_inbound_port_set
|
|
firewall_set
|
|
ws_path_set
|
|
grpc_path_set
|
|
email_set
|
|
UUID_set
|
|
ws_grpc_qr
|
|
vless_qr_config_tls_ws
|
|
stop_service_all
|
|
xray_install
|
|
port_exist_check 80
|
|
port_exist_check "${port}"
|
|
nginx_exist_check
|
|
nginx_systemd
|
|
nginx_ssl_conf_add
|
|
ssl_judge_and_install
|
|
nginx_conf_add
|
|
nginx_servers_conf_add
|
|
xray_conf_add
|
|
tls_type
|
|
basic_information
|
|
enable_process_systemd
|
|
acme_cron_update
|
|
auto_update
|
|
service_restart
|
|
vless_link_image_choice
|
|
show_information
|
|
}
|
|
|
|
install_xray_reality() {
|
|
is_root
|
|
check_and_create_user_group
|
|
check_system
|
|
dependency_install
|
|
basic_optimization
|
|
create_directory
|
|
old_config_exist_check
|
|
ip_check
|
|
xray_install
|
|
port_set
|
|
email_set
|
|
UUID_set
|
|
target_set
|
|
serverNames_set
|
|
keys_set
|
|
shortIds_set
|
|
xray_reality_add_more_choose
|
|
ws_grpc_qr
|
|
firewall_set
|
|
stop_service_all
|
|
port_exist_check "${port}"
|
|
reality_nginx_add_fq
|
|
xray_conf_add
|
|
vless_qr_config_reality
|
|
basic_information
|
|
enable_process_systemd
|
|
auto_update
|
|
service_restart
|
|
vless_link_image_choice
|
|
show_information
|
|
}
|
|
|
|
install_xray_ws_only() {
|
|
is_root
|
|
check_and_create_user_group
|
|
check_system
|
|
dependency_install
|
|
basic_optimization
|
|
create_directory
|
|
old_config_exist_check
|
|
ip_check
|
|
ws_grpc_choose
|
|
ws_inbound_port_set
|
|
grpc_inbound_port_set
|
|
firewall_set
|
|
ws_path_set
|
|
grpc_path_set
|
|
email_set
|
|
UUID_set
|
|
ws_grpc_qr
|
|
vless_qr_config_ws_only
|
|
stop_service_all
|
|
xray_install
|
|
port_exist_check "${xport}"
|
|
port_exist_check "${gport}"
|
|
xray_conf_add
|
|
basic_information
|
|
service_restart
|
|
enable_process_systemd
|
|
auto_update
|
|
vless_link_image_choice
|
|
show_information
|
|
}
|
|
|
|
update_sh() {
|
|
ol_version=${shell_online_version}
|
|
echo "${ol_version}" >${shell_version_tmp}
|
|
[[ -z ${ol_version} ]] && log_echo "${Error} ${RedBG} $(gettext "检测最新版本失败")! ${Font}" && return 1
|
|
echo "${shell_version}" >>${shell_version_tmp}
|
|
newest_version=$(sort -rV ${shell_version_tmp} | head -1)
|
|
oldest_version=$(sort -V ${shell_version_tmp} | head -1)
|
|
version_difference=$(echo "(${newest_version:0:3}-${oldest_version:0:3})>0" | bc)
|
|
if [[ ${shell_version} != ${newest_version} ]]; then
|
|
if [[ ${auto_update} != "YES" ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "新版本")(${newest_version}) $(gettext "更新内容"): ${Font}"
|
|
log_echo "${Green} $(check_version shell_upgrade_details) ${Font}"
|
|
if [[ ${version_difference} == 1 ]]; then
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "存在新版本, 但版本变化较大, 可能存在不兼容情况, 是否更新") [Y/${Red}N${Font}${YellowBG}]? ${Font}"
|
|
else
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "存在新版本, 是否更新") [Y/${Red}N${Font}${GreenBG}]? ${Font}"
|
|
fi
|
|
read -r update_confirm
|
|
else
|
|
[[ -z ${ol_version} ]] && echo "$(gettext "检测 脚本 最新版本失败")!" >>${log_file} && exit 1
|
|
[[ ${version_difference} == 1 ]] && echo "$(gettext "脚本 版本差别过大, 跳过更新")!" >>${log_file} && exit 1
|
|
update_confirm="YES"
|
|
fi
|
|
case $update_confirm in
|
|
[yY][eE][sS] | [yY])
|
|
[[ -L "${idleleo_commend_file}" ]] && rm -f ${idleleo_commend_file}
|
|
wget -N --no-check-certificate -P ${idleleo_dir} https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/install.sh && chmod +x ${idleleo}
|
|
ln -s ${idleleo} ${idleleo_commend_file}
|
|
[[ -f "${xray_qr_config_file}" ]] && jq --arg shell_version "${shell_version}" '.shell_version = $shell_version' "${xray_qr_config_file}" > "${xray_qr_config_file}.tmp" && mv "${xray_qr_config_file}.tmp" "${xray_qr_config_file}"
|
|
clear
|
|
log_echo "${OK} ${GreenBG} $(gettext "更新完成") ${Font}"
|
|
[[ ${version_difference} == 1 ]] && log_echo "${Warning} ${YellowBG} $(gettext "脚本版本变化较大, 若服务无法正常运行请卸载后重装")! ${Font}"
|
|
;;
|
|
*) ;;
|
|
esac
|
|
else
|
|
clear
|
|
log_echo "${OK} ${GreenBG} $(gettext "当前版本为最新版本") ${Font}"
|
|
fi
|
|
|
|
}
|
|
|
|
check_file_integrity() {
|
|
if [[ ! -L "${idleleo_commend_file}" ]] && [[ ! -f "${idleleo}" ]]; then
|
|
check_system
|
|
pkg_install "bc,jq,wget"
|
|
[[ ! -d "${idleleo_dir}" ]] && mkdir -p ${idleleo_dir}
|
|
[[ ! -d "${idleleo_dir}/tmp" ]] && mkdir -p ${idleleo_dir}/tmp
|
|
wget -N --no-check-certificate -P ${idleleo_dir} https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/install.sh && chmod +x ${idleleo}
|
|
judge "$(gettext "下载最新脚本")"
|
|
ln -s ${idleleo} ${idleleo_commend_file}
|
|
clear
|
|
source "$idleleo"
|
|
fi
|
|
}
|
|
|
|
read_version() {
|
|
shell_online_version="$(check_version shell_online_version)"
|
|
xray_online_version="$(check_version xray_online_version)"
|
|
nginx_build_version="$(check_version nginx_build_online_version)"
|
|
}
|
|
|
|
maintain() {
|
|
log_echo "${Error} ${RedBG} $(gettext "该选项暂时无法使用")! ${Font}"
|
|
log_echo "${Error} ${RedBG} $(gettext "$1") ${Font}"
|
|
exit 0
|
|
}
|
|
|
|
list() {
|
|
case $1 in
|
|
'-1' | '--install-tls')
|
|
shell_mode="Nginx+ws+TLS"
|
|
tls_mode="TLS"
|
|
install_xray_ws_tls
|
|
;;
|
|
'-2' | '--install-reality')
|
|
shell_mode="Reality"
|
|
tls_mode="Reality"
|
|
install_xray_reality
|
|
;;
|
|
'-3' | '--install-none')
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式推荐用于负载均衡, 一般情况不推荐使用, 是否安装") [Y/${Red}N${Font}${YellowBG}]? ${Font}"
|
|
read -r wsonly_fq
|
|
case $wsonly_fq in
|
|
[yY][eE][sS] | [yY])
|
|
shell_mode="ws ONLY"
|
|
tls_mode="None"
|
|
install_xray_ws_only
|
|
;;
|
|
*) ;;
|
|
esac
|
|
;;
|
|
'-4' | '--add-upstream')
|
|
nginx_upstream_server_set
|
|
;;
|
|
'-5' | '--add-servernames')
|
|
nginx_servernames_server_set
|
|
;;
|
|
'-au' | '--auto-update')
|
|
auto_update
|
|
;;
|
|
'-c' | '--clean-logs')
|
|
clean_logs
|
|
;;
|
|
'-cs' | '--cert-status')
|
|
check_cert_status
|
|
;;
|
|
'-cu' | '--cert-update')
|
|
cert_update_manuel
|
|
;;
|
|
'-cau' | '--cert-auto-update')
|
|
acme_cron_update
|
|
;;
|
|
'-f' | '--set-fail2ban')
|
|
set_fail2ban
|
|
;;
|
|
'-h' | '--help')
|
|
show_help
|
|
;;
|
|
'-n' | '--nginx-update')
|
|
[[ $2 == "auto_update" ]] && auto_update="YES" && log_file="${log_dir}/auto_update.log"
|
|
nginx_update
|
|
;;
|
|
'-p' | '--port-reset')
|
|
reset_port
|
|
;;
|
|
'--purge' | '--uninstall')
|
|
uninstall_all
|
|
;;
|
|
'-s' | '-show')
|
|
clear
|
|
basic_information
|
|
vless_qr_link_image
|
|
show_information
|
|
;;
|
|
'-t' | '--target-reset')
|
|
reset_target
|
|
;;
|
|
'-tcp' | '--tcp')
|
|
bbr_boost_sh
|
|
;;
|
|
'-tls' | '--tls')
|
|
tls_type
|
|
;;
|
|
'-u' | '--update')
|
|
[[ $2 == "auto_update" ]] && auto_update="YES" && log_file="${log_dir}/auto_update.log"
|
|
update_sh
|
|
;;
|
|
'-uu' | '--uuid-reset')
|
|
reset_UUID
|
|
;;
|
|
'-xa' | '--xray-access')
|
|
clear
|
|
show_access_log
|
|
;;
|
|
'-xe' | '--xray-error')
|
|
clear
|
|
show_error_log
|
|
;;
|
|
'-x' | '--xray-update')
|
|
[[ $2 == "auto_update" ]] && auto_update="YES" && log_file="${log_dir}/auto_update.log"
|
|
xray_update
|
|
;;
|
|
*)
|
|
menu
|
|
;;
|
|
esac
|
|
}
|
|
|
|
show_help() {
|
|
echo "usage: idleleo [OPTION]"
|
|
echo
|
|
echo "OPTION:"
|
|
echo " -1, --install-tls $(gettext "安装") Xray (Nginx+ws/gRPC+TLS)"
|
|
echo " -2, --install-reality $(gettext "安装") Xray (Nginx+Reality+ws/gRPC)"
|
|
echo " -3, --install-none $(gettext "安装") Xray (ws/gRPC ONLY)"
|
|
echo " -4, --add-upstream $(gettext "变更") Nginx $(gettext "负载均衡配置")"
|
|
echo " -5, --add-servernames $(gettext "变更") Nginx serverNames $(gettext "配置")"
|
|
echo " -au, --auto-update $(gettext "设置自动更新")"
|
|
echo " -c, --clean-logs $(gettext "清除日志文件")"
|
|
echo " -cs, --cert-status $(gettext "查看证书状态")"
|
|
echo " -cu, --cert-update $(gettext "更新证书有效期")"
|
|
echo " -cau, --cert-auto-update $(gettext "设置证书自动更新")"
|
|
echo " -f, --set-fail2ban $(gettext "设置 Fail2ban 防暴力破解")"
|
|
echo " -h, --help $(gettext "显示帮助")"
|
|
echo " -n, --nginx-update $(gettext "更新") Nginx"
|
|
echo " -p, --port-reset $(gettext "变更") port"
|
|
echo " --purge, --uninstall $(gettext "脚本卸载")"
|
|
echo " -s, --show $(gettext "显示安装信息")"
|
|
echo " -t, --target-reset $(gettext "变更") target"
|
|
echo " -tcp, --tcp $(gettext "配置") TCP $(gettext "加速")"
|
|
echo " -tls, --tls $(gettext "修改") TLS $(gettext "配置")"
|
|
echo " -u, --update $(gettext "升级脚本")"
|
|
echo " -uu, --uuid-reset $(gettext "变更") UUIDv5/$(gettext "映射字符串")"
|
|
echo " -xa, --xray-access $(gettext "显示") Xray $(gettext "访问信息")"
|
|
echo " -xe, --xray-error $(gettext "显示") Xray $(gettext "错误信息")"
|
|
echo " -x, --xray-update $(gettext "更新") Xray"
|
|
exit 0
|
|
}
|
|
|
|
idleleo_commend() {
|
|
if [[ -L "${idleleo_commend_file}" ]] || [[ -f "${idleleo}" ]]; then
|
|
[[ ! -L "${idleleo_commend_file}" ]] && chmod +x ${idleleo} && ln -s ${idleleo} ${idleleo_commend_file}
|
|
old_version=$(grep "shell_version=" ${idleleo} | head -1 | awk -F '=|"' '{print $3}')
|
|
echo "${old_version}" >${shell_version_tmp}
|
|
echo "${shell_version}" >>${shell_version_tmp}
|
|
oldest_version=$(sort -V ${shell_version_tmp} | head -1)
|
|
version_difference=$(echo "(${shell_version:0:3}-${oldest_version:0:3})>0" | bc)
|
|
if [[ -z ${old_version} ]]; then
|
|
wget -N --no-check-certificate -P ${idleleo_dir} https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/install.sh && chmod +x ${idleleo}
|
|
judge "$(gettext "下载最新脚本")"
|
|
clear
|
|
source "$idleleo"
|
|
elif [[ ${shell_version} != ${oldest_version} ]]; then
|
|
echo
|
|
log_echo "${GreenBG} $(gettext "新版本")(${shell_version}) $(gettext "更新内容"): ${Font}"
|
|
log_echo "${Green} $(check_version shell_upgrade_details) ${Font}"
|
|
if [[ ${version_difference} == 1 ]]; then
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "脚本版本变化较大, 可能存在不兼容情况, 是否继续使用") [Y/${Red}N${Font}${YellowBG}]? ${Font}"
|
|
read -r update_sh_fq
|
|
case $update_sh_fq in
|
|
[yY][eE][sS] | [yY])
|
|
rm -rf ${idleleo}
|
|
wget -N --no-check-certificate -P ${idleleo_dir} https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/install.sh && chmod +x ${idleleo}
|
|
judge "$(gettext "下载最新脚本")"
|
|
clear
|
|
log_echo "${Warning} ${YellowBG} $(gettext "脚本版本变化较大, 若服务无法正常运行请卸载后重装")! ${Font}"
|
|
echo
|
|
;;
|
|
*)
|
|
source "$idleleo"
|
|
;;
|
|
esac
|
|
else
|
|
rm -rf ${idleleo}
|
|
wget -N --no-check-certificate -P ${idleleo_dir} https://raw.githubusercontent.com/hello-yunshu/Xray_bash_onekey/main/install.sh && chmod +x ${idleleo}
|
|
echo
|
|
judge "$(gettext "下载最新脚本")"
|
|
clear
|
|
echo
|
|
fi
|
|
source "$idleleo"
|
|
else
|
|
ol_version=${shell_online_version}
|
|
echo "${ol_version}" >${shell_version_tmp}
|
|
[[ -z ${ol_version} ]] && shell_need_update="${Red}[$(gettext "检测失败")]!${Font}"
|
|
echo "${shell_version}" >>${shell_version_tmp}
|
|
newest_version=$(sort -rV ${shell_version_tmp} | head -1)
|
|
if [[ ${shell_version} != ${newest_version} ]]; then
|
|
shell_need_update="${Red}[$(gettext "有新版")!]${Font}"
|
|
shell_emoji="${Red}>_<${Font}"
|
|
else
|
|
shell_need_update="${Green}[$(gettext "最新版")]${Font}"
|
|
shell_emoji="${Green}^O^${Font}"
|
|
fi
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
if [[ "$(info_extraction nginx_build_version)" == "null" ]] || [[ ! -f "${nginx_dir}/sbin/nginx" ]]; then
|
|
nginx_need_update="${Green}[$(gettext "未安装")]${Font}"
|
|
elif [[ ${nginx_build_version} != $(info_extraction nginx_build_version) ]]; then
|
|
nginx_need_update="${Green}[$(gettext "有新版")!]${Font}"
|
|
else
|
|
nginx_need_update="${Green}[$(gettext "最新版")]${Font}"
|
|
fi
|
|
if [[ -f "${xray_qr_config_file}" ]] && [[ -f "${xray_conf}" ]] && [[ -f "${xray_bin_dir}/xray" ]]; then
|
|
##xray_online_version=$(check_version xray_online_pre_version)
|
|
if [[ "$(info_extraction xray_version)" == "null" ]]; then
|
|
xray_need_update="${Green}[$(gettext "已安装")] ($(gettext "版本未知"))${Font}"
|
|
elif [[ ${xray_online_version} != $(info_extraction xray_version) ]]; then
|
|
xray_need_update="${Green}[$(gettext "有新版")!]${Font}"
|
|
### xray_need_update="${Red}[$(gettext "请务必更新")]!${Font}"
|
|
else
|
|
xray_need_update="${Green}[$(gettext "最新版")]${Font}"
|
|
fi
|
|
else
|
|
xray_need_update="${Red}[$(gettext "未安装")]${Font}"
|
|
fi
|
|
else
|
|
nginx_need_update="${Green}[$(gettext "未安装")]${Font}"
|
|
xray_need_update="${Red}[$(gettext "未安装")]${Font}"
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_program() {
|
|
if [[ -n $(pgrep nginx) ]]; then
|
|
nignx_status="${Green}$(gettext "运行中")..${Font}"
|
|
elif [[ ${tls_mode} == "None" ]] || [[ ${reality_add_nginx} == "off" ]]; then
|
|
nignx_status="${Green}$(gettext "无需测试")${Font}"
|
|
else
|
|
nignx_status="${Red}$(gettext "未运行")${Font}"
|
|
fi
|
|
if [[ -n $(pgrep xray) ]]; then
|
|
xray_status="${Green}$(gettext "运行中")..${Font}"
|
|
else
|
|
xray_status="${Red}$(gettext "未运行")${Font}"
|
|
fi
|
|
}
|
|
|
|
curl_local_connect() {
|
|
curl -Is -o /dev/null -w %{http_code} "https://$1/$2"
|
|
}
|
|
|
|
check_xray_local_connect() {
|
|
if [[ -f "${xray_qr_config_file}" ]]; then
|
|
xray_local_connect_status="${Red}$(gettext "无法连通")${Font}"
|
|
if [[ ${tls_mode} == "TLS" ]]; then
|
|
[[ ${ws_grpc_mode} == "onlyws" ]] && [[ $(curl_local_connect $(info_extraction host) $(info_extraction path)) == "400" ]] && xray_local_connect_status="${Green}$(gettext "本地正常")${Font}"
|
|
[[ ${ws_grpc_mode} == "onlygrpc" ]] && [[ $(curl_local_connect $(info_extraction host) $(info_extraction serviceName)) == "502" ]] && xray_local_connect_status="${Green}$(gettext "本地正常")${Font}"
|
|
[[ ${ws_grpc_mode} == "all" ]] && [[ $(curl_local_connect $(info_extraction host) $(info_extraction serviceName)) == "502" && $(curl_local_connect $(info_extraction host) $(info_extraction path)) == "400" ]] && xray_local_connect_status="${Green}$(gettext "本地正常")${Font}"
|
|
elif [[ ${tls_mode} == "Reality" ]]; then
|
|
xray_local_connect_status="${Green}$(gettext "无需测试")${Font}"
|
|
elif [[ ${tls_mode} == "None" ]]; then
|
|
xray_local_connect_status="${Green}$(gettext "无需测试")${Font}"
|
|
fi
|
|
else
|
|
xray_local_connect_status="${Red}$(gettext "未安装")${Font}"
|
|
fi
|
|
}
|
|
|
|
check_online_version_connect() {
|
|
xray_online_version_status=$(curl_local_connect "www.idleleo.com" "api/xray_shell_versions")
|
|
if [[ ${xray_online_version_status} != "200" ]]; then
|
|
if [[ ${xray_online_version_status} == "403" ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "脚本维护中.. 请稍后再试")! ${Font}"
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "无法检测所需依赖的在线版本, 请稍后再试")! ${Font}"
|
|
fi
|
|
sleep 0.5
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
set_language() {
|
|
echo
|
|
log_echo "${GreenBG} 选择语言 / Select Language / انتخاب زبان / Выберите язык ${Font}"
|
|
echo -e "${Green}1.${Font} 中文"
|
|
echo -e "${Green}2.${Font} English"
|
|
echo -e "${Green}3.${Font} فارسی"
|
|
echo -e "${Green}4.${Font} Русский"
|
|
echo -e "${Green}5.${Font} 한국어"
|
|
|
|
local lang_choice
|
|
read_optimize "$(gettext "请输入数字"): " "lang_choice" "NULL" 1 5 "$(gettext "请输入 1 到 5 之间的有效数字")"
|
|
|
|
case $lang_choice in
|
|
1)
|
|
export LANG=zh_CN.UTF-8
|
|
rm -f "${idleleo_dir}/language.conf"
|
|
rm -rf "${idleleo_dir}/languages"
|
|
;;
|
|
2)
|
|
export LANG=en_US.UTF-8
|
|
;;
|
|
3)
|
|
export LANG=fa_IR.UTF-8
|
|
;;
|
|
4)
|
|
export LANG=ru_RU.UTF-8
|
|
;;
|
|
5)
|
|
export LANG=ko_KR.UTF-8
|
|
;;
|
|
*)
|
|
log_echo "${Error} ${RedBG} $(gettext "无效的选择") ${Font}"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
if [ "$lang_choice" -ne 1 ]; then
|
|
|
|
check_system
|
|
|
|
echo "LANG=$LANG" > "${idleleo_dir}/language.conf"
|
|
|
|
case $ID in
|
|
debian|ubuntu)
|
|
if ! dpkg -s locales-all >/dev/null 2>&1; then
|
|
pkg_install "locales-all"
|
|
#locale-gen "$LANG"
|
|
fi
|
|
#update-locale "LANG=$LANG"
|
|
;;
|
|
centos)
|
|
local ins_lang_code="${LANG%%_*}"
|
|
if ! rpm -q "glibc-langpack-$ins_lang_code" >/dev/null 2>&1; then
|
|
pkg_install "glibc-langpack-$ins_lang_code"
|
|
#localedef -c -i "${LANG%.*}" -f UTF-8 "$LANG"
|
|
fi
|
|
#localectl set-locale "LANG=$LANG"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
source "$idleleo"
|
|
}
|
|
|
|
function backup_directories() {
|
|
local timestamp=$(date +"%Y%m%d%H%M%S")
|
|
local backup_name=""
|
|
read_optimize "$(gettext "请输入备份名称") ($(gettext "不需要后缀")): " "backup_name" ""
|
|
local backup_filename="xray_bash_${backup_name}_${timestamp}.tar.gz"
|
|
local backup_path="/etc/idleleo/${backup_filename}"
|
|
|
|
local tar_output
|
|
tar --exclude='/etc/idleleo/xray_bash_*.tar.gz' -czf "${backup_path}" /etc/idleleo /usr/local/nginx 2>&1 > /dev/null | tee tar_output
|
|
|
|
if [[ $? -ne 0 ]]; then
|
|
log_echo "${Green} tar $(gettext "报错信息"): ${Font}"
|
|
cat tar_output
|
|
log_echo "${Warning} ${YellowBG} $(gettext "备份完整性可能受到影响, 请检查上述错误信息") ${Font}"
|
|
fi
|
|
|
|
if [[ ! -f "${backup_path}" ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "备份失败") ${Font}"
|
|
else
|
|
log_echo "${OK} ${GreenBG} $(gettext "备份成功"): ${backup_path} ${Font}"
|
|
fi
|
|
rm -f tar_output
|
|
}
|
|
|
|
function restore_directories() {
|
|
log_echo "${Warning} ${YellowBG} $(gettext "请确保备份文件在目录"): /etc/idleleo ${Font}"
|
|
local backup_files=($(ls /etc/idleleo/xray_bash_*.tar.gz 2>/dev/null))
|
|
|
|
if [[ ${#backup_files[@]} -eq 0 ]]; then
|
|
log_echo "${Error} ${RedBG} $(gettext "没有找到备份文件") ${Font}"
|
|
return 1
|
|
fi
|
|
|
|
if [[ ${#backup_files[@]} -gt 1 ]]; then
|
|
log_echo "${Warning} ${YellowBG} $(gettext "发现多个备份文件"), $(gettext "将使用最新的文件进行恢复") ${Font}"
|
|
fi
|
|
|
|
local latest_backup_file=${backup_files[-1]}
|
|
log_echo "${Green} $(gettext "找到最新备份文件"): ${latest_backup_file} ${Font}"
|
|
|
|
timeout "$(gettext "恢复备份")!"
|
|
tar -xzf "${latest_backup_file}" -C / &> /dev/null
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
log_echo "${OK} ${GreenBG} $(gettext "恢复成功") ${Font}"
|
|
log_echo "${Info} ${Green} $(gettext "记得安装") xray ${Font}"
|
|
if [[ -d "/usr/local/nginx" ]]; then
|
|
log_echo "${Info} ${Green} $(gettext "记得安装") nginx ${Font}"
|
|
fi
|
|
else
|
|
log_echo "${Error} ${RedBG} $(gettext "恢复失败") ${Font}"
|
|
fi
|
|
}
|
|
|
|
#以下为兼容代码, 1个大版本后删除
|
|
fix_bugs() {
|
|
local log_cleanup_file_path="/etc/logrotate.d/custom_log_cleanup"
|
|
if [[ -f "${log_cleanup_file_path}" ]]; then
|
|
echo
|
|
log_echo "${Warning} ${RedBG} $(gettext "检测存在到") BUG ! ${Font}"
|
|
log_echo "${Warning} ${YellowBG} BUG $(gettext "来源于自动清理日志错误的设置") ${Font}"
|
|
log_echo "${Warning} ${YellowBG} $(gettext "开始修复")... ${Font}"
|
|
[[ -f "${nginx_dir}/sbin/nginx" ]] && chown -fR nobody:nogroup "${nginx_dir}/logs"
|
|
chown -fR nobody:nogroup /var/log/xray/
|
|
rm -f "${log_cleanup_file_path}"
|
|
judge "$(gettext "错误的配置文件删除")"
|
|
log_echo "${Warning} ${YellowBG} $(gettext "即将重新设置自动清理日志")... ${Font}"
|
|
bash "${idleleo}" --clean-logs
|
|
fi
|
|
}
|
|
#兼容代码结束
|
|
|
|
menu() {
|
|
echo
|
|
log_echo "Xray $(gettext "安装管理脚本") ${Red}[${shell_version}]${Font} ${shell_emoji}"
|
|
log_echo "--- $(gettext "作者"): hello-yunshu ---"
|
|
log_echo "--- $(gettext "修改"): hey.run ---"
|
|
log_echo "--- https://github.com/hello-yunshu ---"
|
|
echo
|
|
log_echo "$(gettext "当前模式"): ${shell_mode}"
|
|
log_echo "$(gettext "当前语言"): ${LANG%.*}"
|
|
echo
|
|
|
|
echo -e "$(gettext "可以使用")${RedW} idleleo ${Font}$(gettext "命令管理脚本")${Font}\n"
|
|
|
|
log_echo "—————————————— ${GreenW}$(gettext "版本检测")${Font} ——————————————"
|
|
log_echo "$(gettext "脚本"): ${shell_need_update}"
|
|
log_echo "Xray: ${xray_need_update}"
|
|
log_echo "Nginx: ${nginx_need_update}"
|
|
log_echo "—————————————— ${GreenW}$(gettext "运行状态")${Font} ——————————————"
|
|
log_echo "Xray: ${xray_status}"
|
|
log_echo "Nginx: ${nignx_status}"
|
|
log_echo "$(gettext "连通性"): ${xray_local_connect_status}"
|
|
echo -e "—————————————— ${GreenW}$(gettext "升级向导")${Font} ——————————————"
|
|
echo -e "${Green}0.${Font} $(gettext "升级") $(gettext "脚本")"
|
|
echo -e "${Green}1.${Font} $(gettext "升级") Xray"
|
|
echo -e "${Green}2.${Font} $(gettext "升级") Nginx"
|
|
echo -e "—————————————— ${GreenW}语言 / Language${Font} ———————"
|
|
echo -e "${Green}36.${Font} 中文"
|
|
echo -e " English"
|
|
echo -e " فارسی "
|
|
echo -e " Русский"
|
|
echo -e " 한국어"
|
|
echo -e "—————————————— ${GreenW}$(gettext "安装向导")${Font} ——————————————"
|
|
echo -e "${Green}3.${Font} $(gettext "安装") Xray (Reality+ws/gRPC+Nginx)"
|
|
echo -e "${Green}4.${Font} $(gettext "安装") Xray (Nginx+ws/gRPC+TLS)"
|
|
echo -e "${Green}5.${Font} $(gettext "安装") Xray (ws/gRPC ONLY)"
|
|
echo -e "—————————————— ${GreenW}$(gettext "配置变更")${Font} ——————————————"
|
|
echo -e "${Green}6.${Font} $(gettext "变更") UUIDv5/$(gettext "映射字符串")"
|
|
echo -e "${Green}7.${Font} $(gettext "变更") port"
|
|
echo -e "${Green}8.${Font} $(gettext "变更") target"
|
|
echo -e "${Green}9.${Font} $(gettext "变更") TLS $(gettext "版本")"
|
|
echo -e "${Green}10.${Font} $(gettext "变更") Nginx $(gettext "负载均衡配置")"
|
|
echo -e "${Green}11.${Font} $(gettext "变更") Nginx serverNames $(gettext "配置")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "用户管理")${Font} ——————————————"
|
|
echo -e "${Green}12.${Font} $(gettext "查看") Xray $(gettext "用户")"
|
|
echo -e "${Green}13.${Font} $(gettext "添加") Xray $(gettext "用户")"
|
|
echo -e "${Green}14.${Font} $(gettext "删除") Xray $(gettext "用户")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "查看信息")${Font} ——————————————"
|
|
echo -e "${Green}15.${Font} $(gettext "查看") Xray $(gettext "实时访问日志")"
|
|
echo -e "${Green}16.${Font} $(gettext "查看") Xray $(gettext "实时错误日志")"
|
|
echo -e "${Green}17.${Font} $(gettext "查看") Xray $(gettext "配置信息")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "服务相关")${Font} ——————————————"
|
|
echo -e "${Green}18.${Font} $(gettext "重启") $(gettext "所有服务")"
|
|
echo -e "${Green}19.${Font} $(gettext "启动") $(gettext "所有服务")"
|
|
echo -e "${Green}20.${Font} $(gettext "停止") $(gettext "所有服务")"
|
|
echo -e "${Green}21.${Font} $(gettext "查看") $(gettext "所有服务")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "证书相关")${Font} ——————————————"
|
|
echo -e "${Green}22.${Font} $(gettext "查看") $(gettext "证书状态")"
|
|
echo -e "${Green}23.${Font} $(gettext "更新") $(gettext "证书有效期")"
|
|
echo -e "${Green}24.${Font} $(gettext "设置") $(gettext "证书自动更新")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "其他选项")${Font} ——————————————"
|
|
echo -e "${Green}25.${Font} $(gettext "配置") $(gettext "自动更新")"
|
|
echo -e "${Green}26.${Font} $(gettext "设置") TCP $(gettext "加速")"
|
|
echo -e "${Green}27.${Font} $(gettext "设置") Fail2ban $(gettext "防暴力破解")"
|
|
echo -e "${Green}28.${Font} $(gettext "设置") Xray $(gettext "流量统计")"
|
|
echo -e "${Green}29.${Font} $(gettext "清除") $(gettext "日志文件")"
|
|
echo -e "${Green}30.${Font} $(gettext "测试") $(gettext "服务器网速")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "备份恢复")${Font} ——————————————"
|
|
echo -e "${Green}31.${Font} $(gettext "备份") $(gettext "全部文件")"
|
|
echo -e "${Green}32.${Font} $(gettext "恢复") $(gettext "全部文件")"
|
|
echo -e "—————————————— ${GreenW}$(gettext "卸载向导")${Font} ——————————————"
|
|
echo -e "${Green}33.${Font} $(gettext "卸载") $(gettext "脚本")"
|
|
echo -e "${Green}34.${Font} $(gettext "清空") $(gettext "证书文件")"
|
|
echo -e "${Green}35.${Font} $(gettext "退出") \n"
|
|
|
|
local menu_num
|
|
read_optimize "$(gettext "请输入选项"): " "menu_num" "NULL" 0 36 "$(gettext "请输入 0 到 36 之间的有效数字")"
|
|
case $menu_num in
|
|
0)
|
|
update_sh
|
|
source "$idleleo"
|
|
;;
|
|
1)
|
|
xray_update
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
source "$idleleo"
|
|
;;
|
|
2)
|
|
echo
|
|
log_echo "${Red}[$(gettext "不建议")]${Font} $(gettext "频繁升级 Nginx, 请确认 Nginx 有升级的必要")!"
|
|
timeout "$(gettext "开始升级")!"
|
|
nginx_update
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
source "$idleleo"
|
|
;;
|
|
3)
|
|
shell_mode="Reality"
|
|
tls_mode="Reality"
|
|
install_xray_reality
|
|
source "$idleleo"
|
|
;;
|
|
4)
|
|
shell_mode="Nginx+ws+TLS"
|
|
tls_mode="TLS"
|
|
install_xray_ws_tls
|
|
source "$idleleo"
|
|
;;
|
|
5)
|
|
echo
|
|
log_echo "${Warning} ${YellowBG} $(gettext "此模式推荐用于负载均衡, 一般情况不推荐使用, 是否安装") [Y/${Red}N${Font}${YellowBG}]? ${Font}"
|
|
read -r wsonly_fq
|
|
case $wsonly_fq in
|
|
[yY][eE][sS] | [yY])
|
|
shell_mode="ws ONLY"
|
|
tls_mode="None"
|
|
install_xray_ws_only
|
|
;;
|
|
*) ;;
|
|
esac
|
|
source "$idleleo"
|
|
;;
|
|
6)
|
|
reset_UUID
|
|
judge "$(gettext "变更") UUIDv5/$(gettext "映射字符串")"
|
|
menu
|
|
;;
|
|
7)
|
|
reset_port
|
|
judge "$(gettext "变更") port"
|
|
menu
|
|
;;
|
|
8)
|
|
reset_target
|
|
judge "$(gettext "变更") target"
|
|
menu
|
|
;;
|
|
9)
|
|
tls_type
|
|
judge "$(gettext "变更") TLS $(gettext "版本")"
|
|
menu
|
|
;;
|
|
10)
|
|
nginx_upstream_server_set
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
menu
|
|
;;
|
|
11)
|
|
nginx_servernames_server_set
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
menu
|
|
;;
|
|
12)
|
|
show_user
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
13)
|
|
service_stop
|
|
add_user
|
|
service_start
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
14)
|
|
service_stop
|
|
remove_user
|
|
service_start
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
15)
|
|
clear
|
|
show_access_log
|
|
;;
|
|
16)
|
|
clear
|
|
show_error_log
|
|
;;
|
|
17)
|
|
clear
|
|
basic_information
|
|
vless_qr_link_image
|
|
show_information
|
|
menu
|
|
;;
|
|
18)
|
|
service_restart
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
menu
|
|
;;
|
|
19)
|
|
service_start
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
source "$idleleo"
|
|
;;
|
|
20)
|
|
service_stop
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
source "$idleleo"
|
|
;;
|
|
21)
|
|
if [[ ${tls_mode} == "TLS" ]] || [[ ${reality_add_nginx} == "on" ]]; then
|
|
systemctl status nginx
|
|
fi
|
|
systemctl status xray
|
|
menu
|
|
;;
|
|
22)
|
|
check_cert_status
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
23)
|
|
cert_update_manuel
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
24)
|
|
acme_cron_update
|
|
timeout "$(gettext "回到菜单")!"
|
|
clear
|
|
menu
|
|
;;
|
|
25)
|
|
auto_update
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
menu
|
|
;;
|
|
26)
|
|
clear
|
|
bbr_boost_sh
|
|
;;
|
|
27)
|
|
set_fail2ban
|
|
menu
|
|
;;
|
|
28)
|
|
xray_status_add
|
|
timeout "$(gettext "回到菜单")!"
|
|
menu
|
|
;;
|
|
29)
|
|
clean_logs
|
|
menu
|
|
;;
|
|
30)
|
|
clear
|
|
bash <(curl -Lso- https://git.io/Jlkmw)
|
|
;;
|
|
31)
|
|
backup_directories
|
|
menu
|
|
;;
|
|
32)
|
|
restore_directories
|
|
menu
|
|
;;
|
|
33)
|
|
uninstall_all
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
source "$idleleo"
|
|
;;
|
|
34)
|
|
delete_tls_key_and_crt
|
|
rm -rf ${ssl_chainpath}/*
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
menu
|
|
;;
|
|
35)
|
|
timeout "$(gettext "清空屏幕")!"
|
|
clear
|
|
exit 0
|
|
;;
|
|
36)
|
|
set_language
|
|
bash idleleo
|
|
;;
|
|
*)
|
|
clear
|
|
log_echo "${Error} ${RedBG} $(gettext "请输入正确的数字")! ${Font}"
|
|
menu
|
|
;;
|
|
esac
|
|
}
|
|
|
|
check_file_integrity
|
|
check_online_version_connect
|
|
init_language
|
|
read_version
|
|
judge_mode
|
|
idleleo_commend
|
|
check_program
|
|
check_xray_local_connect
|
|
fix_bugs
|
|
list "$@"
|