dokril 14b3c2afac
Build and Deploy Gateway / build-and-push (push) Successful in 25s
Build and Deploy Gateway / deploy (push) Successful in 14s
Exclude test artifacts from runtime impact analysis
2026-08-28 19:47:58 +03:00

Harbor

Harbor помогает пользоваться несколькими VPN-подписками дома и на Mac без ручной настройки sing-box.

Проект работает в двух режимах:

Режим Где работает Для чего нужен
Harbor Gateway На отдельной Linux-машине Проводит через VPN весь интернет-трафик домашних устройств или работает как общий HTTP/SOCKS5-прокси
Harbor Connect На macOS Даёт приложениям на Mac локальный HTTP/SOCKS5-прокси

Основной экран Connect и Gateway всегда показывает фактически применённые подписку и сервер. Управление подписками открывается отдельной верхней кнопкой в правой панели; Home, «Устройства» и «Диагностика» Gateway доступны и без подписки.

Что понадобится

  • ссылка на подписку от VPN-провайдера, если Harbor должен направлять трафик через VPN;
  • Docker с командой docker compose;
  • для ручной установки Gateway — Git;
  • для Gateway — Linux-машина в одной локальной сети с устройствами;
  • для Connect — Mac с запущенным Docker Desktop.

Harbor не является VPN-провайдером и не создаёт подписки самостоятельно.

Что выбрать

Используйте Harbor Connect, если VPN нужен только приложениям на одном Mac.

Используйте Harbor Gateway, если нужно подключить телевизор, телефон, игровую приставку или сразу несколько устройств. Устройства можно направить через Gateway целиком либо настроить в отдельных приложениях общий прокси.

Оба режима можно использовать вместе. Дома Connect автоматически распознаёт настроенный Harbor Gateway и не запускает второй VPN-маршрут. В другой сети Connect возвращается к локальному VPN.

Установка Harbor Gateway

1. Скачайте проект

git clone https://git.dokops.ru/dokril/vpn-proxy.git
cd vpn-proxy

2. Создайте настройки

cp .env.example .env

Стандартные значения подходят для обычной домашней сети. При необходимости откройте .env в текстовом редакторе и измените порты.

3. Запустите Gateway

docker compose -f docker-compose.gateway.yml up -d --build

Откройте в браузере:

http://АДРЕС-GATEWAY:3456

Например, если Linux-машина имеет адрес 192.168.1.20, интерфейс будет доступен по адресу http://192.168.1.20:3456.

4. При необходимости добавьте подписку

  1. Нажмите «Подписки» — верхнюю кнопку в правой панели Gateway.
  2. Нажмите «Добавить подписку», задайте понятное имя и вставьте ссылку VPN-провайдера.
  3. Выберите сервер внутри добавленной группы.
  4. При нескольких группах выберите нужную действием «Сделать активной».
  5. Включите VPN.

После подключения Harbor покажет два варианта использования:

  • Gateway — укажите IP-адрес Linux-машины как основной шлюз устройства. Через VPN пойдёт весь его интернет-трафик;
  • Gateway Proxy — укажите адрес Linux-машины и порт 8080 в приложении. Поддерживаются HTTP и SOCKS5 на одном порту.

Приватные и локальные адреса не отправляются в VPN, поэтому устройства сохраняют доступ к домашней сети. Общий прокси по умолчанию принимает подключения только из приватных сетей.

Резервный канал Gateway

После добавления подписок откройте «Резерв» — вторую кнопку в правой панели. Выберите основной и резервный серверы (они могут быть из одной или разных подписок), сервисы для проверки и отдельный таймаут каждого сервиса. Там же настраиваются длительность сбоя и восстановления, порог активного трафика, период тишины и защита от частых переключений.

При включении Harbor заранее проверяет dual-конфигурацию. Если VPN остановлен, она начнёт работать только после следующего обычного нажатия питания; сохранение само VPN не включает. Переключение меняет маршрут только для новых соединений — уже открытые соединения не закрываются. Если через VPN идёт активный трафик или его активность нельзя надёжно определить, Harbor ждёт и показывает скорость, число передающих соединений и безопасные подписи основных блокирующих потоков.

