Как держать 20 тысяч VPN клиентов на серверах за $5

в 16:21, , рубрики: BGP, DNS, IPv6, openvpn, vpn, блокировки сайтов, Сетевые технологии, Украина

Месяц назад мы с друзьями сделали бесплатный сервис для обхода блокировок сайтов в Украине Zaborona.Help. За это время сервис стал довольно популярным, аудитория выросла до 20 000 пользователей. Число одновременных подключений в пиковые часы — ≈6 000 клиентов.

Главная особенность нашего сервиса в том, что через VPN маршрутизируется трафик только к заблокированным сетям, остальные сайты работают напрямую. Это не влияет на скорость интернета и не подменяет IP-адрес для остальных сайтов.

В статье описываются тонкости настройки OpenVPN для большого числа клиентов, на дешевых VPS.

  • Как выбрать подходящий хостинг. Отличительные черты плохого хостинга. История о том, как мы долго искали и нашли хостинг в России.
  • Почему IPv6 — хорошо. Правильная настройка IPv6-адресов для VPN-клиентов.
  • Изменение конфигурации OpenVPN на лету, без перезапуска сервера и отключения клиентов.
  • Балансировка нагрузки между серверами и процессами OpenVPN
  • Тонкая настройка Linux для большого числа подключений
  • Особенности кривых операционных систем и роутеров пользователей

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

Хостинг

Поначалу мы использовали несколько серверов в Европе у провайдеров Scaleway, Linode, DigitalOcean. Это были самые дешевые VPS, за $3-5. Сразу же пользователи начали жаловаться, что из-за европейских IP-адресов Яндекс.Музыка и музыка VK.com недоступна. Мы начали искать подходящий хостинг в СНГ.

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

Отличительные черты убогого хостинга

  • Использование термина VDS вместо VPS. Хоть в самой аббревиатуре нет ничего страшного, это своего рода черная метка, которая практически гарантирует низкий уровень сервиса и интерфейс панели управления из 90-х годов.
  • Панель BillManager, ISPmanager и т.д. — эталон переусложненного интерфейса с кучей кнопок, непонятных меню. Процесс заказа сервера в таких панелях выполняется в несколько этапов. Панель управления самим сервером обычно находится на отдельном от панели заказа поддомене, с отдельным логином-паролем, переход в которую осуществляется не самым очевидным способом. Процесс заказа или изменения услуги превращается в настоящие мучение, часто требующее обращение в техподдержку. Если процедура заказа сервера требует больше нескольких кликов и занимает больше двух минут — это плохой хостинг.
  • Интерфейс панели управления BillManager
    Интерфейс панели управления BillManager — отличительная черта устаревшего хостинга
  • Непонимание принципов IPv6. Многие хостеры выделяют один IPv6-адрес и требуют плату за каждый дополнительный. Сеть /64 будет стоить квинтиллионы долларов.
  • Виртуализация OpenVZ.Большинство коммерческих VPS-провайдеров OpenVZ используют интерфейс venet, и панели, которые не позволяют назначать подсеть IPv6-адресов на отдельный контейнер, а только по одному отдельному адресу (/128) на интерфейс. Такие адреса нельзя нормально раздавать клиентам VPN.

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

Наши требования к VPS-серверам

  • Виртуализация XEN или KVM. OpenVZ в большинстве случаев не позволяет нормально управлять IPv6-адресами, имеет ограничения на настройку переменных ядра (sysctl). Для некоторых нужд OpenVZ вполне пригоден, но не для большого и высоконагруженного VPN-сервера.
  • Мощный серверный процессор. Некоторые провайдеры, вроде Scaleway, предлагают бюджетные VPS-серверы на маломощных процессорах ARM или Intel Atom. Бывают даже серверы на процессорах VIA. На таких системах OpenVPN работает медленно, но не из-за шифрования, как можно было бы предположить. Модуль tun, который используется OpenVPN для создания сетевого интерфейса, не оптимизирован под высокие нагрузки: он принимает или отдает только один пакет за системный вызов, из-за чего происходит большое количество переключений контекста между режимом ядра и пользователя. Чем медленнее частота памяти и дешевле процессор, тем медленнее происходит переключение. Кроме того, в коде OpenVPN используются системные вызовы recv и send, оперирующие единичными сетевыми пакетами, из-за чего отправка зашифрованных пакетов тоже происходит не самым оптимальным образом. Поэтому для нормальной работы OpenVPN важно иметь быстрый процессор и память.
  • Безлимитный трафик и хорошие каналы. Пользователи потребляют много медиа-контента в социальных сетях, трафик расходуется очень быстро. Тарифы с низкой квотой трафика (1ТБ) расходуются за сутки.
  • Отдельная маршрутизируемая сеть IPv6 необходима для прямого выделения реальных адресов клиентам. Большинство хостеров даже не понимают, что это значит, и просто назначают на сетевом интерфейсе гипервизора требуемую подсеть, а не создают запись в таблице маршрутизации через существующую (или через link-local-адрес). Это не позволяет без костылей назначить выданный диапазон на сетевой интерфейс VPN и выдавать IPv6-адреса напрямую клиентам: гипервизор хостера отправит NDP-запрос (аналог ARP для IPv6) виртуальной машине, виртуалка не найдет у себя этот адрес, не ответит на запрос, и ничего не заработает. Существуют NDP-прокси, которые позволяют обойти эту проблему, но это неудобно, и из-за этого может создаваться дополнительная нагрузка на гипервизор и маршрутизаторы хостера.

