@@ -1,2 +1 @@
|
|||||||
config_*.json
|
figs/*.kra
|
||||||
config_*.json.backup
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[HiddifyNG in Google Play](https://play.google.com/store/apps/details?id=ang.hiddify.com&pcampaignid=web_share)
|
||||||
|
|
||||||
|
Copy config in a form of a link. Open Hiddify app, click Clipboard button, enter any name for a group (e.g. xray), press Confirm. Then click
|
||||||
|
Configs (on the bottom), you should see "easy-xray" with your server ip. Go to Settings, Custom rules, direct URL or IP section, and paste
|
||||||
|
the content of `misc/customgeo4hiddify.txt` as plain text. Save, then click to connect/start.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[Релизы Nekoray (см. Assets)](https://github.com/MatsuriDayo/nekoray/releases)
|
||||||
|
|
||||||
|
Выбираем ядро xray, добавляем профиль (конфиг-ссылка), настраиваем маршруты (копируем из `misc/customgeo4nekoray.txt`), выбираем режим
|
||||||
|
системного прокси, и запускаем!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
@@ -1,61 +1,140 @@
|
|||||||
# easy-xray
|
# easy-xray
|
||||||
|
|
||||||
*Script for Linux which makes XRay installation and configuration easy*
|
*Script for Linux which makes XRay management easy*
|
||||||
|
|
||||||
(todo) [Readme in Russian](README.ru.md)
|
[Readme in Russian](README.ru.md) [(todo) Readme in Chinese](README.cn.md)
|
||||||
|
|
||||||
(todo) [Readme in Chinese](README.cn.md)
|
[XRay (aka ProjectX)](https://xtls.github.io/en/) is a frontier solution to circumvent the internet censorship. XRay allows to guide traffic
|
||||||
|
through a server (VPS) outside the region of censorship as a proxie, but connection to xray server looks for authorities as a typical
|
||||||
|
connection to a regular website. Attempts to detect VPN such as [active probing](https://ensa.fi/active-probing/) or blocking by the rule
|
||||||
|
"all except https" are eliminated by XRay. Also, XRay server can be configured to open only foreign websites, thus preventing detection by
|
||||||
|
the code on domestic websites. As a proxy, XRay has no need to encrypt already encrypted https traffic, hence CPU load is low. XRay doesn't
|
||||||
|
need to keep the connection alive, and users don't need to manually reconnect to it time-to-time. Also users don't need to turn a client off
|
||||||
|
to go to most domestic websites.
|
||||||
|
|
||||||
[XRay (aka ProjectX)](https://xtls.github.io/en/) is a frontier solution to surpass the internet censorship. It can work as a server and as
|

|
||||||
a client allowing to guide traffic through a VPS outside the region of censorship. XRay configuration can be confusing for a newcomer,
|
|
||||||
so, here is a script which helps to
|
|
||||||
|
|
||||||
- install/upgrade/remove XRay and geodata
|
Besides of its plusses, configuration and management of XRay server is quite sophisticated. So, here is a script which helps to do it. It
|
||||||
|
can
|
||||||
|
|
||||||
|
- install/upgrade/remove XRay
|
||||||
- generate credentials and server/client configs
|
- generate credentials and server/client configs
|
||||||
- add/delete users to the configs
|
- add/delete users to the configs
|
||||||
|
- and more
|
||||||
|
|
||||||
|
### How to use on VPS
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
First, make the script `ex.sh` executable, then 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 which installs and configures XRay.
|
|
||||||
```
|
```
|
||||||
$ chmod +x ex.sh
|
chmod +x ex.sh
|
||||||
$ ./ex.sh help
|
./ex.sh help
|
||||||
$ sudo ./ex.sh install
|
sudo ./ex.sh install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Prerequisites
|
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`.
|
||||||
|
|
||||||
For manipulations with configs, [jq](https://jqlang.github.io/jq/) is needed, it can be found in repositories of almost all popular Linux
|
### Clients
|
||||||
distributions.
|
|
||||||
|
|
||||||
### How it works
|
#### Linux
|
||||||
|
|
||||||
With current configs, XRay creates a tunnel between the client (your laptop, phone etc.) and the server (your VPS). The tunnel uses VLESS
|
XRay itself can be a client, besides plenty of GUI clients that are available for other popular operating systems (see below). You can
|
||||||
[Reality](https://github.com/XTLS/REALITY/blob/main/README.en.md) protocol that obfuscates traffic and in our case imitates
|
manually install XRay with [official script](https://github.com/XTLS/Xray-install) and manually copy `customgeo.dat` to
|
||||||
[grpc](https://en.wikipedia.org/wiki/GRPC). For the censor the tunnel looks like a usual connection to a site. The server responds to https
|
`/usr/local/share/xray/` or just install them both with `sudo ./ex.sh install` command. Then, copy client config from the server and run:
|
||||||
requests as some popular site thus it is not suspicious for an active probing. On the client side *XRay* creates http/https and socks
|
|
||||||
proxies which can be used by your Telegram or web browser like this:
|
|
||||||
|
|
||||||

|
```
|
||||||
|
sudo cp config_client_username.json /usr/local/etc/xray/config.json
|
||||||
|
sudo systemctl start xray
|
||||||
|
```
|
||||||
|
|
||||||
Note that there is no additional encryption layer in VLESS; using it you rely on the encryption that the browser (Telegram app etc.) makes.
|
or
|
||||||
Note also that for current client config, traffic to .cn, .ru, .by and .ir sites goes directly from the client, see
|
|
||||||
[here](https://github.com/EvgenyNerush/coherence-grabber) for details. This makes your server much less attention-grabbing and suspicious,
|
|
||||||
but your connection less anonymous.
|
|
||||||
|
|
||||||
### Other clients
|
```
|
||||||
|
sudo xray run -c config_client_username.json
|
||||||
|
```
|
||||||
|
|
||||||
For Windows, MacOS or Android you can try Nekobox, v2rayNG or ? (TODO): tests and config generation for them.
|
In the current configuration, on the client side XRay creates http/https and socks5 proxies on your PC which can be used by your Telegram
|
||||||
|
app or Web browser like this:
|
||||||
|
|
||||||
### Futher reading
|

|
||||||
|
|
||||||
Template configs contain comments and links and are good start to find another interesting Xray configuration options.
|
To check that traffic to domestic and foreing sites goes by different ways, visit, for example,
|
||||||
|
[whatismyip.com](https://www.whatismyip.com/) and [2ip.ru](https://2ip.ru/). They should show different IP addressess.
|
||||||
|
|
||||||
### Acknowledgements
|
#### Windows
|
||||||
|
|
||||||
[This article (in Russian)](https://habr.com/ru/articles/731608/) helped me to install *XRay* for the first time.
|
Use [Nekoray (Nekobox)](https://github.com/MatsuriDayo/nekoray) client that releases can be found on [this
|
||||||
|
page](https://github.com/MatsuriDayo/nekoray/releases). Choose one of Assets, for instance `nekoray-3.26-2023-12-09-windows64.zip`, download
|
||||||
|
then unzip it and run Nekoray. The following configuration is [quite easy (RU)](Nekoray.ru.md).
|
||||||
|
|
||||||
|
#### MacOS
|
||||||
|
|
||||||
|
Use XRay:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install xray
|
||||||
|
cp customgeo.dat /usr/local/share/xray/ # not yet tested
|
||||||
|
sudo xray -config=config_client_username.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Android
|
||||||
|
|
||||||
|
For many mobile applications it is enough to paste a client config in a link form from the buffer, and add customgeo in an appropriate form
|
||||||
|
(see `misc` dir) to somethere like `Settings/Routing/Custom rules/Direct URL`. Tested applications are listed below.
|
||||||
|
|
||||||
|
Use [V2RayNG](https://play.google.com/store/apps/details?id=com.v2ray.ang&pcampaignid=web_share),
|
||||||
|
[HiddifyNG](https://play.google.com/store/apps/details?id=ang.hiddify.com&pcampaignid=web_share) or [Hiddify
|
||||||
|
Next](https://play.google.com/store/apps/details?id=app.hiddify.com&pcampaignid=web_share). They are very similar to each other, here are
|
||||||
|
some instructions for [V2RayNG (RU)](V2RayNG.ru.md) and [HiddifyNG (EN)](HiddifyNG.en.md).
|
||||||
|
|
||||||
|
#### iOS
|
||||||
|
|
||||||
|
Use [Straisand](https://apps.apple.com/us/app/streisand/id6450534064). Its configuration is very similar to that of V2Ray and Hiddify (see
|
||||||
|
above). Manual copy-paste from json config file is also possible. (customgeo not yet tested)
|
||||||
|
|
||||||
|
#### Others
|
||||||
|
|
||||||
|
[Here](https://github.com/xtls/xray-core) you can find an additional list of clients.
|
||||||
|
|
||||||
|
### Tor
|
||||||
|
|
||||||
|
Most of GUI clients are based on xray core, but do not fully support its configuration, that is crutial for Tor. To use
|
||||||
|
[TorBrowser](https://www.torproject.org/download/) in this case, use bridges. To get a bridge, send a letter to bridges@torproject.org, then
|
||||||
|
copy symbols after `obfs4` and paste them to TorBrowser bridge settings.
|
||||||
|
|
||||||
|
### Bittorrent
|
||||||
|
|
||||||
|
Bittorent protocol is blocked in the current configuration. Using bittorent on a VPS can lead to a ban from VPS provider.
|
||||||
|
|
||||||
|
### What else
|
||||||
|
|
||||||
|
#### Hints
|
||||||
|
|
||||||
|
To choose a good `serverName` (your VPS will mimic this website), you can use [RealiTLScanner](https://github.com/XTLS/RealiTLScanner). This
|
||||||
|
tool scans ip addresses near your server (do it not from your VPS!) and show names found at port 443. With `nmap -T4 hostname` you can check
|
||||||
|
that only ports 80 and 443 are open on hosts of the found websites (as in the configurations of template configs). It is also good to move
|
||||||
|
ssh on your VPS to a port beyond 1024. It can be done in `/etc/ssh/sshd_config`. Check twice that VPS is available at your new port before
|
||||||
|
you comment Port 22!
|
||||||
|
|
||||||
|
```
|
||||||
|
#Port 22
|
||||||
|
Port 43210
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Links
|
||||||
|
|
||||||
|
Template configs contain comments and links and are a good start to find another interesting Xray configuration options.
|
||||||
|
|
||||||
|
See [this link](https://github.com/EvgenyNerush/coherence-grabber) for details on how `customgeo` files are generated.
|
||||||
|
|
||||||
|
[This article (in Russian)](https://habr.com/ru/articles/731608/) helped me to install XRay for the first time.
|
||||||
|
|
||||||
|
The template configs are based on these [gRPC](https://github.com/XTLS/Xray-examples/tree/main/VLESS-gRPC-REALITY)
|
||||||
|
and [XTLS](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision-REALITY) examples.
|
||||||
|
|
||||||
[XRay config reference](https://xtls.github.io/en/config/) is brilliant and helped me much.
|
[XRay config reference](https://xtls.github.io/en/config/) is brilliant and helped me much.
|
||||||
|
|
||||||
Configs for [gRPC](https://github.com/XTLS/Xray-examples/tree/main/VLESS-gRPC-REALITY)
|
|
||||||
and [XTLS](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision-REALITY) on that the template configs are based.
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# easy-xray
|
||||||
|
|
||||||
|
*XRay - это просто*
|
||||||
|
|
||||||
|
[(EN)](README.md) [(CN(todo))](README.cn.md)
|
||||||
|
|
||||||
|
[XRay (aka ProjectX)](https://xtls.github.io/en/) - современное решение для обхода интернет-цензуры. Он - как прокси - позволяет проводить
|
||||||
|
трафик через сервер (VPS) за пределами региона с цензурой, при этом подключение к серверу XRay выглядит как подключение к обычному сайту.
|
||||||
|
Попытки обнаружения VPN, такие как активное зондирование [(active probing)](https://ensa.fi/active-probing/) или блокировка по правилу
|
||||||
|
«блокируем все протоколы, кроме https», для XRay не страшны. Кроме того, сервер XRay можно настроить на открытие только "зарубежных"
|
||||||
|
веб-сайтов, что предотвращает попытки обнаружения туннеля сайтами "домашнего" региона. XRay (в случае использования протокола
|
||||||
|
VLESS-Reality) не шифрует уже зашифрованный https-трафик, поэтому нагрузка на процессор невелика. XRay не нужно поддерживать соединение, и
|
||||||
|
пользователям не нужно время от времени повторно подключаться к нему вручную. При правильной настройке клиента пользователям не нужно
|
||||||
|
отключаться от сервера, чтобы перейти на большинство веб-сайтов "домашнего" региона.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Помимо плюсов, у XRay есть и недостатки - например, сложная настройка и администрирование, что стало мотивацией для создания этого
|
||||||
|
репозитория и скрипта `ex.sh`. Этот скрипт поможет
|
||||||
|
|
||||||
|
- установить/обновить/удалить XRay
|
||||||
|
- генерировать учетные данные и конфигурации сервера/клиента
|
||||||
|
- добавлять/удалять пользователей
|
||||||
|
- и т. д.
|
||||||
|
|
||||||
|
### Как использовать на VPS
|
||||||
|
|
||||||
|
Для начала нужно арендовать VPS сервер вне региона с цензурой (или попросить друзей заграницей сделать это). После на сервер нужно
|
||||||
|
установить [jq](https://jqlang.github.io/jq/) и `openssl` - их можно найти в репозиторияx практически всех популярных Linux дистрибутивов.
|
||||||
|
Затем скачайте `easy-xray` (всю директорию целиком), сделайте исполняемым файл `ex.sh` и запустите нужную команду. Используйте `./ex.sh
|
||||||
|
help` для получения списка всех команд и короткой справки по ним. Для установки и настройки xray используйте `./ex.sh install` - эта команда
|
||||||
|
предложит вам ввести ip-адрес вашего сервера, адрес сайта, под который ваш сервер будет маскироваться, и имена пользователей.
|
||||||
|
|
||||||
|
```
|
||||||
|
chmod +x ex.sh
|
||||||
|
./ex.sh help
|
||||||
|
sudo ./ex.sh install
|
||||||
|
```
|
||||||
|
|
||||||
|
В результате у вас появится директория `conf` с серверным конфигом, основным клиентским конфигом и конфигами пользователей. Серверный конфиг
|
||||||
|
будет должным образом установлен, а xray - запущен с ним. Настало время раздать конфиги пользователям! Для многих графических клиентов
|
||||||
|
удобно использовать конфиги в виде ссылок, которые можно сгенерировать командой `./ex.sh link user_config_file.json`.
|
||||||
|
|
||||||
|
### Клиенты
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
|
||||||
|
Для подключения к XRay-серверу существуют клиенты с графическим интерфейсом, но о них чуть позже. На Linux удобно использовать сам XRay в
|
||||||
|
качестве клиента. XRay можно установить вручную, используя [официальный скрипт](https://github.com/XTLS/Xray-install), после чего
|
||||||
|
скопировать `customgeo.dat` в `/usr/local/share/xray/`. Другой вариант установить XRay и `customgeo.dat` - воспользоваться командой `sudo
|
||||||
|
./ex.sh install`. Затем нужно скопировать клиентский конфиг с сервера и выполнить
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo cp config_client_username.json /usr/local/etc/xray/config.json
|
||||||
|
sudo systemctl start xray
|
||||||
|
```
|
||||||
|
|
||||||
|
или
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo xray run -c config_client_username.json
|
||||||
|
```
|
||||||
|
|
||||||
|
XRay с текущим клиентским конфигом создаёт локальные http/https и socks5 прокси, которые могут быть прописаны в настройки Телеграма или
|
||||||
|
браузера примерно так:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Чтобы проверить, что трафик до "зарубежных" и "домашних" сайтов идёт разными путями, зайдите на
|
||||||
|
[whatismyip.com](https://www.whatismyip.com/) и [2ip.ru](https://2ip.ru/). Они должны показать разные ip-адреса и локации.
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
Используйте [Nekoray (Nekobox)](https://github.com/MatsuriDayo/nekoray) - клиент с графическим интерфейсом. Релизы для Windows можно найти
|
||||||
|
на [этой странице](https://github.com/MatsuriDayo/nekoray/releases) в разделе Assets. Выберите и скачайте, например,
|
||||||
|
`nekoray-3.26-2023-12-09-windows64.zip`, затем распакуйте и запустите. Дальнейшее конфигурирование [описано здесь](Nekoray.ru.md).
|
||||||
|
|
||||||
|
#### MacOS
|
||||||
|
|
||||||
|
Используйте сам XRay:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install xray
|
||||||
|
cp customgeo.dat /usr/local/share/xray/ # not yet tested
|
||||||
|
sudo xray -config=config_client_username.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Android
|
||||||
|
|
||||||
|
Для многих мобильных клиентов вся настройка заключается в том, что нужно вставить конфиг-ссылку из буфера обмена, а после добавить сайты из
|
||||||
|
customgeo в подходящей форме (см. директорию `misc`) в "прямые" маршруты (в `Settings/Routing/Custom rules/Direct URL` или что-то подобное).
|
||||||
|
Приложения, которые были протестированы, перечислены ниже.
|
||||||
|
|
||||||
|
Скачайте из Google Play [V2RayNG](https://play.google.com/store/apps/details?id=com.v2ray.ang&pcampaignid=web_share),
|
||||||
|
[HiddifyNG](https://play.google.com/store/apps/details?id=ang.hiddify.com&pcampaignid=web_share) или [Hiddify
|
||||||
|
Next](https://play.google.com/store/apps/details?id=app.hiddify.com&pcampaignid=web_share). Они очень похожи друг на друга, здесь есть
|
||||||
|
инструкции для [V2RayNG](V2RayNG.ru.md) и [HiddifyNG (EN)](HiddifyNG.en.md).
|
||||||
|
|
||||||
|
#### iOS
|
||||||
|
|
||||||
|
Используйте [Straisand](https://apps.apple.com/us/app/streisand/id6450534064). Конфигурирование аналогично тому, что описано для V2Ray или
|
||||||
|
Hiddify (см. выше). Customgeo - ещё не протестирован.
|
||||||
|
|
||||||
|
#### Другие
|
||||||
|
|
||||||
|
[Здесь](https://github.com/xtls/xray-core) можно найти дополнительный список клиентов.
|
||||||
|
|
||||||
|
### Tor
|
||||||
|
|
||||||
|
В случае использования XRay в качестве клиента с текущей конфигурацией не должно возникнуть проблем. Однако большинство графических
|
||||||
|
клиентов, хотя в качестве ядра используют xray, не дают полного доступа к его конфигурации. Из-за этого
|
||||||
|
[Torbrowser](https://www.torproject.org/download/) не всегда может работать "из коробки". Если подключиться к сети Tor не удаётся,
|
||||||
|
попробуйте использовать мост (специальный промежуточный сервер между вами и сетью Tor). Чтобы получить мост, отправьте письмо с любым
|
||||||
|
текстом на bridges@torproject.org, затем вставьте из ответного письма символы после `obfs4` в настройки моста в Torbrowser.
|
||||||
|
|
||||||
|
### Bittorrent
|
||||||
|
|
||||||
|
Bittorent протокол блокируется в текущих настройках - использование bittorrent может привести к бану со стороны VPS провайдера.
|
||||||
|
|
||||||
|
### Что ещё?
|
||||||
|
|
||||||
|
#### Советы
|
||||||
|
|
||||||
|
Для того, чтобы выбрать сайт, который будет видеть на вашем сервере цензор в случае атаки active probing (`serverName` в конфигах), можно
|
||||||
|
воспользоваться утилитой [RealiTLScanner](https://github.com/XTLS/RealiTLScanner). Она может просканировать адреса, близкие к вашему серверу
|
||||||
|
(делайте это с домашнего компьютера, а не с сервера!), и показать имена сайтов на них. С помощью команды `nmap -T4 hostname` можно
|
||||||
|
проверить, что на выбранном вами сервере открыты только порты 80 и 443 (как в настройках xray здесь). Также неплохо выбрать далёкий порт для
|
||||||
|
ssh вместо 22-го, если на выбранном вами сайте этот порт не открыт. Дважды проверьте, что по выбранному вами порту ssh вы можете зайти на
|
||||||
|
сервер - только после этого закрывайте порт 22.
|
||||||
|
|
||||||
|
```
|
||||||
|
#Port 22
|
||||||
|
Port 43210
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Ссылки
|
||||||
|
|
||||||
|
Шаблонные конфиг-файлы для сервера и клиента (`template_config_*.json`) содержат много комментариев, которые могут помочь в создании своей
|
||||||
|
собственной конфигурации клиента и сервера.
|
||||||
|
|
||||||
|
Шаблонные конфиги сделаны на основе этих [двух](https://github.com/XTLS/Xray-examples/tree/main/VLESS-gRPC-REALITY) [примеров](https://github.com/XTLS/Xray-examples/tree/main/VLESS-TCP-XTLS-Vision-REALITY).
|
||||||
|
|
||||||
|
[Описание всех возможных полей XRay конфигов (EN)](https://xtls.github.io/en/config/) очень подробное и хорошо помогает.
|
||||||
|
|
||||||
|
[Здесь](https://github.com/EvgenyNerush/coherence-grabber) детали того, как собраны сайты для доступа напрямую, прописанные в `customgeo`.
|
||||||
|
|
||||||
|
[Эта статья](https://habr.com/ru/articles/731608/) помогла мне установить XRay в первый раз.
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[V2RayNG в Google Play](https://play.google.com/store/apps/details?id=com.v2ray.ang&pcampaignid=web_share)
|
||||||
|
|
||||||
|
Конфиг-ссылку нужно скопировать и добавить в приложение ("+" справа вверху, далее импорт профиля из буфера обмена).
|
||||||
|
Для нормальной работы российских сайтов нужно скопировать содержимое `misc/customgeo4hiddify.txt` в пользовательские правила (прямые).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 68 KiB |
@@ -1,30 +1,53 @@
|
|||||||
|
|
||||||
|
Ô
|
||||||
COHERENCE-EXTRA lenta.com
|
COHERENCE-EXTRAhabr.comhabrastorage.org lenta.com
|
||||||
rugldn.net
|
rugldn.net
|
||||||
ruyastatic.net
|
ruyastatic.net
|
||||||
ru
|
ru
|
||||||
yandex.net
|
yandex.net
|
||||||
rumycdn.me
|
rumycdn.me
|
||||||
ruavito.st
|
ruavito.st
|
||||||
rugismeteo.st
|
rugismeteo.st
|
||||||
rugismeteo.net
|
ru
|
||||||
ruozonusercontent.com
|
by gismeteo.net
|
||||||
|
ru
|
||||||
|
byozonusercontent.com
|
||||||
ru mradx.net
|
ru mradx.net
|
||||||
ruaestatic.net
|
ruaestatic.net
|
||||||
ru
|
ru!
|
||||||
alicdn.com
|
pushwoosh.com
|
||||||
ru!rambler.pushwoosh.com
|
ru
|
||||||
ruvk.com
|
byvk.com
|
||||||
|
ru
|
||||||
byuserapi.com
|
byuserapi.com
|
||||||
ru otm-r.com
|
ru otm-r.com
|
||||||
ru2gis.com
|
ru2gis.com
|
||||||
ruchampionat.com
|
ruchampionat.com
|
||||||
ru kpcdn.net
|
ru rus-tv.su
|
||||||
rukp.house
|
ru kpcdn.net
|
||||||
rukp.kg
|
ru
|
||||||
rukaspersky-labs.com
|
bykp.house
|
||||||
ruqq.com
|
ru
|
||||||
|
bykp.kg
|
||||||
|
ru
|
||||||
|
bykaspersky-labs.com
|
||||||
|
ru yadro.com
|
||||||
|
ru boosty.to
|
||||||
|
rueaglecdn.com
|
||||||
|
rulivejournal.com
|
||||||
|
rulivejournal.net
|
||||||
|
ruedc.sale
|
||||||
|
ru
|
||||||
|
by"stellarlabs.ai
|
||||||
|
ru
|
||||||
|
bymyminsk.com
|
||||||
|
by#sputniknews.com
|
||||||
|
ru
|
||||||
|
by$sputnikglobe.com
|
||||||
|
ru
|
||||||
|
bydigikala.com
|
||||||
|
irbale.ai
|
||||||
|
ru
|
||||||
irqq.com
|
irqq.com
|
||||||
cn gtimg.com
|
cn gtimg.com
|
||||||
cn zhihu.com
|
cn zhihu.com
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# stdout styles
|
||||||
bold='\033[0;1m'
|
bold='\033[0;1m'
|
||||||
|
italic='\033[0;3m'
|
||||||
underl='\033[0;4m'
|
underl='\033[0;4m'
|
||||||
red='\033[0;31m'
|
red='\033[0;31m'
|
||||||
green='\033[0;32m'
|
green='\033[0;32m'
|
||||||
yellow='\033[0;33m'
|
yellow='\033[0;33m'
|
||||||
normal='\033[0m'
|
normal='\033[0m'
|
||||||
|
|
||||||
# strip lines with comments from jsonC
|
#################
|
||||||
|
### Functions ###
|
||||||
|
#################
|
||||||
|
|
||||||
|
# delete lines with comments from jsonC
|
||||||
jsonc2json () {
|
jsonc2json () {
|
||||||
if [ ! -v $1 ]
|
if [ ! -v $1 ]
|
||||||
then
|
then
|
||||||
@@ -19,126 +25,148 @@ jsonc2json () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# convert string with number of bytes to pretty form
|
||||||
export PATH=$PATH:/usr/local/bin/ # for sudo user this can be not in PATH
|
bytes2MB () {
|
||||||
if command -v xray > /dev/null
|
if [ -v $1 ]
|
||||||
then
|
|
||||||
xray_version=$(xray --version | head -n 1 | cut -c 6-10)
|
|
||||||
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
|
|
||||||
jq_installed=false
|
|
||||||
echo -e "${yellow}Warning: jq not installed but needed for operations with configs${normal}"
|
|
||||||
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
|
then
|
||||||
install_xray=true
|
echo ""
|
||||||
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
|
else
|
||||||
echo -e "${red}xray not installed, something goes wrong${normal}"
|
bytes=$1
|
||||||
fi
|
length=${#bytes}
|
||||||
|
if [ $length -gt 9 ]
|
||||||
|
then
|
||||||
|
head=${bytes::-9}
|
||||||
|
tail=${bytes: -9}
|
||||||
|
echo "${head}.${tail::2} GB"
|
||||||
|
elif [ $length -gt 6 ]
|
||||||
|
then
|
||||||
|
head=${bytes::-6}
|
||||||
|
tail=${bytes: -6}
|
||||||
|
echo "${head}.${tail::2} MB"
|
||||||
|
elif [ $length -gt 3 ]
|
||||||
|
then
|
||||||
|
head=${bytes::-3}
|
||||||
|
tail=${bytes: -3}
|
||||||
|
echo "${head}.${tail::2} kB"
|
||||||
else
|
else
|
||||||
echo -e "${red}You should be root, or run this script with sudo
|
echo "$bytes bytes"
|
||||||
to install xray${normal}"
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# drop quotes (") at the start and at the end of a string
|
||||||
|
strip_quotes () {
|
||||||
|
if [ -v $1 ] || [ ${#1} -lt 2 ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
s=$1
|
||||||
|
s=${s: 1} # from 1 to the end
|
||||||
|
s=${s:: -1} # from 0 to that is before the last one
|
||||||
|
echo $s
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# convert json string with statistics to pretty form;
|
||||||
|
# use with pipe | to deal with multiline strings correctly!
|
||||||
|
pretty_stats () {
|
||||||
|
read stats
|
||||||
|
if [ -v "$stats" ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
bytes=$(echo $stats | jq ".stat.value")
|
||||||
|
echo "$(bytes2MB $(strip_quotes $bytes))"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# check if the mandatory command exists
|
||||||
|
check_command () {
|
||||||
|
cmd=$1
|
||||||
|
cmd_aim=$2
|
||||||
|
comment=$3
|
||||||
|
if command -v $cmd > /dev/null
|
||||||
|
then
|
||||||
|
echo -e "${green}${cmd} found${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${red}${cmd} not found; ${cmd_aim}${normal}"
|
||||||
|
echo -e "${comment}"
|
||||||
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: hosted by your VPS provider,
|
private_key=$(echo $keys | cut -d " " -f 3) # get 3rd field of fields delimited by spaces
|
||||||
in the same country, it is popular,
|
public_key=$(echo $keys | cut -d " " -f 6) # get 6th field
|
||||||
and have only ports 80 (http) and 443 (https) open
|
short_id=$(openssl rand -hex 8) # random short_id for REALITY
|
||||||
(can check with `nmap -T4 hostname`)
|
#
|
||||||
|
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
|
||||||
(4) www.bing.com
|
(4) www.bing.com
|
||||||
(5) www.yahoo.com
|
(5) www.yahoo.com
|
||||||
(6) your variant"
|
(6) www.adobe.com
|
||||||
|
(7) aws.amazon.com
|
||||||
|
(8) discord.com
|
||||||
|
(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"
|
||||||
@@ -152,6 +180,15 @@ and have only ports 80 (http) and 443 (https) open
|
|||||||
then
|
then
|
||||||
fake_site="www.yahoo.com"
|
fake_site="www.yahoo.com"
|
||||||
elif [ $number -eq 6 ]
|
elif [ $number -eq 6 ]
|
||||||
|
then
|
||||||
|
fake_site="www.adobe.com"
|
||||||
|
elif [ $number -eq 7 ]
|
||||||
|
then
|
||||||
|
fake_site="aws.amazon.com"
|
||||||
|
elif [ $number -eq 8 ]
|
||||||
|
then
|
||||||
|
fake_site="discord.com"
|
||||||
|
elif [ $number -eq 9 ]
|
||||||
then
|
then
|
||||||
echo -e "type your variant:"
|
echo -e "type your variant:"
|
||||||
read fake_site
|
read fake_site
|
||||||
@@ -162,24 +199,29 @@ and have only ports 80 (http) and 443 (https) open
|
|||||||
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[].settings.clients[0].id=\"${id}\"
|
| jq ".inbounds[1].settings.clients[0].id=\"${id}\"
|
||||||
| .inbounds[].settings.clients[0].email=\"${email}\"
|
| .inbounds[2].settings.clients[0].id=\"${id}\"
|
||||||
| .inbounds[0].streamSettings.realitySettings.dest=\"${fake_site}:443\"
|
| .inbounds[1].settings.clients[0].email=\"${email}\"
|
||||||
| .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:80\"
|
| .inbounds[2].settings.clients[0].email=\"${email}\"
|
||||||
| .inbounds[].streamSettings.realitySettings.serverNames=${server_names}
|
| .inbounds[1].streamSettings.realitySettings.dest=\"${fake_site}:443\"
|
||||||
| .inbounds[].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
| .inbounds[2].streamSettings.realitySettings.dest=\"${fake_site}:80\"
|
||||||
| .inbounds[].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \
|
| .inbounds[1].streamSettings.realitySettings.serverNames=${server_names}
|
||||||
> config_server.json
|
| .inbounds[2].streamSettings.realitySettings.serverNames=${server_names}
|
||||||
# then make the user (not root) the owner of the file
|
| .inbounds[1].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
||||||
[[ $SUDO_USER ]] && chown "$SUDO_USER:$SUDO_USER" config_server.json
|
| .inbounds[2].streamSettings.realitySettings.privateKey=\"${private_key}\"
|
||||||
|
| .inbounds[1].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]
|
||||||
|
| .inbounds[2].streamSettings.realitySettings.shortIds=[ \"${short_id}\" ]" \
|
||||||
|
> ./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
|
||||||
vnext=" [
|
vnext=" [
|
||||||
{
|
{
|
||||||
\"address\": \"${address}\",
|
\"address\": \"${address}\",
|
||||||
@@ -201,81 +243,72 @@ and have only ports 80 (http) and 443 (https) open
|
|||||||
\"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}"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
elif [ $command = "add" ]
|
# the main part of `./ex.sh add` command, adds config for given users and updates server config
|
||||||
then
|
add () {
|
||||||
echo -e "${bold}add${normal}"
|
export PATH=$PATH:/usr/local/bin/ # brings xray to the path for sudo user
|
||||||
if ! $(command -v xray > /dev/null)
|
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 "${red}xray needed but not installed${normal}"
|
echo -e "${red}server config and config for default user are needed
|
||||||
|
but not present; to generate them, try
|
||||||
|
./ex.sh conf${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_${username}.json
|
||||||
# update server config
|
# update server config
|
||||||
client="
|
client="
|
||||||
{
|
{
|
||||||
@@ -284,45 +317,345 @@ 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
|
# update server config
|
||||||
cat config_server.json.backup | jq ".inbounds[0].settings.clients += [${client}] | .inbounds[0].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > config_server.json
|
cp ./conf/config_server.json ./conf/tmpconfig.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 "${yellow}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}"
|
|
||||||
if ! $jq_installed
|
|
||||||
then
|
|
||||||
echo -e "${red}jq needed but not installed${normal}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -v $2 ]
|
if [ -v $2 ]
|
||||||
then
|
then
|
||||||
echo -e "${red}username not set${normal}"
|
echo -e "${red}usernames not set${normal}"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
|
||||||
username=$2
|
|
||||||
fi
|
fi
|
||||||
config="config_client_${username}.json"
|
check_command jq "needed for operations with configs"
|
||||||
|
if [ ! -f "./conf/config_server.json" ]
|
||||||
|
then
|
||||||
|
echo -e "${red}server config not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# backup server config
|
||||||
|
cp_to_backup ./conf/config_server.json
|
||||||
|
# loop over usernames
|
||||||
|
for username in "${@:2}"
|
||||||
|
do
|
||||||
|
config="./conf/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[0].settings.clients[] | select(.email == \"${username}@example.com\")) | del(.inbounds[0].streamSettings.realitySettings.shortIds[] | select(. == ${short_id}))" > config_server.json
|
ok1=$(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
|
ok2=$(rm ./conf/config_client_${username}.json)
|
||||||
|
if $ok1 && $ok2
|
||||||
|
then
|
||||||
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}"
|
||||||
|
else
|
||||||
|
echo -e "${red}something went wrong with username ${username}${normal}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
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 = "push" ]
|
||||||
|
then
|
||||||
|
push
|
||||||
|
|
||||||
|
elif [ $command = "link" ]
|
||||||
|
then
|
||||||
|
conf_file=$2
|
||||||
|
if [ -v $conf_file ]
|
||||||
|
then
|
||||||
|
echo -e "${red}no config is given${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
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))
|
||||||
|
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 as well
|
||||||
|
${green}here is your link:${normal}"
|
||||||
|
echo $link
|
||||||
|
|
||||||
|
elif [ $command = "stats" ]
|
||||||
|
then
|
||||||
|
client_stats_proxy_down=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>proxy>>>traffic>>>downlink" 2> /dev/null)
|
||||||
|
server_stats_direct_down=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>direct>>>traffic>>>downlink" 2> /dev/null)
|
||||||
|
if [ ! -z "$client_stats_proxy_down" ] # output is not a zero string, hence script is running on a client
|
||||||
|
then
|
||||||
|
## Client statistics ##
|
||||||
|
echo "Downloaded via server: $(echo $client_stats_proxy_down | pretty_stats)"
|
||||||
|
#
|
||||||
|
client_stats_proxy_up=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>proxy>>>traffic>>>uplink" 2> /dev/null)
|
||||||
|
echo "Uploaded via server: $(echo $client_stats_proxy_up | pretty_stats)"
|
||||||
|
#
|
||||||
|
client_stats_direct_down=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>direct>>>traffic>>>downlink" 2> /dev/null)
|
||||||
|
echo "Downloaded via client directly: $(echo $client_stats_direct_down | pretty_stats)"
|
||||||
|
#
|
||||||
|
client_stats_direct_up=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>direct>>>traffic>>>uplink" 2> /dev/null)
|
||||||
|
echo "Uploaded via client directly: $(echo $client_stats_direct_up | pretty_stats)"
|
||||||
|
elif [ ! -z "$server_stats_direct_down" ] # output is not a zero string, hence script is running on a server
|
||||||
|
then
|
||||||
|
## Server statistics ##
|
||||||
|
echo "Downloaded in total: $(echo $server_stats_direct_down | pretty_stats)"
|
||||||
|
#
|
||||||
|
server_stats_direct_up=$(xray api stats -server=127.0.0.1:8080 -name "outbound>>>direct>>>traffic>>>uplink" 2> /dev/null)
|
||||||
|
echo "Uploaded in total: $(echo $server_stats_direct_up | pretty_stats)"
|
||||||
|
#
|
||||||
|
# Per user statistics
|
||||||
|
conf_file="./conf/config_server.json" # assuming xray is running with this config
|
||||||
|
qemails=$(cat $conf_file | jq ".inbounds[1].settings.clients[].email")
|
||||||
|
for qemail in ${qemails[@]}
|
||||||
|
do
|
||||||
|
echo ""
|
||||||
|
email=$(strip_quotes $qemail)
|
||||||
|
user_stats_down=$(xray api stats -server=127.0.0.1:8080 -name "user>>>${email}>>>traffic>>>downlink" 2> /dev/null)
|
||||||
|
echo "Downloaded by ${email}: $(echo $user_stats_down | pretty_stats)"
|
||||||
|
user_stats_up=$(xray api stats -server=127.0.0.1:8080 -name "user>>>${email}>>>traffic>>>uplink" 2> /dev/null)
|
||||||
|
echo "Uploaded by ${email}: $(echo $user_stats_up | pretty_stats)"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo -e "${red}xray should be running to aquire or reset statistics${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
if [ ! -v $2 ] && [ $2 = "reset" ]
|
||||||
|
then
|
||||||
|
echo ""
|
||||||
|
xray api statsquery -server=127.0.0.1:8080 -reset > /dev/null \
|
||||||
|
&& echo -e "${green}statistics reset successfully${normal}" \
|
||||||
|
|| echo -e "${red}statistics reset failed${normal}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
elif [ $command = "import" ]
|
||||||
|
then
|
||||||
|
if [ -v $2 ] || [ -v $3 ]
|
||||||
|
then
|
||||||
|
echo -e "${red}both directories (from and to) should be set${normal}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
from=$2
|
||||||
|
to=$3
|
||||||
|
# backup the server and the main client configs
|
||||||
|
cp_to_backup ${to}/config_server.json
|
||||||
|
#
|
||||||
|
configs="${from}/config_client_*.json"
|
||||||
|
for c in $configs
|
||||||
|
do
|
||||||
|
if [ -f $c ]
|
||||||
|
then
|
||||||
|
uname_with_json=$(echo $c | cut -d "_" -f 3-) # remove "config_client_"
|
||||||
|
uname_from_filename=${uname_with_json:: -5} # remove ".json"
|
||||||
|
email=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].users[0].email" $c))
|
||||||
|
uname_from_email=${email%@*} # remove "@example.com"
|
||||||
|
if [ $uname_from_filename != $uname_from_email ]
|
||||||
|
then
|
||||||
|
echo -e "${yellow}username ${uname_from_filename} (from filename) inconsistent with username ${uname_from_email} (from email),
|
||||||
|
continue with name from email${normal}"
|
||||||
|
fi
|
||||||
|
if [ -f ${to}/config_client_${uname_from_email}.json ] # username already exists
|
||||||
|
then
|
||||||
|
echo -e "${yellow}username ${uname_from_email} already exists in ${to}, no new config created fot it${normal}"
|
||||||
|
else
|
||||||
|
id=$(strip_quotes $(jq ".outbounds[0].settings.vnext[0].users[0].id" $c))
|
||||||
|
short_id=$(strip_quotes $(jq ".outbounds[0].streamSettings.realitySettings.shortId" $c))
|
||||||
|
# make new user config
|
||||||
|
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
|
||||||
|
# update server config
|
||||||
|
client="
|
||||||
|
{
|
||||||
|
\"id\": \"${id}\",
|
||||||
|
\"email\": \"${uname_from_email}@example.com\",
|
||||||
|
\"flow\": \"xtls-rprx-vision\"
|
||||||
|
}
|
||||||
|
"
|
||||||
|
cp ${to}/config_server.json ${to}/tmpconfig.json
|
||||||
|
ok2=$(cat ${to}/tmpconfig.json | jq ".inbounds[1].settings.clients += [${client}] | .inbounds[1].streamSettings.realitySettings.shortIds += [\"${short_id}\"]" > ${to}/config_server.json)
|
||||||
|
rm ${to}/tmpconfig.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
|
||||||
|
then
|
||||||
|
echo -e "${green}${to}/config_client_${uname_from_email}.json is written, ${to}/config_server.json is updated${normal}"
|
||||||
|
else
|
||||||
|
echo -e "${yellow}something went wrong with username ${uname_from_email}${normal}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
elif [ $command = "upgrade" ]
|
elif [ $command = "upgrade" ]
|
||||||
then
|
then
|
||||||
@@ -336,57 +669,52 @@ 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
|
||||||
echo -e "
|
echo -e "
|
||||||
${green}**** Hi, there! How to use: ****${normal}
|
${green}**** Hi, there! ****${normal}
|
||||||
|
|
||||||
|
The aim of ${italic}easy-xray${normal} is to help to administrate an xray server.
|
||||||
|
It's all about ${italic}conf${normal} directory that contains the server config
|
||||||
|
${italic}config_server.json${normal}, the main client config ${italic}config_client.json${normal} and
|
||||||
|
configs for other users ${italic}config_client_*.json${normal}. How to use it:
|
||||||
|
|
||||||
${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, that asks to download and
|
||||||
XRay and generate configs for server and client
|
install XRay, and to 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 given usernames to configs,
|
||||||
|
usernames should by separated by spaces
|
||||||
|
${bold}del ${underl}usernames${normal} delete users with given usernames from configs
|
||||||
|
${bold}push${normal} copy config to xray's dir and restart xray
|
||||||
|
${bold}link ${underl}config${normal} convert user config to a link acceptable by
|
||||||
|
client applications such as Hiddify or V2ray
|
||||||
|
${bold}stats${normal} print some traffic statistics
|
||||||
|
${bold}stats reset${normal} print statistics then set them to zero
|
||||||
|
${bold}import ${underl}from${normal} ${underl}to${normal} import users from one directory that contains
|
||||||
|
user configs to another directory that contains
|
||||||
|
server config and the main client config
|
||||||
${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
|
|
||||||
"
|
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,89 @@
|
|||||||
|
geosite:cn,
|
||||||
|
domain:cn,
|
||||||
|
domain:xn--fiqs8s,
|
||||||
|
domain:xn--fiqz9s,
|
||||||
|
domain:xn--55qx5d,
|
||||||
|
domain:xn--io0a7i,
|
||||||
|
domain:ru,
|
||||||
|
domain:xn--p1ai,
|
||||||
|
domain:by,
|
||||||
|
domain:xn--90ais,
|
||||||
|
domain:ir,
|
||||||
|
domain:habr.com,
|
||||||
|
domain:habrastorage.org,
|
||||||
|
domain:lenta.com,
|
||||||
|
domain:gldn.net,
|
||||||
|
domain:yastatic.net,
|
||||||
|
domain:yandex.net,
|
||||||
|
domain:mycdn.me,
|
||||||
|
domain:avito.st,
|
||||||
|
domain:gismeteo.st,
|
||||||
|
domain:gismeteo.net,
|
||||||
|
domain:ozonusercontent.com,
|
||||||
|
domain:mradx.net,
|
||||||
|
domain:aestatic.net,
|
||||||
|
domain:pushwoosh.com,
|
||||||
|
domain:vk.com,
|
||||||
|
domain:userapi.com,
|
||||||
|
domain:otm-r.com,
|
||||||
|
domain:2gis.com,
|
||||||
|
domain:championat.com,
|
||||||
|
domain:rus-tv.su,
|
||||||
|
domain:kpcdn.net,
|
||||||
|
domain:kp.house,
|
||||||
|
domain:kp.kg,
|
||||||
|
domain:kaspersky-labs.com,
|
||||||
|
domain:yadro.com,
|
||||||
|
domain:boosty.to,
|
||||||
|
domain:eaglecdn.com,
|
||||||
|
domain:livejournal.com,
|
||||||
|
domain:livejournal.net,
|
||||||
|
domain:edc.sale,
|
||||||
|
domain:stellarlabs.ai,
|
||||||
|
domain:myminsk.com,
|
||||||
|
domain:sputniknews.com,
|
||||||
|
domain:sputnikglobe.com,
|
||||||
|
domain:digikala.com,
|
||||||
|
domain:bale.ai,
|
||||||
|
domain:qq.com,
|
||||||
|
domain:gtimg.com,
|
||||||
|
domain:zhihu.com,
|
||||||
|
domain:geetest.com,
|
||||||
|
domain:zhimg.com,
|
||||||
|
domain:126.net,
|
||||||
|
domain:163.com,
|
||||||
|
domain:25ku.com,
|
||||||
|
domain:sohu.com,
|
||||||
|
domain:bcebos.com,
|
||||||
|
domain:ifengimg.com,
|
||||||
|
domain:taobao.com,
|
||||||
|
domain:bdstatic.com,
|
||||||
|
domain:ad-survey.com,
|
||||||
|
domain:ifeng.com,
|
||||||
|
domain:alicdn.com,
|
||||||
|
domain:jd.com,
|
||||||
|
domain:aliapp.org,
|
||||||
|
domain:aliyun.com,
|
||||||
|
domain:iqiyi.com,
|
||||||
|
domain:mgtv.com,
|
||||||
|
domain:iqiyipic.com,
|
||||||
|
domain:hdslb.com,
|
||||||
|
domain:360buyimg.com,
|
||||||
|
domain:bilibili.com,
|
||||||
|
domain:alibaba.com,
|
||||||
|
domain:xiami.com,
|
||||||
|
domain:yinyuetai.com,
|
||||||
|
domain:ctrip.com,
|
||||||
|
domain:tripcdn.com,
|
||||||
|
domain:c-ctrip.com,
|
||||||
|
domain:fliggy.com,
|
||||||
|
domain:qyerstatic.com,
|
||||||
|
domain:baidu.com,
|
||||||
|
domain:mafengwo.net,
|
||||||
|
domain:meituan.com,
|
||||||
|
domain:dianping.com,
|
||||||
|
domain:bdimg.com,
|
||||||
|
domain:chuimg.com,
|
||||||
|
domain:autonavi.com,
|
||||||
|
domain:amap.com,
|
||||||
|
domain:mmstat.com,
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
geosite:cn
|
||||||
|
domain:cn
|
||||||
|
domain:xn--fiqs8s
|
||||||
|
domain:xn--fiqz9s
|
||||||
|
domain:xn--55qx5d
|
||||||
|
domain:xn--io0a7i
|
||||||
|
domain:ru
|
||||||
|
domain:xn--p1ai
|
||||||
|
domain:by
|
||||||
|
domain:xn--90ais
|
||||||
|
domain:ir
|
||||||
|
domain:habr.com
|
||||||
|
domain:habrastorage.org
|
||||||
|
domain:lenta.com
|
||||||
|
domain:gldn.net
|
||||||
|
domain:yastatic.net
|
||||||
|
domain:yandex.net
|
||||||
|
domain:mycdn.me
|
||||||
|
domain:avito.st
|
||||||
|
domain:gismeteo.st
|
||||||
|
domain:gismeteo.net
|
||||||
|
domain:ozonusercontent.com
|
||||||
|
domain:mradx.net
|
||||||
|
domain:aestatic.net
|
||||||
|
domain:pushwoosh.com
|
||||||
|
domain:vk.com
|
||||||
|
domain:userapi.com
|
||||||
|
domain:otm-r.com
|
||||||
|
domain:2gis.com
|
||||||
|
domain:championat.com
|
||||||
|
domain:rus-tv.su
|
||||||
|
domain:kpcdn.net
|
||||||
|
domain:kp.house
|
||||||
|
domain:kp.kg
|
||||||
|
domain:kaspersky-labs.com
|
||||||
|
domain:yadro.com
|
||||||
|
domain:boosty.to
|
||||||
|
domain:eaglecdn.com
|
||||||
|
domain:livejournal.com
|
||||||
|
domain:livejournal.net
|
||||||
|
domain:edc.sale
|
||||||
|
domain:stellarlabs.ai
|
||||||
|
domain:myminsk.com
|
||||||
|
domain:sputniknews.com
|
||||||
|
domain:sputnikglobe.com
|
||||||
|
domain:digikala.com
|
||||||
|
domain:bale.ai
|
||||||
|
domain:qq.com
|
||||||
|
domain:gtimg.com
|
||||||
|
domain:zhihu.com
|
||||||
|
domain:geetest.com
|
||||||
|
domain:zhimg.com
|
||||||
|
domain:126.net
|
||||||
|
domain:163.com
|
||||||
|
domain:25ku.com
|
||||||
|
domain:sohu.com
|
||||||
|
domain:bcebos.com
|
||||||
|
domain:ifengimg.com
|
||||||
|
domain:taobao.com
|
||||||
|
domain:bdstatic.com
|
||||||
|
domain:ad-survey.com
|
||||||
|
domain:ifeng.com
|
||||||
|
domain:alicdn.com
|
||||||
|
domain:jd.com
|
||||||
|
domain:aliapp.org
|
||||||
|
domain:aliyun.com
|
||||||
|
domain:iqiyi.com
|
||||||
|
domain:mgtv.com
|
||||||
|
domain:iqiyipic.com
|
||||||
|
domain:hdslb.com
|
||||||
|
domain:360buyimg.com
|
||||||
|
domain:bilibili.com
|
||||||
|
domain:alibaba.com
|
||||||
|
domain:xiami.com
|
||||||
|
domain:yinyuetai.com
|
||||||
|
domain:ctrip.com
|
||||||
|
domain:tripcdn.com
|
||||||
|
domain:c-ctrip.com
|
||||||
|
domain:fliggy.com
|
||||||
|
domain:qyerstatic.com
|
||||||
|
domain:baidu.com
|
||||||
|
domain:mafengwo.net
|
||||||
|
domain:meituan.com
|
||||||
|
domain:dianping.com
|
||||||
|
domain:bdimg.com
|
||||||
|
domain:chuimg.com
|
||||||
|
domain:autonavi.com
|
||||||
|
domain:amap.com
|
||||||
|
domain:mmstat.com
|
||||||
@@ -7,8 +7,42 @@
|
|||||||
"loglevel": "warning",
|
"loglevel": "warning",
|
||||||
"dnsLog": false
|
"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
|
// client-side inbound configuration
|
||||||
"inbounds": [
|
"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",
|
"tag": "socks",
|
||||||
"port": 800,
|
"port": 800,
|
||||||
@@ -20,14 +54,16 @@
|
|||||||
"destOverride": [
|
"destOverride": [
|
||||||
"http",
|
"http",
|
||||||
"tls"
|
"tls"
|
||||||
]
|
],
|
||||||
|
"routeOnly": true
|
||||||
},
|
},
|
||||||
// settings of inbound `protocol` (see above)
|
// settings of inbound "protocol" (see above)
|
||||||
"settings": {
|
"settings": {
|
||||||
"auth": "noauth",
|
"auth": "noauth",
|
||||||
"udp": true
|
"udp": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// http/https proxy
|
||||||
{
|
{
|
||||||
"tag": "http",
|
"tag": "http",
|
||||||
"port": 801,
|
"port": 801,
|
||||||
@@ -40,9 +76,9 @@
|
|||||||
"http",
|
"http",
|
||||||
"tls"
|
"tls"
|
||||||
],
|
],
|
||||||
"routeOnly": false
|
"routeOnly": true
|
||||||
},
|
},
|
||||||
// settings of inbound `protocol` (see above)
|
// settings of inbound "protocol" (see above)
|
||||||
"settings": {
|
"settings": {
|
||||||
"auth": "noauth",
|
"auth": "noauth",
|
||||||
"udp": true
|
"udp": true
|
||||||
@@ -105,6 +141,13 @@
|
|||||||
"routing": {
|
"routing": {
|
||||||
"domainStrategy": "AsIs",
|
"domainStrategy": "AsIs",
|
||||||
"rules": [
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"inboundTag": [
|
||||||
|
"api"
|
||||||
|
],
|
||||||
|
"outboundTag": "api"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "field",
|
||||||
"domain": [
|
"domain": [
|
||||||
|
|||||||
@@ -7,11 +7,41 @@
|
|||||||
"loglevel": "warning",
|
"loglevel": "warning",
|
||||||
"dnsLog": false
|
"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" ]
|
||||||
|
},
|
||||||
// Forward each inbound connections to corresponding `outboundTag`. If no rules match,
|
// Forward each inbound connections to corresponding `outboundTag`. If no rules match,
|
||||||
// the traffic is sent out by the first outbound in `outbounds` section.
|
// the traffic is sent out by the first outbound in `outbounds` section.
|
||||||
"routing": {
|
"routing": {
|
||||||
"domainStrategy": "IPIfNonMatch",
|
"domainStrategy": "IPIfNonMatch",
|
||||||
"rules": [
|
"rules": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"inboundTag": [
|
||||||
|
"api"
|
||||||
|
],
|
||||||
|
"outboundTag": "api"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "field",
|
"type": "field",
|
||||||
"port": "80",
|
"port": "80",
|
||||||
@@ -64,6 +94,16 @@
|
|||||||
},
|
},
|
||||||
// server-side inbound configuration
|
// server-side inbound configuration
|
||||||
"inbounds": [
|
"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"
|
||||||
|
},
|
||||||
// main inbound, clients connect to it
|
// main inbound, clients connect to it
|
||||||
{
|
{
|
||||||
"listen": "0.0.0.0",
|
"listen": "0.0.0.0",
|
||||||
@@ -117,9 +157,9 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"destOverride": [
|
"destOverride": [
|
||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls"
|
||||||
"quic"
|
],
|
||||||
]
|
"routeOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// extra inbound; its main purpose is to get fallback to "dest" at port 80. Many regular websites
|
// extra inbound; its main purpose is to get fallback to "dest" at port 80. Many regular websites
|
||||||
@@ -176,9 +216,9 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"destOverride": [
|
"destOverride": [
|
||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls"
|
||||||
"quic"
|
],
|
||||||
]
|
"routeOnly": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||