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

Для создания нам надо два сервера VPN1 и VPN2.

VPN1 в идеале должен находиться в той же стране, что и пользователь по двум причинам:

  1. Для ускорения сигнала и минимизации задержек.

  2. Многие ресурсы запрещают доступ из других локаций.

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

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

VPN1:
IP1 - 11.11.11.11
ip1_gateway - 11.11.11.1
IP_VPN1 - 192.168.11.1
ip_gateway_vpn1 - 192.168.11.1

VPN2:
IP2 - 12.12.12.12
ip2_gateway - 12.12.12.1
IP_VPN2 - 192.168.12.1
ip_gateway_vpn2 - 192.168.12.1

На сервере VPN1 мы подключаем пользователей с перенаправлением всего трафика, а на сервер VPN2 подключаем сервер VPN1 с «локальным» подключением. «Локальное» подключение — подключение при котором между серверами создается только туннель и в него идет определенный трафик, а весь трафик по умолчанию идет в обход туннеля.

Приступим к настройке сервера VPN1.

Для начала установим необходимые утилиты:

apt update && apt upgrade
apt install sudo vim shorewall curl wget openvpn dnsutils -y

Включаем пересылку пакетов на сервере. Находим строку и приводим ее к следующему виду:

vim /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p
cd /etc/shorewall/

Далее нам надо взять шаблоны необходимых файлов, чтобы не писать их с нуля:

cp /usr/share/doc/shorewall/examples/two-interfaces/{interfaces,policy,rules,snat,zones} /etc/shorewall/
cp /usr/share/shorewall/configfiles/{tunnels,routes} /etc/shorewall/
mkdir {local,routes.d}

Теперь приводим шаблоны к нашей ситуации. На сервере VPN1 у нас будет три интерфейса:

ens3 – физический интерфейс с внешним статическим IP,
tun1u – виртуальный интерфейс vpn1.server,
tun2u – виртуальный интерфейс vpn2.client.

Сервер VPN1 находится в зоне ru, значит так ее и назовем, а VPN2 находится в зоне nl:

vim zones
fw      firewall
net     ipv4
ru      ipv4
nl      ipv4

Обращаем внимание на названия интерфейсов!

vim interfaces
net     ens3           dhcp,tcpflags,nosmurfs,routefilter,logmartians,sourceroute=0
ru      tun1u          optional,tcpflags,nosmurfs,routefilter,logmartians
nl      tun2u          optional,tcpflags,nosmurfs,routefilter,logmartians

В следующем файле мы прописываем настройки для пересылки трафика VPN, где указываем свои протокол и порт vpn сервера:

vim tunnels
openvpnserver:udp:11443   net     0.0.0.0/0

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

vim snat
MASQUERADE              192.168.11.0/24         ens3
MASQUERADE              192.168.11.0/24         tun2u
vim policy
$FW     net             ACCEPT
$FW     ru              ACCEPT
$FW     nl              ACCEPT
ru      $FW             ACCEPT
ru      net             ACCEPT
ru      nl              ACCEPT
net     all             DROP            $LOG_LEVEL
# THE FOLOWING POLICY MUST BE LAST
all     all             REJECT          $LOG_LEVEL
vim rules
?SECTION ALL
?SECTION ESTABLISHED
?SECTION RELATED
?SECTION INVALID
?SECTION UNTRACKED
?SECTION NEW
#       Don't allow connection pickup from the net
#
Invalid(DROP)   net             all             tcp
#
#       Accept DNS connections from the firewall to the network
#
DNS(ACCEPT)     $FW             net
#
#       Accept SSH connections from the local network for administration
#
SSH(ACCEPT)     net             $FW
SSH(ACCEPT)     nl              $FW
SSH(ACCEPT)     ru              $FW
SSH(ACCEPT)     $FW             net
SSH(ACCEPT)     $FW             nl
SSH(ACCEPT)     $FW             ru
#
#       Allow Ping from the local network
#
Ping(ACCEPT)    nl              $FW
Ping(ACCEPT)    ru              $FW
#
# Drop Ping from the "bad" net zone.. and prevent your log from being flooded..
#
Ping(DROP)      net             $FW
ACCEPT          $FW             nl              icmp
ACCEPT          $FW             ru              icmp
ACCEPT          $FW             net             icmp

Настраиваем vpn сервер, запускаем. Так же перезапускаем shorewall:

systemctl restart shorewall
systemctl enable shorewall

Можем выпустить уже пользовательский сертификат с оборотом всего трафика и проверить работоспособность. Проверить можно на сайте https://2ip.ru ну или на том, который больше нравится. Если подключение пошло, на сайте мы увидели IP сервера, тогда все сделали верно.

Начинаем настраивать VPN2.

Для начала установим необходимые утилиты:

