В данной статье хочу поделиться собственным опытом по настройке всем хорошо известных технологий для маршрутизации трафика до всяких разных ресурсов. Тут не будет подробного описания принципов их работы, на просторах Хабра есть масса статей на эту тематику. Я черпал вдохновение именно оттуда, от себя лично добавить ничего не могу.

Сегодня же хочется сосредоточиться больше на практической реализации с добавлением некоторых фич, которые помогут немного упростить процесс деплоя и переноса сервера, распространения конфигурации на клиенты, минимизируя ручной труд.

Небольшой дисклеймер: В статье нет настройки клиентов под Linux и Android, ибо не пользуюсь. Вот здесь есть хорошие примеры, да и подписка, о которой я расскажу, здорово унифицирует этот процесс. Да и для iOS ограничусь лишь самым базовым.

Лично я познакомился с новым поколением прокси-серверов из материалов многоуважаемого пользователя MiraclePtr. Например, эта публикация послужит отличной иллюстрацией, что такое XTLS и Shadowsocks, о которых пойдет речь ниже.

Общая схема

Для начала определимся, какие инструменты мы хотим использовать и почему.

XTLS Reality

В классической реализации в качестве наживки используется уже существующий сайт, вроде microsoft.com или samsung.com.

У этого подхода есть свои плюсы и минусы, но мы пойдем другим путем и будем использовать прокси в режиме Steal-from-yourself. Принцип точно такой же, только вместо сайта какого-нибудь интернет-гиганта мы будем подсовывать всем любопытным свой собственный, сидящий рядом с нашим прокси-сервером.

Плюсы:

  1. Ниже задержки и, следовательно, чуть выше скорость.

  2. Снаружи это будет выглядеть как просто чей-то любительский сервер (коих легион), на котором что-то делают. Бегают какие-то данные? Мало ли, что там крутится в беке, главное что фронт имеет легитимный сертификат, домен и отдает хоть какое-то содержимое. В относительно спокойные времена (которые, надеюсь, не закончатся) этого должно быть достаточно.

  3. Независимость от желания админов стороннего сайта что-нибудь поменять на своем сервере (или заблокировать, потому что ты их достал).

  4. Нет мороки с поиском и подбором подходящего ресурса, чтобы не вызывать вопросов, почему сайт Samsung отвечает с адреса какого то ноунейм хостера.

  5. Свой сайт позволит нам спрятать на нем файл подписки, с которого клиент будет забирать конфигурацию и обновлять ее в полу- или автоматическом режиме (об этом дальше). Как показала практика, для друзей и знакомых, особенно не очень продвинутых, просто незаменимый вариант.

Минусы:

  1. Нужно платить за свой собственный домен (в теории можно прожить и на каком-нибудь бесплатном DDNS, но у меня уже был оплачен, так что не пробовал).

  2. Если начнется веселье, наш уютный сайт спокойно может полететь в бан в первых рядах. Но мы попробуем компенсировать это скоростью и гибкостью развертывания.

Shadowsocks2022

По моему личному опыту он ощутимо быстрее, чем XTLS. К тому же, только через него у меня завелся Discord (может не разобрался, конечно). Главный минус - его умеют блокировать. Хорошо если блокировка пойдет по протоколу или порту (у нас он все равно генерируется динамически). Хуже, когда в бан отправится целиком IP нашего сервера. Опять же, я сознательно пренебрегаю частью надёжности ради удобства.

Docker

Контейнер есть контейнер. Быстро и просто развернуть, отладить, нет проблем с переносом на другой сервер. Неплохой задел для масштабирования (хоть кластер собирай).

Nginx

Для моих повседневных крайне редких задач он показался достаточно дружелюбным для освоения. По ходу службы нечасто приходится иметь дело с деплоем веб-серверов. По этой же причине поставил перед ним Traefik

Итого, наша схема будет выглядеть следующим образом:

Скрытый текст
Грубая визуализация

Смысл довольно простой. Своих выпускаем в интернет, чужим отдаем страницу с сайтом. Кому надо — зайдет на страницу с конфигом.

Подготовка сервера

Для начала нам нужно разжиться собственным доменом и VPS. Продавцов и того, и другого великое множество, всегда можно найти что-то под свои запросы. Приведу парочку примеров, которые у меня на слуху, чтобы было от чего отталкиваться.

Домены: reg.ru, masterhost.ru, nic.ru

Сервера: hosthatch.com, aeza.net, inferno.name, vdsina.ru

Некоторые VPS хостинги предлагают и домены на продажу. И цены местами вполне ничего.

