За последние пару недель я встретил огромное количество статей с заголовками "Поднимаем свой VPN" или "Настройка OpenVPN в N шагов". На этой волне я тоже решил попробовать сделать VPN для себя и близких - лишним такой опыт (да и сам VPN) точно не будет. Для этого я прикупил один из самых дешевых
Саму приватную сеть было решено развернуть посредством 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 гораздо шире, а следовательно, есть где разгуляться!
Автор:
siailya