История из практики

Рабочая задача: развернуть VPN на MikroTik с поддержкой L2TP и PPTP, авторизация — через Radius.
В роли серверов — стандартные для нас RouterOS CCR1016-12G. Параллельно возникло требование: подобрать клиент под Windows, чтобы можно было просто передать пользователям исполняемый файл, и они могли подключиться — без инструкций, .bat-файлов и шаманства.

Ключевое условие — не палить IPSEC_KEY.

Звучит несложно. Но, как это часто бывает, при попытке найти готовое решение стало ясно: либо его нет, либо оно недостаточно гибкое.

Ну и поехали. Ситуация была, скажем так, срочной. Почему — может, расскажу позже в Telegram-канале.

Результат: написал собственный VPN-клиент.
Ну как "написал" — взял PowerShell-скрипты, обернул в GUI на Python и получил рабочее приложение.

Почему не C#?
Потому что я умею в сети, а не в Cи-шарпы.
Python — мой максимум, и этого хватило, чтобы всё заработало.

Если вы думаете: "Очередной велосипед", — возможно, этот метериал не для вас.
Но если остались — покажу, как (не без помощи AI) я сделал удобный VPN-клиент, поделюсь исходниками и покажу, как собрать .exe под себя — с иконкой, версией и без лишнего гемора.

Приложение работает на Windows 10+ и выполняет следующее:
создаёт L2TP или PPTP-подключение средствами Windows;
добавляет маршруты (192.168.0.0/16, 10.0.0.0/8);
включает Split Tunneling — интернет остаётся через локального провайдера.

Ключевое: весь трафик не уходит в туннель а только трафик до серых сетей.
Плюс — Telegram-уведомления о подключениях: IP, гео, ОС, AS.
Не столько ради мониторинга, сколько для дебага и отладки.

Полный код и инструкции доступны:


Загрузка конфигурации

if getattr(sys, 'frozen', False):
    config_path = os.path.join(sys._MEIPASS, 'config.json')
else:
    config_path = 'config.json'

with open(config_path, 'r') as f:
    config = json.load(f)

Для сборки приложения через pyinstaller, путь к файлам будет отличаться. Это условие — чтобы искать config.json в нужном месте в обоих случаях.

По простому можно запустить код через PyCharm и протестировать что все работает перед сборкой приложения (PyCharm запускать тоже от администратора).

Переменные и константы

TELEGRAM_TOKEN = config['TELEGRAM_TOKEN']
...
SERVERS = {
    "111.111.111.111": {"name": "SERVER1", "gateway": "10.22.22.1"},
    ...
}

Все данные — в конфиге. Здесь мы храним Telegram-данные, IP-серверов и их шлюзы.

Проверка прав администратора

def is_admin():
    return ctypes.windll.shell32.IsUserAnAdmin() != 0

VPN-команды требуют прав администратора. Если их нет — приложение сразу завершится.

Интерфейс на ttkbootstrap

root = ttk.Window(themename="darkly")
app = VPNManagerApp(root)
self.login_entry = ttk.Entry(root, bootstyle="info")

Используем ttkbootstrap — он делает обычный tkinter более симпатичным. Тема "darkly" даёт тёмный вид.
Добавляем поля ввода логина/пароля, выбор сервера, кнопки подключения и отключения.

Работа с VPN

subprocess.call("rasdial /disconnect", shell=True)
command = f"rasdial \"{interface_name}\" {login} {password}"

Используем rasdial и Add-VpnConnection через PowerShell для создания, подключения и удаления VPN-соединений.
После подключения добавляются маршруты через route add.

Telegram-уведомления

await bot.send_message(chat_id=TELEGRAM_CHAT_ID, text=message, parse_mode="Markdown")

После подключения отправляется информация в Telegram: IP, страна, ОС, логин.

Логирование и безопасность

if hide_sensitive:
    message = message.replace(IPSEC_KEY, "[HIDDEN]")

Чтобы лог не слил пароль или PSK — замещаем конфиденциальные данные.