Знаю, выборка, мягко говоря, не самая лучшая. Но какое то представление о ценах и услугах получить можно. Дальше крутить регулятор паранойи в любую сторону и искать наиболее компромиссный вариант. Разумеется, если хочется перестраховаться, лучше держаться подальше от любого аффилированного с РФ ресурса. Но тут встает вопрос оплаты. Если есть зарубежная карточка - отлично. В противном случае остается криптовалюта, которую принимают не все. Да и больше чем на месяц платить рискованно, мало ли что. Но пока мы ничего не нарушаем, можем потренироваться и на более доступных площадках.

Наконец, перейдем от слов к делу

Итак, у нас на руках есть домен и root пароль для доступа к серверу с Ubuntu, который мы получили при заказе VPS. Предлагаю сразу связать доменное имя и IP адрес сервера. Для этого в личном кабинете, где мы покупали домен, ищем вкладку по типу "домены" или "управление зоной DNS". Далее нас интересует меню создания записей DNS (A, AAAA и так далее). Можно повесить на сервер сразу весь домен, но я бы оставил место для дальнейшего творчества.

Создаем А запись. vpn или proxy будут не самым удачным выбором, по понятным причинам. Я остановился на test. Под этим именем миру будет явлен наш сайт-наживка, а клиентам — адрес для подписки. Сама конфигурация прокси-сервера может быть и с другим именем, на случай если у вас несколько серверов в разных местах. Подтверждаем изменения зоны, обновление может занять до 15 минут.

Проверяем доступ командой ping test.example.com. Пинг пошел — значит все хорошо. Теперь можно подключаться по SSH.

Для подключения используем любой удобный SSH клиент. Меня вполне устраивает Windows Terminal.

ssh root@test.example.com

В первую очередь при входе меняем пароль root. Присланному по почте доверия нет.

passwd

Далее обновляем пакеты

apt update && apt upgrade -y

Создаем нового пользователя, добавляем его в группу sudo

adduser testuser
usermod -aG sudo testuser

Если мы не хотим вводить пароль каждый раз при вызове sudo, можем добавить пользователя в список исключений:

visudo

В конец файла добавляем строку testuser ALL=(ALL) NOPASSWD:ALL

На всякий случай проверим, можем ли мы зайти под ним по SSH

ssh testuser@test.example.com

Создаем пару SSH ключей. Команда работает и в powershell. Пароль можно задать, можно и пропустить, чего я делать не советую. Если ключ угонят, пароль послужит вторым фактором.

ssh-keygen -t rsa -b 4096

Добавляем публичный ключ в папку пользователя. Задаем необходимые разрешения. Не забываем убедиться, что команды выполняем от нашего пользователя testuser.

Если вы до этого сидели по root, то переключиться можно командой su testuser

mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "<вставьте сюда свой публичный ключ>" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Вне зависимости, где создавали ключи, оставляем публичный на сервере, приватный забираем себе и прячем в надёжном месте. И никому не показываем. В Windows нужно ограничить доступ к файлу, иначе при подключении выдаст ошибку «Permissions are too open» (ПКМ — Свойства — Безопасность). В Linux тоже самое — chmod 600 <file>

Проверяем, что мы можем войти по ключу на сервер

ssh -i /path/to/private_key testuser@test.example.com

Чтобы не вводить каждый раз sudo перед командами, можем перескочить на root:

sudo su

Теперь, когда мы убедились, что пользователь настроен, настало время немного подкрутить безопасность. В файле /etc/ssh/sshd_config находим, раскомментируем и меняем следующие строки на:

PermitRootLogin no

PubkeyAuthentication yes

PasswordAuthentication no

KbdInteractiveAuthentication no

Перезапускаем службу

sudo systemctl restart ssh

Этим мы запретим вход под рутом и под любыми другими паролями, оставив только вход по ключу. Данные меры, на мой взгляд, являются необходимыми и вполне достаточными для базовой защиты SSH нашего сервера. В таком виде не представляю, как это проломить извне, но для спокойствия души настроим утилиту fail2ban, чтобы отсекать всех пытающихся. Если они хотят нагадить нам в SSH, то какие гарантии, что не захотят нагадить куда то еще? Тем более, когда выставим наружу дополнительные сервисы. Пусть лучше посидят в бане.

apt install fail2ban

Создаем файл jail.local, где настроим мониторинг

nano /etc/fail2ban/jail.local

Вставляем туда наш конфиг:

jail.local