apt update && apt upgrade
apt install sudo vim shorewall curl wget openvpn dnsutils -y

Включаем пересылку пакетов на сервере. Находим строку и приводим ее к следующему виду:

vim /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p
cd /etc/shorewall/

Далее нам надо взять шаблоны необходимых файлов, чтобы не писать их с нуля:

cp /usr/share/doc/shorewall/examples/two-interfaces/{interfaces,policy,rules,snat,zones} /etc/shorewall/
cp /usr/share/shorewall/configfiles/tunnels /etc/shorewall/

Теперь приводим шаблоны к нашей ситуации. На сервере VPN2 у нас будет два интерфейса:

ens3 – физический интерфейс с внешним статическим IP,
tun2u – виртуальный интерфейс vpn2.server.

Сервер VPN2 находится в зоне nl, значит так ее и назовем:

vim zones 
fw      firewall 
net     ipv4 
nl      ipv4

Обращаем внимание на названия интерфесов!

vim interfaces
net     ens3          dhcp,tcpflags,nosmurfs,routefilter,logmartians,sourceroute=0 
nl      tun2u         optional,tcpflags,nosmurfs,routefilter,logmartians

В следующем файле мы прописываем настройки для пересылки трафика VPN где указываем свои протокол и порт vpn сервера:

vim tunnels
openvpnserver:udp:12443   net     0.0.0.0/0

Далее нам надо включить маскардинг, для этого в следующем файле убираем дефолтные настройки и прописываем свои с подстановкой своих подсетей:

vim snat
MASQUERADE              192.168.0.0/16         ens3
vim policy
$FW     net             ACCEPT
$FW     nl              ACCEPT
nl      net             ACCEPT
net     all             DROP            $LOG_LEVEL
# THE FOLOWING POLICY MUST BE LAST
all     all             REJECT          $LOG_LEVEL
vim rules
?SECTION ALL 
?SECTION ESTABLISHED 
?SECTION RELATED 
?SECTION INVALID 
?SECTION UNTRACKED 
?SECTION NEW 
#       Don't allow connection pickup from the net 
# 
Invalid(DROP)   net             all             tcp 
# 
#       Accept DNS connections from the firewall to the network 
# 
DNS(ACCEPT)     $FW             net 
# 
#       Accept SSH connections from the local network for administration 
# 
SSH(ACCEPT)     net             $FW 
SSH(ACCEPT)     nl              $FW 
SSH(ACCEPT)     $FW             net 
SSH(ACCEPT)     $FW             nl 
# 
#       Allow Ping from the local network 
# 
Ping(ACCEPT)    nl              $FW 
Ping(ACCEPT)    nl              nl 
# 
# Drop Ping from the "bad" net zone.. and prevent your log from being flooded.. 
# 
Ping(DROP)      net             $FW 
ACCEPT          $FW             nl              icmp 
ACCEPT          $FW             net             icmp

Настраиваем vpn сервер, запускаем. Так же перезапускаем shorewall

systemctl restart shorewall 
systemctl enable shorewall

Теперь можем создать пользовательский сертификат, но без оборачивания всего трафика в vpn, который только создаст туннель между VPN1 сервером и VPN2, локальный. Сертификат отправляем на VPN1 сервер, включаем и добавляем в автозагрузку.

Теперь начинаем делать то, ради чего все и затевалось. Нам надо настроить маршрутизацию трафика по зонам (да, мы делаем только два сервера, но можно сделать и больше). Первое, что мы должны сделать, это создать список адресов локации.

Сложный, нудный, но веселый вариант

Для этого мы идем на сайт и выбираем для какой страны (страна, где мы находимся).

Мы получаем список сетей с начальным и конечным адресами и в таком виде мы не можем их использовать, нам надо привести их к следующему виду xx.xx.xx.xx/xx, а для этого нужно правльно высчитать маску каждой сети из таблицы. Можно вручную считать на бумажке или в уме, а можно пойти сюда и считать с помощью калькулятора сетей. Нужно быть очень внимательным при пересчете, ведь допущенные ошибки могут привести к тому, что трафик будет перенаправляться не так, как нам надо или система совсем не заведется.

И так, считаем сети и сразу записываем в файл /etc/shorewall/local/ru на сервере VPN1 в колонку в виде:
 xx.xx.xx.xx/xx
 xx.xxx.xx.xx/xx
 и т.д.
Работа достаточно большая, особенно если страна большая)

Простой и скучный вариант

Идем на тот же сайт, но чуть дальше, выбираем страну и формат CIDR и скачиваем архив со списком адресов в нужном нам формате, однако в списке есть первые лишние строки, удаляем их и сохраняем в файл /etc/shorewall/local/ru на сервере VPN1.