Выключенный резерв полностью пассивен: Harbor не запускает проверки, таймер выбора и отдельный подсчёт активности. Если dual-конфигурация уже загружена, отключение не перезапускает VPN и не меняет текущий маршрут; обычный stop и следующий запуск вернут single-channel config. Последние важные события — включение VPN, обновления подписок, переключения и ошибки — доступны в последней кнопке «Журнал» и хранятся 30 дней без ссылок подписок и сырых диагностических ответов.

Устройства Gateway

Откройте «Устройства» в правой панели Gateway — подписка для просмотра списка не требуется. Harbor раз в 15 секунд читает локальную таблицу соседей и показывает каждое устройство одной компактной строкой: заданное название, hostname или IP, последний контакт, выбранный график трафика и иконку применённого маршрута. По умолчанию график показывает приблизительный выход VPN/Direct; переключатель Вход возвращает накопленную разбивку Gateway/Прокси. Наведите курсор на имя или переведите на него фокус, чтобы открыть IP, MAC и доступный hostname; нажатие на значение копирует его. Hostname определяется через локальное обратное разрешение имён и может отсутствовать, если сеть его не публикует. Технические interface и manufacturer продолжают храниться для идентификации, но не занимают место в строке. Список разделён на «Закреплённые», «Остальные» и «Фоновые»: последняя группа сохраняется между перезапусками, показывает только identity/presence и кнопку возврата без графика, traffic и route controls. Название, закрепление, фоновое положение и накопленные totals сохраняются в volume Gateway, пока устройство остаётся в inventory.

Красная кнопка Сбросить данные после отдельного подтверждения обнуляет вход и выход всех устройств и начинает считать их заново. Общий график скорости на Home и уже сохранённая история Prometheus/Grafana не очищаются: входной counter выглядит для Prometheus как стандартный reset, а для выхода Harbor сохраняет только baseline отображения и не изменяет raw dataplane counters.

У однозначно распознанного устройства маршрут можно переключить последней иконкой между VPN и Напрямую независимо от закрепления; точное значение и следующее действие показаны в tooltip. VPN означает обработку через sing-box и правила Gateway: например, включённое локальное доменное правило всё равно может выбрать прямой выход внутри sing-box. Напрямую полностью обходит sing-box на уровне iptables. Traffic totals учитываются в обоих режимах. Если правило не удалось применить, Harbor сохраняет выбранный режим и отдельно показывает последний фактически применённый маршрут.

Список приблизительный: имя и пользовательские настройки привязаны к MAC и сохраняются при обычной смене IP, но новый private/randomized MAC считается новым устройством — переносить имя по одному только DHCP-адресу небезопасно. Запись автоматически удаляется после 30 дней без подтверждённого контакта независимо от имени, закрепления или фонового положения; временная ошибка чтения сети этот срок не продвигает. Один MAC с несколькими IP помечается как неоднозначный, а устройство появляется только после сетевого контакта с Gateway. Интерфейс самого Gateway не выдаётся за Wi-Fi/Ethernet устройства. Внешние сервисы распознавания производителя не используются. Прокси учитывает подключения устройства к общему proxy-порту Harbor, а Gateway — остальной публичный трафик через Gateway; трафик, который вообще не дошёл до Harbor, увидеть нельзя. Локальные, приватные и multicast-пакеты в totals не входят. При аварийном restart dataplane возможна потеря последних примерно 30 секунд; история по часам пока не хранится.

Home показывает фактически применённый VPN-сервер, накопленное Учтено Harbor и большой нижний график средней скорости Download/Upload за фактический интервал между снимками. Учтено Harbor — сумма Gateway и явного Прокси для всех наблюдавшихся устройств; это не лимит VPN-провайдера и не весь физический трафик Linux-машины. Накопленный total сохраняется при очистке старых устройств, а короткая история скорости после перезапуска начинает заполняться заново.

Установка Harbor Connect на macOS

1. Запустите Docker Desktop

Установщик проверит наличие Docker, Docker Compose, curl и tar. Если Docker Desktop не запущен, установка остановится с понятным сообщением.

2. Запустите установщик

curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | sh

