HAPP Gateway
| Статус | PRODUCTION / ACTIVE |
|---|---|
| Текущий режим | Automatic healthcheck + hourly optimization |
| Основной идентификатор | BYPASS
|
| Автопереключение | Включено |
| Rollback | Включён |
| Healthcheck | Каждые ~3 минуты |
| Optimizer | Примерно 1 раз в час |
| Порог переключения | 15% |
| Последнее документирование | 17.09.2026 |
HAPP Gateway: автоматический выбор сервера и отказоустойчивость
Назначение
HAPP Gateway — шлюз для выборочной маршрутизации трафика через HAPP/VLESS.
Система работает в LXC-контейнере и предоставляет одновременно:
- локальный HTTP proxy;
- локальный SOCKS proxy;
- HTTP/SOCKS proxy для устройств локальной сети;
- TUN-интерфейс для policy routing;
- автоматический контроль работоспособности HAPP;
- автоматическое обновление подписки;
- автоматический benchmark доступных серверов;
- автоматическое аварийное переключение;
- периодическую оптимизацию выбора сервера.
| Параметр | Значение |
|---|---|
| Контейнер | happ-gateway
|
| IP | 192.168.1.52
|
| ОС | Debian 13 |
| HAPP CLI | /usr/local/bin/happ
|
| HAPP home | /root/.config/happ-cli
|
| HTTP proxy локальный | 127.0.0.1:10809
|
| SOCKS proxy локальный | 127.0.0.1:10808
|
| HTTP proxy LAN | 192.168.1.52:11081
|
| SOCKS proxy LAN | 192.168.1.52:11080
|
| TUN interface | thapp
|
| Policy routing table | 100
|
Основные задачи системы:
- автоматически контролировать работоспособность текущего HAPP-сервера;
- обновлять список серверов;
- тестировать доступные серверы;
- выбирать наиболее быстрый рабочий сервер;
- автоматически переключаться при отказе;
- не переключаться без необходимости;
- синхронизировать Proxy и TUN;
- сохранять прямой маршрут до upstream HAPP-сервера;
- не допускать рекурсивной маршрутизации HAPP через самого себя;
- автоматически очищать временные маршруты после benchmark;
- выполнять проверку нового сервера после переключения;
- выполнять rollback при неудачном переключении.
Общая схема
Internet
^
|
HAPP upstream
^
|
direct route table 100
^
|
+-------------------+
| happ-gateway |
| 192.168.1.52 |
+-------------------+
| |
Proxy mode TUN mode
| |
127.0.0.1:10809 thapp
127.0.0.1:10808
|
socat LAN
|
+----------+----------+
| |
HTTP 11081 SOCKS 11080
Управление системой выполняют два независимых контура:
+----------------------+
| HAPP CONTROL |
+----------------------+
| |
| |
HEALTHCHECK OPTIMIZER
~3 минуты ~1 час
| |
+------+-------+
|
HAPP SWITCH
|
Proxy + TUN
Основные systemd-службы
happ-gateway.service
Основной HAPP Proxy.
Файл:
/etc/systemd/system/happ-gateway.service
Пример текущей команды запуска:
ExecStart=/usr/local/bin/happ \ --home /root/.config/happ-cli \ connect 60 \ --mode proxy \ --socks 10808 \ --http 10809
Перед запуском выполняются:
ExecStartPre=/usr/local/sbin/happ-wait-network.sh ExecStartPre=/usr/local/sbin/happ-prep-routes.sh
happ-prep-routes.sh подготавливает прямые маршруты, необходимые HAPP до создания Proxy/TUN.
happ-tun.service
Запускает HAPP в режиме TUN.
Файл:
/etc/systemd/system/happ-tun.service
Пример:
ExecStart=/usr/local/bin/happ \ --home /root/.config/happ-cli \ connect 60 \ --mode tun
Перед запуском также выполняется:
ExecStartPre=/usr/local/sbin/happ-wait-network.sh ExecStartPre=/usr/local/sbin/happ-prep-routes.sh
После создания TUN-интерфейса:
ExecStartPost=/usr/local/sbin/happ-tun-routes.sh
happ-http.service
Публикует HTTP proxy в локальную сеть.
192.168.1.52:11081
|
v
127.0.0.1:10809
Используется socat.
Служба связана с happ-gateway.service, поэтому при перезапуске основного gateway LAN proxy также перезапускается.
happ-socat.service
Публикует SOCKS proxy:
192.168.1.52:11080
|
v
127.0.0.1:10808
Также используется socat.
Идентификация серверов
Важно: HAPP ID нельзя считать постоянным идентификатором сервера.
После обновления подписки номера HAPP могут измениться.
Например:
ОБХОД №8 -> HAPP #60
После следующего обновления подписки тот же сервер теоретически может получить другой ID:
ОБХОД №8 -> HAPP #47
Поэтому постоянным логическим идентификатором системы является:
BYPASS=N
HAPP ID считается временным.
Текущее состояние
Состояние production хранится в:
/var/lib/happ/current
Пример:
BYPASS=8 ID=60 ENDPOINT=selec180.apruxdomain.website:444 UPDATED=2026-09-16T23:43:32+03:00
Здесь:
| Поле | Назначение |
|---|---|
BYPASS |
Постоянный логический номер обхода |
ID |
Текущий временный HAPP ID |
ENDPOINT |
Текущий upstream endpoint |
UPDATED |
Время последнего изменения production mapping |
Почему нельзя использовать только endpoint
В подписке могут существовать несколько записей с одним и тем же endpoint.
Например:
HAPP #43 selec180.apruxdomain.website:444 АВТО ОБХОД HAPP #60 selec180.apruxdomain.website:444 ОБХОД №8
Поэтому endpoint также не является достаточным идентификатором.
Для production используется именно явный тег:
ОБХОД №N
Автоматические записи вида:
АВТО ОБХОД
не используются системой автоматического выбора.
Resolver BYPASS -> HAPP ID
Скрипт:
/usr/local/sbin/happ-resolve-bypass.sh
Назначение:
ОБХОД №8
|
v
актуальный список HAPP
|
v
ID / protocol / endpoint
Пример:
/usr/local/sbin/happ-resolve-bypass.sh 8
Результат:
BYPASS=8 ID=60 PROTOCOL=vless ENDPOINT=selec180.apruxdomain.website:444
Таким образом остальные компоненты системы работают с постоянным BYPASS, а resolver определяет актуальный HAPP ID.
Подготовка маршрутов
Скрипт:
/usr/local/sbin/happ-prep-routes.sh
Он динамически определяет:
- IP сервера подписки;
- IP текущего HAPP upstream;
- текущий endpoint HAPP;
- необходимые direct routes.
Пример:
DIRECT: sub.renawave.space -> 37.9.4.201 via 192.168.1.1 dev eth0 table 100 DIRECT: selec180.apruxdomain.website -> 31.129.42.180 via 192.168.1.1 dev eth0 table 100 Current HAPP server #60 endpoint selec180.apruxdomain.website:444 prepared
Это критически важно.
Без direct route может возникнуть рекурсивная маршрутизация:
HAPP upstream
^
|
HAPP
^
|
thapp
^
|
HAPP
^
|
thapp
...
То есть HAPP пытается подключиться к собственному upstream через собственный TUN.
Результатом становятся timeout, TLS error или полная потеря доступа к upstream.
Policy routing
Используется routing table:
100
Основная схема:
0.0.0.0/1 dev thapp 128.0.0.0/1 dev thapp
То есть основной интернет-трафик направляется через HAPP TUN.
Локальные/служебные сети обходят TUN.
Пример:
10.0.0.0/8 via 192.168.1.1 dev eth0 172.16.0.0/12 via 192.168.1.1 dev eth0 192.168.0.0/16 via 192.168.1.1 dev eth0 10.20.0.0/24 via 192.168.1.53 dev eth0
Дополнительно динамически создаются прямые маршруты до:
- текущего HAPP upstream;
- сервера подписки.
Пример состояния на момент документирования:
31.129.42.180 via 192.168.1.1 dev eth0 37.9.4.201 via 192.168.1.1 dev eth0
Проверка:
ip route show table 100
Важно: IP-адреса 31.129.42.180 и 37.9.4.201 приведены как пример состояния системы на момент документирования. Они разрешаются динамически и могут измениться.
happ-tun-routes.sh
Файл:
/usr/local/sbin/happ-tun-routes.sh
После финальной очистки конфигурации в нём больше нет IP конкретных HAPP-серверов или сервера подписки.
Сохраняются только инфраструктурные маршруты:
192.168.1.0/24 10.20.0.0/24
Пример логики:
ip route replace table 100 \
192.168.1.0/24 dev eth0 src 192.168.1.52
ip route replace table 100 \
10.20.0.0/24 via 192.168.1.53 dev eth0
Таким образом смена HAPP upstream не требует ручного изменения happ-tun-routes.sh.
Обновление подписки
Скрипт:
/usr/local/sbin/happ-refresh-current.sh
Алгоритм:
прочитать текущий BYPASS
|
v
direct route к subscription
|
v
happ sub update ramba
|
v
найти тот же ОБХОД №N
|
v
получить актуальный HAPP ID
|
+---- ID/endpoint не изменились
| |
| v
| ничего не перезапускать
|
+---- mapping изменился
|
v
обновить systemd units
|
v
restart
|
v
verify
Пример:
Current selection: ОБХОД №8 Old ID: #60 New ID: #60 Old endpoint: selec180.apruxdomain.website:444 New endpoint: selec180.apruxdomain.website:444 REFRESH OK: mapping unchanged
Если mapping не изменился, production не перезапускается.
Benchmark серверов
Скрипт:
/usr/local/sbin/happ-benchmark.sh
Benchmark проверяет только явно заданные серверы:
ОБХОД №1 ОБХОД №2 ОБХОД №3 ...
Записи:
АВТО ОБХОД
исключаются.
Протокол hysteria2 в текущей реализации benchmark пропускается:
SKIP (hysteria2)
Тестируются VLESS-кандидаты.
Алгоритм benchmark
Для каждого кандидата выполняется:
endpoint | v direct /32 route | v temporary HAPP proxy | v warm-up | v Telegram request x3 | v median | v WORKING / REJECTED
Основная проверка выполняется запросом:
https://api.telegram.org
Рабочий результат:
HTTP 302
Ping или обычное TCP-соединение не используются как основной критерий.
Таким образом проверяется не просто доступность IP, а реальное прохождение HTTPS-трафика через конкретный HAPP-сервер.
Расчёт скорости
Для каждого кандидата выполняется три теста.
Пример:
test 1: 0.201306s OK test 2: 0.221358s OK test 3: 5.189619s OK
Используется медиана:
MEDIAN: 0.221358s
Это позволяет уменьшить влияние одиночного всплеска задержки.
Для признания сервера рабочим требуется не менее двух успешных запросов из трёх.
Если условие не выполняется:
REJECTED
Пример результата benchmark
WORKING BYPASS SERVERS ОБХОД №5 HAPP #57 188.225.82.56:7443 0.221358s ОБХОД №8 HAPP #60 selec180.apruxdomain.website:444 0.223532s ОБХОД №4 HAPP #56 188.225.58.133:7443 0.366614s ОБХОД №13 HAPP #65 selec248.apruxdomain.website:444 0.611755s BEST: BYPASS=5 ID=57 ENDPOINT=188.225.82.56:7443 MEDIAN=0.221358s
Очистка временных маршрутов
Во время benchmark для каждого upstream создаётся временный direct /32 route.
Например:
188.225.82.56/32 188.225.58.133/32 ...
После завершения benchmark временные candidate routes автоматически удаляются.
Cleanup сначала завершает временный HAPP-процесс benchmark, затем удаляет созданные маршруты.
После очистки вызывается:
/usr/local/sbin/happ-prep-routes.sh
Он повторно создаёт необходимые production routes.
Нормальное состояние после benchmark содержит только необходимые dynamic direct routes.
Пример на момент документирования:
31.129.42.180 via 192.168.1.1 dev eth0 37.9.4.201 via 192.168.1.1 dev eth0
Временные маршруты других кандидатов после benchmark отсутствуют.
Переключение HAPP-сервера
Скрипт:
/usr/local/sbin/happ-switch.sh
На вход передаётся BYPASS, а не HAPP ID.
Пример:
/usr/local/sbin/happ-switch.sh 8
Алгоритм:
ОБХОД №8
|
v
resolver
|
v
актуальный HAPP ID
|
v
direct route
|
v
backup конфигурации
|
v
обновление gateway + TUN
|
v
restart Proxy
|
v
Telegram readiness check
|
v
restart TUN
|
v
LAN Telegram check
|
+-------- OK --------> сохранить state
|
+-------- FAIL ------> rollback
После запуска нового Proxy выполняется readiness-loop.
Пример успешной проверки:
HTTP=302
Только после успешной проверки Proxy выполняется переключение TUN.
Rollback
Перед переключением создаются резервные копии:
happ-gateway.service;happ-tun.service;/var/lib/happ/current.
Если новый сервер не проходит проверку, выполняется автоматический rollback.
При rollback старый BYPASS заново разрешается через актуальный список подписки.
Это важно, потому что старый HAPP ID после обновления подписки уже мог измениться.
Логика:
new server
|
v
verification
|
+--+--+
| |
OK FAIL
| |
save resolve old BYPASS
|
v
restore
|
v
restart
Healthcheck
Скрипт:
/usr/local/sbin/happ-healthcheck.sh
Systemd timer:
happ-healthcheck.timer
Период проверки:
примерно каждые 3 минуты
Проверяется реальный Telegram-запрос через production HTTP proxy.
Пример:
HEALTHY: Telegram HTTP=302 TIME=0.212754s
Счётчик последовательных ошибок хранится:
/var/lib/happ/fail-count
При успешной проверке:
fail-count = 0
Аварийное восстановление
Одна ошибка не приводит к немедленному переключению.
Используется защита от случайных кратковременных сбоев.
Алгоритм:
Telegram check
|
v
FAIL
|
v
fail-count = 1
|
v
ждать
|
v
следующий healthcheck
|
v
FAIL
|
v
fail-count = 2
|
v
refresh subscription
|
v
benchmark
|
v
best working BYPASS
|
v
switch
Таким образом переключение выполняется после двух последовательных ошибок.
Hourly Optimizer
Скрипт:
/usr/local/sbin/happ-optimizer.sh
Systemd timer:
happ-optimizer.timer
Период:
примерно один раз в час
Используется также:
RandomizedDelaySec=5min
Поэтому фактическое время запуска может немного отличаться от ровного часа.
Алгоритм Optimizer
Optimizer выполняет:
- обновление подписки;
- синхронизацию текущего BYPASS;
- benchmark доступных серверов;
- определение median текущего сервера;
- определение BEST;
- сравнение производительности;
- принятие решения KEEP/SWITCH.
Схема:
sub update
|
v
sync current BYPASS
|
v
benchmark
|
+---------------------+
| |
v v
CURRENT BEST
| |
+----------+----------+
|
v
comparison
|
+-----+-----+
| |
KEEP SWITCH
Защита от постоянных переключений
Используется порог:
MIN_GAIN_PERCENT=15
Новый сервер должен быть минимум на 15% быстрее текущего.
Если выигрыш меньше 15%, переключение не выполняется.
Пример:
Current: ОБХОД №8 Best: ОБХОД №5 (0.221358s) Current median: 0.223532s Improvement: 0.97% Required: 15% KEEP: improvement is below threshold.
Это предотвращает бессмысленные переключения из-за разницы в несколько миллисекунд.
Если текущий сервер вообще не проходит benchmark, правило 15% не применяется.
В этом случае выполняется аварийное переключение на лучший рабочий BYPASS.
Блокировка параллельных операций
Управляющие скрипты используют общий lock-файл:
/run/happ-control.lock
через:
flock
Он защищает основные управляющие операции от параллельного выполнения.
При передаче управления в happ-switch.sh вызывающий контроллер освобождает блокировку, после чего happ-switch.sh получает её самостоятельно.
Это существенно снижает риск одновременного выполнения:
- healthcheck;
- optimizer;
- ручного switch.
Текущий production
На момент документирования:
BYPASS=8 HAPP ID=60 Endpoint=selec180.apruxdomain.website:444 Resolved IP=31.129.42.180
Типичная измеренная задержка Telegram:
~0.2–0.3 сек
Важно:
HAPP ID=60 не является постоянным.
Также IP:
31.129.42.180
является результатом DNS-разрешения endpoint на момент документирования и может измениться.
Постоянным логическим идентификатором является:
BYPASS=8
Systemd timers
Проверка:
systemctl list-timers --all --no-pager | grep happ
Нормальное состояние:
happ-healthcheck.timer active happ-optimizer.timer active happ-autoselect.timer inactive
Старый:
happ-autoselect.timer
оставлен выключенным.
Он не учитывает новую модель:
BYPASS -> dynamic HAPP ID
и не должен использоваться совместно с новой системой.
Быстрая диагностика
Проверить production
/usr/local/sbin/happ-healthcheck.sh
Ожидаемый результат:
HEALTHY: Telegram HTTP=302 TIME=...
Проверить текущее состояние
cat /var/lib/happ/current
Пример:
BYPASS=8 ID=60 ENDPOINT=selec180.apruxdomain.website:444 UPDATED=...
Проверить маршруты
ip route show table 100
Проверить Proxy из LAN
curl --max-time 8 \
-x http://192.168.1.52:11081 \
-o /dev/null -sS \
-w 'HTTP=%{http_code} TIME=%{time_total}s\n' \
https://api.telegram.org
Ожидается:
HTTP=302
Проверить HAPP список
/usr/local/bin/happ \ --home /root/.config/happ-cli \ list
Проверить конкретный BYPASS
Например, ОБХОД №8:
/usr/local/sbin/happ-resolve-bypass.sh 8
Обновить подписку и синхронизировать production
/usr/local/sbin/happ-refresh-current.sh
Запустить benchmark вручную
/usr/local/sbin/happ-benchmark.sh
Benchmark не переключает production самостоятельно.
Запустить optimizer вручную
/usr/local/sbin/happ-optimizer.sh
Optimizer уже может принять решение о переключении.
Переключиться вручную
Например, на ОБХОД №5:
/usr/local/sbin/happ-switch.sh 5
Перед ручным переключением желательно убедиться, что выбранный BYPASS присутствует в актуальной подписке.
Проверить службы
systemctl status happ-gateway \ happ-tun \ happ-http \ happ-socat \ --no-pager
Проверить таймеры
systemctl status happ-healthcheck.timer --no-pager systemctl status happ-optimizer.timer --no-pager
Последние логи healthcheck
journalctl -u happ-healthcheck.service -n 50 --no-pager
Последние логи optimizer
journalctl -u happ-optimizer.service -n 100 --no-pager
Основные файлы
| Файл | Назначение |
|---|---|
/usr/local/sbin/happ-wait-network.sh
|
Ожидание готовности сети |
/usr/local/sbin/happ-prep-routes.sh
|
Подготовка dynamic direct routes |
/usr/local/sbin/happ-tun-routes.sh
|
Базовые маршруты после запуска TUN |
/usr/local/sbin/happ-resolve-bypass.sh
|
BYPASS -> ID / protocol / endpoint |
/usr/local/sbin/happ-refresh-current.sh
|
Обновление подписки и синхронизация текущего BYPASS |
/usr/local/sbin/happ-benchmark.sh
|
Benchmark HAPP-серверов |
/usr/local/sbin/happ-switch.sh
|
Безопасное переключение production |
/usr/local/sbin/happ-healthcheck.sh
|
Аварийный контроль production |
/usr/local/sbin/happ-optimizer.sh
|
Плановый выбор более быстрого сервера |
/var/lib/happ/current
|
Текущее production-состояние |
/var/lib/happ/fail-count
|
Счётчик последовательных отказов |
/run/happ-control.lock
|
Блокировка управляющих операций |
Основные systemd units
| Unit | Назначение |
|---|---|
happ-gateway.service
|
Основной HTTP/SOCKS HAPP Proxy |
happ-tun.service
|
HAPP TUN |
happ-http.service
|
Публикация HTTP proxy в LAN |
happ-socat.service
|
Публикация SOCKS proxy в LAN |
happ-healthcheck.service
|
Проверка production |
happ-healthcheck.timer
|
Запуск healthcheck примерно каждые 3 минуты |
happ-optimizer.service
|
Полный цикл оптимизации |
happ-optimizer.timer
|
Запуск optimizer примерно раз в час |
happ-autoselect.timer
|
Старый механизм — отключён |
Логика системы целиком
HAPP Gateway
|
+-----------------+-----------------+
| |
каждые ~3 мин каждый ~1 час
HEALTHCHECK OPTIMIZER
| |
v v
Telegram через Proxy sub update
| |
+-----+-----+ v
| | sync BYPASS
| | |
HEALTHY FAIL v
| | benchmark
| | |
ничего первый FAIL +-----+-----+
| | |
ждать CURRENT BEST
| | |
следующий check +-----+-----+
| |
FAIL v
| comparison
v |
второй FAIL +-----+-----+
| | |
v < 15% >= 15%
refresh | |
| v v
v KEEP SWITCH
benchmark |
| |
v |
best working BYPASS |
| |
v |
SWITCH <------------------------------+
|
v
resolve BYPASS
|
v
direct route
|
v
restart Proxy
|
v
Telegram verify
|
+-----+-----+
| |
FAIL OK
| |
v v
rollback restart TUN
|
v
LAN verification
|
+----+----+
| |
FAIL OK
| |
v v
rollback SAVE STATE
Проверенное production-состояние
На момент завершения настройки система прошла полный цикл:
refresh subscription OK BYPASS resolution OK benchmark OK temporary route cleanup OK optimizer decision OK production healthcheck OK Telegram HTTP 302 OK
Последний контрольный optimizer:
Current: ОБХОД №8 Best: ОБХОД №5 Current median: 0.223532s Best median: 0.221358s Improvement: 0.97% Required: 15% KEEP
После benchmark таблица маршрутизации была автоматически очищена от временных candidate routes.
Production после полного цикла:
HEALTHY Telegram HTTP=302 TIME ~0.27s
Результат
После внедрения новой схемы HAPP Gateway:
- не зависит от постоянства HAPP ID;
- использует
BYPASSкак постоянный логический идентификатор; - автоматически обновляет подписку;
- синхронизирует BYPASS с актуальным HAPP ID;
- автоматически восстанавливает direct routes;
- предотвращает рекурсивную маршрутизацию upstream через HAPP TUN;
- контролирует реальную доступность Telegram;
- тестирует серверы через реальный HAPP proxy;
- использует медиану вместо одного измерения;
- требует минимум два успешных теста из трёх;
- не переключается при незначительной разнице скорости;
- автоматически переключается при отказе;
- синхронно обновляет Proxy и TUN;
- выполняет post-switch verification;
- поддерживает автоматический rollback;
- автоматически очищает временные benchmark routes;
- координирует управляющие операции через общий
flock; - автоматически выполняет healthcheck примерно каждые 3 минуты;
- автоматически выполняет полную оптимизацию примерно раз в час.
Текущая схема считается production-ready.
История конфигурации
17.09.2026
- внедрён постоянный идентификатор
BYPASS; - реализован resolver
BYPASS -> HAPP ID; - реализовано динамическое обновление подписки;
- реализована автоматическая синхронизация HAPP ID;
- реализован benchmark VLESS-серверов;
- основной критерий проверки переведён на реальный HTTPS-запрос к Telegram;
- реализован расчёт median;
- реализован безопасный switch Proxy + TUN;
- реализован rollback;
- добавлен healthcheck timer;
- добавлен hourly optimizer;
- установлен порог переключения 15%;
- добавлена очистка временных
/32routes; - удалены hardcoded upstream IP из
happ-tun-routes.sh; - старый
happ-autoselect.timerотключён; - выполнена финальная production-проверка.