Закончили? Идем дальше. Теперь нам надо сделать так, чтобы данные адреса в нужном формате попали в конфигурационный файл, плюс включить пересылку трафика на VPN2, для этого нам надо создать скрипт (можно не паниковать, я уже давно все написал, нам надо только скопировать и вставить, подставляя свои значения):

cd /etc/shorewall/
vim auto.sh
#!/bin/bash

input=local/ru 
output=routes.d/ru 
localnet="<ip1_gateway>" 
interface=ens3
tun2=tun2u  
ip2="<IP2>"
ip_gateway_vpn2="<ip_gateway_vpn2>"

echo "#provider   dest                gateway         device" > $output 
echo "#provider   dest                gateway         device 
main        0.0.0.0/0		$ip_gateway_vpn2	$tun2 
main        $ip2	$localnet	$interface  #connect nl 
main        195.201.201.32	$localnet	$interface  #check 2ip.ru
INCLUDE /etc/shorewall/routes.d/ru" > routes  
while IFS= read -r network 
do
    echo "main      $network                  $localnet     $interface" >> $output 
done < $input
Важное замечание

Данная схема будет работать только в том случае, если и клиент подключатся из той же зоны, где сервер VPN1, в противном случае доступа к серверу не будет. Однако если есть желание дать другу из Турции сертификат к своему vpn, то надо взять его IP адрес и добавить в файл routes:

vim /etc/shorewall/routes
...
main        <IP_of_friend> 	<localnet>	<interface>
...

Теперь делаем файл исполняемым:

chmod +x auto.sh

Запускаем скрипт и перезапускаем shorewall:

./auto.sh
shorewall restart

Теперь у нас практически все готово, сначала проверим работу. Подключаемся к vpn и идем проверять. Переходим на сайт 2ip.ru и видим адрес VPN1, так как мы прописали пересылку пакетов на этот сайт через VPN1. Теперь идем на сайт 2ip.ua или любой другой, но который точно не находится в зоне ru (в примере я делал для нее) и видим адрес VPN2. Если все так, тогда поздравляю, если нет, тогда стоит проверить все еще раз по шагам.

Остался последний шаг на сервере VPN1, если конечно не хотим делать все вручную каждый раз после перезагрузки (при чем доступ по ssh будет закрыт). Нам надо настроить условие автозагрузки shorewall. Для этого мы редактируем файл /usr/lib/systemd/system/shorewall.service  и меняем строчку «After=network-online.target» на «After=openvpn@cli002008.service», где cli002008 имя моего сертификата:

vim /usr/lib/systemd/system/shorewall.service
Проблемное место

На свежей версии debian shorewall не хочет запускаться после openvpn, что мы указывали выше. Я не разобрался пока в проблеме, если у кого-то есть ответ, то пишите в комментариях. Пока предложу другое решение, запускать через cron:

crontab -e
...
@reboot sleep 10; systemctl restart shorewall
...

Теперь все готово!

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

Можно настроить обновление данных в автоматическом режиме. Через крон будет скачиваться файл с адресами и записываться в shorewall, но данный способ является платным. Надо купить подписку и получить ссылку и токен для скачивания в следующем формате:

curl -o firewall.gz 'https://dl.ip2location.com/v1/firewall?token=mOdUlMdh0nK9Oap3iHaJxFrX0koqVahHX9Е9gfZhP9nURa126U4xnS9vKlbU3gry&country=RU|BY&format=cidr'
Реклама

Для облегчения жизни предлагаю собственный скрипт для создания vpn сервера и клиентских сертификатов. Всем желающим добро пожаловать в ЛС.

Благодарности за помощь

Благодарю за редакторские правки Дарью.