Установщик:

  • сохранит рабочую копию в ~/.vpn-proxy-client;
  • предложит порт для локального прокси;
  • соберёт и запустит контейнер Harbor Connect;
  • добавит пользовательский LaunchAgent для определения текущего Gateway.

По умолчанию используются адреса:

Назначение Адрес
Интерфейс Harbor Connect http://127.0.0.1:3456
HTTP-прокси 127.0.0.1:8082
SOCKS5-прокси 127.0.0.1:8082

3. Добавьте подписку

Откройте http://127.0.0.1:3456, добавьте подписку с понятным именем, выберите сервер внутри её группы и включите VPN. Остальные подписки можно добавить через правую панель «Подписки»; у каждой сохраняются собственные серверы, лимит и выбор.

Сам по себе локальный прокси не перенаправляет приложения автоматически. Адрес 127.0.0.1:8082 нужно указать в настройках нужного приложения или в системных настройках macOS.

Другие порты

Передайте нужные значения при повторном запуске установщика:

curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | \
  VPN_PROXY_CLIENT_PORT=9080 \
  VPN_PROXY_CLIENT_UI_PORT=3457 \
  sh

Допустимы порты от 1024 до 65535. Установщик не позволит выбрать занятый порт или один порт одновременно для интерфейса и прокси.

Правила маршрутизации

После добавления подписки откройте «Правила маршрутизации» справа от основного экрана. При первом обновлении Harbor добавит включённое правило *.ru → Напрямую. Для каждого точного домена, suffix или фрагмента имени можно выбрать результат VPN либо Напрямую, выключить правило или удалить его. Правила проверяются сверху вниз, первое совпадение выбирает маршрут. Чтобы изменить порядок, возьмите строку за три точки слева и перетащите; с клавиатуры нажмите на этом хвате Space или Enter, переместите правило стрелками и повторно нажмите для размещения.

Правила применяются только к трафику, который вошёл в VPN-маршрутизацию Harbor. Устройство Gateway в режиме «Напрямую» и Connect при активном Harbor Gateway обходят локальный список; «Напрямую» внутри правила — результат уже найденного совпадения. Для устройства Gateway с маршрутом VPN и при обычном локальном VPN список применяется.

Полный URL можно вставить в поле точного домена, но Harbor сохранит только hostname. Путь и параметры HTTPS зашифрованы и недоступны sing-box на уровне маршрутизации. GeoSite, GeoIP и подключаемые списки пока не поддерживаются.

При сохранении Harbor проверяет фактическое состояние sing-box. Работающий процесс применяет новую конфигурацию, только если она изменилась. Если sing-box остановлен, правила сохраняются с признаком «ждут запуска» и начнут работать при следующем запуске или restart; в Connect с активным Harbor Gateway они сохраняются как желаемые, но локально не применяются.

Системный прокси macOS

Сначала посмотрите точное имя сетевого подключения:

networksetup -listallnetworkservices

Для подключения с именем Wi-Fi включите HTTP, HTTPS и SOCKS5-прокси:

networksetup -setwebproxy Wi-Fi 127.0.0.1 8082
networksetup -setsecurewebproxy Wi-Fi 127.0.0.1 8082
networksetup -setsocksfirewallproxy Wi-Fi 127.0.0.1 8082

Чтобы отключить их:

networksetup -setwebproxystate Wi-Fi off
networksetup -setsecurewebproxystate Wi-Fi off
networksetup -setsocksfirewallproxystate Wi-Fi off

Если сетевое подключение называется иначе, замените Wi-Fi его точным именем.

Автоматическое использование домашнего Gateway

Harbor Connect раз в пять секунд узнаёт у macOS адрес текущего основного шлюза. Если по этому адресу работает Harbor Gateway с той же выбранной VPN-подпиской, Connect оставляет локальный прокси доступным для приложений, но не создаёт второй VPN-маршрут: трафик уже обрабатывает Gateway.

Для этого:

  1. добавьте одну и ту же ссылку подписки в Gateway и Connect и выберите соответствующий профиль на обоих устройствах;
  2. убедитесь, что Mac может открыть интерфейс Gateway на порту 3456;
  3. оставьте автоматический режим включённым в Harbor Connect.

