Перейти к содержанию

Настройка разделение трафика с использование Wireguard


Рекомендуемые сообщения

  • Эксперты

Вступление или зачем нам вообще это надо?

В наше интересное время все чаше приходиться использовать VPN, но тут начинается другая проблема часть местных интернет ресурсов может быть недоступна через сервер VPN. И начинается постоянное передергивание включения выключения VPN соединения.

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

Практически все материалы по разделению трафика были заимствованы и доработаны из статьи с хабр Укрощаем одноглазого змея. Разбираемся с WireGuard и делаем свой умный VPN я не претендую на авторство метода, скриптов или любых материалов из оригинальной статьи. А так же настоятельно рекомендую ознакомиться с оригиналом статьи для лучшего понимания идеи.

Цель данной публикации познакомить с вариантом разделения трафика, предоставить сжатую инструкцию по настройке. Так же в отличии от оригинальной статьи настройка выполнялась с установкой веб интерфейса в виде wg-easy так как ручная генерация новых клиентов описанная автором мне кажется мягко говоря неудобной и не оправданной.

Для реализации надо:

1.       Удаленный сервер с настроенным wg сервером

2.       Локальная машина Linux (желательно виртуальная отдельно от других приложений) для работы достаточно 256 мб ОЗУ но зависит от количества клиентов и объема трафика.

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

Выполним первоначальную настройку сервера для установки. Основная настройка будет выполнятся с использованием скрипта, но для создания клиентских подключений используется wg-easy установленным с использованием docker-compose.

Обновляем репозитории и пакеты:

apt update -y &&
apt upgrade -y

Устанавливаем Docker:

apt install curl && curl -fsSL https://get.docker.com -o get-docker.sh  && sh get-docker.sh

Запускаем и включаем службу Docker

systemctl start docker  && systemctl enable docker

Устанавливаем Docker Compose:

curl -L --fail https://raw.githubusercontent.com/linuxserver/docker-docker-compose/master/run.sh -o /usr/local/bin/docker-compose  && chmod +x /usr/local/bin/docker-compose

Так же устанавливает пакеты необходимые для работы wg и скрипта настройки маршрутов.

apt install -y wireguard iptables ipcalc qrencode curl jq traceroute net-tools netscript

Настройка соединения с внешним сервером

Наш внутренний сервер подключается как клиент к внешнему серверу с настроенным wireguard. Для этого на внешнем сервере разворачиваем серверную часть wg (рекомендую использовать скрипты dwg) или заходим на ранее созданный и генерируем нового клиента.

Нам необходимо получить файл конфигурации для подключения клиента вида:

[Interface]
PrivateKey = <Seckret>
Address = 10.10.10.14/24
DNS = 10.2.0.100
MTU = 1280

[Peer]
PublicKey = <Seckret>
PresharedKey = <Seckret>
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Endpoint = <Seckret>:51820

Данные этого файла конфигурации необходимо в неизменном виде разместить в wg-external.conf

cd /etc/wireguard
nano wg-external.conf

Запускаем туннель до внешнего сервера

wg-quick up wg-external

Для проверки работы туннеля команда wg

 

image.png.b6b79a33a79193d50b7120dea48f72d9.png

На текущий момент мы получили такую схему подключения

 

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

Настройка клиентской части внутреннего сервера

Для настройки клиентской части был выбран WG-EASY но можно использовать любой вариант настройки wg от ручного как предлагает автор оригинальной статьи так и различные графические интерфейсы.

Создадим каталог с docker-compose файлом для запуска wg-easy

mkdir wg-easy && cd wg-easy
nano docker-compose.yml

Вставляем в файл следующее содержимое

version: "3"
services:
  wg-easy:
    environment:
      - WG_HOST=192.168.0.132
      - PASSWORD=MySecretPassword
      - WG_PORT=51820
      - WG_DEFAULT_ADDRESS=10.10.9.x
      - WG_DEFAULT_DNS=192.168.0.1
      - WG_ALLOWED_IPS=0.0.0.0/0, ::/0
      - WG_MTU=1280
    image: ditek/wg-easy
    container_name: wg-easy
    volumes:
      - /wg-easy:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    dns:
      - 192.168.0.1

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