На наш запрос откликнулось около десятка компаний, но почти все из них имели признаки убогого хостинга и не подходили. В результате мы-таки нашли ЕДИНСТВЕННОГО хостинг-провайдера, удовлетворяющего всем нашим нуждам.

Это звучит странно, но я готов аргументированно доказать в комментариях, что 99% отечественных хостеров — фуфло, недотягивающее до уровня Европы. Особенно буду рад пообщаться с представителями крупных компаний, вроде МастерХост, REG.ru, 1GB.ru, Timeweb.

Как мы подружились с Veesp.com

Настоящим открытием для нас стал хостер Veesp.com с датацентром в Санкт-Петербурге. Это единственный хостер, который знал как правильно готовить IPv6. На каждый VPS сервер выделяется сеть /64 и по запросу /56.

У них есть две линейки тарифов VPS. Мы используем тариф «Storage 1», с безлимитным трафиком. Сервера на этом тарифе имеют процессор Intel Xeon X5650. Также есть линейка тарифов «Compute», с SSD диском, мощным процессором Intel Xeon E5v4 и памятью DDR4.

Линейка тарифов Compute VPS провайдера Veesp.com
Линейка тарифов Compute VPS провайдера Veesp.com

Панель управления сравнима по удобству с DigitalOcean. Есть даже оплата через Bitcoin!

На текущий момент мы полностью переехали на площадку Veesp.com и используем шесть серверов Storage 1 для OpenVPN. Музыка в VK и Яндексе снова работает, пользователи довольны.

IPv6

Я очень люблю IPv6. Он позволяет избавиться от кучи ненужных сущностей, вроде NAT и проброса портов. Для VPN он удобен тем, что каждый клиент ходит в интернет со своим реальным IP-адресом. К сожалению, многие хостинг-провайдеры и системные администраторы противятся и недолюбливают этот протокол, из-за этого его неправильно настраивают и используют.

Самая распространенная ошибка — выдавать один IPv6-адрес на сервер.
Сайт slash64.net посвященный этому заблуждению.

Почему нужно выделять минимум /64 на каждый конечный узел

  • Для простоты. Согласно RFC 6177, сеть /64 является рекомендуемым блоком для всех конечных узлов, будь то домашний интернет или хостинг. Это 2⁶⁴, или восемнадцать квинтиллионов IP-адресов. Такой подход избавит от путаницы и угадывания, как именно настроена сеть на каждом отдельном узле.
  • Меньшее потребление памяти на маршрутизаторах. Сетевому администратору достаточно маршрутизировать на ваш одну большую подсеть, а не несколько мелких.
  • Не ломает протокол автоконфигурации SLAAC. Если вы, вдруг, захотите сделать полноценную локальную сеть (L2) поверх интернета, в ней будет корректно работать IPv6.
  • По логике Email-провайдеров, крупных сайтов вроде Google и Facebook, один клиент — одна /64 сеть. Поэтому, если хостер выдает разным клиентам адреса из одного диапазона /64, вас могут заблокировать за действия, которые совершили соседи по диапазону.
  • IPv6-адреса не должны продаваться поштучно. Это глупость, потому что минимальный рекомендованный блок /64, который должен выдаваться бесплатно, будет стоить квинтиллионы денег, даже если цена за один IP-адрес будет один рубль.

Чтобы выдавать клиентам VPN IPv6-адреса напрямую без костылей, нужно иметь отдельную маршрутизируемую сеть через IPv6-адрес на сервере, то есть подсеть, из которой планируется раздавать адреса клиентам, не должна быть назначена на интерфейс сервера, но должна маршрутизироваться через какой-либо адрес на сетевом интерфейсе сервера.

Существует два распространенных варианта раздачи маршрутизируемах сетей.
Первый вариант: одна /64 на сетевом интерфейсе, и /56, маршрутизируемая через первую /64. Вы можете побить /56 так, как вам хочется, либо же назначить всю /56 на интерфейс VPN.

Второй вариант: одна или несколько /64 (или больше), маршрутизирутизируемая через link-local-адрес.

У большинства хостеров выделенную сеть нужно заказывать отдельно. Veesp.com выдает блок /56 на каждый сервер бесплатно. К сожалению, даже продвинутые хостеры, вроде DigitalOcean, не предоставляют такой услуги. Здесь есть список хостеров, предоставляющих данную услугу version6.ru/vps, от @rm.

NAT и Firewall

На серверах забороны больше двух сотен правил iptables, по несколько на каждый диапазон из списка запрещенных в Украине сетей.
Сложный набор правил неудобно обслуживать стандартными средствами iptables-save и iptables-restore, потому что в случае изменения одного правила, необходимо будет редактировать сотни однотипных строк.

Упрощаем написание правил файрволла с помощью ferm

Ferm — утилита для управления сложными правилами iptables со своим синтаксическим сахаром. Она позволяет создать удобочитаемую конфигурацию iptables, использовать переменные, массивы и циклы, но не ограничивает вас, в отличие от других надстроек над iptables: вы можете делать абсолютно все, использовать все возможности и модули netfilter.

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

