add CDN support at the second ip address

This commit is contained in:
Evgeny Nerush 2024-03-26 17:00:10 +03:00
parent 78762bbb58
commit 520bca6992
9 changed files with 530 additions and 19 deletions

1
CDN.md Normal file
View file

@ -0,0 +1 @@
TODO

32
CDN.ru.md Normal file
View 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
```

View file

@ -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
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
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
@ -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.
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
Script `ex.sh` is written without Docker in mind, but can be used with Docker. Download `easy-xray` folder (main branch) and build the

View file

@ -31,7 +31,8 @@ VLESS-Reality) не шифрует уже зашифрованный https-тр
установить [jq](https://jqlang.github.io/jq/) и `openssl` - их можно найти в репозиторияx практически всех популярных Linux дистрибутивов.
Затем скачайте `easy-xray` (всю директорию целиком), сделайте исполняемым файл `ex.sh` и запустите нужную команду. Используйте `./ex.sh
help` для получения списка всех команд и короткой справки по ним. Для установки и настройки xray используйте `./ex.sh install` - эта команда
предложит вам ввести ip-адрес вашего сервера, адрес сайта, под который ваш сервер будет маскироваться, и имена пользователей.
предложит вам ввести ip-адрес вашего сервера, адрес сайта, под который ваш сервер будет маскироваться, и имена пользователей. Не
используйте easy-xray для пользователя root, используйте обычного пользователя и sudo!
```
chmod +x ex.sh
@ -43,6 +44,10 @@ sudo ./ex.sh install
будет должным образом установлен, а xray - запущен с ним. Настало время раздать конфиги пользователям! Для многих графических клиентов
удобно использовать конфиги в виде ссылок, которые можно сгенерировать командой `./ex.sh link user_config_file.json`.
Если у вашего VPS сервера есть два IP-адреса (IPv4 и IPv6), easy-xray может быть сконфигурирован так, чтобы IPv6-адрес
использовался для доступа через сеть CDN от Cloudflare по протоколу grpc-tls. См. детали в [инструкции](CDN.ru.md).
#### Docker
Скрипт `ex.sh` написан прежде всего для использования в системе с systemd, однако может быть использован и в Docker. Для этого скачайте

131
ex.sh
View file

@ -137,7 +137,17 @@ conf () {
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:"
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
if [ -v $address ]
then
@ -145,11 +155,11 @@ conf () {
exit 1
fi
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
if [ ! -v $answer ] && [ $answer = 'n' ]
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
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)
@ -217,10 +227,33 @@ Better if it is quite popular and not blocked in your country:
email="love@xray.com"
#
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 ##
jsonc2json template_config_server.jsonc \
| jq ".inbounds[1].settings.clients[0].id=\"${id}\"
| .inbounds[2].settings.clients[0].id=\"${id}\"
| .inbounds[1].listen=\"${listen}\"
| .inbounds[1].settings.clients[0].email=\"${email}\"
| .inbounds[2].settings.clients[0].email=\"${email}\"
| .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[2].streamSettings.realitySettings.privateKey=\"${private_key}\"
| .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
# make the user (not root) the owner of the file
[[ $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}"
exit 1
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
@ -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)
# then make the user (not root) an owner of a file
[[ $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
# update server config
client="
@ -348,9 +406,13 @@ no new config created fot it${normal}"
\"flow\": \"xtls-rprx-vision\"
}
"
# update server config
grpc_client_id="
{
\"id\": \"${id}\"
}
"
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
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
if $ok1 && $ok2
@ -449,6 +511,16 @@ sudo ./ex.sh install${normal}"
echo -e "${red}customgeo.dat not copied to ${dat_dir}${normal}"
exit 1
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
echo -e "${red}xray not installed, something goes wrong${normal}"
exit 1
@ -547,14 +619,19 @@ then
echo -e "${yellow}no config for user ${username}${normal}"
else
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
# 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
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ./conf/config_server.json
if [ $command = "del" ]
then
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
then
rm ./conf/tmp_server_config.json
@ -602,17 +679,26 @@ then
exit 1
fi
check_command jq "needed for operations with configs"
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
network=$(strip_quotes $(jq ".outbounds[0].streamSettings.network" $conf_file))
if [ $network = "tcp" ] # tls-vless-reality config
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
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
${green}here is your link:${normal}"
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)
# 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
#
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
client="
{
@ -717,8 +809,13 @@ then
\"flow\": \"xtls-rprx-vision\"
}
"
grpc_client_id="
{
\"id\": \"${id}\"
}
"
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
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" ${to}/config_server.json
if $ok1 && $ok2

85
nginx.conf Normal file
View 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 {
# }
# }
}

View 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"
}
]
}
}

View file

@ -246,6 +246,30 @@
],
"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

35
template_site4cdn.conf Normal file
View 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;
}
}