Комментарии (16)


  1. anzay911
    27.06.2023 12:11
    +5

    Если статья начинается с установки vim, хорошо бы если в ней было описано, как из него выйти. Шутка.


    1. dumasti Автор
      27.06.2023 12:11
      +2

      с долей правды)


  1. ivankudryavtsev
    27.06.2023 12:11

    Эх, ребята, веселый вариант был бы подключением сетевой пробы на ip dest и решением добавлять ли его в локальную таблицу или отправлять в remote по geoip или иному списку. Между прочим, в сетях шпд это уже лет 5 как применяется в разных формах. А вы "скачиваем список, добавляем в маршруты"...

    Базы GeoIP, списки РКН вкупе с iptables, tcpdump+простой скрипт на питоне решают вопросик легко.


  1. net_racoon
    27.06.2023 12:11

    А почему нельзя пушить клиенту специфик маршруты?


    1. dumasti Автор
      27.06.2023 12:11
      +1

      потому что если пушить будет VPN1, то клиент будет ходить на эти адреса через VPN сервер, но на остальные будет ходить мимо туннеля. А VPN2 должен пушить все адреса не входящие в список.


      1. net_racoon
        27.06.2023 12:11

        Ну получается адреса, которые не в списке, пойдут через локальный Инет. Или не понимаю задачи.


      1. aborouhin
        27.06.2023 12:11
        +2

        Эта проблема как раз легко решается. Инвертировать список CIDR, так, чтобы пушить "все, кроме" - задача тривиальная. А вот какое количество маршрутов сможет переварить OpenVPN-клиент на среднем смартфоне (и с т.зр. использования им ресурсов, и с т.зр. времени установки соединения) - вопрос интересный.

        P.S. У меня самогó схема похожая - VPN в РФ для пользователей и на нём маршрутизация по настраиваемым правилам, но эти правила посложнее (используются не только GeoIP, но и списки РКН, и вручную добавленные исключения, это настраивается индивидуально под разных клиентов, да и точек выхода в сумме 4 - собственно VPN-сервер, роутер в офисе в РФ для тех сайтов, которые блокируют доступ с IP дата-центров, сервер в Голландии, роутер в Турции).


        1. dumasti Автор
          27.06.2023 12:11
          +1

          Это вторая проблема, пушить столько маршрутов на конечное устройство - многие устройства просто не потянут. Но инвертировать список это уже сложнее. Для примера нам надо чтобы по стране нашего местонахождения трафик выходил с первого сервера, а весь остальной мир со второго. А теперь считаем: в IPv4 - 4 294 967 296 адресов, в условной стране их пусть будет 200 000. Вопрос: что легче и быстрее обработать (в том числе и серверу) 200 000 адресов, а все остальное пересылать на другой сервер или оставшиеся 4 294 767 296 адресов?


          1. aborouhin
            27.06.2023 12:11

            Ну мы же не индивидуально каждый адрес с маской /32 пушить будем :) После суммаризации большой разницы не будет (количество "дырок" в списке всех возможных адресов равно количеству промежутков между этими "дырками" +/- 1, а что там округлится до ровных масок, а что придётся делить на несколько диапазонов - уж точно не на порядок будет разница)


          1. aborouhin
            27.06.2023 12:11
            +1

            P.S. Посчитал сейчас по GeoIP базе от Maxmind. Все российские сети - 12138 префиксов, все сети, кроме российских - 47310 префиксов. Разница в 4 раза, да, как раз за счёт дробления "промежутков" между российскими диапазонами, - но вряд ли это будет сильно критично для каких-либо применений.


        1. Joyz
          27.06.2023 12:11

          Поделитесь инструкцией как это все настраивали ;)


  1. NikaLapka
    27.06.2023 12:11
    -1

    Позвольте подать идею, только не топите её сразу, можно же просто, до времени положить на полочку и иногда возвращаться к ней:

    Почти год я платил условные 5$ за VPS\VPN хостинг, причина проста, например, купил новый ноутбук, нужно загрузить обычный intel wifi драйвер.. и так и сяк - не получается, эмоции, гнев, или очередные изменения у провайдера и то что работало вчера, сегодня уже не работает.. и однажды, коллега по работе на моё возмущение ответил, - "а я просто в "популярном" веб браузере, установил "популярное" дополнение и всё работает, смотри..", я посмотрел, и оно действительно работает. Начал искать, а какие ещё есть бесплатные варианты. Потом сел и задал себе вопрос, - "я собираю разные конструкторы в Linux.. разве не смогу я сделать, тот же прокси, VPN, маршрутизацию.. через данные бесплатные аналоги? конечно смогу!", но что лучше 5$ или бесплатно. Для кого-то это бигмак и кола, а для меня два обеда. А в год.. но самая главная причина: я не хочу платить даже такие деньги за такой сервис различных хостинг провайдеров, т.к. они врут, обманывают, предоставляют не грамотный сервис. Почему-то у меня не возникает отторжения, когда я пополняю счёт на 5$ в том же DO, Vultr, Hetzner,.. т.к. на мой взгляд их товар стоит этих денег, но то что рекомендуют, как пример в см выше - это уровень 3-4$ за год.


  1. oller
    27.06.2023 12:11

    Главная проблема openvpn, это блокирование его как зарубежном, так и в РФ


    1. dumasti Автор
      27.06.2023 12:11

      Это бесконечный цикл: одни блокируют, другие ищут новые способы это обойти. А блокируют не только OpenVPN трафик, но и Wireguard, strongswang, softeather и другие. Вопрос в том, как замаскировать свой трафик так, чтобы его сложнее было распознать.


  1. Joyz
    27.06.2023 12:11

    А почему выбрали OpenVPN, а не более популярный Wireguard ?


    1. dumasti Автор
      27.06.2023 12:11

      я не считаю Wireguard более популярным. Да и работал с ним я всего пару раз.