2023-10-18 22:09:51 +03:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
bold='\033[0;1m'
|
|
|
|
underl='\033[0;4m'
|
|
|
|
red='\033[0;31m'
|
|
|
|
green='\033[0;32m'
|
|
|
|
yellow='\033[0;33m'
|
|
|
|
normal='\033[0m'
|
|
|
|
|
2023-10-27 14:15:09 +03:00
|
|
|
export PATH=$PATH:/usr/local/bin/ # for sudo user this can be not in PATH
|
2023-10-18 22:09:51 +03:00
|
|
|
if command -v xray > /dev/null
|
|
|
|
then
|
|
|
|
xray_version=$(xray --version | head -n 1 | cut -c 6-10)
|
2023-10-31 14:11:40 +03:00
|
|
|
echo -e "${green}xray ${xray_version} detected${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
if command -v jq > /dev/null
|
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
jq_installed=true
|
2023-10-18 22:09:51 +03:00
|
|
|
echo -e "${green}jq found${normal}"
|
|
|
|
else
|
2023-10-26 13:51:34 +03:00
|
|
|
jq_installed=false
|
2023-10-31 14:11:40 +03:00
|
|
|
echo -e "${yellow}Warning: jq not installed but needed for operations with configs${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
if [ $(id -u) -eq 0 ]
|
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
is_root=true
|
2023-10-18 22:09:51 +03:00
|
|
|
echo -e "${green}running as root${normal}"
|
|
|
|
else
|
2023-10-26 13:51:34 +03:00
|
|
|
is_root=false
|
2023-10-31 14:11:40 +03:00
|
|
|
echo -e "${yellow}Warning: you should be root to install xray${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
|
|
|
|
command="help"
|
|
|
|
if [ ! -v $1 ]
|
|
|
|
then
|
|
|
|
command=$1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ $command = "install" ]
|
|
|
|
then
|
|
|
|
|
|
|
|
echo -e "${bold}Download and install xray?${normal} (Y/n)"
|
2023-10-27 14:15:09 +03:00
|
|
|
read answer_di
|
|
|
|
if [ -v $answer_di ] || [ $(echo $answer_di | cut -c 1) != "n" ]
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
install_xray=true
|
|
|
|
if command -v xray > /dev/null
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
|
|
|
echo -e "xray ${version} detected, install anyway? (y/N)"
|
2023-10-27 14:15:09 +03:00
|
|
|
read answer_ia
|
|
|
|
if [ -v $answer_ia ] || ([ $(echo $answer_ia | cut -c 1) != "y" ] && [ $(echo $answer_ia | cut -c 1) != "Y" ])
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
install_xray=false
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if $install_xray
|
|
|
|
then
|
|
|
|
if $is_root
|
|
|
|
then
|
|
|
|
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
2023-10-27 14:15:09 +03:00
|
|
|
mkdir -p /var/log/xray
|
|
|
|
touch /var/log/xray/error.log
|
2023-10-26 13:51:34 +03:00
|
|
|
echo -e "${green}xray installed${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
else
|
2023-10-26 13:51:34 +03:00
|
|
|
echo -e "${red}xray not installed, something goes wrong${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
2023-10-26 13:51:34 +03:00
|
|
|
else
|
|
|
|
echo -e "${red}You should be root, or run this script with sudo
|
|
|
|
to install xray${normal}"
|
|
|
|
exit 1
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo -e "${bold}Generate configs?${normal} (Y/n)"
|
2023-10-27 14:15:09 +03:00
|
|
|
read answer_gc
|
|
|
|
if [ -v $answer_gc ] || [ $(echo $answer_gc | cut -c 1) != "n" ]
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
if ! $(command -v xray > /dev/null)
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
|
|
|
echo -e "${red}xray not installed, can't generate configs"
|
|
|
|
exit 1
|
2023-10-26 13:51:34 +03:00
|
|
|
fi
|
|
|
|
if ! $jq_installed
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
|
|
|
echo -e "${red}jq not installed, can't generate configs"
|
|
|
|
exit 1
|
|
|
|
else
|
2023-10-24 23:13:26 +03:00
|
|
|
echo -e "${bold}Enter IPv4 or IPv6 address of your xray server, or its domain name:${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
read address
|
2023-10-31 14:11:40 +03:00
|
|
|
id=$(xray uuid) # generate random uuid for vless
|
2023-10-18 22:09:51 +03:00
|
|
|
keys=$(xray x25519)
|
2023-10-20 22:39:22 +03:00
|
|
|
private_key=$(echo $keys | cut -d " " -f 3)
|
|
|
|
public_key=$(echo $keys | cut -d " " -f 6)
|
2023-10-31 14:11:40 +03:00
|
|
|
# generate random short_id for grpc-reality
|
2023-10-18 22:09:51 +03:00
|
|
|
if command -v openssl > /dev/null
|
|
|
|
then
|
|
|
|
short_id=$(openssl rand -hex 8)
|
|
|
|
else
|
|
|
|
echo -e "Enter a random (up to) 16-digit hex number,
|
|
|
|
containing only digits 0-9 and letters a-f, for instance
|
|
|
|
1234567890abcdef"
|
|
|
|
read short_id
|
|
|
|
if [ -v $short_id ]
|
|
|
|
then
|
2023-10-20 22:39:22 +03:00
|
|
|
echo -e "${red}short id not set${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
echo -e "${bold}Choose a fake site to mimic.${normal}
|
|
|
|
It is better if it is hosted by your VPS provider
|
|
|
|
or is in the same country. Better if it is popular.
|
|
|
|
(1) www.yahoo.com (default)
|
|
|
|
(2) www.microsoft.com
|
|
|
|
(3) www.google.com
|
|
|
|
(4) www.nvidia.com
|
|
|
|
(5) www.amd.com
|
|
|
|
(6) www.samsung.com
|
|
|
|
(7) your variant"
|
|
|
|
read number
|
|
|
|
if [ ! -v $number ]
|
|
|
|
then
|
|
|
|
if [ $number -eq 2 ]
|
|
|
|
then
|
|
|
|
fake_site="www.microsoft.com"
|
|
|
|
elif [ $number -eq 3 ]
|
|
|
|
then
|
|
|
|
fake_site="www.google.com"
|
|
|
|
elif [ $number -eq 4 ]
|
|
|
|
then
|
|
|
|
fake_site="www.nvidia.com"
|
|
|
|
elif [ $number -eq 5 ]
|
|
|
|
then
|
|
|
|
fake_site="www.amd.com"
|
|
|
|
elif [ $number -eq 6 ]
|
|
|
|
then
|
|
|
|
fake_site="www.samsung.com"
|
|
|
|
elif [ $number -eq 7 ]
|
|
|
|
then
|
|
|
|
echo -e "type your variant:"
|
|
|
|
read fake_site
|
|
|
|
if [ -v $fake_site ]
|
|
|
|
then
|
|
|
|
fake_site="www.yahoo.com"
|
|
|
|
fi
|
2023-10-20 22:39:22 +03:00
|
|
|
else
|
|
|
|
fake_site="www.yahoo.com"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
fake_site="www.yahoo.com"
|
|
|
|
fi
|
|
|
|
echo -e "${green}mimic ${fake_site}${normal}"
|
2023-10-24 23:13:26 +03:00
|
|
|
email="love@xray.com"
|
2023-10-20 22:39:22 +03:00
|
|
|
clients=" [
|
2023-10-18 22:09:51 +03:00
|
|
|
{
|
2023-10-20 22:39:22 +03:00
|
|
|
\"id\": \"${id}\",
|
2023-10-24 23:13:26 +03:00
|
|
|
\"email\": \"${email}\",
|
|
|
|
\"flow\": \"\"
|
2023-10-18 22:09:51 +03:00
|
|
|
}
|
2023-10-20 22:39:22 +03:00
|
|
|
]"
|
|
|
|
serverRealitySettings=" {
|
|
|
|
\"show\": false,
|
2023-10-24 23:13:26 +03:00
|
|
|
\"dest\": \"${fake_site}:443\",
|
2023-10-20 22:39:22 +03:00
|
|
|
\"xver\": 0,
|
|
|
|
\"serverNames\": [ \"${fake_site}\" ],
|
|
|
|
\"privateKey\": \"${private_key}\",
|
|
|
|
\"shortIds\": [ \"${short_id}\" ]
|
|
|
|
}"
|
2023-10-18 22:09:51 +03:00
|
|
|
# make server config
|
2023-10-24 23:13:26 +03:00
|
|
|
cat template_config_server.json | jq ".inbounds[].settings.clients=${clients} | .inbounds[].streamSettings.realitySettings=${serverRealitySettings}" > config_server.json
|
2023-10-18 22:09:51 +03:00
|
|
|
|
2023-10-20 22:39:22 +03:00
|
|
|
vnext=" [
|
2023-10-18 22:09:51 +03:00
|
|
|
{
|
2023-10-20 22:39:22 +03:00
|
|
|
\"address\": \"${address}\",
|
2023-10-25 11:35:04 +03:00
|
|
|
\"port\": 50051,
|
2023-10-20 22:39:22 +03:00
|
|
|
\"users\": [
|
2023-10-18 22:09:51 +03:00
|
|
|
{
|
2023-10-20 22:39:22 +03:00
|
|
|
\"id\": \"${id}\",
|
|
|
|
\"alterId\": 0,
|
2023-10-24 23:13:26 +03:00
|
|
|
\"email\": \"${email}\",
|
2023-10-20 22:39:22 +03:00
|
|
|
\"security\": \"auto\",
|
|
|
|
\"encryption\": \"none\",
|
2023-10-24 23:13:26 +03:00
|
|
|
\"flow\": \"\"
|
2023-10-18 22:09:51 +03:00
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2023-10-20 22:39:22 +03:00
|
|
|
]"
|
|
|
|
clientRealitySettings=" {
|
2023-10-24 23:13:26 +03:00
|
|
|
\"serverName\": \"${fake_site}\",
|
2023-10-20 22:39:22 +03:00
|
|
|
\"fingerprint\": \"chrome\",
|
|
|
|
\"show\": false,
|
2023-10-24 23:13:26 +03:00
|
|
|
\"publicKey\": \"${public_key}\",
|
2023-10-20 22:39:22 +03:00
|
|
|
\"shortId\": \"${short_id}\",
|
|
|
|
\"spiderX\": \"\"
|
|
|
|
}"
|
2023-10-18 22:09:51 +03:00
|
|
|
# make main client config
|
2023-10-24 23:13:26 +03:00
|
|
|
cat template_config_client.json | jq ".outbounds |= map(if .settings.vnext then .settings.vnext=${vnext} else . end) | .outbounds |= map(if .streamSettings.realitySettings then .streamSettings.realitySettings=${clientRealitySettings} else . end)" > config_client.json
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
elif [ $command = "add" ]
|
|
|
|
then
|
2023-10-31 14:11:40 +03:00
|
|
|
echo -e "${bold}add${normal}"
|
|
|
|
if ! $(command -v xray > /dev/null)
|
|
|
|
then
|
|
|
|
echo -e "${red}xray needed but not installed${normal}"
|
2023-10-31 22:32:30 +03:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
if ! $jq_installed
|
|
|
|
then
|
|
|
|
echo -e "${red}jq needed but not installed${normal}"
|
|
|
|
exit 1
|
2023-10-31 14:11:40 +03:00
|
|
|
fi
|
|
|
|
if [ ! -f "config_client.json" ] || [ ! -r "config_server.json" ]
|
|
|
|
then
|
|
|
|
echo -e "${red}server config and config for default user are needed but not present,
|
|
|
|
first generate them with ${normal}install${red} command.${normal}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
if [ -v $2 ]
|
|
|
|
then
|
|
|
|
echo -e "${red}username not set${normal}
|
|
|
|
For default user, use config_client.json generated
|
|
|
|
by ${underl}install${normal} command. Otherwise use non-void username,
|
|
|
|
preferably of letters and digits only."
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
username=$2
|
|
|
|
fi
|
|
|
|
configs=(config_client_*.json)
|
|
|
|
username_exists=false
|
|
|
|
for c in ${configs[@]}
|
|
|
|
do
|
|
|
|
if [ -f $c ]
|
|
|
|
then
|
|
|
|
email=$(jq '.outbounds[0].settings.vnext[0].users[0].email' $c)
|
|
|
|
name=$(echo $email | cut -d "@" -f 1 | cut -c 2-)
|
|
|
|
if [ $username = $name ]
|
|
|
|
then
|
|
|
|
username_exists=true
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
if $username_exists
|
|
|
|
then
|
|
|
|
echo -e "${red}username ${username} already exists, try another one${normal}"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
id=$(xray uuid) # generate random uuid for vless
|
|
|
|
# generate random short_id for grpc-reality
|
|
|
|
if command -v openssl > /dev/null
|
|
|
|
then
|
|
|
|
short_id=$(openssl rand -hex 8)
|
|
|
|
else
|
|
|
|
echo -e "Enter a random (up to) 16-digit hex number,
|
|
|
|
containing only digits 0-9 and letters a-f, for instance
|
|
|
|
1234567890abcdef"
|
|
|
|
read short_id
|
|
|
|
if [ -v $short_id ]
|
|
|
|
then
|
|
|
|
echo -e "${red}short id not set${normal}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
# make new user config from default user config
|
|
|
|
cat config_client.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\" | .outbounds[0].settings.vnext[0].users[0].email=\"${username}@example.com\" | .outbounds[0].streamSettings.realitySettings.shortId=\"${short_id}\"" > config_client_${username}.json
|
|
|
|
# update server config
|
|
|
|
client="
|
|
|
|
{
|
|
|
|
\"id\": \"${id}\",
|
|
|
|
\"email\": \"${username}@example.com\",
|
|
|
|
\"flow\": \"\"
|
|
|
|
}
|
|
|
|
"
|
|
|
|
cp config_server.json config_server.json.backup
|
2023-10-31 22:32:30 +03:00
|
|
|
cat config_server.json.backup | jq ".inbounds[0].settings.clients += [${client}] | .inbounds[0].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > config_server.json
|
2023-10-31 14:11:40 +03:00
|
|
|
echo -e "${green}config_client_${username}.json is written,
|
|
|
|
config_server.json is updated${normal}"
|
|
|
|
fi
|
2023-10-18 22:09:51 +03:00
|
|
|
|
|
|
|
elif [ $command = "del" ]
|
|
|
|
then
|
2023-10-31 22:32:30 +03:00
|
|
|
echo -e "${bold}del${normal}"
|
|
|
|
if ! $jq_installed
|
|
|
|
then
|
|
|
|
echo -e "${red}jq needed but not installed${normal}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
if [ -v $2 ]
|
|
|
|
then
|
|
|
|
echo -e "${red}username not set${normal}"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
username=$2
|
|
|
|
fi
|
|
|
|
config="config_client_${username}.json"
|
|
|
|
if [ ! -f $config ]
|
|
|
|
then
|
|
|
|
echo -e "${red}no config for user ${username}${normal}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config)
|
|
|
|
cp config_server.json config_server.json.backup
|
|
|
|
cat config_server.json.backup | jq "del(.inbounds[0].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[0].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > config_server.json
|
|
|
|
rm config_client_${username}.json
|
|
|
|
echo -e "${green}config_client_${username}.json is deleted,
|
|
|
|
config_server.json is updated${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
|
2023-10-20 22:39:22 +03:00
|
|
|
elif [ $command = "upgrade" ]
|
|
|
|
then
|
2023-10-27 14:15:09 +03:00
|
|
|
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
|
|
|
|
then
|
|
|
|
echo -e "${green}xray upgraded${normal}"
|
|
|
|
else
|
|
|
|
echo -e "${red}xray not upgraded${normal}"
|
|
|
|
fi
|
2023-10-20 22:39:22 +03:00
|
|
|
|
2023-10-18 22:09:51 +03:00
|
|
|
elif [ $command = "remove" ]
|
|
|
|
then
|
|
|
|
echo -e "Remove xray? (y/N)"
|
2023-10-27 14:15:09 +03:00
|
|
|
read answer_rx
|
|
|
|
if [ ! -v $answer_rx ] && ([ $(echo $answer_rx | cut -c 1) = "y" ] || [ $(echo $answer_rx | cut -c 1) = "Y" ])
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
|
|
|
echo -e "${red}Please type YES to remove${normal}"
|
2023-10-27 14:15:09 +03:00
|
|
|
read answer_y
|
|
|
|
if [ ! -v $answer_y ] && ([ $answer_y = "YES" ] || [ $answer_y = "yes" ])
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
2023-10-26 13:51:34 +03:00
|
|
|
if $is_root
|
2023-10-18 22:09:51 +03:00
|
|
|
then
|
|
|
|
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
|
|
|
|
then
|
2023-10-27 14:15:09 +03:00
|
|
|
echo -e "${green}xray removed${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
else
|
2023-10-27 14:15:09 +03:00
|
|
|
echo -e "${red}xray not removed${normal}"
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
2023-10-26 13:51:34 +03:00
|
|
|
else
|
|
|
|
echo -e "${red}You should be root, or run this script with sudo
|
|
|
|
to remove xray${normal}"
|
|
|
|
exit 1
|
2023-10-18 22:09:51 +03:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
else # "help", default
|
|
|
|
echo -e "
|
|
|
|
${green}**** Hi, there! How to use: ****${normal}
|
|
|
|
|
|
|
|
${bold}./ex.sh ${underl}command${normal}
|
|
|
|
|
|
|
|
Here is the list of all available commands:
|
|
|
|
|
|
|
|
${bold}help${normal} show this message (default)
|
|
|
|
${bold}install${normal} run interactive prompt, which asks to download and install
|
2023-10-27 14:15:09 +03:00
|
|
|
XRay and generate configs for server and client
|
2023-10-18 22:09:51 +03:00
|
|
|
${bold}add ${underl}username${normal} add user with (any, fake) username to configs
|
|
|
|
${bold}del ${underl}username${normal} delete user with given username from configs
|
2023-10-27 14:15:09 +03:00
|
|
|
${bold}upgrade${normal} upgrade xray, do not touch configs
|
2023-10-18 22:09:51 +03:00
|
|
|
${bold}remove${normal} remove xray"
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo -e "
|
|
|
|
Command is done.
|
|
|
|
|
2023-10-30 14:47:03 +03:00
|
|
|
${bold}Important:${normal} It is assumed that configs are stored and updated
|
2023-10-27 14:15:09 +03:00
|
|
|
locally as config_server.json, config_client.json or
|
|
|
|
config_client_username.json files. You should manually
|
|
|
|
start XRay with one of configs, depending
|
2023-10-18 22:09:51 +03:00
|
|
|
which role - server or client - XRay should play:
|
|
|
|
sudo cp config_(role).json /usr/local/etc/xray/config.json
|
|
|
|
sudo systemctl start xray
|
|
|
|
or
|
2023-10-27 14:15:09 +03:00
|
|
|
sudo xray run -c config_(role).json
|
|
|
|
"
|
2023-10-18 22:09:51 +03:00
|
|
|
|