[DEFAULT]
ignoreip =
bantime.increment = true

[sshd]
mode = aggressive
enabled = true
findtime = 120
maxretry = 3
bantime = 3600

Пройдемся вкратце по параметрам:

  • ignoreip Белый список (через пробел). Советую добавить туда хотя бы один, на случай, если что-то пойдет не так и мы забаним сами себя.

  • bantime.increment Инкрементное увеличение времени бана для самых настойчивых.

  • mode = aggressive Самый сильный режим из доступных. По умолчанию утилита отсекает только явные попытки авторизации на 22 порту, этот же будет блокировать по всем неудачным событиям в журнале.

  • Если в течение findtime секунд произойдет maxretry попыток авторизации, забанить IP на bantime секунд. Настраивайте по вашему вкусу.

Перезапускаем службу

systemctl restart fail2ban.service

Посмотреть, как обстоят дела, можно двумя способами:

fail2ban-client status sshd

Или через лог:

cat /var/log/fail2ban.log

Засим подготовку сервера можно считать законченной. Понятное дело, что безопасность не бывает излишней и сделать можно еще много всего. Но это явно лучше, чем ничего. Да и статья о другом.

Установка Docker

Установка Docker не составляет больших трудностей. Есть несколько способов, мы будем использовать стандартный, вот отсюда. Копируем, вставляем в терминал.

Установка Docker из репозитория
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Сборка конфигурации

Теперь приступим к самому главному.

За основу я взял репозиторий https://github.com/myelectronix/xtls-reality-docker, за что большое спасибо его автору.

Нам понадобятся 2 папки: одна для всего проекта и вторая, куда мы сложим конфиги для сайта. Я назвал ее html. Создадим одним махом:

mkdir -p /home/testuser/my_xtls_server/html

С помощью команды nano создаем файлы и вставляем код.

.env
# Адрес сайта под который будем маскироваться. Для нас это прокси внутри сети Docker
SNI=traefik

# Имя хоста для балансировки traefik. Он же адрес нашего сайта
HOST=

# Настройка для XTLS (по умолчанию)
SHORT_ID=aabbccdd

# Так будут называться профили в клиенте
VLESS_PROFILE_NAME=
SS_PROFILE_NAME=

# Имя файла подписки
NGINX_SUB_FILE=

# Адрес почты для сертификатов LE
LE_ACME_EMAIL=

Файл переменных для docker compose. Не забываем прописать корректный адрес файла подписки

compose.yaml
services:
  xtls-reality:
    container_name: xtls-reality
    restart: always
    network_mode: host
    build: .
    environment:
      - SNI=${SNI}
      - HOST=${HOST}
      - SHORT_ID=${SHORT_ID}
      - VLESS_PROFILE_NAME=${VLESS_PROFILE_NAME}
      - SS_PROFILE_NAME=${SS_PROFILE_NAME}
      - NGINX_SUB_FILE=${NGINX_SUB_FILE}
    volumes:
      - xtls-reality-volume:/opt/xray
      - ./html/${NGINX_SUB_FILE}:/opt/xray/config/${NGINX_SUB_FILE}
    extra_hosts:
      - "traefik:172.228.0.2"
      - "nginx:172.228.0.3"
  
  traefik:
    container_name: traefik
    image: docker.io/traefik:latest
    restart: always
    command:
     - --api.insecure=false
     - --providers.docker=true
     - --providers.docker.exposedbydefault=false
     - --entrypoints.web.address=:80
     - --entrypoints.web.http.redirections.entryPoint.to=https
     - --entrypoints.web.http.redirections.entryPoint.scheme=https
     - --entrypoints.https.address=:443
     - --entrypoints.websecure.http.tls.certresolver=le
     - --certificatesresolvers.le.acme.tlschallenge=true
     - --certificatesresolvers.le.acme.email=${LE_ACME_EMAIL}
     - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
    volumes:
      - ./traefik:/letsencrypt:rw
      - /run/docker.sock:/var/run/docker.sock:ro
    networks:
      xtls-network:
        ipv4_address: 172.228.0.2
  
  nginx:
    container_name: nginx
    image: nginx:latest
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./html:/usr/share/nginx/html:ro
    labels:
      traefik.enable: "true"
      traefik.http.services.nginx.loadbalancer.server.port: "8085"
      traefik.http.routers.nginx.rule: Host(`${HOST}`)
      traefik.http.routers.nginx.tls: "true"
      traefik.http.routers.nginx.entrypoints: https
      traefik.http.routers.nginx.tls.certresolver: le
      traefik.frontend.passHostHeader: "true"
    networks:
      xtls-network:
        ipv4_address: 172.228.0.3
  
