Всё описанное ниже — результат технического эксперимента. Материал не является рекламой, не призывает к каким-либо действиям, носит исключительно ознакомительный характер и подготовлен в рамках исследования.
Основной источник информации репозиторий на GitHub
VPS сервер
VPS можно купить где угодно с возможность оплачивать всем чем только можно и даже криптой. В качестве рабочих примеров timeweb.cloud, hostmenow.org, regxa.com. Как итог на руках должны быть логин и пароль от сервера с Debian, на котором есть белый ip адрес. В качестве примера возьмем 10.10.10.10
Domain
Приобретаем доменное имя. Проще всего сделать это там же где и был куплен VPS. Если есть желание сэкономить, можно пойти на spaceship.com, а можно купить и на reg.ru, в общем варинтов тоже много, цена будет зависеть исключительно от того что будет выбрано. В качестве примера example-site.com
DNS
Там же где и купили домен, прописываем белый адрес в DNS записи, что бы весь мир узнал своих героев! Выглядить будет примерно вот так:
- record 1
- Type - A (IPv4 address)
- Name - example-site.com
- Value - 10.10.10.10
- TTL - выбрать самое минимальное значение, например “1 hour”
- record 2
- Type - A (IPv4 address)
- Name - www.example-site.com
- Value - 10.10.10.10
- TTL - выбрать самое минимальное значение, например “1 hour”
Некоторые провайдеры в полях Name хотят видеть иные записи:
- вместо example-site.com - @
- вместо www.example-site.com - www
После того как всё прописано надо ждать… Что бы узнать о распространение DNS записи переодически можно делать:
sudo dig example-site.com
В поле ANSWER должно быть НЕ 0.
nginx
Пока записи распространяются, можно установить и настроить nginx:
Обновляем репозитории и ставим пакет:
sudo apt update && sudo apt install nginx -y
Создаем рабочую папку для сайта:
sudo mkdir -p /var/www/example-site
sudo chown -R $USER:$USER /var/www/example-site
Создаем тестовую страницу:
sudo echo "<h1>[ THE EXAMPLE SITE: OPERATIONAL ]</h1>" > /var/www/example-site/index.html
Создаем файл конфигурации:
sudo mcedit /etc/nginx/sites-available/example-site
и добавляем в него
server {
listen 80;
server_name example-site.com www.example-site.com;
root /var/www/example-site;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Создаем символическую ссылку и активируем:
sudo ln -s /etc/nginx/sites-available/example-site /etc/nginx/sites-enabled
Удаляем стандартный конфиг:
sudo rm /etc/nginx/sites-enabled/default
sudo rm /etc/nginx/sites-available/default
Проверяем систему на ошибки и перезапускаем:
sudo nginx -t
sudo systemctl restart nginx
Последний пункт “Золотое правило nginx” - создал/изменил, проверил, рестартанул
Рекомендуется оформить страницу сайта, как рабочую. Для этого можно попросить любую нейронку сгенирировать её
SSL
Когда у в поле ANSWER появился не 0, получаем сертификат. Для этого устанавливаем бота Let’s Encrypt, который будет заботиться об этом.
sudo apt update && sudo apt install certbot python3-certbot-nginx -y
Затем получаем сертификат (если в поле ANSWER 0, то сертификат получить не удастся):
sudo certbot --nginx -d example-site.com -d www.example-site.com
- Бот спросит email для уведомлений о продлении.
- Попросит согласиться с условиями.
- Cпросит, нужно ли делать Redirect (перенаправление с http на https) - выбираем ДА
- Бот перепишет конфиг Nginx и добавит туда защиту.
Сертификаты Let’s Encrypt живут 90 дней. Certbot создает задачу в планировщике для автопродления, проверить это можно командой:
sudo certbot renew --dry-run
В итоге заходя на сайт “example-site.com” с локальной машины подключение должно пройти по https и никто не должен ругаться.
Подготовка nginx
Чтобы и сайт, и Xray жили на 443 порту, нам понадобится реализовать fallback - откат при запросе сайта. Xray станет главным, он первым принимает входящие соединения на 443 порту и делает следующее:
если стучится VPN-клиент с правильным ключом — Xray его пропускает;
если заходит обычный пользователь или бот-сканер — Xray перекидывает запрос на локальный сайт.
Так как сайт сейчас слушает 443 порт, его необходимо перевести на другой порт (например 8443), который будет доступен только внутри сервера (localhost). Для этого правим конфигурацию, которую отредактировал бот Let’s Encrypt:
sudo mcedit /etc/nginx/sites-available/example-site
и меняем
server {
server_name example-site.com www.example-site.com;
root /var/www/example-site;
index index.html;
location / {
try_files $uri $uri/ =404;
}
# BEFORE: listen 443 ssl; # managed by Certbot
# AFTER:
listen 127.0.0.1:8443 ssl;
ssl_certificate /etc/letsencrypt/live/example-site.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example-site.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.example-site.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = example-site.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example-site.come www.example-site.com;
return 404; # managed by Certbot
}
После сохранения проверяем и рестартуем:
sudo nginx -t && sudo systemctl restart nginx
Стоит отметить важное замечание по безопасности: Необходимо убедитесь, что порт 8443 закрыт снаружи и доступен только для 127.0.0.1. Проверить можно с помощь:
sudo ss -tulpn
Вывод должен содержать запись
127.0.0.1:8443
больше порт 8443 “висеть” нигде не должен.
Xray
Установка Xray из официального скрипта:
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
Команда скачает последнюю версию Xray и создаст системную службу.
Генерация ключей и UUID
Для работы протокола Reality необходимо сгенирировать ключи:
sudo xray x25519
После выполнения команды получаем Private key, Password и Hash32. Их необходимо сохранить в блокнот. Приватный ключ пойдет в конфиг сервера, а пароль — в настройки клиента.
Также сгенерируем и сохраним UUID (пароль):
sudo xray uuid
и короткое имя сервера (shortId), естественно сохранить:
sudo openssl rand -hex 8
Настройка конфигурации
Когда есть все необходимые данные, требуется отредактировать конфигурационный файл Xray сервера:
sudo mcedit /usr/local/etc/xray/config.json
и прописать в нем следующее:
{
"log": {
"loglevel": "warning",
"access": "/var/log/xray/access.log",
"error": "/var/log/xray/error.log"
},
"inbounds": [
{
"listen": "IP_ADDRES",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "UUID",
"flow": "xtls-rprx-vision",
"level": 0,
"email": "SOME-NAME"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "127.0.0.1:8443"
}
]
},
"streamSettings": {
"network": "raw",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "127.0.0.1:8443",
"xver": 0,
"serverNames": [
"example-site.com",
"www.example-site.com"
],
"privateKey": "PRIVATE_KEY",
"shortIds": [
"SHORTID"
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
]
}
При этом на место “PRIVATE_KEY”, “UUID”, “SHORTID” вставить свои, ранее полученные значения, а в поле “IP_ADDRES” подставить белый ip адрес (это поле можно удалить, тогда будудет Xray будет слушать на всех интерфейсах). “SOME-NAME” - любое имя для дальнейшей идентификации пользователя.
После обновления конфигурации проверяем, что всё работает:
sudo xray -test -config /usr/local/etc/xray/config.json
Если есть сообщение “Configuration OK”, то рестартуем, если нет, то можно загнать конфигу в кокой-нибудь автоформатер, например сюда.
sudo systemctl restart xray && sudo systemctl status xray
Также проверим, что всё в порядке с портами - Xray должен занять 443 порт.
sudo ss -tulpn
После чего сайт должен снова быть доступен.
BBR
Bottleneck Bandwidth and Round-trip propagation time (BBR) — это алгоритм управления перегрузками для протокола TCP.
Редактируем репозитории
sudo mcedit /etc/apt/sources.list
Добавляем следующую строку в конец файла и сохраняем его:
deb http://archive.debian.org/debian buster-backports main
Обновляем список доступных пакетов и устанавливаем последюю версию
sudo apt update && sudo apt -t buster-backports install linux-image-amd64
Редактируем файл конфигурации sysctl.conf и включаем BBR
sudo mcedit /etc/sysctl.conf
Добавляем следующие строки в конец файла:
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
Ребутаем VPS
sudo reboot
Для проверки работы bbr:
lsmod | grep bbr && lsmod | grep fq
Видим что-то вроде:
tcp_bbr 21450 90
sch_fq 21450 2
IPhone, Android, MacOS, Windows
Чтобы добавить еще одного пользователя достаточно добавить новый объект в массив “clients” внутри существующего конфига. Каждый клиент должен иметь свой уникальный UUID. Для этого генерируем новый UUID и добавляется в соотвествубщее поле. Xray поймет, кто именно подключился, по значению UUID в заголовке пакета.
Формирование ссылки
Ссылку можно делать руками, а можно и нельзя… Создаем файл скрипта:
sudo mcedit ./link_former.py
и вставляем код:
#! /bin/python3
import json
import uuid
import subprocess
import urllib.parse
def restart_xray():
try:
subprocess.run(["systemctl", "restart", "xray"], check=True)
print("Xray service restarted successfully.")
except subprocess.CalledProcessError:
print("Error restarting Xray. Check permissions (sudo).")
def add_or_update_user():
config_path = '/usr/local/etc/xray/config.json'
username = input("Enter username: ")
public_key = input("Enter Password: ")
try:
with open(config_path, 'r+') as f:
config = json.load(f)
inbound = config['inbounds'][0]
clients = inbound['settings']['clients']
# Search and overwrite
existing_user = next((c for c in clients if c.get('email') == username), None)
user_id = str(uuid.uuid4())
if existing_user:
existing_user['id'] = user_id
print(f"\nUser '{username}' updated.")
else:
clients.append({"id": user_id, "flow": "xtls-rprx-vision", "email": username, "level": 0})
print(f"\nUser '{username}' added.")
f.seek(0)
json.dump(config, f, indent=2)
f.truncate()
# Parameters from the config
stream_settings = inbound['streamSettings']
reality = stream_settings['realitySettings']
# Build query parameters
params = {
"encryption": "none",
"flow": "xtls-rprx-vision",
"security": "reality",
"sni": reality['serverNames'][0],
"fp": "chrome",
"pbk": public_key,
"sid": reality['shortIds'][0],
"type": "raw"
}
query_string = urllib.parse.urlencode(params)
link = f"vless://{user_id}@{reality['serverNames'][0]}:{inbound['port']}?{query_string}#{username}"
print(f"\nReady link:\n{link}\n")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
add_or_update_user()
restart_xray()
Даем права на испольнения
sudo chmod 755 ./link_former.py
После запуска
./link_former.py
Скрипт попросит ввести:
- новое имя пользователя - вводим то что нравится
- пароль, который получили при генерации ключей
В итоге сформируется ссылка, которая будет использоваться для конфигурации клиента.
v2Box (Android, IPhone, MacOS)
Для работы на мобильных телефонах IPhone и компьютерах MacOS используется приложение v2Box, для Android - v2rayNG. Эти приложения пробросывают весь трафик на ваш Xray сервер.
Что бы подключиться необходимо:
- установить v2Box;
- скопировать полученную конфигурационную ссылку;
- в приложении перейти в пункт “Конфигурации”;
- нажать плюс (+) и выбрать “Импортировать v2ray URI из буфера”.
v2rayN (Windows)
Для Windows есть разные варианты c графической оболочкой, один из самых популярных v2rayN:
- переходим в официальный репозиторий;
- скачиваем релищ под необходимую архитектуру и распаковывем;
- запускаем исполняемый файл “v2rayN.exe” от имени администратора;
- заходим в пункт “Configuration”;
- выбираем “Import Share link from clipboard”;
- подтверждаем “Confirm”;
- в нижней части окна программы переводим бегунок “Enable Tun” во включенное положение;
- в окне “System proxy” (справа от Enable Tun) выбираем “Set system proxy”
- в окне “Routing” (справа от System proxy) выбираем “V4-Global”
Linux (cli)
Сначала требуется сформировать конфигурацию и затем уже на её основе использовать клиентов Xray. Файл с настройками клиента можно сформировать руками, а можно не руками:
sudo mcedit ./json_former.py
и вставляем код:
#! /bin/python3
import json
import uuid
import subprocess
def restart_xray():
try:
subprocess.run(["systemctl", "restart", "xray"], check=True)
print("Xray service restarted successfully.")
except subprocess.CalledProcessError:
print("Error restarting Xray. Check permissions (sudo).")
def add_or_update_user():
config_path = '/usr/local/etc/xray/config.json'
username = input("Enter username: ")
public_key = input("Enter Password: ")
try:
with open(config_path, 'r+') as f:
config = json.load(f)
inbound = config['inbounds'][0] # Get the first inbound
clients = inbound['settings']['clients']
# Search and overwrite
existing_user = next((c for c in clients if c.get('email') == username), None)
user_id = str(uuid.uuid4())
if existing_user:
existing_user['id'] = user_id
print(f"\nUser '{username}' updated.")
else:
clients.append({"id": user_id, "flow": "xtls-rprx-vision", "email": username, "level": 0})
print(f"\nUser '{username}' added.")
f.seek(0)
json.dump(config, f, indent=2, ensure_ascii=False)
f.truncate()
# Parameters from the config
stream_settings = inbound['streamSettings']
reality = stream_settings['realitySettings']
client_config = {
'log': {
'loglevel': 'warning'
},
'dns': {
"hosts": {
reality['serverNames'][0]: inbound['listen']
},
"servers": [
"8.8.8.8",
"1.1.1.1",
"8.8.4.4"
],
},
"inbounds": [
{
"tag": "socks",
"port": 10808,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": True,
"destOverride": ["http", "tls", "quic"],
"routeOnly": False
},
"settings": {
"auth": "noauth",
"udp": True
}
}
],
"outbounds": [
{ "tag": "proxy",
"protocol": "vless",
"settings": {
"address": reality['serverNames'][0],
"port": inbound['port'],
"id": user_id,
"encryption": "none",
"flow": "xtls-rprx-vision",
"level": 0
},
"streamSettings": {
"network": "raw",
"security": "reality",
"realitySettings": {
"serverName": reality['serverNames'][0],
"fingerprint": "chrome",
"show": False,
"publicKey": public_key,
"shortId": reality['shortIds'][0]
}
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"network": "tcp,udp",
"nonIPQuery": "drop"
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"inboundTag": ["socks"],
"port": 53,
"network": "tcp,udp",
"outboundTag": "dns-out"
},
{
"type": "field",
"inboundTag": ["socks"],
"outboundTag": "proxy",
"network": "tcp,udp"
}
]
}
}
client_filename = f"{username}_client.json"
with open(client_filename, 'w') as cf:
json.dump(client_config, cf, indent=2, ensure_ascii=False)
print(f"\nConfiguration saved to file: {client_filename}")
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
add_or_update_user()
restart_xray()
Даем права на испольнения
sudo chmod 755 ./json_former.py
И запускаем. Смысл такой же как и в “link_former.py”
sudo ./json_former.py
Для Linux существуют версии и с графической оболочкой, например тот же v2rayN, но для консольной версии самый простой способ — использовать само ядро Xray-core.
Установка Xray официальным скриптом:
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
Проверяем конфигурацию и заодно сам Xray:
sudo xray -test -config NEW_CLIEN_CONFIG.json
Что бы пробросить весь трафик через socks туннель, сначала его необходимо завернуть на виртуальный интерфейс. Это можно сделать с помощью tun2proxy. Для этого идем на оффициальный репозиторий и копируем ссылку под необходимую архитектуру. Для примера возьмем x86.
sudo wget https://github.com/tun2proxy/tun2proxy/releases/latest/download/tun2proxy-x86_64-unknown-linux-gnu.zip
Распаковываем и даём права:
sudo unzip ./tun2proxy-x86_64-unknown-linux-gnu.zip && chmod +x tun2proxy-bin
Перемещаем и проверяем что всё готово:
sudo mv tun2proxy-bin /usr/local/bin/tun2proxy && tun2proxy --version
Далее запускаем Xray:
sudo xray run -c client_config.json
и в соседнем окне tun2proxy:
sudo tun2proxy --setup --proxy socks5://127.0.0.1:10808
На место [IP_ADDRESS] необходимо подставить белый ip сервера.
Следует оговориться, что этот трюк можно провернуть и иным способом, не через socks, а transparent proxy (tproxy), но тогда не следует забывать и про маршрутизацию, в лучше случае nftables, а где-то и вовсе iptables. По этому socks…
Управление маршрутами и блокировками
Что бы более гибкого управлять трафиком (например что-то слать через Vray, а что-то напрямую через провайдера), можно исправить конфигурацию и добавить дополнительные правила - “rules” в блоке “routing”.
Для блокировки рекламы, аналитики и исключения работы с уязвимыми протоколами используются блоки которые отправляют весь трафик по тегу “block” из конфигурации тем самым блокируя его:
{
"_note": "Vulnerable prots",
"type": "field",
"inboundTag": ["socks-in"],
"outboundTag": "block",
"network": "udp",
"port": "135,137,138,139"
},
{
"_note": "Adds blocking",
"type": "field",
"inboundTag": ["socks-in"],
"domain": ["geosite.dat:category-ads-all"],
"outboundTag": "block"
}
“Specific IP address” и “Block ads”. Вставлять дополнительные настройки необходимо по такому же принципу, как располагаются уже существующие. Следует выделить два подхода:
- Автоматический
{
"_note": "Domain names",
"type": "field",
"inboundTag": ["socks-in"],
"domain": ["geosite:private", "geosite:category-ru"],
"outboundTag": "direct"
},
{
"_note": "IP addresses",
"type": "field",
"inboundTag": ["socks-in"],
"ip": ["geoip:private", "geoip:ru"],
"outboundTag": "direct"
}
- geosite:private - БД с доменными именами, из которой взяты локальные домены (localhost, .local, .lan)
- geosite:category-ru - БД с доменными именами, из которой взяты популярные домены в зоне .ru, .su, .рф
- geoip:private - БД с ip адресами, из которой взяты диапазоны «серых» IP-адресов (192.168.x.x, 10.x.x.x, 127.0.0.1)
- geoip:ru - БД с ip адресами из которой взяты все диапазоны IP-адресов, зарегистрированные за российскими провайдерами
Таким образом, применя эти настройки часть трафика пойдет без vray - direct. Остальная часть, отправится через Vray.
- Ручной
{
"_note": "Manual proxing",
"type": "field",
"domain": [
"domain:2ip.io",
"domain:youtube.com"
],
"outboundTag": "vless-reality"
},
{
"_note": "Manual directing",
"type": "field",
"domain": [
"domain:yandex.ru",
"domain:vk.ru"
],
"outboundTag": "direct"
}
- direct - отправить без Vray
- proxy - отправить через Vray
Применя эти настройки часть трафика пойдет без vray - direct. Остальная часть, отправится через Vray - proxy.
Ознакомиться со списком доменов, ip адресами, обновить базу и узнать про ещё более гибкие настроки можно в репозитории на GitHub.