Ссылка должна содержать персональный секрет или token длиной не менее 16 символов — обычные ссылки подписок уже соответствуют этому условию. Ссылка между устройствами не передаётся: она используется локально для проверки, что Connect нашёл именно ваш Gateway. До отдельного pairing-flow Connect не получает от Gateway имя фактически применённых подписки и сервера, поэтому в режиме Gateway честно показывает Gateway · сервер не определён. При смене сети или после трёх неудачных проверок Connect возвращается к локальному VPN.

Повседневные команды

Все команды Gateway выполняются из каталога проекта. Команды Connect — из ~/.vpn-proxy-client.

Harbor Gateway

Действие Команда
Запустить или обновить после изменения файлов docker compose -f docker-compose.gateway.yml up -d --build
Обновить только интерфейс и управление docker compose -f docker-compose.gateway.yml build vpn-proxy-control && docker compose -f docker-compose.gateway.yml up -d --no-deps vpn-proxy-control
Показать состояние docker compose -f docker-compose.gateway.yml ps
Смотреть журнал docker compose -f docker-compose.gateway.yml logs -f
Перезапустить только интерфейс и управление docker compose -f docker-compose.gateway.yml restart vpn-proxy-control
Перезапустить VPN dataplane docker compose -f docker-compose.gateway.yml restart vpn-proxy-dataplane
Остановить docker compose -f docker-compose.gateway.yml down
Удалить вместе с сохранёнными данными docker compose -f docker-compose.gateway.yml down -v

Harbor Connect

cd ~/.vpn-proxy-client
Действие Команда
Обновить и снова запустить ./scripts/install-macos-client.sh
Показать состояние docker compose -f docker-compose.client.yml ps
Смотреть журнал docker compose -f docker-compose.client.yml logs -f
Перезапустить docker compose -f docker-compose.client.yml restart
Остановить docker compose -f docker-compose.client.yml down
Удалить вместе с сохранёнными данными docker compose -f docker-compose.client.yml down -v

Команда с -v удаляет подписку, выбранный сервер и другие сохранённые данные. Для обычной остановки используйте down без -v.

Обновление

Gateway

git pull --ff-only
docker compose -f docker-compose.gateway.yml up -d --build

Connect

Повторно запустите однострочный установщик. Он обновит рабочую копию, снова спросит порт прокси и пересоберёт Connect:

curl -fsSL https://git.dokops.ru/dokril/vpn-proxy/raw/branch/master/install.sh | sh

Если раньше использовался нестандартный порт, укажите его снова через VPN_PROXY_CLIENT_PORT.

Версии

Текущая версия всегда показана в правом нижнем углу интерфейса. Connect показывает строку M (Mac client). Gateway показывает C (Gateway client UI), B (текущий control-backend) и D (фактически развёрнутый dataplane). Поэтому после control-only deploy B обновится сразу, а D может намеренно остаться на прежней версии до следующего runtime-deploy. Наведите курсор или переведите клавиатурный фокус на цифру, чтобы увидеть смысл major, minor или hotfix; у D также указана фактическая версия sing-box.

Компонентные версии меняются в src/shared/versions.ts. У всех компонентов должен совпадать major, у Gateway client и backend — major.minor; hotfix может отличаться. Runtime-значения доступны через GET /api/version.

Для изменения версии используйте npm run version:harbor -- affected HEAD, затем npm run version:harbor -- bump <major|minor|hotfix> [компонент] и npm run version:harbor -- check HEAD. Правила выбора уровня закреплены в обязательном repo skill manage-harbor-versions.

Настройки .env

Для большинства установок достаточно стандартных значений.

Переменная По умолчанию Назначение
PORT 3456 Внутренний порт веб-интерфейса Gateway
CLIENT_UI_PORT 3456 Порт интерфейса Connect на Mac
PROXY_PORT 8080 Порт общего прокси Gateway
CLIENT_PROXY_PORT 8082 Порт локального прокси Connect
HARBOR_GATEWAY_CONTROL_PORT 3456 Порт, на котором Connect проверяет домашний Gateway
PROXY_BIND_IP 0.0.0.0 Адрес, на котором Gateway принимает прокси-подключения
PROXY_ALLOWED_CIDRS приватные IPv4-сети Сети, которым разрешён доступ к Gateway Proxy
GATEWAY_CLIENT_CIDRS приватные IPv4-сети Сети, трафик которых Gateway может маршрутизировать
DIRECT_TRAFFIC_MARK 0x40000000 Зарезервированный одиночный connmark-бит учёта Direct; измените при конфликте с host QoS/firewall, не пересекаясь с TPROXY_MARK
LOG_LEVEL info Уровень подробности журнала