В параметр WG_HOST указываем IP адрес в вашей сети по которому можно будет обратиться к серверу WG. Сервер разделения трафика должен иметь фиксированный IP адрес.

В параметр PASSWORD указываем пароль от веб интерфейса.

Параметр WG_DEFAULT_ADDRESS можно оставить без изменений, но если планируете использовать на одном устройстве несколько подключений WG в активном состоянии одновременно необходимо что бы сети не пересекались (актуально для роутеров kenetik). Для этого достаточно изменить на 10.10.8.x или любую другую не используемую подсеть.

Параметр WG_DEFAULT_DNS если мы используем только внутри локальной сети то указываем наш роутер или ip на котором установлен локальный DNS. Так же указываем его в секции dns.

Запускаем сборку и установку контейнера

docker-compose up -d

Выходим в корневой каталог

cd

Проверяем работу контейнера

docker ps

image.thumb.png.7098bcb19e5f54cd8ab3cc00230603d8.png

Теперь нам доступно создание клиентов на локальном сервере через веб интерфейс по адресу

http://IP_server:51821

Заходим с паролем указанным в докер файле и создаем клиента.

Подключаемся к локальному серверу с любого устройства и проверяем работу сети.

Проверяем IP адрес и видим наш адрес удаленного сервера.

Теперь схема подключения выглядит так:

 

image.thumb.png.ab652a5815e3e2aa3485c3100993c841.png

Фактически мы сделали туннель до внешнего сервера через промежуточную точку, осталось сделать разделение трафика на промежуточном сервере.

Настройка скрипта разделения

Идея как и сам скрипт позаимствован из оригинальной статьи автора (рекомендую ознакомится для более точного понимания), Я же перескажу основную идею скрипта. Мы хотим что бы наш локальный интернет не ходил на удаленный сервер а выходил через обычный интернет.

Создадим скрипт в отдельной директории

mkdir exclude_routes
nano update_exclude_routes.sh

И вставляем сюда скрипт

#!/bin/bash
#To crontab (export EDITOR=nano; crontab -e)
#@reboot sleep 30 && bash /root/update_exclude_routes.sh > /root/update_routes_log.txt 2>&1
#0 3 * * mon bash /root/update_exclude_routes.sh > /root/update_routes_log.txt 2>&1

function ProgressBar {
  let _progress=(${1}*100/${2}*100)/100
  let _done=(${_progress}*4)/10
  let _left=40-$_done
  _fill=$(printf "%${_done}s")
  _empty=$(printf "%${_left}s")
  printf "\rAdd routes to route table (${1}/${2}): [${_fill// /#}${_empty// /-}] ${_progress}%%"
}

#Variables
file_raw="russian_subnets_list_raw.txt"
file_user="subnets_user_list.txt"
file_user_hostnames="hosts_user_list.txt"
file_for_calc="russian_subnets_list_raw_for_calc.txt"
file_processed="russian_subnets_list_processed.txt"
gateway_for_internal_ip=`ip route | awk '/default/ {print $3; exit}'`
interface=` ip link show | awk -F ': ' '/state UP/ && !/docker/ && !/veth/ {print $2}' | head -n 1 | sed 's/@.*//' `
#interface="eth0"

#Get addresses RU segment
echo "Download RU subnets..."
curl --progress-bar "https://stat.ripe.net/data/country-resource-list/data.json?resource=ru" | jq -r ".data.resources.ipv4[]" > $file_raw

echo "Deaggregate subnets..."
cat $file_raw |grep "-" > $file_for_calc
cat $file_raw |grep -v "-" > $file_processed
for line in $(cat $file_for_calc); do ipcalc $line |grep -v "deaggregate" >> $file_processed; done

