Important
Материал носит исключительно информационный и учебный характер. Любое иное использование выходит за рамки ознакомления и может противоречить действующему законодательству. Автор не отвечает за последствия применения описанных подходов.
Warning
Все действия вы выполняете на свой страх и риск.
Автор не несет ответственности за возможный ущерб оборудованию, программному обеспечению, ограничения доступа, а также иные побочные эффекты. Предполагается, что вы осознаёте возможные риски и понимаете, что делаете.
Скрипт для Keenetic OS 5: синхронизирует списки доменов в разделе "Маршруты DNS" с базой v2fly/domain-list-community, сохраняет маршруты и режет большие списки на части автоматически.
Note
Требуется Keenetic OS 5.
- читает текущую конфигурацию и ищет группы доменов с нужным префиксом
- превращает описание группы в имя файла из v2fly (
Facebook [1/2]→facebook,Google Play→google-play) - тянет
data/<name>, раскрываетinclude:, игнорирует пустые/keyword:/regexp:правила - пересобирает группы доменов; при превышении лимита режет на части
<name>,<name>-2,<name>-3и т.д. - сохраняет существующие маршруты DNS (
auto/reject/disable) после пересоздания групп и добавляет маршруты на интерфейс из конфига
- Если у группы уже были DNS-маршруты, они восстанавливаются после синхронизации. Это защищает ручные маршруты от удаления при пересоздании
object-group. routeInterfaceизconfig.jsonиспользуется для создания или обновления маршрута на нужный интерфейс, напримерProxy0илиWireguard0.- HTTP-сервис перечитывает
config.jsonна каждый/syncи/clean. Если поменятьrouteInterface,domainsили другие настройки, перезапускать сервис не нужно. - Можно вести несколько VPN/proxy-групп одновременно. Для разных интерфейсов используйте массив профилей: каждый профиль синхронизирует только свой явный список
domainsи создаёт маршруты на свойrouteInterface.
Поддерживаются два формата: один объект конфига или массив профилей.
Ключи:
baseUrl— источник доменных листов.prefix— префикс для поиска групп доменов в конфиге (domain-listпо умолчанию).timeoutMs,retries— таймаут в миллисекундах и количество попыток загрузки.maxEntriesPerGroup— максимум доменов в группе; при превышении создаются<name>-2,<name>-3и т.д. По умолчанию 300.routeInterface— интерфейс, через который будут идти маршруты. Например,Wireguard0(можно узнать через командуshow interfaceв CLIhttp://<router_id>/a).domains— явный список описаний доменных групп для профиля. Используется в массиве профилей, чтобы разные списки можно было привязать к разным интерфейсам.initialDomains— если групп с нужным префиксом нет, создадутся новые группы с описанием из списка и маршрутом (если задан интерфейс). В массиве профилей также работает как совместимый alias дляdomains.dryRun— только логирует командыndmc, без применения.
Одиночный объект сохраняет старое поведение: скрипт ищет все группы с prefix, а initialDomains используется только если таких групп нет.
Пример одиночного конфига:
{
"baseUrl": "https://raw.githubusercontent.com/v2fly/domain-list-community/master/data/",
"prefix": "domain-list",
"timeoutMs": 20000,
"retries": 3,
"maxEntriesPerGroup": 300,
"routeInterface": "Wireguard0",
"initialDomains": [
"Facebook",
"Google Play",
"Instagram",
"JetBrains",
"Linkedin",
"OpenAI",
"SoundCloud",
"Spotify",
"Telegram",
"Twitter",
"WhatsApp",
"YouTube"
],
"dryRun": false
}Пример нескольких VPN/proxy-групп с одним prefix, но разными интерфейсами:
[
{
"baseUrl": "https://raw.githubusercontent.com/v2fly/domain-list-community/master/data/",
"prefix": "domain-list",
"timeoutMs": 20000,
"retries": 3,
"maxEntriesPerGroup": 300,
"routeInterface": "Proxy0",
"domains": ["YouTube", "Instagram"],
"dryRun": false
},
{
"baseUrl": "https://raw.githubusercontent.com/v2fly/domain-list-community/master/data/",
"prefix": "domain-list",
"timeoutMs": 20000,
"retries": 3,
"maxEntriesPerGroup": 300,
"routeInterface": "Wireguard0",
"domains": ["OpenAI", "Anthropic", "Discord"],
"dryRun": false
}
]В примере выше YouTube и Instagram будут идти через VPN/proxy-группу Proxy0, а OpenAI, Anthropic и Discord — через отдельную VPN-группу Wireguard0. При одинаковом prefix профили не забирают списки друг друга: scope задаётся через domains.
Tip
Вы можете не создавать списки руками и прописать в конфиге initialDomains.
Раздел: http://192.168.1.1/staticRoutes/dns
Ниже два варианта: автоматический (рекомендуемый) через OPKG-репозиторий и ручной (если хотите поставить zip вручную).
Репозиторий: https://yangirov.github.io/keenetic-geosite-sync/all
# Подключение к роутеру
ssh root@192.168.1.1 -p 222
# Зависимости для HTTPS-загрузки
opkg update --force-space
opkg install ca-certificates wget-ssl --force-space
opkg remove wget-nossl 2>/dev/null || true
# Подключаем репозиторий
mkdir -p /opt/etc/opkg
echo "src/gz kgs https://yangirov.github.io/keenetic-geosite-sync/all" > /opt/etc/opkg/kgs.conf
# Установка пакета
opkg update --force-space
opkg install keenetic-geosite-sync --force-spaceПосле установки файлы окажутся в /opt/keenetic-geosite-sync, конфиг — /opt/keenetic-geosite-sync/config.json.
Обновление пакета:
opkg update --force-space
opkg upgrade keenetic-geosite-sync --force-spaceУдаление пакета и зависимостей:
opkg remove --autoremove keenetic-geosite-syncИнформация об установленной версии:
opkg info keenetic-geosite-syncПодробнее про ручную установку
# Подключение к роутеру по SSH
ssh root@192.168.1.1 -p 222
# Установка зависимостей
opkg update --force-space
opkg install node --force-space # обязательно для запуска
opkg install curl unzip --force-space # опционально, только для скачивания архива
opkg install cron --force-space # опционально, если нужен запуск по расписанию
# Скачивание и установка релиза
cd /opt && curl -L https://github.com/yangirov/keenetic-geosite-sync/releases/latest/download/keenetic-geosite-sync-dist.zip -o /tmp/kgs.zip && mkdir -p /opt/keenetic-geosite-sync && unzip -o /tmp/kgs.zip -d /opt/keenetic-geosite-sync && rm /tmp/kgs.zipДалее создайте сервис вручную:
# Создание загрузочного скрипта
mkdir -p /opt/scripts
cp /opt/keenetic-geosite-sync/scripts/geosite-sync.sh /opt/scripts/geosite-sync.sh
chmod +x /opt/scripts/geosite-sync.sh
# Создание сервиса Entware
cp /opt/keenetic-geosite-sync/scripts/S99geosite-sync /opt/etc/init.d/S99geosite-sync
chmod +x /opt/etc/init.d/S99geosite-sync
# Запуск сервиса
/opt/etc/init.d/S99geosite-sync start
# Остановка сервиса
/opt/etc/init.d/S99geosite-sync stop
# Перезапуск сервиса
/opt/etc/init.d/S99geosite-sync restart
# Логи сервиса
/opt/etc/init.d/S99geosite-sync logsДля проверки без изменений поставьте в конфиге "dryRun": true.
Конфиг находится в /opt/keenetic-geosite-sync/config.json — отредактируйте его перед запуском.
После установки и синхронизации, вы сможете отключать правила маршрутизации.
HTTP-сервер поднимается автоматически при старте приложения и слушает порт 3939.
Автосинхронизации при старте нет — дерните /sync вручную или настройте cron.
config.json перечитывается на каждый /sync и /clean, поэтому изменение routeInterface или списка domains не требует рестарта сервиса.
/sync— GET/POST. Запускает синхронизацию.429, если уже выполняется;500при ошибке./clean— GET/POST. Удаляет все группы/маршруты с префиксом изconfig.json./health— GET. Просто отвечает200 OK.
Примеры:
curl http://192.168.1.1:3939/health
curl http://192.168.1.1:3939/sync
curl http://192.168.1.1:3939/cleanЧтобы упростить работу с доменными списками в веб-интерфейсе Keenetic, есть пользовательский скрипт scripts/tampermonkey.js. Он добавляет автокомплит по именам из v2fly/domain-list-community и кнопки для быстрого вызова API сервиса.
- Установите расширение Tampermonkey.
- Создайте новый скрипт и вставьте содержимое
scripts/tampermonkey.js.
Откройте страницу http://192.168.1.1/staticRoutes/dns — в модальном меню добавления списка появится автодополнение по именам доменов из v2fly/domain-list-community.
В интерфейсе Keenetic появятся кнопки, которые вызывают API сервиса (/health, /sync, /clean) по умолчанию на http://192.168.1.1:3939.
Если API у вас на другом хосте/порту — поменяйте константу API_BASE в начале скрипта.
Пример настройки раз в неделю, по субботам в 04:00:
opkg update --force-space
opkg install cron --force-space
echo '0 4 * * 6 curl -s http://127.0.0.1:3939/sync' >> /opt/etc/crontab
/opt/etc/init.d/S10cron restart 2>/dev/null || trueСборка пакета выполняется в GitHub Actions (.github/workflows/publish.yml) при пушах в main/master и тегах v*.*.*. Итоговые ipk публикуются в https://yangirov.github.io/keenetic-geosite-sync/all вместе с Packages/Packages.gz. На тег дополнительно создаётся GitHub Release с keenetic-geosite-sync-dist.zip и ipk.
Также можно собрать через Docker (для тестирования локально):
docker run --rm -it -v "$PWD":/src -w /src node:20-bookworm bash -lc "apt-get update && apt-get install -y ca-certificates && chmod +x opkg/build.sh && ./opkg/build.sh"