volumes:
  xtls-reality-volume:

networks:
  xtls-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.228.0.0/24

Тут хочу пояснить один нюанс, связанный с сетью. Все контейнеры внутри одной docker сети могут общаться между собой по именам. Но у нас прокси-сервер генерирует динамически порт для SS, поэтому должен использовать хостовую сеть. Поэтому мы явно задаем IP всем остальным контейнерам и добавляем их имена в hosts прокси-сервера. Тогда все резолвится как надо.

Docker volume нужен чтобы не пересоздавать конфиг каждый раз при перезапуске контейнера

Dockerfile
FROM alpine:latest

ARG XRAY_CORE_VERSION=v1.8.24

RUN set -e &&\
    apk add --no-cache bash openssl curl &&\
    wget https://github.com/XTLS/Xray-core/releases/download/${XRAY_CORE_VERSION}/Xray-linux-64.zip &&\
    mkdir /opt/xray &&\
    mkdir /opt/xray/config &&\
    unzip ./Xray-linux-64.zip -d /opt/xray  &&\
    rm -rf Xray-linux-64.zip

WORKDIR /opt/xray

COPY config.json config/config.json
COPY client_config_gen.sh .
COPY entrypoint.sh .

EXPOSE 443
ENTRYPOINT [ "/bin/bash","./entrypoint.sh" ]

Версия ядра указывается здесь. По сути он делает все то же самое, что и при установке на голое железо, с добавлением скриптов динамической конфигурации сервера.

entrypoint.sh
#!/bin/bash

LOCKFILE=config/.lockfile
if [ ! -f $LOCKFILE ]
then

#Генерируем UUID для XTLS
echo "Generate UUID..."
/opt/xray/xray uuid > config/uuid

#Создаем пару ключей
echo "Generate public & private keys..."
/opt/xray/xray x25519 > config/keys

#Разбиваем их по файлам
awk '/Public/{print $3}' config/keys > config/public
awk '/Private/{print $3}' config/keys > config/private

#Генерируем пароль для Shadowsocks, если попался слэш, меняем его на произвольный символ
echo "Generate shadowsocks password"
openssl rand -base64 16 > config/ss_pass
cat config/ss_pass
sed -i 's|/|X|g' config/ss_pass
SS_PASS=$(cat config/ss_pass)

#Генерируем случайный порт для SS
echo $((RANDOM % 15000 + 49152)) > config/ss_port
SS_PORT=$(cat config/ss_port)

# Задаем переменные
UUID=$(cat config/uuid)
PRIVATE=$(cat config/private)

#Наполням config.json созданными параметрами

sed -i 's/"id":.*/"id": "'${UUID}'",/' config/config.json

sed -i 's/"privateKey":.*/"privateKey": "'${PRIVATE}'",/' config/config.json

sed -i 's|"password":.*|"password": "'${SS_PASS}'",|' config/config.json

sed -i 's|"port": 12345,|"port": '${SS_PORT}',|' config/config.json

sed -i 's/"dest":.*/"dest": "'${SNI}':443",/' config/config.json

sed -i '/serverNames/{n;s/.*/\t\t\t\t"'${HOST}'"/}' config/config.json

sed -i '/shortIds/{n;s/.*/\t\t\t\t"'${SHORT_ID}'"/}' config/config.json

touch $LOCKFILE
fi

#Запускаем сервер
echo "XTLS reality starting..."
bash client_config_gen.sh
/opt/xray/xray run -config /opt/xray/config/config.json 

Этот скрипт выполнится перед запуском сервера и заполнит файл конфигурации созданными значениями.

client_config_gen.sh
#!/bin/bash
# Забираем параметры из сгенерированных файлов
UUID=$(cat config/uuid)
PUB_KEY=$(cat config/public)
SS_PASS=$(cat config/ss_pass)
SS_PORT=$(cat config/ss_port)

# Кодируем конфиг для SS, некоторые клиенты не распознают его в чистом виде
ENCODED=$(echo -n "2022-blake3-aes-128-gcm:${SS_PASS}@${HOST}:${SS_PORT}" | base64 -w0)

# Формируем файл подписки
echo "vless://${UUID}@${HOST}:443?security=reality&encryption=none&pbk=${PUB_KEY}&headerType=none&fp=chrome&type=tcp&flow=xtls-rprx-vision&sni=${HOST}&sid=${SHORT_ID}#${VLESS_PROFILE_NAME}" > config/${NGINX_SUB_FILE}
echo "ss://${ENCODED}#${SS_PROFILE_NAME}" >> config/${NGINX_SUB_FILE}