if [ -e $file_user  ]
then echo "Add user subnets..."
  cat $file_user |grep -v "#" >> $file_processed
fi

if [ -e $file_user_hostnames  ]
then echo "Add user hostnames..."
  for line in $(cat $file_user_hostnames); do nslookup line |grep "Address" |grep -v "#" |awk '{print $2"/32"}' >> $file_processed; done
fi

#Flush route table
echo "Flush route table (down interface $interface)..."
ifdown $interface > /dev/null 2>&1
echo "Up interface $interface..."
ifup $interface > /dev/null 2>&1

#Add route
routes_count_in_file=`wc -l $file_processed`
routes_count_current=0
for line in $(cat $file_processed); do ip route add $line via $gateway_for_internal_ip dev $interface; let "routes_count_current+=1" ; ProgressBar ${routes_count_current} ${routes_count_in_file}; done
echo ""

echo "Remove temp files..."
rm $file_raw $file_processed $file_json $file_for_calc

routes_count=`ip r | wc -l`
echo "Routes in routing table: $routes_count"

Сохраняем и проверяем работу:

bash update_exclude_routes.sh

 

Данный скрипт можно использовать не только для разделения на Ru и не RU сегмент интернета. Можно использовать любые списки сетей, фактически скрипт делает автоматическое добавление маршрутов.

На данном этапе разделение по подсетям уже готово, все ip адреса которые относятся к RU сегменту будут идти через основной интернет.

Дополнительно мы можем положить в данную папку файлы со списком сайтов и подстей которые мы хотим тоже пустить по короткому маршруту через основной интеренет.

subnets_user_list.txt – для подсетей

hosts_user_list.txt – для сайтов, адреса определяются через nslookup

Отдельно хочу обратить внимание на параметр interface он должен указывать на ваш основной интерфейс по которому сервер подключен к интернету. Скрипт должен автоматически определить данный интерфейс, но если вы столкнулись с ошибкой вида «Cannot find device "eth0@if27"» при запуске необходимо скорректировать скрипт и вписать руками конкретный интерфейс.

Для этого нам надо определить основной интерфейс подключения. Это можно сделать командой ifconfig

image.thumb.png.bd5e3d0c3b427471bd77b846c888a693.png

Нас интересует имя того интерфейса который получил адрес в нашей локальной сети.

Корректируем в файле скрипта параметр:

interface="eth0"

И запускаем скрипт

bash update_exclude_routes.sh

Фактически мы получили нашу целевую схему:

 

image.thumb.png.1ddcf69ebd92971a42e6ff220093d4e2.png

Нам осталось только настроить автоматический запуск при перезагрузке и периодическое обновление таблицы маршрутов.

Добавим авто запуск wg туннеля до удаленного сервера

systemctl enable [email protected]

И добавим запуск скрипта при перезапуске в крон

export EDITOR=nano; crontab -e

Добавляем в конец следующие строчки

@reboot sleep 30 && bash exclude_routes/update_exclude_routes.sh > exclude_routes/update_routes_log.txt 2>&1
0 3 * * mon bash exclude_routes/update_exclude_routes.sh > exclude_routes/update_routes_log.txt 2>&1

Перезапускаем сервер и проверяем.

Для проверки наличия маршрутов можно воспользоваться командой:

ip r | wc -l

Команда возвращает количество прописанных маршрутов, по моим наблюдениям количество маршрутов должно быть более 10000 при корректной работе скрипта.

Подключаем наших конечных пользователей (рекомендую напрямую роутер) и пользуемся.

Заключение

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

P.S. В оригинальной статье разобран так же разобран кейс добавления конкретных маршрутов на удаленный сервер которые мы должны были направить на обычный доступ в интернет. Я разбирал работу этой части скрипта но она полностью еще не адаптирована для использования с WG-EASY, по этому возможно позднее дополню публикацию.

Изменено пользователем Deniom
Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...