Остальные значения в .env.example относятся к сборке контейнера и внутренней маршрутизации. Меняйте их только при нестандартном развёртывании.

После изменения .env пересоздайте контейнер командой up -d — обычного restart недостаточно.

Prometheus и Grafana

Gateway публикует уже накопленные Harbor traffic counters по адресу http://<gateway>:3456/metrics. Scrape не запускает дополнительный netfilter read и не меняет сохранённое состояние. Harbor обновляет snapshot раз в 15 секунд, поэтому рекомендуемый начальный scrape interval и refresh dashboard — 30 секунд:

scrape_configs:
  - job_name: harbor_gateway
    scrape_interval: 30s
    scrape_timeout: 3s
    metrics_path: /metrics
    static_configs:
      - targets: ["<gateway>:3456"]

harbor_traffic_bytes_total содержит общий накопленный объём по источникам Gateway/Proxy. harbor_device_traffic_bytes_total содержит upload/download по стабильному device_id; пользовательское название и текущий IP находятся в harbor_device_info. harbor_device_domain_traffic_bytes_total добавляет наблюдённые домен, сервис, источник и направление для каждого устройства. harbor_domain_traffic_attribution_events_total{outcome} помогает отличить нераспознанный hostname, неизвестное устройство и неподдерживаемый inbound без динамических high-cardinality labels.

Фактический выход экспортируется отдельно. harbor_singbox_tracked_bytes_total{source,outbound,direction} показывает наблюдённые sing-box байты с outbound="vpn|direct|unknown"; вариант с префиксом harbor_device_... добавляет device_id. harbor_direct_ipv4_packet_bytes_total{direction} считает IPv4-пакеты, которые Gateway направил напрямую вместо sing-box, включая policy Direct и работу при остановленном VPN runtime; вариант harbor_device_... содержит атрибутированную детализацию. source="gateway|proxy" по-прежнему означает место входа, а outbound — выбранный sing-box выход.

Dashboard начинает со скорости скачивания и отправки в конце выбранного периода, общего трафика и VPN / Direct внутри sing-box за этот период. Для стандартного диапазона, который заканчивается сейчас, карточки скорости показывают текущее значение. Единый фильтр Устройства по умолчанию охватывает все устройства, но позволяет выбрать одно; он управляет скоростью, общим трафиком, маршрутами, сервисами, доменами и технической детализацией. Таблица «Все устройства за период» намеренно остаётся общей: она показывает все устройства с ненулевым трафиком, сортируется в обе стороны и выбирает устройство в том же фильтре. Блок «Куда уходит трафик» показывает основные назначения и Top-15 доменов без пагинации. Свёрнутая техническая детализация отдельно показывает точки входа Gateway / Proxy и Direct IPv4 мимо sing-box. Автообновление настроено на 30 секунд; индикатор показывает возраст самого старого из контуров общего, domain / sing-box и Direct IPv4 трафика, предупреждает после 60 секунд и считает данные устаревшими после 120 секунд.

Domain и sing-box outbound counters снимаются с активных соединений раз в 2 секунды и хранятся в памяти dataplane до его перезапуска; историю и retention хранит Prometheus. Перед routing sing-box до 1 секунды распознаёт HTTP Host, TLS SNI и QUIC Server Name. YouTube и OpenAI / ChatGPT объединяются по известным связанным доменам в label service, остальные значения сохраняют домен как имя сервиса. Если устройство и Harbor source известны, но hostname недоступен (например, ECH или IP-only), трафик попадает в domain="_unknown",service="Не распознано" и не теряется. Новые domain series сверх process limit складываются в _other.