Cобираем конфиги для клиента и формируем тот самый файл подписки. По какой-то причине, клиент для iOS не хотел принимать голый конфиг SS, но после упаковки в base64 все подтянулось нормально.

config.json
{
  "log": {
    "loglevel": "info"
  },
  "routing": {
    "rules": [
      {
        "type": "field",
        "protocol": "bittorrent",
        "outboundTag": "block"
      }
    ],
    "domainStrategy": "IPIfNonMatch"
  },
  "inbounds": [
    {
      "port": 443,
      "protocol": "vless",
      "tag": "vless_tls",
      "settings": {
        "clients": [
          {
            "id": "",
            "flow": "xtls-rprx-vision"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
		"realitySettings": {
			"show": false,
			"dest": "",
			"xver": 0,
			"serverNames": [
				""
			],
			"privateKey": "",
			"minClientVer": "",
			"maxClientVer": "",
			"maxTimeDiff": 0,
			"shortIds": [
				"aabbccdd"
			]
		}
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls",
          "quic"
        ]
      }
    },
    {
      "port": 12345,
      "protocol": "shadowsocks",
      "settings": {
        "method": "2022-blake3-aes-128-gcm",
        "password": "",
        "network": "tcp,udp"
       },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls",
          "quic"
        ]
      }
    }  
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "tag": "direct"
    },
    {
      "protocol": "blackhole",
      "tag": "block"
    }
  ]
}

Стандартный конфиг для настройки. Добавлена блокировка торрентов, на всякий случай. Не смотрите на порт 12345 у Shadowsocks. Это мой костыль, чтобы можно было легко найти и заменить на нормальный при настройке в entrypoint.sh.

nginx.conf
worker_processes 1;

events {
    worker_connections 1024;
}

http {
    server {
        listen 8085;
        server_name test.example.com;
        include /etc/nginx/mime.types;

        location / {
            root /usr/share/nginx/html;
            limit_rate 128k;
	    add_header X-Robots-Tag "noindex, nofollow";
        }
	location /XXXXX {
	    root /usr/share/nginx/html;
	    limit_rate 128k;
	    add_header Cache-Control 'must-revalidate';
	    add_header Content-Type text/plain;
	    try_files /XXXXX =404;
	    autoindex off;
	    add_header X-Robots-Tag "noindex, nofollow";
	}
    }
}

Лучшее, на что я способен при работе с nginx. Вместо XXXXX вставляем любую рандомно сгенерированную строку. Чем рандомнее — тем лучше. Не забываем создать соотв. файл в папке html и прописать его в .env. По этому адресу будут доступны настройки нашего прокси. И не забываем прописать домен. Остальные параметры предполагают ограничение доступа роботам и урезание скорости до минимума на нашем сайте-заглушке.

Index.html может быть абсолютно любым, в теории даже пустым. Есть, где проявить фантазию

Развертывание

После того как мы заполнили все поля, пора запускать нашу систему:

docker compose -f /path/to/compose.yml up -d

Посмотреть список контейнеров:

docker ps -a

Посмотреть логи выбранного контейнера:

docker logs <id or name>

Завершить работу:

docker compose down

Если мы хотим пересоздать конфигурацию, добавляем параметр -v в последнюю команду. Это удалит docker volume, в котором лежат все настройки сервера.

Настройка клиента Windows

В качестве клиента я использую NekoBox. Скачать его можно с GitHub разработчика

Перво-наперво идем вот сюда и скачиваем 2 файла: geoip.dat и geoip.db. Копируем с заменой в корень NekoВox. Это база всех заблокированных IP в РФ (известно кем). Она поможет нам с маршрутизацией.

Запускаем программу, открываем Настройки и идем по порядку.

На вкладке Группы добавляем новую, тип Подписка, придумываем название и вставляем адрес нашего файла с настройками (test.example.com/та_самая_рандомная_строка). Подтверждаем, нажимаем Обновить. Если все настроено верно, в главном окне появится вкладка группы со списком наших серверов.

Далее у нас Основные настройки. В разделе Общие прописываем URL теста задержки. В моей версии клиента вариант по умолчанию почему-то не работал.

http://www.gstatic.com/generate_204