Здравствуйте, спасибо за статью. после того как прочитал вашу, получилось наконец реализовать "умный VPN", по оригинальной статье почему не получилось.  Есть одна проблема у меня. при включении ютуба по крайней мере на телефоне. видео-шортсы не грузятся, хотя остальное вроде как нормально работает. с помощью проги на телефоне отследил адреса куда стучится youtube. сделал трассировку по этим ip и нашел адрес (188.234.140.81) который должен по  идее проходить через external, но по факту идет через internal. есть вариант как можно подсеть добавить в исключения для скрипта? или можно такую проблема решить? я новичок, только учусь пользоваться linux, так что сам врядли смогу решить проблему

Ссылка на комментарий
Поделиться на другие сайты

  • 2 месяца спустя...
  • Студенты

Спасибо за статью, очень полезна. А как быть если хочется удаленых серверов более 2х? Допустим 3 usa, germany и china. 

Как их подключить к местноиу? И на местном сделать что-то вроде балансира? Чтоб сбалонсировать нагрузку на удаленые сервера, но при этом если нагрузка мала в приоритете подключался к конкретному допустим к germany

Ссылка на комментарий
Поделиться на другие сайты

  • Админы
1 час назад, Rodney Hawk сказал:

Спасибо за статью, очень полезна. А как быть если хочется удаленых серверов более 2х? Допустим 3 usa, germany и china. 

Как их подключить к местноиу? И на местном сделать что-то вроде балансира? Чтоб сбалонсировать нагрузку на удаленые сервера, но при этом если нагрузка мала в приоритете подключался к конкретному допустим к germany

 

Ссылка на комментарий
Поделиться на другие сайты

  • Админы
1 минуту назад, Rodney Hawk сказал:

Так меня не Marzban интересует, а wg)

Аа

с утра  не проснулся еще))

Дак никак тогда)

Ссылка на комментарий
Поделиться на другие сайты

  • Студенты

Херня какая-то. Я вообще ничего не понимаю. При поднятии туннеля ssh сразу отваливается. Хотя по этой инструкции после поднятия туннеля ssh работает. Я понимаю что wg-easy только через туннель будет работать. Но интернета на туннели нет. Говорю как подключившийся клиент.

Если смотреть через хоста туннель работает и там и там. Но интернета нет в обоих случаях(инструкциях) с клиента. 

Как дорогой TrustMe у тебя не отваливается ssh я не понимаю, и все работает. Я ведь делаю точно по инструкции.

после запуска туннеля в ssh

root@root:/etc/wireguard# wg-quick up wg-external
[#] ip link add wg-external type wireguard
[#] wg setconf wg-external /dev/fd/63
[#] ip -4 address add 10.10.10.2/24 dev wg-external
[#] ip link set mtu 1280 up dev wg-external
[#] resolvconf -a wg-external -m 0 -x
[#] wg set wg-external fwmark 51820
[#] ip -6 rule add not fwmark 51820 table 51820
[#] ip -6 rule add table main suppress_prefixlength 0
[#] ip -6 route add ::/0 dev wg-external table 51820
[#] nft -f /dev/fd/63
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] ip -4 route add 0.0.0.0/0 dev wg-external table 51820
client_loop: send disconnect: Connection reset

повторное подключение с поднятым туннелем дает это

PS C:\Users\Rodney> ssh [email protected]
ssh: connect to host 85.192.30.25 port 22: Connection timed out

Аналогично и с Marzban'ом на Caddy. Запускаем docker network и ssh в отвале.

Если к удаленному серверу не возможно подключится по ssh значит и клиентское приложение wireguard или тот же Outline не будет получать интернет трафик с удаленного сервера. 

Если не мучатся со всем этим(но очень хочется), а чисто поставить wg-easy то все работает.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...

Важная информация

Вы принимаете наши Условия использования, Политика конфиденциальности, Правила. А также использование Мы разместили cookie-файлы на ваше устройство, чтобы помочь сделать этот сайт лучше. Вы можете изменить свои настройки cookie-файлов, или продолжить без изменения настроек.

Яндекс.Метрика