Вот как эта задача решается через ferm:

@def $WAN_0 = eth0;
@def $WAN_1 = eth1;
@def $WAN_2 = eth2;

@def $BLOCKED_NETWORKS = (
123.123.123.123
234.234.234.234
....
);


chain INPUT {
     saddr $BLOCKED_NETWORKS of ($WAN_0 $WAN_1 $WAN_2) DROP;
}

В результате будет создано правило для каждого адреса из $BLOCKED_NETWORKS на каждый сетевой интерфейс. Такая запись легко читается и занимает в три раза меньше строк. Ее проще редактировать.

В нашем случае iptables выполняет три функции: NAT для IPv4-соединений, ограничение доступа в другие сети и балансировка нагрузки между процессами OpenVPN. Разберем каждую задачу подробно.

NAT для IPv4-соединений

Клиентам выдается «серый» IP-адрес из диапазона 192.168.*.*, поэтому маршрутизировать его напрямую в интернет нельзя. Для того, чтобы выпустить клиентов в IPv4-интернет, нужно использовать преобразование сетевых адресов (NAT).
Тем же самым занимается ваш домашний WiFi-роутер. На каждое исходящие соединение клиента создается трансляция в памяти сервера, которая хранит информацию о том, кому какое подключение принадлежит. Несмотря на то, что эта операция требует мало ресурсов сервера, при огромном количестве подключений (десятки тысяч), это может стать ресурсоемкой задачей для слабого сервера.
Этой проблемы нет в IPv6, так как каждому VPN-клиенту выдается реальный IP-адрес, который напрямую маршрутизируется в интернет. Серверу остается только перебрасывать пакеты с одного интерфейса на другой, без создания трансляций и хранения информации о каждом подключении.

Ограничение доступа в другие сети

Любой пользователь может добавить опцию redirect-gateway в конфиг OpenVPN и использовать наши сервера как маршрут по умолчанию. Нужно закрыть доступ ко всем сетям, кроме заблокированных в Украине

Балансировка нагрузки между процессами OpenVPN

Архитектура OpenVPN однопоточная, поэтому один процесс демона OpenVPN использует только одно ядро процессора. Для лучшей утилизации всех ядер процессора, число процессов должно равняться количеству ядер на сервере. Балансировка между процессами выполняется с помощью модуля statistic, который случайном образом перенаправляет входящие подключения на разные внутренние порты.

Балансировка между серверами

Мы используем самый простой способ балансировки — с помощью множественных А-записей DNS. Все клиенты подключаются к серверу через доменное имя vpn.zaborona.help. Этот домен имеет шесть А-записей, которые направлены на все сервера. В итоге, в момент подключения, клиент выбирает случайный сервер из доступных. Так общее число подключений равномерно распределяется между всеми серверами. Конфигурация OpenVPN на всех серверах идентична, за исключением диапазонов IPv6-адресов, выдаваемых клиентам.
image
Панель управления DNS-записями. Балансировка с помощью множественых А-записей. Малое значение TTL позволяет быстро удалять адреса из общего списка.

Можно быстро посмотреть, на какие IP-адреса резолвится домен из разных точек планеты, с помощью сервиса host-tracker.com, выбрав любой из тестов, например http или ping.

Результат для домена vpn.zaborona.help: www.host-tracker.com/InstantCheck/ResultComplete/ec0e5a90-ed56-e711-b124-0003ff7328cc

Рекурсивные DNS-резолверы

Многие украинские провайдеры блокируют DNS-запросы к запрещенным доменам, перехватывая запросы в том числе и к сторонним DNS-серверам, вроде 8.8.8.8. Поэтому важно, чтобы клиенты посылали DNS-запросы через VPN тоннель, где их не сможет модифицировать провайдер.
Это не так просто сделать, потому что в новых версиях Windows запросы могут уходить ко всем DNS-серверам в системе, и будет использоваться тот, который ответит быстрее. DNS-сервер провайдера находится физически ближе к клиенту, поэтому, с большой вероятностью, система быстрее получит подмененный ответ провайдера, а не корректный ответ DNS внутри VPN, и сайт останется заблокирован.
Для решения этой проблемы ValdikSS написал патч для OpenVPN, блокирующий утечки DNS в Windows. Он использует Windows Filtering Platform — специальный слой файрволла Windows, позволяющий блокировать запросы к сторонним DNS, пока запущен OpenVPN.

Разворачивание сервера

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

Конфиги максимально унифицированы и могут быть без изменений развернуты на сервере. Это удобно при использоватии инструментов автоматического деплоя, вроде Ansible.
Единственное уникальные данные для каждого сервера — подсеть IPv6, подписанная в конфигурационном файле OpenVPN.

На серверах используется Ubuntu 16.04 LTS с ядром 4.4.0.

Установка пакетов

В репозитории дистрибутива содержится устаревшая версия OpenVPN 2.3, поэтому добавляем официальные репозитории проекта с OpenVPN 2.4. Все остальные пакеты ставим из стандартной поставки.

wget -O - https://swupdate.openvpn.net/repos/repo-public.gpg|apt-key add - 
echo "deb http://build.openvpn.net/debian/openvpn/release/2.4 xenial main" > /etc/apt/sources.list.d/openvpn-aptrepo.list
apt update
apt upgrade
apt install openvpn dnsmasq ferm

Конфигурация OpenVPN

Так как все сервера настроены идентично, просто копируем конфиги вместе с файлами ключей и сертификатам в папку /etc/openvpn. Никакой генерации ключей/сертификатов не выполняется. Число процессов OpenVPN настраивает по числу ядер на сервере, в нашем случае 2. Каждый отдельный процесс имеет свой конфиг: zaborona1.conf и zaborona2.conf.

Чтобы избежать путаницы, я буду называть процессы OpenVPN демонами, но сути это несколько отдельных серверов, запущенных внутри одного VPS.

Список файлов в /etc/openvpn

/etc/openvpn/zaborona1.conf  # конфиг первого демона
/etc/openvpn/zaborona2.conf  # конфиг второго демона

/etc/openvpn/ccd/DEFAULT # файл с изменяемым на лету настройками для первого демона
/etc/openvpn/ccd2/DEFAULT #  файл с изменяемым на лету настройками для второго демона

/etc/openvpn/logs # папка с логами


/etc/openvpn/ca.crt # корневой сертификат
/etc/openvpn/zaborona.help.crt # сертификат сервера
/etc/openvpn/zaborona.help.key # ключ сервера
/etc/openvpn/dh2048.pem # файл с Diffie-Hellman группами (необходим для шифрования)

Содержимое файлов:

zaborona1.conf

mode server
# Несмотря на то, что протокол UDP быстрее, мы используем TCP для экономии трафика и аккумулятора мобильных уcтройств, так как в режиме UDP  клиент вынужден чаще посылать keep-alive пакеты, чтобы поддерживать NAT-трансляцию на роутере или CGNAT.
proto tcp

# Тип инкапсуляции L3, то есть ip уровень. Нам не нужен L2 уровень.
dev-type tun
# Имя tun-интерфейса на сервере
dev zaborona1

# Раздавать клиенту адреса из общей /24, а не резать на подсети /30.
topology subnet

# Диапазон "серых" ipv4-адресов, выдаваемых клиентам. 
server 192.168.224.0 255.255.252.0
# Диапазон реальных ipv6-адресов, выдаваемых клиентам. Уникален для каждого сервера.
server-ipv6 2a00:1838:32:200::/112

txqueuelen 250
keepalive 300 900
persist-tun
persist-key

cipher AES-128-CBC
ncp-ciphers AES-128-GCM

#user nobody
duplicate-cn

log logs/zaborona1.log
status logs/status1.log 30

# Путь к папке с конфигами пользователей. Эта опция позволяет назначить индивидуальные опции для каждого пользователя. Файл перечитывается заново при каждом подключении клиента, поэтому изменения можно выполнять без перезапуска сервера.
client-config-dir ccd

ca ca.crt
cert zaborona.help.crt
key zaborona.help.key
dh dh2048.pem

zaborona2.conf

mode server
port 1195
proto tcp

dev-type tun
dev zaborona2

topology subnet
server 192.168.228.0 255.255.252.0
server-ipv6 2a00:1838:32:280::/112

txqueuelen 250
keepalive 300 900
persist-tun
persist-key

cipher AES-128-CBC
ncp-ciphers AES-128-GCM

#user nobody
duplicate-cn

log logs/zaborona2.log
status logs/status2.log 30
client-config-dir ccd2

ca ca.crt
cert zaborona.help.crt
key zaborona.help.key
dh dh2048.pem

ccd/DEFAULT

push "dhcp-option DNS 192.168.224.1"

push "dhcp-option DNS 74.82.42.42" # HE.net DNS 
push "route 74.82.42.42" # Route to HE.net DNS

push "route 77.88.8.8" # Route to Yandex DNS

push "dhcp-option DNS6 2001:4860:4860::8888" # Google IPv6 dns
push "route-ipv6 2001:4860:4860::8888"

push "dhcp-option DNS6 2001:4860:4860::8844" # Google IPv6 dns
push "route-ipv6 2001:4860:4860::8844"

#Persist TUN
push "persist-tun"

# Routes

# Yandex network
push "route 5.45.192.0 255.255.192.0"
push "route 5.255.192.0 255.255.192.0"
push "route 37.9.64.0 255.255.192.0"
push "route 37.140.128.0 255.255.192.0"
push "route 77.75.152.0 255.255.248.0"
push "route 77.88.0.0 255.255.192.0"
push "route 84.201.128.0 255.255.192.0"
push "route 87.250.224.0 255.255.224.0"
push "route 93.158.128.0 255.255.192.0"
push "route 95.108.128.0 255.255.128.0"
push "route 100.43.64.0 255.255.224.0"
push "route 109.235.160.0 255.255.248.0"
push "route 130.193.32.0 255.255.224.0"
push "route 141.8.128.0 255.255.192.0"
push "route 178.154.128.0 255.255.128.0"
push "route 185.32.185.0 255.255.255.0"
push "route 185.32.186.0 255.255.255.0"
push "route 185.71.76.0 255.255.252.0"
push "route 199.21.96.0 255.255.252.0"
push "route 199.36.240.0 255.255.252.0"
push "route 213.180.192.0 255.255.224.0"

push "route-ipv6 2001:678:384::/48"
push "route-ipv6 2620:10f:d000::/44"
push "route-ipv6 2a02:6b8::/32"
push "route-ipv6 2a02:5180::/32"

# Mail.ru network
push "route 5.61.16.0 255.255.248.0"
push "route 5.61.232.0 255.255.248.0"
push "route 79.137.157.0 255.255.255.0"
push "route 79.137.183.0 255.255.255.0"
push "route 94.100.176.0 255.255.240.0"
push "route 95.163.32.0 255.255.224.0"
push "route 95.163.248.0 255.255.248.0"
push "route 128.140.168.0 255.255.248.0"
push "route 178.22.88.0 255.255.248.0"
push "route 178.237.16.0 255.255.240.0"
push "route 185.5.136.0 255.255.252.0"
push "route 185.16.148.0 255.255.252.0"
push "route 185.16.244.0 255.255.252.0"
push "route 188.93.56.0 255.255.248.0"
push "route 194.186.63.0 255.255.255.0"
push "route 195.211.20.0 255.255.252.0"
push "route 195.211.128.0 255.255.252.0"
push "route 195.218.168.0 255.255.255.0"
push "route 208.87.92.0 255.255.252.0"
push "route 217.20.144.0 255.255.240.0"
push "route 217.69.128.0 255.255.240.0"
push "route 185.6.244.0 255.255.252.0"
push "route 185.30.176.0 255.255.252.0"
push "route 195.218.190.0 255.255.254.0"

push "route-ipv6 2a00:1148::/32"
push "route-ipv6 2a00:a300::/32"
push "route-ipv6 2a00:b4c0::/32"
push "route-ipv6 2a04:4b40::/29"

# VK.com network
push "route 87.240.128.0 255.255.192.0"
push "route 93.186.224.0 255.255.240.0"
push "route 95.142.192.0 255.255.240.0"
push "route 95.213.0.0 255.255.192.0"
push "route 185.29.130.0 255.255.255.0"
push "route 185.32.248.0 255.255.252.0"

# Kaspersky network
push "route 77.74.176.0 255.255.252.0"
push "route 77.74.181.0 255.255.255.0"
push "route 77.74.183.0 255.255.255.0"
push "route 93.159.228.0 255.255.252.0"
push "route 185.54.220.0 255.255.254.0"
push "route 185.85.12.0 255.255.255.0"
push "route 185.85.14.0 255.255.254.0"
push "route 77.74.176.0 255.255.248.0"
push "route 91.103.64.0 255.255.248.0"
push "route 93.159.224.0 255.255.248.0"

push "route-ipv6 2a03:2480::/33"

# DrWeb
push "route 178.248.232.183 255.255.255.255"
push "route 178.248.233.94 255.255.255.255"
push "route 195.88.252.0 255.255.254.0"

ccd2/DEFAULT

push "dhcp-option DNS 192.168.228.1"

push "dhcp-option DNS 74.82.42.42" # HE.net DNS 
push "route 74.82.42.42" # Route to HE.net DNS

push "route 77.88.8.8" # Route to Yandex DNS

push "dhcp-option DNS6 2001:4860:4860::8888" # Google ipv6 dns
push "route-ipv6 2001:4860:4860::8888"

push "dhcp-option DNS6 2001:4860:4860::8844" # Google ipv6 dns
push "route-ipv6 2001:4860:4860::8844"

#Persist TUN
push "persist-tun"

# Routes

# Yandex network
push "route 5.45.192.0 255.255.192.0"
push "route 5.255.192.0 255.255.192.0"
push "route 37.9.64.0 255.255.192.0"
push "route 37.140.128.0 255.255.192.0"
push "route 77.75.152.0 255.255.248.0"
push "route 77.88.0.0 255.255.192.0"
push "route 84.201.128.0 255.255.192.0"
push "route 87.250.224.0 255.255.224.0"
push "route 93.158.128.0 255.255.192.0"
push "route 95.108.128.0 255.255.128.0"
push "route 100.43.64.0 255.255.224.0"
push "route 109.235.160.0 255.255.248.0"
push "route 130.193.32.0 255.255.224.0"
push "route 141.8.128.0 255.255.192.0"
push "route 178.154.128.0 255.255.128.0"
push "route 185.32.185.0 255.255.255.0"
push "route 185.32.186.0 255.255.255.0"
push "route 185.71.76.0 255.255.252.0"
push "route 199.21.96.0 255.255.252.0"
push "route 199.36.240.0 255.255.252.0"
push "route 213.180.192.0 255.255.224.0"

push "route-ipv6 2001:678:384::/48"
push "route-ipv6 2620:10f:d000::/44"
push "route-ipv6 2a02:6b8::/32"
push "route-ipv6 2a02:5180::/32"

# Mail.ru network
push "route 5.61.16.0 255.255.248.0"
push "route 5.61.232.0 255.255.248.0"
push "route 79.137.157.0 255.255.255.0"
push "route 79.137.183.0 255.255.255.0"
push "route 94.100.176.0 255.255.240.0"
push "route 95.163.32.0 255.255.224.0"
push "route 95.163.248.0 255.255.248.0"
push "route 128.140.168.0 255.255.248.0"
push "route 178.22.88.0 255.255.248.0"
push "route 178.237.16.0 255.255.240.0"
push "route 185.5.136.0 255.255.252.0"
push "route 185.16.148.0 255.255.252.0"
push "route 185.16.244.0 255.255.252.0"
push "route 188.93.56.0 255.255.248.0"
push "route 194.186.63.0 255.255.255.0"
push "route 195.211.20.0 255.255.252.0"
push "route 195.211.128.0 255.255.252.0"
push "route 195.218.168.0 255.255.255.0"
push "route 208.87.92.0 255.255.252.0"
push "route 217.20.144.0 255.255.240.0"
push "route 217.69.128.0 255.255.240.0"
push "route 185.6.244.0 255.255.252.0"
push "route 185.30.176.0 255.255.252.0"
push "route 195.218.190.0 255.255.254.0"

push "route-ipv6 2a00:1148::/32"
push "route-ipv6 2a00:a300::/32"
push "route-ipv6 2a00:b4c0::/32"
push "route-ipv6 2a04:4b40::/29"

# VK.com network
push "route 87.240.128.0 255.255.192.0"
push "route 93.186.224.0 255.255.240.0"
push "route 95.142.192.0 255.255.240.0"
push "route 95.213.0.0 255.255.192.0"
push "route 185.29.130.0 255.255.255.0"
push "route 185.32.248.0 255.255.252.0"

# Kaspersky network
push "route 77.74.176.0 255.255.252.0"
push "route 77.74.181.0 255.255.255.0"
push "route 77.74.183.0 255.255.255.0"
push "route 93.159.228.0 255.255.252.0"
push "route 185.54.220.0 255.255.254.0"
push "route 185.85.12.0 255.255.255.0"
push "route 185.85.14.0 255.255.254.0"
push "route 77.74.176.0 255.255.248.0"
push "route 91.103.64.0 255.255.248.0"
push "route 93.159.224.0 255.255.248.0"

push "route-ipv6 2a03:2480::/33"

# DrWeb
push "route 178.248.232.183 255.255.255.255"
push "route 178.248.233.94 255.255.255.255"
push "route 195.88.252.0 255.255.254.0"

Конфиги разных демонов отличаются только номером порта для входящих соединений и диапазоном IP-адресов, выдаваемых клиентам.

Изменения настроек на лету с помощью client-config-dir

Первое время мы постоянно реадктировали список заблокированных сетей, из-за этого приходилось перезапускать демоны OpenVPN каждый раз при изменении конфигов. Из-за этого у клиентов разрывалось подключение к серверу.
Решением этой проблемы стала опция client-config-dir. Она используется для того, чтобы назначит индивидуальные настройки поименно каждому пользователю. Так как у нас все пользователи подключаются от имени одного клиента public, то файл один на всех <b>ccd/DEFAULT. Хитрость в том, что файл перечитывается заново при каждом подключении клиента и не требует перезапуска сервера для применения настроек.
В результате мы можем редактировать настройки сервера без отключения клиентов. и для преминения новых настроек пользователю достаточно переподключиться к серверу. Так как пользователи рано или поздно в любом случае перподключаются, новые настройки со временем применяются всем клиентам.

Ferm

Настройки фаерволла идентичны на всех серверах, поэтому копируем файл /etc/ferm/ferm.conf без изменений. По-умолчанию, после установки, пакет ferm сразу активирует стандартный набор правил в котором запрещены все соединения, кроме SSH на 22 порту. Так что если у вас SSH сервер находится на другом порту, будьте аккуратны, чтобы не заблокировать себя.

/etc/ferm/ferm.conf

# Имена tun-интерфейсов из конфига OpenVPN. zaborona1, zaborona2 можно заменить на zaborona+.
@def $VPN = (
zaborona+
);

# Интерфейсы сервера, смотрящие в интернет
@def $WAN_4 = eth0;
@def $WAN_6 = eth0;


# Диапазоны "серых" адресов, выдаваемых клиентам
@def $VPN_ADDR_4 = (
192.168.224.0/22
192.168.228.0/22
);


@def $ALLOW_SSH = (
Список адресов, с которых разрешено подключение по SSH
);


@def $ALLOWED_NETWORKS_V4 = (
Список ipv4-сетей, заблокированных в Украине
);

@def $ALLOWED_NETWORKS_V6 = (
Список ipv6-сетей, заблокированных в Украине
);

table filter {
  chain ZABORONA_V4 {
      daddr $ALLOWED_NETWORKS_V4 ACCEPT;
  }
  chain FORWARD {
      policy DROP;
      mod conntrack ctstate INVALID DROP;
      if $WAN_4 of $VPN mod conntrack ctstate (ESTABLISHED RELATED) ACCEPT;
      if $VPN of $WAN_4 jump ZABORONA_V4;
  }
  chain INPUT {
      saddr $ALLOW_SSH protocol tcp dport 22 ACCEPT;
      protocol tcp dport 22 REJECT reject-with icmp-port-unreachable;
  }
}

table nat {
   chain POSTROUTING {
       saddr $VPN_ADDR_4 of $WAN_4 MASQUERADE;
   }
  # Балансировка меджду демонами OpenVPN
   chain PREROUTING {
       interface $WAN_4 protocol tcp dport 1194 mod conntrack ctstate NEW mod statistic mode random probability 0.50000000000 REDIRECT to-ports 1195;
    }
}

# IPv6:
domain ip6 {
   table filter {
       chain ZABORONA_V6 {
           daddr $ALLOWED_NETWORKS_V6 ACCEPT;
       }
       chain FORWARD {
           policy DROP;
           mod conntrack ctstate INVALID DROP;
           if $WAN_6 of $VPN mod conntrack ctstate (ESTABLISHED RELATED) ACCEPT;
           if $VPN of $WAN_6 jump ZABORONA_V6;
           
       }
   }
}

Для сравнения, вот как выглядит тот же набор правил, полученный через iptables-save:

iptables-save

# Generated by iptables-save v1.6.0 on Fri Jun 23 19:44:10 2017
*filter
:INPUT ACCEPT [54622:15244109]
:FORWARD DROP [50:2520]
:OUTPUT ACCEPT [59291:85277655]
:ZABORONA_V4 - [0:0]
-A INPUT -s 1.2.3.4/32 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -i eth0 -o zaborona+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i zaborona+ -o eth0 -j ZABORONA_V4
-A ZABORONA_V4 -d 87.240.128.0/18 -j ACCEPT
-A ZABORONA_V4 -d 93.186.224.0/20 -j ACCEPT
-A ZABORONA_V4 -d 95.142.192.0/20 -j ACCEPT
-A ZABORONA_V4 -d 95.213.0.0/18 -j ACCEPT
-A ZABORONA_V4 -d 185.29.130.0/24 -j ACCEPT
-A ZABORONA_V4 -d 185.32.248.0/22 -j ACCEPT
-A ZABORONA_V4 -d 5.45.192.0/18 -j ACCEPT
-A ZABORONA_V4 -d 5.255.192.0/18 -j ACCEPT
-A ZABORONA_V4 -d 37.9.64.0/18 -j ACCEPT
-A ZABORONA_V4 -d 37.140.128.0/18 -j ACCEPT
-A ZABORONA_V4 -d 77.75.152.0/21 -j ACCEPT
-A ZABORONA_V4 -d 77.88.0.0/18 -j ACCEPT
-A ZABORONA_V4 -d 84.201.128.0/18 -j ACCEPT
-A ZABORONA_V4 -d 87.250.224.0/19 -j ACCEPT
-A ZABORONA_V4 -d 93.158.128.0/18 -j ACCEPT
-A ZABORONA_V4 -d 95.108.128.0/17 -j ACCEPT
-A ZABORONA_V4 -d 100.43.64.0/19 -j ACCEPT
-A ZABORONA_V4 -d 109.235.160.0/21 -j ACCEPT
-A ZABORONA_V4 -d 130.193.32.0/19 -j ACCEPT
-A ZABORONA_V4 -d 141.8.128.0/18 -j ACCEPT
-A ZABORONA_V4 -d 178.154.128.0/17 -j ACCEPT
-A ZABORONA_V4 -d 185.32.185.0/24 -j ACCEPT
-A ZABORONA_V4 -d 185.32.186.0/24 -j ACCEPT
-A ZABORONA_V4 -d 185.71.76.0/22 -j ACCEPT
-A ZABORONA_V4 -d 199.21.96.0/22 -j ACCEPT
-A ZABORONA_V4 -d 199.36.240.0/22 -j ACCEPT
-A ZABORONA_V4 -d 213.180.192.0/19 -j ACCEPT
-A ZABORONA_V4 -d 5.61.16.0/21 -j ACCEPT
-A ZABORONA_V4 -d 5.61.232.0/21 -j ACCEPT
-A ZABORONA_V4 -d 79.137.157.0/24 -j ACCEPT
-A ZABORONA_V4 -d 79.137.183.0/24 -j ACCEPT
-A ZABORONA_V4 -d 94.100.176.0/20 -j ACCEPT
-A ZABORONA_V4 -d 95.163.32.0/19 -j ACCEPT
-A ZABORONA_V4 -d 95.163.248.0/21 -j ACCEPT
-A ZABORONA_V4 -d 128.140.168.0/21 -j ACCEPT
-A ZABORONA_V4 -d 178.22.88.0/21 -j ACCEPT
-A ZABORONA_V4 -d 178.237.16.0/20 -j ACCEPT
-A ZABORONA_V4 -d 185.5.136.0/22 -j ACCEPT
-A ZABORONA_V4 -d 185.16.148.0/22 -j ACCEPT
-A ZABORONA_V4 -d 185.16.244.0/22 -j ACCEPT
-A ZABORONA_V4 -d 188.93.56.0/21 -j ACCEPT
-A ZABORONA_V4 -d 194.186.63.0/24 -j ACCEPT
-A ZABORONA_V4 -d 195.211.20.0/22 -j ACCEPT
-A ZABORONA_V4 -d 195.218.168.0/24 -j ACCEPT
-A ZABORONA_V4 -d 217.20.144.0/20 -j ACCEPT
-A ZABORONA_V4 -d 217.69.128.0/20 -j ACCEPT
-A ZABORONA_V4 -d 195.211.128.0/22 -j ACCEPT
-A ZABORONA_V4 -d 208.87.92.0/22 -j ACCEPT
-A ZABORONA_V4 -d 77.74.176.0/22 -j ACCEPT
-A ZABORONA_V4 -d 77.74.181.0/24 -j ACCEPT
-A ZABORONA_V4 -d 77.74.183.0/24 -j ACCEPT
-A ZABORONA_V4 -d 93.159.228.0/22 -j ACCEPT
-A ZABORONA_V4 -d 185.54.220.0/23 -j ACCEPT
-A ZABORONA_V4 -d 185.85.12.0/24 -j ACCEPT
-A ZABORONA_V4 -d 185.85.14.0/23 -j ACCEPT
-A ZABORONA_V4 -d 77.74.176.0/21 -j ACCEPT
-A ZABORONA_V4 -d 91.103.64.0/21 -j ACCEPT
-A ZABORONA_V4 -d 93.159.224.0/21 -j ACCEPT
-A ZABORONA_V4 -d 8.8.8.8/32 -j ACCEPT
-A ZABORONA_V4 -d 8.8.4.4/32 -j ACCEPT
-A ZABORONA_V4 -d 74.82.42.42/32 -j ACCEPT
-A ZABORONA_V4 -d 77.75.152.0/21 -j ACCEPT
-A ZABORONA_V4 -d 185.71.72.0/21 -j ACCEPT
-A ZABORONA_V4 -d 185.6.244.0/22 -j ACCEPT
-A ZABORONA_V4 -d 185.30.176.0/22 -j ACCEPT
-A ZABORONA_V4 -d 195.218.190.0/23 -j ACCEPT
-A ZABORONA_V4 -d 195.88.252.0/23 -j ACCEPT
-A ZABORONA_V4 -d 178.248.232.183/32 -j ACCEPT
-A ZABORONA_V4 -d 178.248.233.94/32 -j ACCEPT
COMMIT
# Completed on Fri Jun 23 19:44:10 2017
# Generated by iptables-save v1.6.0 on Fri Jun 23 19:44:10 2017
*nat
:PREROUTING ACCEPT [917:61256]
:INPUT ACCEPT [430:26400]
:OUTPUT ACCEPT [122:8320]
:POSTROUTING ACCEPT [122:8320]
-A PREROUTING -i eth0 -p tcp -m tcp --dport 1194 -m conntrack --ctstate NEW -m statistic --mode random --probability 0.50000000000 -j REDIRECT --to-ports 1195
-A POSTROUTING -s 192.168.224.0/22 -o eth0 -j MASQUERADE
-A POSTROUTING -s 192.168.228.0/22 -o eth0 -j MASQUERADE
COMMIT
# Completed on Fri Jun 23 19:44:10 2017

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

-A PREROUTING -i eth0 -p tcp -m tcp --dport 1194 -m conntrack --ctstate NEW -m statistic --mode random --probability 0.50000000000 -j REDIRECT --to-ports 1195

С 50% вероятностью подключения к порту 1194 перенаправляются на порт 1195. Так, подключения равномерно распределяются между двумя процессами OpenVPN. Если бы процессов было больше, нужно было бы добавить дополнительные правила на каждый процесс и изменить вероятность срабатывания каждого правила.

Кеширующий резолвер dnsmasq

По-умолчанию dnsmasq принимает запросы только с локального интерфейса 127.0.0.1, поэтому разрешаем запросы с адресов VPN клиентов и устанавливаем размер DNS-кеша.

/etc/dnsmasq.d/zaborona

listen-address=127.0.0.1,192.168.224.1,192.168.228.1
cache-size=1000

sysctl

Файл systctl.conf настройки ядра. В нем включаем форвардинг IP-пакетов и другие опции.
Что еще важного тут сказать?

/etc/sysctl.conf

# Включаем форвардинг ipv4 и ipv6 пакетов
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

net.netfilter.nf_conntrack_max=65535
net.netfilter.nf_conntrack_generic_timeout = 600
net.netfilter.nf_conntrack_icmp_timeout = 30
net.netfilter.nf_conntrack_tcp_timeout_close = 10
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300
net.netfilter.nf_conntrack_udp_timeout = 60
net.netfilter.nf_conntrack_udp_timeout_stream = 180
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_rmem = 4096 262143 4194304
net.core.rmem_max = 4194304
net.core.rmem_default = 262143
net.ipv4.tcp_wmem = 4096 262143 4194304
net.core.wmem_max = 4194304
net.core.wmem_default = 262143
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 90
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_congestion_control=bbr
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv6.conf.all.use_tempaddr = 2

Старт сервисов

После того, как все сервисы настроены, можно добавить их старт в автозагрузку.

Предварительно увеличиваем лимит на число открытых файловых дескрипторов для процессов OpenVPN, иначе при большом числе клиентов мы их превысим и получим ошибку Too many open files из-за большого числа открытых сокетов.

systemctl edit openvpn@.service 

[Service]       
LimitNOFILE=8192
# Перечитываем стартовые скрипты, чтобы изменения вступили в силу.
systemctl daemon-reload

# Добавляем в автозагрузку и сразу стартуем оба процесса OpenVPN.
systemctl enable --now openvpn@zaborona1
systemctl enable --now openvpn@zaborona2  

# Перезапускаем сервисы dnsmasq и ferm. Они добавлены в автозагрузку по умолчанию после установки.
systemctl restart dnsmasq
systemctl restart ferm

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

Автор: zhovner

Источник

Поделиться

* - обязательные к заполнению поля