Четыре части, ноль зависимостей
Клиент для Windows, сервер ключей, сборщик маршрутов и скрипт, который поднимает сервер целиком. Весь Python — только стандартная библиотека: ни одного pip install ни на сервере, ни у игрока.
Что делает каждая часть и почему так
Клиент для Windows
Python и tkinter, собирается PyInstaller в один exe, который сам запрашивает права администратора.
- Туннель не изобретает. Ставит и снимает службу AmneziaWG командами
/installtunnelserviceи/uninstalltunnelservice, а сам только следит за ней. - Статус из трёх источников: состояние службы через Service Control Manager, пинг до сервера внутри туннеля через
IcmpSendEchoи возраст последнего рукопожатия изawg show. Рукопожатие старше 180 секунд — связи нет, даже если служба «работает». - Пинг через WinAPI, а не через ping.exe: вывод ping.exe зависит от языка Windows, а
IcmpSendEchoвозвращает число. - Находит мешающий VPN.
GetBestInterfaceExпоказывает, через какой интерфейс система пойдёт к серверу. Если это не физическая сетевая карта, трафик забрал чужой TUN — окно называет его по имени и подсказывает, что сделать. - Закрытый ключ не лежит на виду. Файл настроек хранится в ProgramData, папку
icaclsзакрывает для всех, кроме администраторов и SYSTEM. - Сервер ключей упал — игра нет. Перед стартом приложение берёт свежий файл настроек, а если сервер недоступен, запускается на сохранённом.
Сервер ключей
HTTPS на http.server и ssl: два метода, POST /v1/config и /v1/status.
- Ключ — это адрес, отпечаток и секрет. Строка
accel://— base64url от JSON:{"h": "203.0.113.7", "p": 443, "f": "SHA-256 сертификата сервера", "t": "секрет клиента, 128 бит"} - Свой отпечаток вместо удостоверяющего центра. Сертификат самоподписанный, домен не нужен. Клиент сверяет SHA-256 сертификата с отпечатком из ключа и только после этого отправляет секрет — подменить сервер посередине нельзя.
- Секреты на сервере не хранятся — только их SHA-256. Утечка
keys.jsonне даёт ни одного рабочего ключа. - Подбор не ускоряем: на неизвестный ключ ответ приходит через полсекунды.
- Медленный клиент не держит приём: TLS-рукопожатие идёт в потоке запроса, а не в цикле приёма соединений. Запись
keys.jsonатомарная, через временный файл.
Список адресов для туннеля
Из него получается строка AllowedIPs — именно она решает, что идёт через ускоритель.
- Три источника: анонсы сети Riot Direct (AS6507) из RIPEstat, подсети AWS EC2 в регионах eu-central-1 и eu-north-1 плюс Global Accelerator из
ip-ranges.json— Riot перенёс игровые серверы в AWS — и свои адреса из файла. - Склейка и вырезание. Соседние подсети объединяются, а IP самого VPS вырезается из списка: попади он в туннель, пакеты туннеля пошли бы в туннель и связь пропала бы.
- Лучше старый список, чем половина нового. Если любой источник не скачался, скрипт завершается с ошибкой и ничего не печатает — сервер остаётся на прежнем списке.
- Проверка одной командой:
accel.sh covered IPотвечает, идёт ли адрес через туннель.
Сервер целиком
Bash для Ubuntu 22.04 / 24.04: от голого VPS до работающего туннеля одной командой.
- Установка с проверками: AmneziaWG из PPA, заголовки ядра для будущих ядер (иначе после обновления DKMS не пересоберёт модуль и туннель не поднимется), отказ на OpenVZ/LXC, где модуль ядра не загрузить. Запасной вариант
--plain— обычный WireGuard. - Обфускация AmneziaWG: мусорные пакеты перед рукопожатием (Jc, Jmin, Jmax) и свои размеры и заголовки пакетов (S1, S2, H1–H4), случайные при установке. На пинг не влияет: меняется только рукопожатие.
- Сеть без сюрпризов: MTU 1380 с запасом на PPPoE домашних провайдеров, MSS clamping для TCP, NAT через iptables в PostUp/PostDown.
- Клиенты на ходу: новый пир добавляется и в конфиг, и в работающий туннель — перезапуск не нужен, остальные игроки не отваливаются.
- status ловит общий ключ: по каждому клиенту видно, откуда он подключён. Если адрес скачет — одним файлом пользуются два устройства.
От выдачи до продления — без ручной возни
issue-key ivan 30
Создаётся пир в туннеле, секрет и ключ accel:// на 30 дней.
Ключ в окне
Приложение сверяет сертификат, забирает файл настроек и срок подписки.
Свежий файл
Новые адреса серверов Riot подтягиваются без участия игрока.
Таймер раз в час
Пир снимается с туннеля, сервер ключей отвечает «подписка закончилась» с датой.
extend ivan 30
Дни прибавляются к сроку, пир возвращается. Ключ у игрока тот же.
Управление сервером — это accel.sh
| Команда | Что делает |
|---|---|
install | Ставит AmneziaWG (или WireGuard с --plain), поднимает туннель, скачивает адреса, создаёт первого клиента |
enable-keys | Включает сервер ключей: сертификат, служба systemd, ежечасный таймер отключения |
issue-key ИМЯ ДНЕЙ | Новый клиент и ключ на срок |
extend ИМЯ ДНЕЙ | Продлить подписку от даты окончания или от сегодня, если срок уже вышел |
keys | У кого какой срок и кто отключён |
remove-client ИМЯ | Отключить устройство: ключ и файл настроек перестают работать |
update-routes | Заново скачать адреса Riot и AWS и пересобрать файлы клиентов |
check IP / covered IP | Пинг и маршрут от сервера до адреса / идёт ли адрес через туннель |
status | Клиенты, откуда подключены, когда было рукопожатие |