Что в итоге

Это приложение:

  • создаёт VPN соединение (L2TP/PPTP)

  • подключает его через rasdial

  • добавляет маршруты

  • логирует каждый шаг

  • отправляет информацию о подключении в Telegram

  • показывает красивый GUI на Python


? Сборка VPN-клиента в .exe: от иконки до метаданных

После того как мы написали рабочий VPN GUI-клиент, пора собрать его в .exe, чтобы можно было запускать на любом Windows-компьютере без Python и консоли.

Разберем по шагам, как именно я это делал.

version.txt — метаинформация

StringStruct('FileDescription', 'VPN-клиент для Windows с GUI и Telegram-уведомлениями')
...
StringStruct('CompanyName', 'netscripor')

Файл version.txt задаёт, что будет отображаться в свойствах .exe:

  • имя продукта;

  • автор;

  • версия;

  • описание;

  • иконка и прочее. Полный пример — в репозитории.

Команда сборки с PyInstaller

pyinstaller --onefile --noconsole --uac-admin --icon=vpn.ico --version-file=version.txt --add-data "pp.png;." --add-data "vpn.ico;." --add-data "config.json:." "main.py"

Разберем, что делает каждая часть:

Аргумент

Назначение

--onefile

Всё в одном .exe без папки dist

--noconsole

Не открывать черное окно консоли при запуске

--uac-admin

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

--icon=vpn.ico

Иконка приложения

--version-file=version.txt

Метаданные для свойства файла

--add-data "pp.png;."

Картинка логотипа в GUI

--add-data "vpn.ico;."

Иконка в окне программы

--add-data "config.json;."

Конфиг-файл (внимание: подставляется тестовая версия!)

main.py

Главный исполняемый файл

После выполнения команды в каталоге dist/ появится main.exe, готовый к запуску. Он будет:

  • выглядеть как полноценное Windows-приложение (с иконкой и описанием),

  • требовать админ-доступ при запуске,

  • не показывать консоль,

  • работать независимо от наличия Python на ПК.

? Заключение

Да, это не Enterprise-решение.
Но оно решает конкретную задачу: простой, автономный, настраиваемый VPN-клиент под Windows с поддержкой Split Tunneling и Telegram-логированием. И главное — его можно дорабатывать под себя.

Если статья была полезной — звёздочку на GitHub и подписку в Telegram я восприму с благодарностью.

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


  1. podguzovvasily
    17.07.2025 10:44

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


    1. Litlmidl Автор
      17.07.2025 10:44

      Так это для корпоративного использования.
      Подаете данные в минцифры и никто вас трогать не будет.


  1. c46fd3da
    17.07.2025 10:44

    Пока WG нормально работал, ГОДАМИ пользовались https://tunsafe.com

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

    IMHO изобретать велосипед на технологиях двадцатилетней давности, как в статье, могут только люди с избытком свободного времени. =)


    1. Litlmidl Автор
      17.07.2025 10:44

      Спасибо за мнение! Тут ключевой момент — это была задача в корпоративной среде, где уже настроен MikroTik + RADIUS + L2TP/PPTP, и задача стояла именно “не менять сервер, а сделать клиент с GUI”.


  1. 321785
    17.07.2025 10:44

    PowerShell + WPF = интерфейс. Python тут лишний.


  1. pr0l
    17.07.2025 10:44

    если уж хотелось заморочиться то возможно и свой костыль создать. Но майкрософт давно это сделало - CMAK. Собирал его в свое время, работал отлично

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


    1. amiton
      17.07.2025 10:44

      Полностью поддерживаю. Через cmak прекрасно создаётся инсталлятор с прописанными маршрутами. Для удаленных пользователей обычно лучше sstp с сертификатами, он почти всегда и везде работает. Если нужно добавление сертификата, то делается скрипт с авто добавлением. Все это пакуется например винраром с созданием sfx архива с автоматическим запуском скрипта и инсталлятора. И всё.