mirror of
https://github.com/EvgenyNerush/easy-xray.git
synced 2025-12-14 13:55:07 +03:00
bring better UX; refactor
This commit is contained in:
16
README.md
16
README.md
@@ -42,6 +42,22 @@ Note also that for current client config, traffic to .cn, .ru, .by and .ir sites
|
|||||||
[here](https://github.com/EvgenyNerush/coherence-grabber) for details. This makes your server much less attention-grabbing and suspicious,
|
[here](https://github.com/EvgenyNerush/coherence-grabber) for details. This makes your server much less attention-grabbing and suspicious,
|
||||||
but your connection less anonymous.
|
but your connection less anonymous.
|
||||||
|
|
||||||
|
### More deep description??
|
||||||
|
|
||||||
|
Important: It is assumed that configs are stored and updated
|
||||||
|
locally as `config_server.json`, `config_client.json` or
|
||||||
|
`config_client_username.json` files. You should manually
|
||||||
|
start XRay with one of configs, depending
|
||||||
|
which role - server or client - XRay should play:
|
||||||
|
```
|
||||||
|
sudo cp config_(role).json /usr/local/etc/xray/config.json
|
||||||
|
sudo systemctl start xray
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
sudo xray run -c config_(role).json
|
||||||
|
```
|
||||||
|
|
||||||
### Other clients
|
### Other clients
|
||||||
|
|
||||||
For Windows, MacOS or Android you can try Nekobox, v2rayNG or ? (TODO): tests and config generation for them.
|
For Windows, MacOS or Android you can try Nekobox, v2rayNG or ? (TODO): tests and config generation for them.
|
||||||
|
|||||||
515
ex.sh
515
ex.sh
@@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# stdout styles
|
||||||
bold='\033[0;1m'
|
bold='\033[0;1m'
|
||||||
underl='\033[0;4m'
|
underl='\033[0;4m'
|
||||||
red='\033[0;31m'
|
red='\033[0;31m'
|
||||||
@@ -7,6 +8,10 @@ green='\033[0;32m'
|
|||||||
yellow='\033[0;33m'
|
yellow='\033[0;33m'
|
||||||
normal='\033[0m'
|
normal='\033[0m'
|
||||||
|
|
||||||
|
#################
|
||||||
|
### Functions ###
|
||||||
|
#################
|
||||||
|
|
||||||
# delete lines with comments from jsonC
|
# delete lines with comments from jsonC
|
||||||
jsonc2json () {
|
jsonc2json () {
|
||||||
if [ ! -v $1 ]
|
if [ ! -v $1 ]
|
||||||
@@ -62,7 +67,7 @@ strip_quotes () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# convert json string with statistics to pretty form;
|
# convert json string with statistics to pretty form;
|
||||||
# (!) use with pipe | to deal with multiline strings correctly
|
# use with pipe | to deal with multiline strings correctly!
|
||||||
pretty_stats () {
|
pretty_stats () {
|
||||||
read stats
|
read stats
|
||||||
if [ -v "$stats" ]
|
if [ -v "$stats" ]
|
||||||
@@ -74,112 +79,78 @@ pretty_stats () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
export PATH=$PATH:/usr/local/bin/ # for sudo user this can be not in PATH
|
# check if the mandatory command exists
|
||||||
if command -v xray > /dev/null
|
check_command () {
|
||||||
|
cmd=$1
|
||||||
|
cmd_aim=$2
|
||||||
|
comment=$3
|
||||||
|
if command -v $cmd > /dev/null
|
||||||
then
|
then
|
||||||
xray_version=$(xray --version | head -n 1 | cut -c 6-10)
|
echo -e "${green}${cmd} found${normal}"
|
||||||
echo -e "${green}xray ${xray_version} detected${normal}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command -v jq > /dev/null
|
|
||||||
then
|
|
||||||
jq_installed=true
|
|
||||||
echo -e "${green}jq found${normal}"
|
|
||||||
else
|
else
|
||||||
jq_installed=false
|
echo -e "${red}${cmd} not found; ${cmd_aim}${normal}"
|
||||||
echo -e "${yellow}Warning: jq not installed but needed for operations with configs${normal}"
|
echo -e "${comment}"
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $(id -u) -eq 0 ]
|
|
||||||
then
|
|
||||||
is_root=true
|
|
||||||
echo -e "${green}running as root${normal}"
|
|
||||||
else
|
|
||||||
is_root=false
|
|
||||||
echo -e "${yellow}Warning: you should be root to install xray${normal}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
command="help"
|
|
||||||
if [ ! -v $1 ]
|
|
||||||
then
|
|
||||||
command=$1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $command = "install" ]
|
|
||||||
then
|
|
||||||
|
|
||||||
echo -e "${bold}Download and install xray?${normal} (Y/n)"
|
|
||||||
read answer_di
|
|
||||||
if [ -v $answer_di ] || [ $(echo $answer_di | cut -c 1) != "n" ]
|
|
||||||
then
|
|
||||||
install_xray=true
|
|
||||||
if command -v xray > /dev/null
|
|
||||||
then
|
|
||||||
echo -e "xray ${version} detected, install anyway? (y/N)"
|
|
||||||
read answer_ia
|
|
||||||
if [ -v $answer_ia ] || ([ $(echo $answer_ia | cut -c 1) != "y" ] && [ $(echo $answer_ia | cut -c 1) != "Y" ])
|
|
||||||
then
|
|
||||||
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
|
|
||||||
then
|
|
||||||
dat_dir="/usr/local/share/xray/"
|
|
||||||
mkdir -p $dat_dir
|
|
||||||
cp customgeo.dat ${dat_dir}
|
|
||||||
echo -e "${green}xray installed${normal}"
|
|
||||||
else
|
|
||||||
echo -e "${red}xray not installed, something goes wrong${normal}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${red}You should be root, or run this script with sudo
|
|
||||||
to install xray${normal}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
}
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${bold}Generate configs?${normal} (Y/n)"
|
# make directory `dir`; if it already exists, first move it to dir.backup;
|
||||||
read answer_gc
|
# if dir.backup already exists, first move it to dir.backup.backup; if it exists,
|
||||||
if [ -v $answer_gc ] || [ $(echo $answer_gc | cut -c 1) != "n" ]
|
# first delete it
|
||||||
|
unsafe_mkdir () {
|
||||||
|
dir=$1
|
||||||
|
if [ -d "$dir" ]
|
||||||
then
|
then
|
||||||
if ! $(command -v xray > /dev/null)
|
if [ -d "${dir}.backup" ]
|
||||||
then
|
then
|
||||||
echo -e "${red}xray not installed, can't generate configs"
|
if [ -d "${dir}.backup.backup" ]
|
||||||
exit 1
|
then
|
||||||
|
rm -r "${dir}.backup.backup"
|
||||||
fi
|
fi
|
||||||
if ! $jq_installed
|
mv "${dir}.backup" "${dir}.backup.backup"
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}.backup.backup"
|
||||||
|
fi
|
||||||
|
mv "$dir" "${dir}.backup"
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}.backup"
|
||||||
|
fi
|
||||||
|
mkdir "$dir"
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${dir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# copy file to file.backup with the same logic as in `unsafe_mkdir`
|
||||||
|
cp_to_backup () {
|
||||||
|
file=$1
|
||||||
|
if [ -f "${file}.backup" ]
|
||||||
then
|
then
|
||||||
echo -e "${red}jq not installed, can't generate configs"
|
cp "${file}.backup" "${file}.backup.backup"
|
||||||
exit 1
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${file}.backup.backup"
|
||||||
else
|
fi
|
||||||
echo -e "${bold}Enter IPv4 or IPv6 address of your xray server, or its domain name:${normal}"
|
cp "$file" "${file}.backup"
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" "${file}.backup"
|
||||||
|
}
|
||||||
|
|
||||||
|
# the main part of `./ex.sh conf` command, generates config files for server and clients
|
||||||
|
conf () {
|
||||||
|
export PATH=$PATH:/usr/local/bin/ # brings xray to the path for sudo user
|
||||||
|
check_command xray "needed for config generation" "to install xray, try: sudo ./ex.sh install"
|
||||||
|
check_command jq "needed for operations with configs"
|
||||||
|
check_command openssl "needed for strong random numbers excluding some types of attacks"
|
||||||
|
#
|
||||||
|
echo -e "Enter IPv4 or IPv6 address of your xray server, or its domain name:"
|
||||||
read address
|
read address
|
||||||
id=$(xray uuid) # generate random uuid for vless
|
if [ -v $address ]
|
||||||
keys=$(xray x25519)
|
|
||||||
private_key=$(echo $keys | cut -d " " -f 3)
|
|
||||||
public_key=$(echo $keys | cut -d " " -f 6)
|
|
||||||
# generate random short_id for grpc-reality
|
|
||||||
if command -v openssl > /dev/null
|
|
||||||
then
|
then
|
||||||
short_id=$(openssl rand -hex 8)
|
echo -e "${red}no address given${normal}"
|
||||||
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
id=$(xray uuid) # random uuid for VLESS
|
||||||
echo -e "${bold}Choose a fake site to mimic.${normal}
|
keys=$(xray x25519) # string "Private key: Abc... Public key: Xyz..."
|
||||||
Better if it is popular and not blocked in your country:
|
private_key=$(echo $keys | cut -d " " -f 3) # get 3rd field of fields delimited by spaces
|
||||||
|
public_key=$(echo $keys | cut -d " " -f 6) # get 6th field
|
||||||
|
short_id=$(openssl rand -hex 8) # random short_id for REALITY
|
||||||
|
#
|
||||||
|
echo -e "Choose a fake site to mimic.
|
||||||
|
Better if it is quite popular and not blocked in your country:
|
||||||
(1) www.youtube.com (default)
|
(1) www.youtube.com (default)
|
||||||
(2) www.microsoft.com
|
(2) www.microsoft.com
|
||||||
(3) www.google.com
|
(3) www.google.com
|
||||||
@@ -191,8 +162,10 @@ Better if it is popular and not blocked in your country:
|
|||||||
(9) your variant"
|
(9) your variant"
|
||||||
read number
|
read number
|
||||||
default_fake_site="www.youtube.com"
|
default_fake_site="www.youtube.com"
|
||||||
if [ ! -v $number ]
|
if [ -v $number ]
|
||||||
then
|
then
|
||||||
|
fake_site=$default_fake_site
|
||||||
|
else
|
||||||
if [ $number -eq 2 ]
|
if [ $number -eq 2 ]
|
||||||
then
|
then
|
||||||
fake_site="www.microsoft.com"
|
fake_site="www.microsoft.com"
|
||||||
@@ -225,13 +198,13 @@ Better if it is popular and not blocked in your country:
|
|||||||
else
|
else
|
||||||
fake_site=$default_fake_site
|
fake_site=$default_fake_site
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
fake_site=$default_fake_site
|
|
||||||
fi
|
fi
|
||||||
server_names="[ \"$fake_site\" ]"
|
|
||||||
echo -e "${green}mimic ${fake_site}${normal}"
|
echo -e "${green}mimic ${fake_site}${normal}"
|
||||||
|
server_names="[ \"$fake_site\" ]"
|
||||||
email="love@xray.com"
|
email="love@xray.com"
|
||||||
# make server config
|
#
|
||||||
|
unsafe_mkdir conf
|
||||||
|
## Make server config ##
|
||||||
jsonc2json template_config_server.jsonc \
|
jsonc2json template_config_server.jsonc \
|
||||||
| jq ".inbounds[1].settings.clients[0].id=\"${id}\"
|
| jq ".inbounds[1].settings.clients[0].id=\"${id}\"
|
||||||
| .inbounds[2].settings.clients[0].id=\"${id}\"
|
| .inbounds[2].settings.clients[0].id=\"${id}\"
|
||||||
@@ -245,9 +218,9 @@ Better if it is popular and not blocked in your country:
|
|||||||
| .inbounds[2].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
| .inbounds[2].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
||||||
| .inbounds[1].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]
|
| .inbounds[1].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]
|
||||||
| .inbounds[2].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \
|
| .inbounds[2].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \
|
||||||
> config_server.json
|
> ./conf/config_server.json
|
||||||
# then make the user (not root) the owner of the file
|
# make the user (not root) the owner of the file
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
vnext=" [
|
vnext=" [
|
||||||
{
|
{
|
||||||
\"address\": \"${address}\",
|
\"address\": \"${address}\",
|
||||||
@@ -269,81 +242,71 @@ Better if it is popular and not blocked in your country:
|
|||||||
\"publicKey\": \"${public_key}\",
|
\"publicKey\": \"${public_key}\",
|
||||||
\"shortId\": \"${short_id}\",
|
\"shortId\": \"${short_id}\",
|
||||||
}"
|
}"
|
||||||
# make main client config
|
## Make main client config ##
|
||||||
jsonc2json template_config_client.jsonc | 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
|
jsonc2json template_config_client.jsonc \
|
||||||
# then make the user (not root) an owner of a file
|
| jq ".outbounds
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_client.json
|
|= map(if .settings.vnext then .settings.vnext=${vnext} else . end)
|
||||||
fi
|
| .outbounds
|
||||||
|
|= map(if .streamSettings.realitySettings then .streamSettings.realitySettings=${clientRealitySettings} else . end)" \
|
||||||
|
> ./conf/config_client.json
|
||||||
|
# make the user (not root) an owner of a file
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client.json
|
||||||
|
if [ -f "./conf/config_client.json" ] && [ -f "./conf/config_server.json" ]
|
||||||
|
then
|
||||||
|
echo -e "${green}config files are generated${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${red}config files are not generated${normal}"
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
elif [ $command = "add" ]
|
# the main part of `./ex.sh add` command, adds config for given users and updates server config
|
||||||
|
add () {
|
||||||
|
export PATH=$PATH:/usr/local/bin/ # brings xray to the path for sudo user
|
||||||
|
check_command xray "needed for config generation" "to install xray, try: sudo ./ex.sh install"
|
||||||
|
check_command jq "needed for operations with configs"
|
||||||
|
check_command openssl "needed for strong random numbers excluding some types of attacks"
|
||||||
|
if [ ! -f "./conf/config_client.json" ] || [ ! -f "./conf/config_server.json" ]
|
||||||
then
|
then
|
||||||
echo -e "${bold}add${normal}"
|
echo -e "${red}server config and config for default user are needed
|
||||||
if ! $(command -v xray > /dev/null)
|
but not present; to generate them, try
|
||||||
then
|
./ex.sh conf${normal}"
|
||||||
echo -e "${red}xray needed but not installed${normal}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! $jq_installed
|
if [ -v $1 ]
|
||||||
then
|
then
|
||||||
echo -e "${red}jq needed but not installed${normal}"
|
echo -e "${red}usernames not set${normal}
|
||||||
exit 1
|
|
||||||
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
|
For default user, use config_client.json generated
|
||||||
by ${underl}install${normal} command. Otherwise use non-void username,
|
by ${underl}install${normal} command. Otherwise use non-void usernames,
|
||||||
preferably of letters and digits only."
|
preferably of letters and digits only."
|
||||||
exit 1
|
exit 1
|
||||||
else
|
|
||||||
username=$2
|
|
||||||
fi
|
fi
|
||||||
configs=(config_client_*.json)
|
# backup server config
|
||||||
username_exists=false
|
cp_to_backup ./conf/config_server.json
|
||||||
for c in ${configs[@]}
|
# loop over usernames
|
||||||
|
for username in "$@"
|
||||||
do
|
do
|
||||||
if [ -f $c ]
|
username_exists=false
|
||||||
then
|
client_emails=$(jq ".inbounds[1].settings.clients[].email" ./conf/config_server.json)
|
||||||
email=$(jq '.outbounds[0].settings.vnext[0].users[0].email' $c)
|
for email in ${client_emails[@]}
|
||||||
|
do
|
||||||
|
# convert "name@example.com" to name
|
||||||
name=$(echo $email | cut -d "@" -f 1 | cut -c 2-)
|
name=$(echo $email | cut -d "@" -f 1 | cut -c 2-)
|
||||||
if [ $username = $name ]
|
if [ $username = $name ]
|
||||||
then
|
then
|
||||||
username_exists=true
|
username_exists=true
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
if $username_exists
|
if $username_exists
|
||||||
then
|
then
|
||||||
echo -e "${red}username ${username} already exists, try another one${normal}"
|
echo -e "${yellow}username ${username} already exists, no new config created fot it${normal}"
|
||||||
exit 1
|
|
||||||
else
|
else
|
||||||
id=$(xray uuid) # generate random uuid for vless
|
id=$(xray uuid) # generate random uuid for vless
|
||||||
# generate random short_id for grpc-reality
|
# generate random short_id for grpc-reality
|
||||||
if command -v openssl > /dev/null
|
|
||||||
then
|
|
||||||
short_id=$(openssl rand -hex 8)
|
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
|
# 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
|
ok1=$(cat ./conf/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}\"" > ./conf/config_client_${username}.json)
|
||||||
# then make the user (not root) an owner of a file
|
# then make the user (not root) an owner of a file
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_client.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client.json
|
||||||
# update server config
|
# update server config
|
||||||
client="
|
client="
|
||||||
{
|
{
|
||||||
@@ -352,45 +315,203 @@ containing only digits 0-9 and letters a-f, for instance
|
|||||||
\"flow\": \"xtls-rprx-vision\"
|
\"flow\": \"xtls-rprx-vision\"
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
cp config_server.json config_server.json.backup
|
# update server config from backup
|
||||||
# update server config
|
cp ./conf/config_server.json ./conf/tmpconfig.json
|
||||||
cat config_server.json.backup | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > config_server.json
|
ok2=$(cat ./conf/tmpconfig.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > ./conf/config_server.json)
|
||||||
|
rm ./conf/tmpconfig.json
|
||||||
# then make the user (not root) an owner of a file
|
# then make the user (not root) an owner of a file
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
echo -e "${green}config_client_${username}.json is written,
|
if $ok1 && $ok2
|
||||||
config_server.json is updated${normal}"
|
then
|
||||||
|
echo -e "${green}config_client_${username}.json is written, config_server.json is updated${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${red}something went wrong with username ${username}${normal}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# `./ex.sh push` command, copies config to xray's dir and restarts xray
|
||||||
|
push () {
|
||||||
|
if [ $(id -u) -ne 0 ] # not root
|
||||||
|
then
|
||||||
|
echo -e "${red}you should have root privileges for that, try
|
||||||
|
sudo ./ex.sh push${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo -e "Which config to use, server/client/other? (S/c/o)"
|
||||||
|
read answer
|
||||||
|
if [ ! -v $answer ] && [ ${answer::1} = "c" ]
|
||||||
|
then
|
||||||
|
# use main client config
|
||||||
|
config="config_client.json"
|
||||||
|
elif [ ! -v $answer ] && [ ${answer::1} = "o" ]
|
||||||
|
then
|
||||||
|
# use config of some other user
|
||||||
|
echo -e "Which config from ./conf/ to use? (write the filename)"
|
||||||
|
read answer
|
||||||
|
config="$answer"
|
||||||
|
else
|
||||||
|
# use server config
|
||||||
|
config="config_server.json"
|
||||||
|
fi
|
||||||
|
if $(cp ./conf/${config} /usr/local/etc/xray/config.json && systemctl restart xray)
|
||||||
|
then
|
||||||
|
sleep 1s # gives time to xray restart
|
||||||
|
journalctl -u xray | tail -n 5 # message about xray start
|
||||||
|
else
|
||||||
|
echo -e "${red}can't copy config or start xray, try
|
||||||
|
sudo xray run -c ./conf/${config}${normal}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#############
|
||||||
|
### MAIN ####
|
||||||
|
#############
|
||||||
|
|
||||||
|
command="help" # default
|
||||||
|
if [ ! -v $1 ]
|
||||||
|
then
|
||||||
|
command=$1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $command = "install" ]
|
||||||
|
then
|
||||||
|
if [ $(id -u) -ne 0 ] # not root
|
||||||
|
then
|
||||||
|
echo -e "${red}you should have root privileges to install xray, try
|
||||||
|
sudo ./ex.sh install${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
if command -v xray > /dev/null # xray already installed
|
||||||
|
then
|
||||||
|
echo -e "${yellow}xray ${version} detected, install anyway?${normal} (y/N)"
|
||||||
|
read answer
|
||||||
|
# default answer, answer not set or it's first letter is not `y` or `Y`
|
||||||
|
if [ -v $answer ] || ([ ${answer::1} != "y" ] && [ ${answer::1} != "Y" ])
|
||||||
|
then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
|
||||||
|
then
|
||||||
|
echo -e "${green}xray installed${normal}"
|
||||||
|
dat_dir="/usr/local/share/xray/"
|
||||||
|
mkdir -p $dat_dir
|
||||||
|
if cp customgeo.dat ${dat_dir}
|
||||||
|
then
|
||||||
|
echo -e "${green}customgeo.dat copied to ${dat_dir}${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${red}customgeo.dat not copied to ${dat_dir}${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${red}xray not installed, something goes wrong${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
echo -e "Generate configs? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ ! -v $answer ] && [ ${answer::1} = "n" ]
|
||||||
|
then
|
||||||
|
# config generation is not requested
|
||||||
|
echo -e "If you have a config file for xray, you can manually
|
||||||
|
start xray with the following commands:
|
||||||
|
sudo cp yourconfig.json /usr/local/etc/xray/config.json
|
||||||
|
sudo systemctl start xray
|
||||||
|
or
|
||||||
|
sudo xray run -c yourconfig.json"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
# config generation is requested
|
||||||
|
conf
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
echo -e "Add other users? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ -v $answer ] || [ ${answer::1} != "n" ]
|
||||||
|
then
|
||||||
|
echo -e "Enter usernames separated by spaces"
|
||||||
|
read usernames
|
||||||
|
add $usernames
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
echo -e "Copy config to xray's dir and restart xray? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ -v $answer ] || [ ${answer::1} != "n" ]
|
||||||
|
then
|
||||||
|
push
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ $command = "conf" ]
|
||||||
|
then
|
||||||
|
conf
|
||||||
|
#
|
||||||
|
echo -e "Add other users? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ -v $answer ] || [ ${answer::1} != "n" ]
|
||||||
|
then
|
||||||
|
echo -e "Enter usernames separated by spaces"
|
||||||
|
read usernames
|
||||||
|
add $usernames
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
echo -e "Copy config to xray's dir and restart xray? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ -v $answer ] || [ ${answer::1} != "n" ]
|
||||||
|
then
|
||||||
|
push
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ $command = "add" ]
|
||||||
|
then
|
||||||
|
add "${@:2}"
|
||||||
|
#
|
||||||
|
echo -e "Copy config to xray's dir and restart xray? (Y/n)"
|
||||||
|
read answer
|
||||||
|
if [ -v $answer ] || [ ${answer::1} != "n" ]
|
||||||
|
then
|
||||||
|
push
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [ $command = "del" ]
|
elif [ $command = "del" ]
|
||||||
then
|
then
|
||||||
echo -e "${bold}del${normal}"
|
check_command jq "needed for operations with configs"
|
||||||
if ! $jq_installed
|
if [ ! -f "./conf/config_server.json" ]
|
||||||
then
|
then
|
||||||
echo -e "${red}jq needed but not installed${normal}"
|
echo -e "${red}server config not found"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ -v $2 ]
|
# backup server config
|
||||||
then
|
cp_to_backup ./conf/config_server.json
|
||||||
echo -e "${red}username not set${normal}"
|
# loop over usernames
|
||||||
exit 1
|
for username in "${@:2}"
|
||||||
else
|
do
|
||||||
username=$2
|
config="./conf/config_client_${username}.json"
|
||||||
fi
|
|
||||||
config="config_client_${username}.json"
|
|
||||||
if [ ! -f $config ]
|
if [ ! -f $config ]
|
||||||
then
|
then
|
||||||
echo -e "${red}no config for user ${username}${normal}"
|
echo -e "${yellow}no config for user ${username}${normal}"
|
||||||
exit 1
|
else
|
||||||
fi
|
|
||||||
short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config)
|
short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config)
|
||||||
cp config_server.json config_server.json.backup
|
cp ./conf/config_server.json ./conf/tmpconfig.json
|
||||||
# update server config
|
# update server config
|
||||||
cat config_server.json.backup | jq "del(.inbounds[1].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[1].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > config_server.json
|
cat ./conf/tmpconfig.json | jq "del(.inbounds[1].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[1].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > ./conf/config_server.json
|
||||||
|
rm ./conf/tmpconfig.json
|
||||||
# then make the user (not root) an owner of a file
|
# then make the user (not root) an owner of a file
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
rm config_client_${username}.json
|
rm config_client_${username}.json
|
||||||
echo -e "${green}config_client_${username}.json is deleted,
|
echo -e "${green}config_client_${username}.json is deleted,
|
||||||
config_server.json is updated${normal}"
|
config_server.json is updated${normal}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
add
|
||||||
|
push
|
||||||
|
|
||||||
|
elif [ $command = "push" ]
|
||||||
|
then
|
||||||
|
push
|
||||||
|
|
||||||
elif [ $command = "stats" ]
|
elif [ $command = "stats" ]
|
||||||
then
|
then
|
||||||
@@ -454,27 +575,21 @@ then
|
|||||||
elif [ $command = "remove" ]
|
elif [ $command = "remove" ]
|
||||||
then
|
then
|
||||||
echo -e "Remove xray? (y/N)"
|
echo -e "Remove xray? (y/N)"
|
||||||
read answer_rx
|
read answer
|
||||||
if [ ! -v $answer_rx ] && ([ $(echo $answer_rx | cut -c 1) = "y" ] || [ $(echo $answer_rx | cut -c 1) = "Y" ])
|
if [ ! -v $answer ] && [ ${answer::1} = "y" ]
|
||||||
then
|
then
|
||||||
echo -e "${red}Please type YES to remove${normal}"
|
if [ $(id -u) -ne 0 ] # not root
|
||||||
read answer_y
|
|
||||||
if [ ! -v $answer_y ] && ([ $answer_y = "YES" ] || [ $answer_y = "yes" ])
|
|
||||||
then
|
|
||||||
if $is_root
|
|
||||||
then
|
then
|
||||||
|
echo -e "${red}you should have root privileges for that, try
|
||||||
|
sudo ./ex.sh push${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
|
if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge
|
||||||
then
|
then
|
||||||
echo -e "${green}xray removed${normal}"
|
echo -e "${green}xray removed${normal}"
|
||||||
else
|
else
|
||||||
echo -e "${red}xray not removed${normal}"
|
echo -e "${red}xray not removed${normal}"
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo -e "${red}You should be root, or run this script with sudo
|
|
||||||
to remove xray${normal}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else # "help", default
|
else # "help", default
|
||||||
@@ -483,30 +598,18 @@ ${green}**** Hi, there! How to use: ****${normal}
|
|||||||
|
|
||||||
${bold}./ex.sh ${underl}command${normal}
|
${bold}./ex.sh ${underl}command${normal}
|
||||||
|
|
||||||
Here is the list of all available commands:
|
Here is a list of all the commands available:
|
||||||
|
|
||||||
${bold}help${normal} show this message (default)
|
${bold}help${normal} show this message (default)
|
||||||
${bold}install${normal} run interactive prompt, which asks to download and install
|
${bold}install${normal} run interactive prompt, which asks to download and install
|
||||||
XRay and generate configs for server and client
|
XRay and generate configs
|
||||||
${bold}add ${underl}username${normal} add user with (any, fake) username to configs
|
${bold}conf${normal} generate config files for server and clients
|
||||||
${bold}del ${underl}username${normal} delete user with given username from configs
|
${bold}add ${underl}usernames${normal} add users with (any, fake) usernames to configs
|
||||||
|
${bold}del ${underl}usernames${normal} delete users with given usernames from configs
|
||||||
|
${bold}push${normal} copy config to xray's dir and restarts xray
|
||||||
${bold}stats${normal} print some traffic statistics
|
${bold}stats${normal} print some traffic statistics
|
||||||
${bold}stats reset${normal} print statistics then set them to zero
|
${bold}stats reset${normal} print statistics then set them to zero
|
||||||
${bold}upgrade${normal} upgrade xray, do not touch configs
|
${bold}upgrade${normal} upgrade xray, do not touch configs
|
||||||
${bold}remove${normal} remove xray"
|
${bold}remove${normal} remove xray"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "
|
|
||||||
Command is done.
|
|
||||||
|
|
||||||
${bold}Important:${normal} It is assumed that configs are stored and updated
|
|
||||||
locally as config_server.json, config_client.json or
|
|
||||||
config_client_username.json files. You should manually
|
|
||||||
start XRay with one of configs, depending
|
|
||||||
which role - server or client - XRay should play:
|
|
||||||
sudo cp config_(role).json /usr/local/etc/xray/config.json
|
|
||||||
sudo systemctl start xray
|
|
||||||
or
|
|
||||||
sudo xray run -c config_(role).json
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user