mirror of
https://github.com/EvgenyNerush/easy-xray.git
synced 2024-11-24 09:35:32 +03:00
add CDN support at the second ip address
This commit is contained in:
parent
78762bbb58
commit
520bca6992
9 changed files with 530 additions and 19 deletions
1
CDN.md
Normal file
1
CDN.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
TODO
|
32
CDN.ru.md
Normal file
32
CDN.ru.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#### Дополнительный канал связи
|
||||||
|
|
||||||
|
Если вы делитесь доступом к своему серверу с другими людьми, рано или поздно IP-адрес вашего сервера может утечь к РКН, который добавит его
|
||||||
|
в список блокируемых сайтов, доступ к серверу при этом пропадёт. Если же сервер работает через сеть доставки контента (content delivery
|
||||||
|
network, CDN), то для доступа используется не IP-адрес, а доменное имя. Для того, чтобы заблокировать сервер в этом случае нужно будет
|
||||||
|
заблокировать один из серверов доменных имён CDN-провайдера (на котором "резолвится" ваше доменное имя). На этом сервере имён может
|
||||||
|
резолвиться большое число других сайтов (в том числе российских), и в случае блокировки они тоже перестанут работать. Так что, возможно, РКН
|
||||||
|
не станет идти на такие риски и не будет блокировать ваш сервер даже в случае обнаружения.
|
||||||
|
|
||||||
|
CDN от Cloudflare позволяет бесплатно транспортировать grpc-трафик, однако вам потребуется купить какое-либо доменное имя. Чтобы понять
|
||||||
|
общую концепцию работы xray через CDN, прочитайте [вот эту статью](https://habr.com/ru/articles/761798/).
|
||||||
|
|
||||||
|
**До запуска установки xray** скопируйте ваши сертификаты Cloudflare `cert.pem` и `cert.key` в директорию со скриптом `ex.sh`!
|
||||||
|
|
||||||
|
Vless не может быть сконфигурирован с fallback при использовании grpc, соответственно, не может противостоять атаке active-probing. Поэтому
|
||||||
|
помимо xray нужно установить веб-сервер **nginx**, который будет обеспечивать перенаправление на сайт-заглушку. Easy-xray сгенерирует
|
||||||
|
"сайт" для nginx, который слушает IPv6 адрес и перенаправляет реальных пользователей на xray-сервер, слушающий на 127.0.0.1:50051. При
|
||||||
|
настройке easy-xray (при выполнении команды `sudo ./ex.sh install` или `./ex.sh conf`) укажите ваше доменное имя, и следуйте дальнейшим
|
||||||
|
инструкциям. После установки нужно проверить конфигурацию nginx и запустить его с помощью команд
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo nginx -t
|
||||||
|
sudo systemctl start nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
Если при попытке зайти на ваш "сайт" из браузера редирект (fallback) на сайт-заглушку не происходит (error 502, bad gateway), возможно,
|
||||||
|
политики SELinux запрещают nginx выполнять сетевые соединения. Чтобы это исправить, выполните команду
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo setsebool -P httpd_can_network_connect 1
|
||||||
|
```
|
||||||
|
|
|
@ -29,7 +29,7 @@ can
|
||||||
First you need a Linux server (VPS) with [jq](https://jqlang.github.io/jq/) and `openssl` installed, they can be found in repositories of
|
First you need a Linux server (VPS) with [jq](https://jqlang.github.io/jq/) and `openssl` installed, they can be found in repositories of
|
||||||
almost all popular Linux distributions. Then download whole `easy-xray` folder to the VPS, make the script `ex.sh` executable, and run a
|
almost all popular Linux distributions. Then download whole `easy-xray` folder to the VPS, make the script `ex.sh` executable, and run a
|
||||||
desired command with it. Use `./ex.sh help` to see the list of all available commands and `./ex.sh install` to start interactive prompt
|
desired command with it. Use `./ex.sh help` to see the list of all available commands and `./ex.sh install` to start interactive prompt
|
||||||
that installs and configures XRay.
|
that installs and configures XRay. Do not use easy-xray for user `root`, use usual user and `sudo` instead.
|
||||||
|
|
||||||
```
|
```
|
||||||
chmod +x ex.sh
|
chmod +x ex.sh
|
||||||
|
@ -40,6 +40,9 @@ sudo ./ex.sh install
|
||||||
Now you have `conf` folder with server and client configs and some user configs. Server config is properly installed and XRay is running.
|
Now you have `conf` folder with server and client configs and some user configs. Server config is properly installed and XRay is running.
|
||||||
Time to share configs or *links* with users! To generate config in the link form, use `./ex.sh link user_config_file.json`.
|
Time to share configs or *links* with users! To generate config in the link form, use `./ex.sh link user_config_file.json`.
|
||||||
|
|
||||||
|
If your VPS have both IPv4 and IPv6 addressess, easy-xray can be configured such that IPv6 address is used for access with grpc-tls
|
||||||
|
protocol via CDN (e.g. Cloudflare). See [CDN instruction](CDN.md) for details.
|
||||||
|
|
||||||
#### Docker
|
#### Docker
|
||||||
|
|
||||||
Script `ex.sh` is written without Docker in mind, but can be used with Docker. Download `easy-xray` folder (main branch) and build the
|
Script `ex.sh` is written without Docker in mind, but can be used with Docker. Download `easy-xray` folder (main branch) and build the
|
||||||
|
|
|
@ -31,7 +31,8 @@ VLESS-Reality) не шифрует уже зашифрованный https-тр
|
||||||
установить [jq](https://jqlang.github.io/jq/) и `openssl` - их можно найти в репозиторияx практически всех популярных Linux дистрибутивов.
|
установить [jq](https://jqlang.github.io/jq/) и `openssl` - их можно найти в репозиторияx практически всех популярных Linux дистрибутивов.
|
||||||
Затем скачайте `easy-xray` (всю директорию целиком), сделайте исполняемым файл `ex.sh` и запустите нужную команду. Используйте `./ex.sh
|
Затем скачайте `easy-xray` (всю директорию целиком), сделайте исполняемым файл `ex.sh` и запустите нужную команду. Используйте `./ex.sh
|
||||||
help` для получения списка всех команд и короткой справки по ним. Для установки и настройки xray используйте `./ex.sh install` - эта команда
|
help` для получения списка всех команд и короткой справки по ним. Для установки и настройки xray используйте `./ex.sh install` - эта команда
|
||||||
предложит вам ввести ip-адрес вашего сервера, адрес сайта, под который ваш сервер будет маскироваться, и имена пользователей.
|
предложит вам ввести ip-адрес вашего сервера, адрес сайта, под который ваш сервер будет маскироваться, и имена пользователей. Не
|
||||||
|
используйте easy-xray для пользователя root, используйте обычного пользователя и sudo!
|
||||||
|
|
||||||
```
|
```
|
||||||
chmod +x ex.sh
|
chmod +x ex.sh
|
||||||
|
@ -43,6 +44,10 @@ sudo ./ex.sh install
|
||||||
будет должным образом установлен, а xray - запущен с ним. Настало время раздать конфиги пользователям! Для многих графических клиентов
|
будет должным образом установлен, а xray - запущен с ним. Настало время раздать конфиги пользователям! Для многих графических клиентов
|
||||||
удобно использовать конфиги в виде ссылок, которые можно сгенерировать командой `./ex.sh link user_config_file.json`.
|
удобно использовать конфиги в виде ссылок, которые можно сгенерировать командой `./ex.sh link user_config_file.json`.
|
||||||
|
|
||||||
|
Если у вашего VPS сервера есть два IP-адреса (IPv4 и IPv6), easy-xray может быть сконфигурирован так, чтобы IPv6-адрес
|
||||||
|
использовался для доступа через сеть CDN от Cloudflare по протоколу grpc-tls. См. детали в [инструкции](CDN.ru.md).
|
||||||
|
|
||||||
|
|
||||||
#### Docker
|
#### Docker
|
||||||
|
|
||||||
Скрипт `ex.sh` написан прежде всего для использования в системе с systemd, однако может быть использован и в Docker. Для этого скачайте
|
Скрипт `ex.sh` написан прежде всего для использования в системе с systemd, однако может быть использован и в Docker. Для этого скачайте
|
||||||
|
|
131
ex.sh
131
ex.sh
|
@ -137,7 +137,17 @@ conf () {
|
||||||
check_command jq "needed for operations with configs"
|
check_command jq "needed for operations with configs"
|
||||||
check_command openssl "needed for strong random numbers excluding some types of attacks"
|
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:"
|
echo -e "Enter domain name to use with IPv6 and CDN (e.g. Cloudflare),
|
||||||
|
or leave blank for simple default configuration:"
|
||||||
|
read server_name4cdn
|
||||||
|
#
|
||||||
|
if [ -v $server_name4cdn ]
|
||||||
|
then
|
||||||
|
echo -e "Enter IPv4 or IPv6 address of your xray server, or its domain name:"
|
||||||
|
else
|
||||||
|
check_command sed "needed to make nginx's site to use cdn"
|
||||||
|
echo -e "Enter IPv4 address of your xray server:"
|
||||||
|
fi
|
||||||
read address
|
read address
|
||||||
if [ -v $address ]
|
if [ -v $address ]
|
||||||
then
|
then
|
||||||
|
@ -145,11 +155,11 @@ conf () {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
id=$(xray uuid) # random uuid for VLESS
|
id=$(xray uuid) # random uuid for VLESS
|
||||||
echo -e "Generate private and public keys? (Y/n)"
|
echo -e "Generate xray private and public keys? (Y/n)"
|
||||||
read answer
|
read answer
|
||||||
if [ ! -v $answer ] && [ $answer = 'n' ]
|
if [ ! -v $answer ] && [ $answer = 'n' ]
|
||||||
then
|
then
|
||||||
echo -e "Enter private and public keys delimited by a space:"
|
echo -e "Enter xray private and public keys delimited by a space:"
|
||||||
read answer
|
read answer
|
||||||
private_key=$(echo $answer | cut -d " " -f 1) # get the first field of fields delimited by spaces
|
private_key=$(echo $answer | cut -d " " -f 1) # get the first field of fields delimited by spaces
|
||||||
public_key=$(echo $answer | cut -d " " -f 2)
|
public_key=$(echo $answer | cut -d " " -f 2)
|
||||||
|
@ -217,10 +227,33 @@ Better if it is quite popular and not blocked in your country:
|
||||||
email="love@xray.com"
|
email="love@xray.com"
|
||||||
#
|
#
|
||||||
unsafe_mkdir conf
|
unsafe_mkdir conf
|
||||||
|
#
|
||||||
|
if [ -v $server_name4cdn ]
|
||||||
|
then
|
||||||
|
listen="0.0.0.0"
|
||||||
|
else
|
||||||
|
listen=$address # otherwise xray will listen also at ip6
|
||||||
|
# grpc service name (location); letters and digits only
|
||||||
|
echo -e "Enter grpc service name or hit Enter to autogenerate:"
|
||||||
|
read service_name
|
||||||
|
if [ -v ${service_name} ]
|
||||||
|
then
|
||||||
|
service_name=$(openssl rand -base64 9 | sed 's![^[:alnum:]]!!g')
|
||||||
|
fi
|
||||||
|
# config for nginx; `!` in sed allows not to escape special characters such as dot and plus sign
|
||||||
|
cat ./template_site4cdn.conf \
|
||||||
|
| sed "s!server_domain_name!${server_name4cdn}!" \
|
||||||
|
| sed "s!www.youtube.com!${fake_site}!" \
|
||||||
|
| sed "s!your_service_name!${service_name}!" \
|
||||||
|
> ./conf/site4cdn.conf
|
||||||
|
cp ./conf/site4cdn.conf /etc/nginx/sites-enabled/
|
||||||
|
fi
|
||||||
|
#
|
||||||
## Make server config ##
|
## 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}\"
|
||||||
|
| .inbounds[1].listen=\"${listen}\"
|
||||||
| .inbounds[1].settings.clients[0].email=\"${email}\"
|
| .inbounds[1].settings.clients[0].email=\"${email}\"
|
||||||
| .inbounds[2].settings.clients[0].email=\"${email}\"
|
| .inbounds[2].settings.clients[0].email=\"${email}\"
|
||||||
| .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:443\"
|
| .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:443\"
|
||||||
|
@ -230,7 +263,9 @@ Better if it is quite popular and not blocked in your country:
|
||||||
| .inbounds[1].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
| .inbounds[1].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
||||||
| .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}\" ]
|
||||||
|
| .inbounds[3].settings.clients[0].id=\"${id}\"
|
||||||
|
| .inbounds[3].streamSettings.grpcSettings.serviceName=\"${service_name}\" " \
|
||||||
> ./conf/config_server.json
|
> ./conf/config_server.json
|
||||||
# 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" ./conf/config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
|
@ -271,6 +306,24 @@ Better if it is quite popular and not blocked in your country:
|
||||||
echo -e "${red}config files are not generated${normal}"
|
echo -e "${red}config files are not generated${normal}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
## Make main client config_cdn ##
|
||||||
|
if [ ! -v $server_name4cdn ]
|
||||||
|
then
|
||||||
|
jsonc2json template_config_client_cdn.jsonc \
|
||||||
|
| jq ".outbounds[0].settings.vnext[0].address=\"${server_name4cdn}\"
|
||||||
|
| .outbounds[0].settings.vnext[0].users[0].id=\"${id}\"
|
||||||
|
| .outbounds[0].streamSettings.grpcSettings.serviceName=\"${service_name}\"" \
|
||||||
|
> ./conf/config_client_cdn.json
|
||||||
|
# make the user (not root) an owner of a file
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client_cdn.json
|
||||||
|
if [ -f "./conf/config_client_cdn.json" ]
|
||||||
|
then
|
||||||
|
echo -e "${green}config_cdn file is generated${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${red}config_cdn file is not generated${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# the main part of `./ex.sh add` command, adds config for given users and updates server config
|
# the main part of `./ex.sh add` command, adds config for given users and updates server config
|
||||||
|
@ -339,6 +392,11 @@ no new config created fot it${normal}"
|
||||||
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)
|
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" ./conf/config_client_${username}.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client_${username}.json
|
||||||
|
if [ -f "./conf/config_client_cdn.json" ]
|
||||||
|
then
|
||||||
|
cat ./conf/config_client_cdn.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\"" > ./conf/config_client_${username}_cdn.json
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client_${username}_cdn.json
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
# update server config
|
# update server config
|
||||||
client="
|
client="
|
||||||
|
@ -348,9 +406,13 @@ no new config created fot it${normal}"
|
||||||
\"flow\": \"xtls-rprx-vision\"
|
\"flow\": \"xtls-rprx-vision\"
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
# update server config
|
grpc_client_id="
|
||||||
|
{
|
||||||
|
\"id\": \"${id}\"
|
||||||
|
}
|
||||||
|
"
|
||||||
cp ./conf/config_server.json ./conf/tmp_server_config.json
|
cp ./conf/config_server.json ./conf/tmp_server_config.json
|
||||||
ok2=$(cat ./conf/tmp_server_config.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > ./conf/config_server.json)
|
ok2=$(cat ./conf/tmp_server_config.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"] | .inbounds[3].settings.clients += [${grpc_client_id}]" > ./conf/config_server.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" ./conf/config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
if $ok1 && $ok2
|
if $ok1 && $ok2
|
||||||
|
@ -449,6 +511,16 @@ sudo ./ex.sh install${normal}"
|
||||||
echo -e "${red}customgeo.dat not copied to ${dat_dir}${normal}"
|
echo -e "${red}customgeo.dat not copied to ${dat_dir}${normal}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
# for cert.pem
|
||||||
|
mkdir -p /etc/ssl/certs/
|
||||||
|
# for cert.key
|
||||||
|
mkdir -p /etc/ssl/private/
|
||||||
|
# for nginx's 'site'
|
||||||
|
mkdir -p /etc/nginx/sites-enabled/
|
||||||
|
#
|
||||||
|
cp -b ./cert.pem /etc/ssl/certs/
|
||||||
|
cp -b ./cert.key /etc/ssl/private/
|
||||||
|
cp -b ./nginx.conf /etc/nginx/nginx.conf
|
||||||
else
|
else
|
||||||
echo -e "${red}xray not installed, something goes wrong${normal}"
|
echo -e "${red}xray not installed, something goes wrong${normal}"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -547,14 +619,19 @@ then
|
||||||
echo -e "${yellow}no config for user ${username}${normal}"
|
echo -e "${yellow}no config for user ${username}${normal}"
|
||||||
else
|
else
|
||||||
short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config)
|
short_id=$(jq ".outbounds[0].streamSettings.realitySettings.shortId" $config)
|
||||||
|
id=$(jq ".outbounds[0].settings.vnext[0].users[0].id" $config)
|
||||||
cp ./conf/config_server.json ./conf/tmp_server_config.json
|
cp ./conf/config_server.json ./conf/tmp_server_config.json
|
||||||
# update server config
|
# update server config
|
||||||
ok1=$(cat ./conf/tmp_server_config.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)
|
ok1=$(cat ./conf/tmp_server_config.json | jq "del(.inbounds[1].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[1].streamSettings.realitySettings.shortIds[] | select(. == ${short_id})) | del(.inbounds[3].settings.clients[] | select(.id == ${id}))" > ./conf/config_server.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" ./conf/config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
|
||||||
if [ $command = "del" ]
|
if [ $command = "del" ]
|
||||||
then
|
then
|
||||||
ok2=$(rm ./conf/config_client_${username}.json)
|
ok2=$(rm ./conf/config_client_${username}.json)
|
||||||
|
if [ -f "./conf/config_client_${username}_cdn.json" ]
|
||||||
|
then
|
||||||
|
rm ./conf/config_client_${username}_cdn.json
|
||||||
|
fi
|
||||||
if $ok1 && $ok2
|
if $ok1 && $ok2
|
||||||
then
|
then
|
||||||
rm ./conf/tmp_server_config.json
|
rm ./conf/tmp_server_config.json
|
||||||
|
@ -602,17 +679,26 @@ then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
check_command jq "needed for operations with configs"
|
check_command jq "needed for operations with configs"
|
||||||
id=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].users[0].id" $conf_file))
|
network=$(strip_quotes $(jq ".outbounds[0].streamSettings.network" $conf_file))
|
||||||
address=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].address" $conf_file))
|
if [ $network = "tcp" ] # tls-vless-reality config
|
||||||
if [[ $address == *":"* ]] # address contains ':', as IPv6 does
|
|
||||||
then
|
then
|
||||||
address="[${address}]"
|
id=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].users[0].id" $conf_file))
|
||||||
|
address=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].address" $conf_file))
|
||||||
|
if [[ $address == *":"* ]] # address contains ':', as IPv6 does
|
||||||
|
then
|
||||||
|
address="[${address}]"
|
||||||
|
fi
|
||||||
|
port=$(jq ".outbounds[0].settings.vnext[0].port" $conf_file)
|
||||||
|
public_key=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.publicKey" $conf_file))
|
||||||
|
server_name=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.serverName" $conf_file))
|
||||||
|
short_id=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.shortId" $conf_file))
|
||||||
|
link="vless://${id}@${address}:${port}?fragment=&security=reality&encryption=none&pbk=${public_key}&fp=chrome&type=tcp&flow=xtls-rprx-vision&sni=${server_name}&sid=${short_id}#easy-xray+%F0%9F%97%BD"
|
||||||
|
else # grpc config
|
||||||
|
id=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].users[0].id" $conf_file))
|
||||||
|
address=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].address" $conf_file))
|
||||||
|
service_name=$(strip_quotes $(jq ".outbounds[0].streamSettings.grpcSettings.serviceName" $conf_file))
|
||||||
|
link="vless://${id}@${address}:443?security=tls&encryption=none&type=grpc&serviceName=${service_name}#easy-xray+%F0%9F%97%BD+CDN"
|
||||||
fi
|
fi
|
||||||
port=$(jq ".outbounds[0].settings.vnext[0].port" $conf_file)
|
|
||||||
public_key=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.publicKey" $conf_file))
|
|
||||||
server_name=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.serverName" $conf_file))
|
|
||||||
short_id=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.shortId" $conf_file))
|
|
||||||
link="vless://${id}@${address}:${port}?fragment=&security=reality&encryption=none&pbk=${public_key}&fp=chrome&type=tcp&flow=xtls-rprx-vision&sni=${server_name}&sid=${short_id}#easy-xray+%F0%9F%97%BD"
|
|
||||||
echo -e "${yellow}don't forget to share misc/customgeo4hiddify.txt or misc/customgeo4nekoray.txt as well
|
echo -e "${yellow}don't forget to share misc/customgeo4hiddify.txt or misc/customgeo4nekoray.txt as well
|
||||||
${green}here is your link:${normal}"
|
${green}here is your link:${normal}"
|
||||||
echo $link
|
echo $link
|
||||||
|
@ -709,6 +795,12 @@ then
|
||||||
ok1=$(cat ${to}/config_client.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\" | .outbounds[0].settings.vnext[0].users[0].email=\"${uname_from_email}@example.com\" | .outbounds[0].streamSettings.realitySettings.shortId=\"${short_id}\"" > ${to}/config_client_${uname_from_email}.json)
|
ok1=$(cat ${to}/config_client.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\" | .outbounds[0].settings.vnext[0].users[0].email=\"${uname_from_email}@example.com\" | .outbounds[0].streamSettings.realitySettings.shortId=\"${short_id}\"" > ${to}/config_client_${uname_from_email}.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" ${to}/config_client_${uname_from_email}.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ${to}/config_client_${uname_from_email}.json
|
||||||
|
#
|
||||||
|
if [ -f "./conf/config_client_cdn.json" ]
|
||||||
|
then
|
||||||
|
cat ./conf/config_client_cdn.json | jq ".outbounds[0].settings.vnext[0].users[0].id=\"${id}\"" > ./conf/config_client_${uname_from_email}_cdn.json
|
||||||
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_client_${username}_cdn.json
|
||||||
|
fi
|
||||||
# update server config
|
# update server config
|
||||||
client="
|
client="
|
||||||
{
|
{
|
||||||
|
@ -717,8 +809,13 @@ then
|
||||||
\"flow\": \"xtls-rprx-vision\"
|
\"flow\": \"xtls-rprx-vision\"
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
grpc_client_id="
|
||||||
|
{
|
||||||
|
\"id\": \"${id}\"
|
||||||
|
}
|
||||||
|
"
|
||||||
cp ${to}/config_server.json ${to}/tmp_server_config.json
|
cp ${to}/config_server.json ${to}/tmp_server_config.json
|
||||||
ok2=$(cat ${to}/tmp_server_config.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > ${to}/config_server.json)
|
ok2=$(cat ${to}/tmp_server_config.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"] | .inbounds[3].settings.clients += [${grpc_client_id}]" > ${to}/config_server.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" ${to}/config_server.json
|
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ${to}/config_server.json
|
||||||
if $ok1 && $ok2
|
if $ok1 && $ok2
|
||||||
|
|
85
nginx.conf
Normal file
85
nginx.conf
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
# For more information on configuration, see:
|
||||||
|
# * Official English Documentation: http://nginx.org/en/docs/
|
||||||
|
# * Official Russian Documentation: http://nginx.org/ru/docs/
|
||||||
|
|
||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
pid /run/nginx.pid;
|
||||||
|
|
||||||
|
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
|
||||||
|
include /usr/share/nginx/modules/*.conf;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 4096;
|
||||||
|
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
include /etc/nginx/sites-enabled/*;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Load modular configuration files from the /etc/nginx/conf.d directory.
|
||||||
|
# See http://nginx.org/en/docs/ngx_core_module.html#include
|
||||||
|
# for more information.
|
||||||
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
|
||||||
|
#server {
|
||||||
|
# listen 80;
|
||||||
|
# listen [::]:80;
|
||||||
|
# server_name _;
|
||||||
|
# root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
# # Load configuration files for the default server block.
|
||||||
|
# include /etc/nginx/default.d/*.conf;
|
||||||
|
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# location = /404.html {
|
||||||
|
# }
|
||||||
|
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
# location = /50x.html {
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Settings for a TLS enabled server.
|
||||||
|
#
|
||||||
|
# server {
|
||||||
|
# listen 443 ssl http2;
|
||||||
|
# listen [::]:443 ssl http2;
|
||||||
|
# server_name _;
|
||||||
|
# root /usr/share/nginx/html;
|
||||||
|
#
|
||||||
|
# ssl_certificate "/etc/pki/nginx/server.crt";
|
||||||
|
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
|
||||||
|
# ssl_session_cache shared:SSL:1m;
|
||||||
|
# ssl_session_timeout 10m;
|
||||||
|
# ssl_ciphers PROFILE=SYSTEM;
|
||||||
|
# ssl_prefer_server_ciphers on;
|
||||||
|
#
|
||||||
|
# # Load configuration files for the default server block.
|
||||||
|
# include /etc/nginx/default.d/*.conf;
|
||||||
|
#
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# location = /40x.html {
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
# location = /50x.html {
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
229
template_config_client_cdn.jsonc
Normal file
229
template_config_client_cdn.jsonc
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// This config is based on
|
||||||
|
// https://github.com/XTLS/Xray-examples/blob/main/VLESS-TCP-XTLS-Vision-REALITY/REALITY.ENG.md
|
||||||
|
{
|
||||||
|
"log": {
|
||||||
|
"access": "none",
|
||||||
|
"error": "",
|
||||||
|
"loglevel": "warning",
|
||||||
|
"dnsLog": false
|
||||||
|
},
|
||||||
|
// Turns on traffic statistics, see https://xtls.github.io/en/config/stats.html#statsobject
|
||||||
|
// and https://xtls.github.io/en/config/policy.html#policyobject
|
||||||
|
// and special "api" tag below
|
||||||
|
"stats": {
|
||||||
|
},
|
||||||
|
"policy": {
|
||||||
|
"levels": {
|
||||||
|
// default level
|
||||||
|
"0": {
|
||||||
|
"statsUserUplink": true,
|
||||||
|
"statsUserDownlink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"system": {
|
||||||
|
"statsOutboundUplink": true,
|
||||||
|
"statsOutboundDownlink": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// enables API interface https://xtls.github.io/en/config/api.html#apiobject
|
||||||
|
"api": {
|
||||||
|
"tag": "api",
|
||||||
|
"services": [ "StatsService" ]
|
||||||
|
},
|
||||||
|
// client-side inbound configuration
|
||||||
|
"inbounds": [
|
||||||
|
// gRPC API inbound, used to get statistics
|
||||||
|
{
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 8080,
|
||||||
|
"protocol": "dokodemo-door",
|
||||||
|
"settings": {
|
||||||
|
"address": "127.0.0.1"
|
||||||
|
},
|
||||||
|
"tag": "api"
|
||||||
|
},
|
||||||
|
// socks proxy
|
||||||
|
{
|
||||||
|
"tag": "socks",
|
||||||
|
"port": 800,
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"protocol": "socks",
|
||||||
|
// used to make transparent proxies, see https://xtls.github.io/en/config/inbound.html#sniffingobject
|
||||||
|
"sniffing": {
|
||||||
|
"enabled": true,
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls"
|
||||||
|
],
|
||||||
|
"routeOnly": true
|
||||||
|
},
|
||||||
|
// settings of inbound "protocol" (see above)
|
||||||
|
"settings": {
|
||||||
|
"auth": "noauth",
|
||||||
|
"udp": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// http/https proxy
|
||||||
|
{
|
||||||
|
"tag": "http",
|
||||||
|
"port": 801,
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"protocol": "http",
|
||||||
|
// used to make transparent proxies, see https://xtls.github.io/en/config/inbound.html#sniffingobject
|
||||||
|
"sniffing": {
|
||||||
|
"enabled": true,
|
||||||
|
"destOverride": [
|
||||||
|
"http",
|
||||||
|
"tls"
|
||||||
|
],
|
||||||
|
"routeOnly": true
|
||||||
|
},
|
||||||
|
// settings of inbound "protocol" (see above)
|
||||||
|
"settings": {
|
||||||
|
"auth": "noauth",
|
||||||
|
"udp": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// client-side outbound configuration
|
||||||
|
"outbounds": [
|
||||||
|
// fallback, see `routing` section
|
||||||
|
{
|
||||||
|
"tag": "proxy",
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"vnext": [
|
||||||
|
{
|
||||||
|
"address": "server_domain_name",
|
||||||
|
"port": 443,
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
// should match server side
|
||||||
|
"id": "client_id",
|
||||||
|
"encryption": "none"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "grpc",
|
||||||
|
"security": "tls",
|
||||||
|
"grpcSettings": {
|
||||||
|
// should match server side
|
||||||
|
"serviceName": "your_service_name",
|
||||||
|
// for Cloudflare CDN, see this example https://github.com/XTLS/Xray-examples/blob/main/VLESS-GRPC/client.json
|
||||||
|
// and https://xtls.github.io/en/config/transports/grpc.html#grpcobject
|
||||||
|
"idle_timeout": 60,
|
||||||
|
"permit_without_stream": true,
|
||||||
|
"initial_windows_size": 35536
|
||||||
|
},
|
||||||
|
"tlsSettings": {
|
||||||
|
"alpn": ["h2"],
|
||||||
|
"fingerprint": "chrome"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// this outbound is to guide traffic to local sites not through the server
|
||||||
|
// but directly from the client; `tag` is just an outbound label
|
||||||
|
"tag": "direct",
|
||||||
|
"protocol": "freedom",
|
||||||
|
"settings": {}
|
||||||
|
},
|
||||||
|
// for that should be blocked
|
||||||
|
{
|
||||||
|
"protocol": "blackhole",
|
||||||
|
"tag": "block"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// Forward each inbound connections to corresponding `outboundTag`. If no rules match,
|
||||||
|
// the traffic is sent out by the first outbound in `outbounds` section.
|
||||||
|
"routing": {
|
||||||
|
"domainStrategy": "AsIs",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"inboundTag": [
|
||||||
|
"api"
|
||||||
|
],
|
||||||
|
"outboundTag": "api"
|
||||||
|
},
|
||||||
|
// guide udp traffic to `direct` outbound
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"network": "udp",
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
// block localhost connections through xray
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"ip": [
|
||||||
|
"geoip:private"
|
||||||
|
],
|
||||||
|
"outboundTag": "block"
|
||||||
|
},
|
||||||
|
// guide bittorent traffic to `direct` outbound
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"protocol": [ "bittorrent" ],
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
// traffic to popular ports of torrent trackers
|
||||||
|
// and to popular ports of torrent clients
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"port": "6969,6881-6889",
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
// traffic from popular ports of torrent clients
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"sourcePort": "6881-6889",
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
// exceptions for some *.ru sites that shouldn't be blocked or accessed directly
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"domain": [
|
||||||
|
"ext:customgeo.dat:coherence-extra-exceptions"
|
||||||
|
],
|
||||||
|
"outboundTag": "proxy"
|
||||||
|
},
|
||||||
|
// guide domestic sites traffic to `direct` outbound
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"domain": [
|
||||||
|
"geosite:cn",
|
||||||
|
"domain:cn",
|
||||||
|
// punycode for national Chinese top-level domains .中国, .中國, .公司, .网络
|
||||||
|
"domain:xn--fiqs8s",
|
||||||
|
"domain:xn--fiqz9s",
|
||||||
|
"domain:xn--55qx5d",
|
||||||
|
"domain:xn--io0a7i",
|
||||||
|
"domain:ru",
|
||||||
|
// punycode for cyrillic Russian top-level domain .рф
|
||||||
|
"domain:xn--p1ai",
|
||||||
|
"domain:by",
|
||||||
|
// punycode for national Belorussian top-level domain .бел
|
||||||
|
"domain:xn--90ais",
|
||||||
|
"domain:ir",
|
||||||
|
// extra domains that are used by domestic sites, see https://github.com/EvgenyNerush/coherence-grabber/tree/main
|
||||||
|
"ext:customgeo.dat:coherence-extra",
|
||||||
|
"ext:customgeo.dat:coherence-extra-plus"
|
||||||
|
],
|
||||||
|
"outboundTag": "direct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"ip": [
|
||||||
|
"geoip:cn",
|
||||||
|
"geoip:ru",
|
||||||
|
"geoip:by",
|
||||||
|
"geoip:ir"
|
||||||
|
],
|
||||||
|
"outboundTag": "direct"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -246,6 +246,30 @@
|
||||||
],
|
],
|
||||||
"routeOnly": true
|
"routeOnly": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// this inbound can be used with Nginx configured to listen grpc on IPv6 address;
|
||||||
|
// vless can't give a reasonable fallback when used with grpc, but nginx can;
|
||||||
|
// see 'CDN' section in Readme for details
|
||||||
|
{
|
||||||
|
"tag": "grpc",
|
||||||
|
"listen": "127.0.0.1",
|
||||||
|
"port": 50051,
|
||||||
|
"protocol": "vless",
|
||||||
|
"settings": {
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"id": "client_id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"decryption": "none"
|
||||||
|
},
|
||||||
|
"streamSettings": {
|
||||||
|
"network": "grpc",
|
||||||
|
"grpcSettings": {
|
||||||
|
// nginx config should contain `location /your_service_name`
|
||||||
|
"serviceName": "your_service_name"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// server-side outbound configuration
|
// server-side outbound configuration
|
||||||
|
|
35
template_site4cdn.conf
Normal file
35
template_site4cdn.conf
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
server {
|
||||||
|
# listen ip6 addresses
|
||||||
|
listen [::]:443 ssl http2 so_keepalive=on;
|
||||||
|
|
||||||
|
# your server domain name in CDN, for instance myserver.example.com
|
||||||
|
server_name server_domain_name;
|
||||||
|
|
||||||
|
# fallback: proxy_pass redirects request to another server
|
||||||
|
location / {
|
||||||
|
proxy_pass https://www.youtube.com;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# path to certificates (self-signed or from Cloudflare)
|
||||||
|
ssl_certificate /etc/ssl/certs/cert.pem;
|
||||||
|
ssl_certificate_key /etc/ssl/private/cert.key;
|
||||||
|
|
||||||
|
|
||||||
|
client_header_timeout 52w;
|
||||||
|
keepalive_timeout 52w;
|
||||||
|
# secret location; should match that in the xray server config
|
||||||
|
location /your_service_name {
|
||||||
|
if ($content_type !~ "application/grpc") {
|
||||||
|
# redirect to the root location
|
||||||
|
return 302 /;
|
||||||
|
}
|
||||||
|
client_max_body_size 0;
|
||||||
|
client_body_buffer_size 512k;
|
||||||
|
grpc_set_header X-Real-IP $remote_addr;
|
||||||
|
client_body_timeout 52w;
|
||||||
|
grpc_read_timeout 52w;
|
||||||
|
# connect to xray on localhost
|
||||||
|
grpc_pass grpc://127.0.0.1:50051;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue