За последние пару недель я встретил огромное количество статей с заголовками "Поднимаем свой VPN" или "Настройка OpenVPN в N шагов". На этой волне я тоже решил попробовать сделать VPN для себя и близких - лишним такой опыт (да и сам VPN) точно не будет. Для этого я прикупил один из самых дешевых VPS с заграничным IP и минимальными характеристиками. Такое удовольствие мне обошлось в ~250р за месяц.
Саму приватную сеть было решено развернуть посредством OpenVPN. На тот момент я не слышал ничего про другие сервисы, а инструкций по настройке OpenVPN было более чем предостаточно (как узнал позже, развернуть все можно буквально в пару строчек).
Уже после пары часов возни с конфигами и сертификатами и полной настройки VPN, в панели управления сервером я обнаружил, что максимальная скорость канала - 10Мбит/с (это было написано ещё на странице заказа, но я проглядел этот момент). В техподдержке пояснили, что это ограничение становится активным при превышении скорости трафика в 10Мбит/с за час (значит, что нужно прогнать примерно 4,5Гб за это время). Получилось неловко, конечно, но я не планировал использовать VPN даже в таком объеме. Тем не менее, мне стала интересна задача мониторинга трафика и возможность предупредить себя, если вдруг скорость трафика через VPN приблизится к пороговому значению.
Что уже есть
Первым делом я попытался найти готовые решения для мониторинга OpenVPN, все-таки это довольно популярная реализация, вокруг которой должно быть большое сообщество.
Я выделил для себя 2 решения:
OpenVPN-Admin - целый комбайн, который служит не только для мониторинга, но и для управления сертификатами и самим сервером OpenVPN
OpenVPN-Monitor - просто live-time мониторинг с географической картой, на которой отображаются подключенные клиенты
Первое решение в моем случае было бы чересчур избыточно, мне никогда не пригодилось бы 80% функционала. Во втором же случае оказалось, что мониторинг ведется только на текущий момент, при этом статистика не собирается - нет возможности посмотреть, сколько клиент загрузил/выгрузил за последний час, а именно ради этого я искал решение.
Помимо двух этих вариантов мне не удалось найти ничего, что отвечало бы моим требованиями или что я сумел бы переделать под свои нужды.
Формулировка задачи
Так что я решил за пару выходных набросать свое решение и заодно попрактиковаться в некоторых вещах. Что конкретно я хотел:
Собирать статистику использования VPN по каждому пользователю
Отслеживать общее потребление трафика
Предупреждать, если трафик за последний час переваливает за 8-9Мбит/с
А ещё смотреть за всем этим делом в веб-интерфейсе (в эстетических целях) и попробовать запаковать все в Docker (в образовательных целях)
Парсим, парсим, парсим
Чтобы анализировать статистику, нужно сначала собрать статистику. OpenVPN предоставляет довольно удобный интерфейс для получения статистики об использовании трафика. В конфигурации сервера по умолчанию уже включена соответствующая директива:
status openvpn-status.log
Она позволяет указать файл, в который будет записываться статистика об использовании трафика подключенными клиентами. После имени файла можно дополнительно указать число - интервал в секундах, через который файл будет автоматически обновляться (по умолчанию это 60 секунд).
Для комплексного подхода и, по-моему, более гуманного, чем парсинг файла, можно использовать management-server, для этого в конфиге нужно указать следующую директиву:
management localhost 7505
Дополнительно можно указать пароль для подключения к интерфейсу (подробнее).
После этого появится возможность подключиться к серверу OpenVPN посредством telnet:
Собираем статистику
OpenVPN любезно отдает статистику в настоящем времени, но, увы, не собирает и не хранит её. Можно получить только подключенных клиентов и количество их трафика за последнюю сессию, так что ответственность за сбор придется взять на себя.
Для сбора статистики я выбрал вариант с использованием management-interface и для этого написал небольшой скрипт на Python. Раз в N секунд он обращается к интерфейсу управления, запрашивает статус и создает/обновляет записи в MongoDB для каждого пользователя:
Можно лучше
Уже при написании статьи я заметил некоторые свои ошибки. Да, хранить данные можно было гораздо оптимальнее и обойтись всего одной коллекцией - только segments. По ней можно провести весь анализ, практически не добавляя новых полей, а поля с разностью (d_received и d_send) можно вычислять динамически, если не планируется анализ слишком больших отрезков времени
Для получения общего потребления трафика за час достаточно просто выбрать все записи, время которых попадает в этот промежуток, и просуммировать трафик по ним (вернее, их разницы в трафике по сравнению с предыдущими записями). Для клиентов нужно то же самое, но с фильтрацией по имени.
Теперь статистика собирается, остается наращивать функционал! В моем случае нужно было только отображать её в вебе и выдавать предупреждения, если скорость трафика будет превышена!
Делаем удобно
Для отображения в вебе я сделал простое веб-приложение на Vue и API для него на Flask. Ничего необычного в нём нет - одна страничка, на которой отображается общая статистика и карточки для каждого из пользователей:
Веб-интерфейс - здорово, но как быть с уведомлением о превышении скорости трафика? Изначально у меня были мысли о том, чтобы отправлять уведомления прямо в браузер, но до них я так и не добрался, потому что в голову пришло другое решение - сделать бота в ТГ и слать сообщения из него!
Пакуем в Докер
В качестве практики я решил упаковать всё в Docker. Так как MongoDB у меня уже была развернута на другом сервере, её я не стал разворачивать и обошелся двумя Dockerfile - один для веба и один для парсера. Так как оба из микросервисов сделаны на Питоне, то и Dockerfile у них отличаются не сильно
# Dockerfile для веба
# Билдим фронтенд
FROM node:16.14-alpine3.14 AS builder
WORKDIR /usr/app/client
COPY ./client /usr/app/client
RUN npm i
RUN npm run build
# Собираем фронтенд и сервер
FROM python:3.10.4-alpine3.14
COPY app.py app.py
COPY requirements.txt requirements.txt
COPY --from=builder /usr/app/client/dist /client/dist
RUN pip install -r requirements.txt
EXPOSE 5000
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0" ]
# Dockerfile для парсера
FROM python:3.8.13-buster
COPY main.py main.py
COPY OVPNInterface.py OVPNInterface.py
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5555
CMD [ "python3", "-m", "main" ]
В заключение
Спасибо, что прочитали! В этой статье я хотел просто поделиться опытом в сборе статистики трафика и "интеграции" OpenVPN в реальную жизнь. Вряд ли конкретно мое решение может быть использовано кем-то ещё, но возможности того же management-interface гораздо шире, а следовательно, есть где разгуляться!
Комментарии (17)
Barnaby
03.04.2022 16:09+2В Outline можно выставить лимит на 30 дней. Зачем брать vps с таким странным ограничением?
siailya Автор
04.04.2022 15:48Сам впервые столкнулся с таким ограничением и сперва, когда проверил скорость через speedtest-cli, подумал, что оно вовсе не работает (тест показал 500/120 Мбит на загрузку и отправку соответственно). Только ТП и разъяснила механизм работы. Но по сути из этого родилась идея сделать то, что я сделал, так что только рад этому странному ограничению :)
aborouhin
03.04.2022 16:18+2OpenVPN мониторить - это, конечно, дело нужное, но на той же самой VPS надо бы мониторить заодно загрузку CPU / памяти / место на диске (самая мерзкая засада, по моему опыту, когда какой-то ранее неведомый лог решает разрастись на весь диск...) / SSH сессии и т.п. Ну и мониторить это логично из одного места. Посему - zabbix (ну или что-то аналогичное на вкус), веб-интерфейс и алерты куда надо в комплекте, - ну а решений, как openvpn к нему прикрутить, хватает готовых.
Harwest
03.04.2022 18:19+1«прикупил один из самых дешевых VPS с заграничным IP и минимальными характеристиками»
Прикупил vps в ЦОДе РТ в городе Н-ске: очень удивился когда через VPN этого vps заработал LinkedIn, Insta, и простигосподи PornHub o_Oaborouhin
03.04.2022 19:20Лотерея. На VPS от reg.ru длительное время никакие блокировки не действовали, потом в один прекрасный момент без предупреждения поменялся аплинк (то ли с РТ на ТТК, то ли наоборот, уже не помню) - и всё оказалось зарезано.
NikaLapka
03.04.2022 19:02+5развернуть все можно буквально в пару строчек).
curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh chmod +x openvpn-install.sh
Здесь Паша Эмильевич, обладавший сверхъестественным чутьем, понял, что сейчас его будут бить, может быть, даже ногами. (с)
Пример правильных пары строчек для первоначальной настройки(debian 11.3) openvpn:
apt install openvpn && cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/server
Для параноиков, перфекционистов, выпускников Академии Звёздного Флота и т.п. единственно верный путь: https://openvpn.net/community-resources/creating-configuration-files-for-server-and-clients/
ogost
04.04.2022 06:08А почему не wireguard? Мне он показался проще в настройке, и оверхед небольшой.
Tarakanator
04.04.2022 13:53Когда я выбирал.
wireguard-прошивка моего роутера не умела.
openvpn-можно конечно, но он не особо шустрый. и вопрос маршрутов.
zerotier-тогда я про него не знал, но в плюс запишу лёгкую смен VPN сервера. минусы не знаю т.к. не пробовал. В первую очередь вопрос маршрутов
ipsec+gre мой выбор. Можно выбрать только нужные маршруты, есть доступ по сертификатам. Недостатки: если хочется накрутить побольше безопасности, то родной виндовый и андроидовский клиенты работать не будут (виндовый вроде как можно пролечить, но я не смог, и он сертификаты ставит на комп, а не на пользователя)
siailya Автор
04.04.2022 15:30До него просто-напросто не успел докопаться в поисках решения, разум затуманил OpenVPN
Сейчас мельком посмотрел на wireguard, в некоторых моментах он мне тоже показался проще (например та же статистика, которую я собираю через management-interface достается просто просто командой wg), так что попробую и его пощупать на досуге
newyorkin
04.04.2022 06:54Коли уж у нас есть Докер, вот так можно было развернуть и сам OpenVPN, в пару строчек без установки его на хостовую машину:
https://github.com/kylemanna/docker-openvpn
https://github.com/kylemanna/docker-openvpn/blob/master/docs/docker-compose.md
siailya Автор
04.04.2022 14:59Об этом, честно говоря, у меня даже мыслей не было - видимо недостаточно "контейнерное" мышление :)
В идеале, наверное, нужно абсолютно всё упаковать в контейнеры (в т.ч. БД) и поднимать одним docker-compose up
Спасибо за наводку, обязательно попробую!
nuBacuk
04.04.2022 18:54+1Только не обновляется он, сделал форк и сделал сборку для arm и мелочи поправил https://github.com/nuBacuk/docker-openvpn-arm64.
Rebeiro1976
04.04.2022 08:45-16 лет vps в Германии, скорость по тарифу опсоса, пинг конечно больше, ну это не критично, я в игры не играю, тут купил vps в России, попробовать, это ппц, ничему меня жизнь не учит, вся парнуха забанена, зато кавказцентр открывается))) это как? я обычно впн проверяю, кавказ врубаю, если открылся значит норм, а тут коллизия какая то, деньги хоть вернули, пару лет назад, тоже покупал vps не помню у кого, написано было безлимит и скорость 100 мегабит, в результате было 10 мегабит, написал в поддержку, мне ответили типа, за каждые еще 10 мегабит надо 100 р доплачивать))) пять баллов))) извините я не совсем трезв, душа поет
Amihailov
04.04.2022 09:50+1Ищущим могу посоветовать вот такой комбайн VPN-сервера (wireguard, web-интерфейс, статистика, pihole, firewall и прочее) от ИБшника энтузиаста https://gitlab.com/cyber5k/mistborn
BDI
Когда сам озадачивался учётом трафика(у меня был вариант когда было ограничение на месячный объём), мне хватило возможностей vnstat с указанием vpn интерфейса.
Автоматизацией на основании собранных данных не занимался, но с ключом --xml или --json
vnstat выдаёт вполне «машиночитаемый» результат, который можно использовать в своих нуждах.
siailya Автор
Если правильно понял, получится получить только общий трафик интерфейса OpenVPN? То есть анализ по каждому клиенту отдельно не провести?
BDI
Да, трафик через конкретный интерфейс. Но если цель мониторить исчерпание лимита сервера, то этого достаточно. Если надо по каждому пользователю, тогда вариант не подходит.