В разделе Подписка ставим галочку автообновления подписок, настраиваем интервал. И очистку списка серверов при обновлении. Это поможет не столько нам (можно и на кнопку нажать), сколько нашим друзьям и родственникам.
Опция работает немного странно, активное подключение не удаляется при очистке и в окне будут висеть два одинаковых сервера. И если меняется конфигурация, то пропадет соединение с интернетом. Фиксится отключение.

В разделе Безопасность обязательно выставляем uTLS по умолчанию. Я использую chrome

Последнее, но не по значимости, это Маршруты

В разделе Общие выставляем "Подслушивать для маршрутизации", в стратегиях выставляем ipv4_only. Насколько я понял, это не самый оптимальный вариант, но у меня кривовато работало с ipv6. С тех пор, как поменял — горя не знал.

В разделе DNS прописываем удаленный DNS https://8.8.8.8/dns-query Стратегии также оставляем ipv4_only.

На вкладке Базовые маршруты добавляем в колонку Прокси geoip:antizapret и geosite:antizapret в IP и Домен соответственно

Outbound по-умолчанию ставим bypass. Таким образом мы используем маршрутизацию по белому списку и сами решаем, что пойдет в прокси. Все остальное пойдет напрямик. Еще поделюсь своим кастомным списком доменов, вдруг пригодится:

Скрытый текст
domain:youtube.com
domain:youtu.be
domain:yt.be
domain:googlevideo.com
domain:ytimg.com
domain:ggpht.com
domain:gvt1.com
domain:youtube-nocookie.com
domain:youtube-ui.l.google.com
domain:youtubeembeddedplayer.googleapis.com
domain:youtube.googleapis.com
domain:youtubei.googleapis.com
domain:yt-video-upload.l.google.com
domain:wide-youtube.l.google.com
domain:habr.com
domain:chatgpt.com
domain:openai.com
domain:discord.gg
domain:discord.com
domain:discordapp.com
domain:discord.media
domain:discordapp.net
domain:discordcdn.com
domain:discord.dev
domain:discord.new
domain:discord.gift
domain:discordstatus.com
domain:dis.gd
domain:discord.co
domain:byspotify.com
domain:pscdn.co
domain:scdn.co
domain:spoti.fi
domain:spotify-everywhere.com
domain:spotify.com
domain:spotify.design
domain:spotifycdn.com
domain:spotifycdn.net
domain:spotifycharts.com
domain:spotifycodes.com
domain:spotifyforbrands.com
domain:spotifyjobs.com
domain:audio-ak-spotify-com.akamaized.net
domain:audio4-ak-spotify-com.akamaized.net
domain:cdn-spotify-experiments.conductrics.com
domain:heads-ak-spotify-com.akamaized.net
domain:heads4-ak-spotify-com.akamaized.net
domain:spotify.com.edgesuite.net
domain:spotify.map.fastly.net
domain:spotify.map.fastlylb.net
domain:spiceworks.com
domain:teamviewer.com

Жмем ОК, закрываем окно с настройками, переходим на вкладку нашей группы и сперва проверяем, есть ли связь с серверами. Жмем ПКМ - Текущая группа - Полный тест. Ставим галочки, ждем, смотрим, все ли отработало корректно. Если все хорошо, подключаемся к любому серверу, ставим галочку "Режим системного прокси". Заходим в браузер и пробуем открыть какой-нибудь ранее недоступный ресурс. Если открывается — празднуем победу. Если нет — фиксим ошибки и тогда уже празднуем.

В защиту именно такого подхода скажу, что он позволяет не париться с фильтрацией RU ресурсов и, самое главное, не пускает в прокси всякий хлам по типу обновлений винды, загрузок Steam и всего остального софта, который умеет только в системный прокси. За несколько месяцев эксплуатации мне пришлось добавить всего пару доменов, которые блокировали пользователей из РФ + Ютуб, ибо блокировка последнего не имеет законных оснований и потому в список не попадает. Со всем остальным база справляется прекрасно.

Клиенты для iOS

Для iOS я использовал 2 клиента: FoXray и Shadowrocket. Первый бесплатный, второй, соответственно, платный. Но как по мне он стоит своих денег как минимум за то, что у него оказался внезапный клиент под AppleTV.

Настройка благо и там и там не очень сложная. Нажимаем на «+», находим в списке протоколов Subscription, вставляем туда адрес нашего сервера, сохраняем. Сами конфиги подтянутся автоматом.

Дополнительно можно добавить в исключение зону RU, в Shadowrocket это делается в Настройках — default.conf — Общее — Пропустить прокси — добавить *.ru.

Заключение

Как то так, в общем. Спасибо за внимание.