Direct IPv4 считает L3 packet bytes с IP-заголовками и retransmit, а sing-box tracker — логические TCP/UDP bytes без tunnel overhead. Эти семейства нельзя складывать в один «точный общий трафик». Snapshot polling может пропустить короткие соединения и финальный хвост; IPv6, трафик вне Gateway, назначения из BYPASS_CIDRS и quota провайдера не входят в новый route split.

Готовый dashboard: monitoring/grafana/harbor-gateway.json. При импорте Grafana попросит выбрать Prometheus data source. Та же конфигурация и dashboard доступны для копирования в Gateway drawer «Как использовать» → «Prometheus и Grafana».

Если что-то не работает

Интерфейс не открывается

Проверьте контейнер и журнал:

docker compose -f docker-compose.gateway.yml ps
docker compose -f docker-compose.gateway.yml logs --tail=100

Для Connect замените имя файла на docker-compose.client.yml и выполняйте команду из ~/.vpn-proxy-client.

Прокси не отвечает

Убедитесь, что Harbor включён в интерфейсе, а приложение использует правильные адрес и порт. Для Connect это обычно 127.0.0.1:8082; для Gateway — IP Linux-машины и порт 8080.

Connect не распознаёт Gateway

Проверьте три условия:

  • Gateway является текущим основным шлюзом Mac;
  • на обоих устройствах сохранена одна и та же подписка;
  • с Mac открывается http://АДРЕС-GATEWAY:3456.

Проверка конфигурации без запуска

docker compose -f docker-compose.gateway.yml config
docker compose -f docker-compose.client.yml config
docker compose -f docker-compose.client.local.yml config

Эти команды только проверяют и показывают итоговую конфигурацию Docker Compose.

Локальное тестирование Harbor Connect

Тестовый Connect запускается рядом с установленным клиентом и использует отдельные контейнер, volumes и порты:

docker compose -f docker-compose.client.local.yml up -d --build

Интерфейс доступен на http://127.0.0.1:3457, HTTP/SOCKS5-прокси — на 127.0.0.1:8083. Остановить и удалить только тестовый стек можно командой:

docker compose -f docker-compose.client.local.yml down -v

Порты можно заменить через LOCAL_CLIENT_UI_PORT и LOCAL_CLIENT_PROXY_PORT.

Служебные команды

Этот раздел нужен тем, кто собирает, проверяет или развёртывает сам проект. Для обычного использования он не требуется.

Команды npm

Команда Назначение
npm ci Установить точные версии зависимостей из package-lock.json
npm test Запустить автоматические проверки
npm run build Собрать веб-интерфейс в dist/
npm run dev Запустить Vite для разработки интерфейса
npm start Запустить управляющий Node.js-сервис в подготовленном окружении

Сборка и развёртывание

Команда Назначение
./scripts/build-runtime-base.sh Собрать базовый runtime-образ с Node.js, сетевыми утилитами и sing-box
./scripts/build-on-107-deploy-111.sh Собрать Gateway на хосте 107 и развернуть на хосте 111; хосты меняются через BUILD_HOST и DEPLOY_HOST
GATEWAY_IMAGE=<образ> ./scripts/deploy-gateway.sh Развернуть уже собранный образ в /opt/vpn-proxy
./scripts/harbor-network-monitor.sh Один раз записать текущий Gateway macOS; обычно этот скрипт запускает установленный LaunchAgent

Отправка изменений в ветку master также запускает автоматическую сборку и развёртывание Gateway через Gitea Actions. Каждый деплой пересоздаёт vpn-proxy-control, поэтому строка B соответствует текущему коду API. Процесс sing-box и сетевые правила остаются в vpn-proxy-dataplane; он пересоздаётся только при изменении его runtime-зависимостей, а его фактическая версия показывается отдельно как D.

Хранение данных

Подписка, выбранный сервер и состояние подключения хранятся в именованных Docker volumes. Поэтому обычные команды restart, down, обновление проекта и повторная сборка не удаляют настройки.

Не публикуйте файл .env, ссылку подписки и содержимое Docker volumes. .env уже исключён из Git.

S
Description
No description provided
Readme
12 MiB
Server + Mac
Latest
2026-05-19 14:48:00 +03:00
Languages
TypeScript 51.8%
JavaScript 37.3%
CSS 8.2%
Shell 2.6%
Dockerfile 0.1%