{"id":50237784,"url":"https://github.com/grandvan709/roscomvpn-geo-sync","last_synced_at":"2026-05-26T20:33:01.195Z","repository":{"id":357518572,"uuid":"1237319020","full_name":"grandvan709/roscomvpn-geo-sync","owner":"grandvan709","description":"Self-hosted mirror of roscomvpn geo files + automatic Remnawave routing deeplink updates","archived":false,"fork":false,"pushed_at":"2026-05-13T06:11:11.000Z","size":40,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-13T06:35:29.972Z","etag":null,"topics":["bash","docker","python3","remnawave","routing","telegrambot","xray"],"latest_commit_sha":null,"homepage":"https://t.me/grand_van","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grandvan709.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-13T04:31:37.000Z","updated_at":"2026-05-13T06:11:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/grandvan709/roscomvpn-geo-sync","commit_stats":null,"previous_names":["grandvan709/roscomvpn-geo-sync"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/grandvan709/roscomvpn-geo-sync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grandvan709%2Froscomvpn-geo-sync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grandvan709%2Froscomvpn-geo-sync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grandvan709%2Froscomvpn-geo-sync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grandvan709%2Froscomvpn-geo-sync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grandvan709","download_url":"https://codeload.github.com/grandvan709/roscomvpn-geo-sync/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grandvan709%2Froscomvpn-geo-sync/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33538659,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","docker","python3","remnawave","routing","telegrambot","xray"],"created_at":"2026-05-26T20:32:57.222Z","updated_at":"2026-05-26T20:33:01.182Z","avatar_url":"https://github.com/grandvan709.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=center\u003eАвто-зеркало \u003ccode\u003egeoip.dat\u003c/code\u003e / \u003ccode\u003egeosite.dat\u003c/code\u003e + авто-обновление routing-deeplinks в \u003ccode\u003eRemnawave\u003c/code\u003e\u003c/h1\u003e\n\n\u003e **Собственное зеркало** geo-файлов от [hydraponique/roscomvpn-*](https://github.com/hydraponique) для VPN-инфры на Xray-ядре (INCY, Happ) и **автоматическое обновление** routing-deeplinks в Remnawave-панели через API\n\n\u003cp align=center\u003eДанный репозиторий был создан и поддерживается в связи с тем, что \u003cb\u003eРоскомнадзор\u003c/b\u003e начал блокировать GitHub и его CDN. VPN-клиенты на Xray-ядре (INCY, Happ) используют geo-файлы для split-tunneling — без них маршрутизация ломается. Этот сервис позволяет раздавать geo-файлы с собственного домена и автоматически обновлять routing-deeplinks в Remnawave-панели.\u003c/p\u003e\n\n---\n\n## 🚀 Возможности\n\n- ✅ Скачивание `geoip.dat` и `geosite.dat` с GitHub Releases и проверкой sha256\n- ✅ Fallback на jsDelivr с проверкой размера и magic byte при недоступности GitHub\n- ✅ Атомарная замена локального кэша (старая версия не теряется при сбое)\n- ✅ Загрузка свежих файлов на удалённый сервер раздачи через rsync (опционально)\n- ✅ Health-check публичного URL раздачи после rsync (опционально)\n- ✅ Автоматическая генерация routing-deeplinks для INCY и Happ из upstream `JSONSUB.JSON`\n- ✅ Автоматический PATCH `/api/subscription-settings` в Remnawave: правило INCY Routing + поле Happ Routing (опционально)\n- ✅ Вывод готовых deeplinks в логи — для ручной вставки в панель если автоматизация отключена\n- ✅ Telegram-уведомления о результатах каждого запуска (✅ OK / ⚠️ used fallback / ❌ FAILED)\n- ✅ Регулярное выполнение по cron-расписанию (настраивается через `.env`)\n- ✅ Валидация конфигурации при старте\n- ✅ Автоматические повторы при сбоях сети (tenacity)\n- ✅ Подробное логирование\n\n## 📋 Требования\n\n- Docker\n- (опционально) Удалённый сервер с настроенным rsync для раздачи geo-файлов с собственного домена\n- (опционально) Remnawave-панель + API-токен для автоматического PATCH deeplinks\n- (опционально) Telegram-бот для уведомлений\n\n---\n\n## 🔧 Установка\n\n### 1. Устанавливаем Docker\n```bash\nsudo curl -fsSL https://get.docker.com | sh\n```\n\n### 2. Создаем папку `/opt/geo-mirror` и переходим в нее\n```bash\nsudo mkdir -p /opt/geo-mirror \u0026\u0026 cd /opt/geo-mirror\n```\n\n### 3. Скачиваем файлы `.env.example` (его сразу ренеймим в `.env`) и `docker-compose.yml`\n```bash\nsudo wget -O .env https://raw.githubusercontent.com/grandvan709/roscomvpn-geo-sync/refs/heads/master/.env.example \u0026\u0026 \\\nsudo wget -O docker-compose.yml https://raw.githubusercontent.com/grandvan709/roscomvpn-geo-sync/refs/heads/master/docker-compose.yml\n```\n\n### 4. Заполняем файл `.env` необходимыми значениями (см раздел \"Конфигурация\")\n```bash\nsudo nano .env\n```\n\n### 5. (опционально, если используется rsync) Кладём приватный SSH-ключ\n```bash\nsudo cp /path/to/private-key /opt/geo-mirror/ssh-key\nsudo chmod 600 /opt/geo-mirror/ssh-key\n```\n\n\u003e Если rsync не используется — закомментируйте строку `./ssh-key:/app/ssh-key:ro` в `docker-compose.yml`, иначе Docker создаст пустую директорию вместо файла и контейнер упадёт.\n\n## ⚙️ Конфигурация\n\n### Обязательные переменные\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eПеременная\u003c/th\u003e\n    \u003cth\u003eПо умолчанию\u003c/th\u003e\n    \u003cth\u003eОписание\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eGEOIP_REPO\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003ehydraponique/roscomvpn-geoip\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eGitHub-репозиторий с релизами \u003ccode\u003egeoip.dat\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eGEOSITE_REPO\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003ehydraponique/roscomvpn-geosite\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eGitHub-репозиторий с релизами \u003ccode\u003egeosite.dat\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eROUTING_REPO\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003ehydraponique/roscomvpn-routing\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eGitHub-репозиторий с \u003ccode\u003eINCY/JSONSUB.JSON\u003c/code\u003e и \u003ccode\u003eHAPP/JSONSUB.JSON\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eROUTING_BRANCH\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003emain\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eВетка репозитория, откуда тянуть JSONSUB\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eROUTING_CLIENTS\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eINCY,HAPP\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eКлиенты, для которых строить deeplinks (через запятую). Поддерживается: \u003ccode\u003eINCY\u003c/code\u003e, \u003ccode\u003eHAPP\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n### Опциональные переменные\n\n| Переменная | По умолчанию | Описание |\n|-----------|:----------:|---------|\n| `TZ` | `UTC` | Часовой пояс контейнера ([список](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) |\n| `CRON_SCHEDULE` | `0 */12 * * *` | Расписание cron (по умолчанию — каждые 12 часов) |\n| `GEOIP_MIN_SIZE` | `10000` | Минимальный размер `geoip.dat` (байт). Защита от обрезанных загрузок при fallback на jsDelivr |\n| `GEOSITE_MIN_SIZE` | `10000` | Минимальный размер `geosite.dat` (байт) |\n\n### rsync на удалённый сервер (опционально)\n\nЕсли эти переменные не заданы — geo-файлы сохраняются только в локальный кэш `./files/`, rsync пропускается.\n\n| Переменная | По умолчанию | Описание |\n|-----------|:----------:|---------|\n| `RSYNC_HOST` | — | Хост удалённого сервера раздачи |\n| `RSYNC_USER` | — | SSH-пользователь на удалённом сервере |\n| `RSYNC_PORT` | `22` | SSH-порт |\n| `RSYNC_REMOTE_DEST` | `./` | Целевая директория rsync. Для `rrsync`-restricted цели используйте `./` |\n| `SSH_KEY_PATH` | `/app/ssh-key` | Путь к SSH-ключу внутри контейнера (не менять, маунт через docker-compose) |\n| `GEO_PUBLIC_URL` | — | Публичный URL раздачи (например `https://geo.example.com`). Если задан — подставляется в JSONSUB и используется для health-check после rsync. Если НЕ задан — в JSONSUB остаются оригинальные URL'ы (`cdn.jsdelivr.net`) |\n\n### Push deeplinks в Remnawave-панель (опционально)\n\nЕсли `REMNAWAVE_API_URL` и `REMNAWAVE_API_TOKEN` не заданы оба — PATCH в панель пропускается, deeplinks выводятся только в логах (для ручного копирования в Response Rules / Happ Routing).\n\n| Переменная | По умолчанию | Описание |\n|-----------|:----------:|---------|\n| `REMNAWAVE_API_URL` | — | URL Remnawave-панели (без `/api`) |\n| `REMNAWAVE_API_TOKEN` | — | Bearer JWT API-токен (создаётся в Remnawave UI → Settings → API Keys) |\n| `REMNAWAVE_CADDY_TOKEN` | — | Опционально: `X-Api-Key` заголовок (если ваша панель за Caddy auth-portal требует его для `/api/*`) |\n| `INCY_RULE_NAME` | `INCY Routing` | Имя правила в Response Rules, содержащего header с key=`routing` для INCY-клиентов |\n\n### Telegram-уведомления (опционально)\n\nПосле каждого запуска бот отправляет итоговое сообщение со сводкой (✅ OK / ⚠️ used fallback / ❌ FAILED). Если переменные не заданы — Telegram-уведомления отключены, статус виден только в логах.\n\n| Переменная | Описание |\n|-----------|---------|\n| `TELEGRAM_BOT_TOKEN` | Токен бота (получить у [@BotFather](https://t.me/BotFather)) |\n| `TELEGRAM_CHAT_ID` | ID чата/группы (узнать через [@userinfobot](https://t.me/userinfobot) или [@getidsbot](https://t.me/getidsbot)) |\n| `TELEGRAM_THREAD_ID` | ID топика в супергруппе (опционально) |\n\n### Примеры CRON_SCHEDULE\n\n```env\nCRON_SCHEDULE='0 */12 * * *'     # каждые 12 часов (по умолчанию)\nCRON_SCHEDULE='0 */6 * * *'      # каждые 6 часов\nCRON_SCHEDULE='0 4 * * *'        # один раз в день в 04:00\nCRON_SCHEDULE='*/30 * * * *'     # каждые 30 минут (для тестов)\nCRON_SCHEDULE='0 0 * * 0'        # один раз в неделю в воскресенье\n```\n\n**Формат cron:** `минуты часы дни_месяца месяцы дни_недели`\n\n---\n\n## 🌐 Setup rsync на удалённый сервер раздачи\n\nНа сервере, который будет раздавать `geo.example.com/*.dat`:\n\n### 1. Создать директорию для файлов\n```bash\nsudo mkdir -p /opt/geo-mirror/files\nsudo chown -R yourSshUser:yourSshUser /opt/geo-mirror\n```\n\n### 2. Установить `rsync` и `rrsync` (restricted rsync wrapper)\n```bash\nsudo apt-get install rsync\n```\n\n### 3. Сгенерировать SSH-ключ на сервере, где будет запускаться контейнер\n```bash\nssh-keygen -t ed25519 -N '' -f /opt/geo-mirror/ssh-key -C 'roscomvpn-geo-sync'\nsudo chmod 600 /opt/geo-mirror/ssh-key\n```\n\n### 4. Добавить публичный ключ в `authorized_keys` на raздающем сервере (с `rrsync`-ограничением)\n```bash\necho 'command=\"/usr/bin/rrsync -wo /opt/geo-mirror/files/\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty \u003cсодержимое /opt/geo-mirror/ssh-key.pub\u003e' \u003e\u003e ~yourSshUser/.ssh/authorized_keys\n```\n\n\u003e `rrsync -wo` — write-only режим, ключ может только заливать файлы в одну директорию, никаких shell-команд.\n\n### 5. Настроить веб-сервер для раздачи. Пример Caddyfile\n```caddy\ngeo.example.com {\n    root * /opt/geo-mirror/files\n    file_server\n    @geodat path *.dat\n    header @geodat {\n        Cache-Control \"public, max-age=3600\"\n        Content-Type \"application/octet-stream\"\n    }\n}\n```\n\n### 6. В `.env` контейнера прописать соответствующие значения\n```env\nRSYNC_HOST=geo.example.com\nRSYNC_USER=yourSshUser\nRSYNC_PORT=22\nRSYNC_REMOTE_DEST=./\nGEO_PUBLIC_URL=https://geo.example.com\n```\n\n---\n\n## 🔗 Setup Remnawave-интеграции (Phase 2b)\n\n### 1. В Remnawave-панели создать правило в Response Rules\n\nВ UI Remnawave → **Subscription → Settings → Response Rules** — добавить правило:\n- **Name:** `INCY Routing` (или другое, тогда укажите в `INCY_RULE_NAME`)\n- **Condition:** `user-agent CONTAINS incy` (case-insensitive)\n- **Response type:** `XRAY_JSON`\n- **Response modifications → headers:** добавить header с key `routing` и любым тестовым value (скрипт перепишет его при первом запуске)\n\n### 2. Создать API-токен в Remnawave\n\nВ UI Remnawave → **Settings → API Keys** → создать новый ключ с ролью `ADMIN` или `API`. Скопировать Bearer JWT.\n\n### 3. В `.env` контейнера прописать\n```env\nREMNAWAVE_API_URL=https://your-panel.example.com\nREMNAWAVE_API_TOKEN=eyJ...\nINCY_RULE_NAME=INCY Routing\n```\n\n\u003e Поле **Happ Routing** в `Subscription → Settings → Announce \u0026 Routing` обновляется автоматически — отдельной настройки не требует.\n\n---\n\n## 🚀 Запуск\n\n### Первый запуск\n```bash\ncd /opt/geo-mirror \u0026\u0026 sudo docker compose up -d\n```\n\n### Проверка логов\n```bash\ncd /opt/geo-mirror \u0026\u0026 sudo docker compose logs -f -t\n```\n\n### Остановка\n```bash\ncd /opt/geo-mirror \u0026\u0026 sudo docker compose down\n```\n\n### Перезагрузка\n```bash\ncd /opt/geo-mirror \u0026\u0026 sudo docker compose down \u0026\u0026 sudo docker compose up -d\n```\n\n---\n\n## 📊 Структура логов\n\n```\n2026-05-13 04:39:32,904 [INFO] === geo-sync run start ===\n2026-05-13 04:39:33,565 [INFO] HTTP Request: GET https://api.github.com/repos/hydraponique/roscomvpn-geoip/releases/latest \"HTTP/1.1 200 OK\"\n2026-05-13 04:39:34,422 [INFO] HTTP Request: GET .../releases/download/202605120620/geoip.dat \"HTTP/1.1 302 Found\"\n2026-05-13 04:39:39,679 [INFO] HTTP Request: GET https://raw.githubusercontent.com/hydraponique/roscomvpn-routing/main/INCY/JSONSUB.JSON \"HTTP/1.1 200 OK\"\n2026-05-13 04:39:39,681 [INFO] INCY Routing: ://routing/onadd/eyJOYW1lIjoiUm9zY29tVlBOIEpTT04i...\n2026-05-13 04:39:40,129 [INFO] HTTP Request: GET https://raw.githubusercontent.com/hydraponique/roscomvpn-routing/main/HAPP/JSONSUB.JSON \"HTTP/1.1 200 OK\"\n2026-05-13 04:39:40,129 [INFO] Happ Routing: happ://routing/onadd/eyJOYW1lIjoiUm9zY29tVlBOIEpTT04i...\n2026-05-13 04:39:40,129 [INFO] === geo-sync run done: OK ===\n\nSchedule: 0 */12 * * *\nSwitching to periodic mode...\n==========================================\n```\n\n### Пример Telegram-сообщения\n\n```\n✅ roscomvpn-geo-sync — OK\ngeoip.dat: ⬆ updated [github:202605120620, 407.0KiB]\ngeosite.dat: ✓ no changes [github:202604152235, 66.3KiB]\nrsync to remote: ✓ OK\nrouting-INCY: ⬆ updated\nrouting-HAPP: ⬆ updated\nRouting applied to Remnawave: INCY + HAPP\n```\n\n\u003e Сам deeplink (длинная base64-строка) в Telegram **не вставляется** — он только в логах контейнера. Это снижает шум в чате.\n\n---\n\n## 💡 Обновление ПО\n\n### 1. Переходим в нашу папку\n```bash\ncd /opt/geo-mirror\n```\n\n### 2. Останавливаем контейнер\n```bash\nsudo docker compose down\n```\n\n### 3. Скачиваем новый образ\n```bash\nsudo docker compose pull\n```\n\n### 4. Запускаем контейнер и смотрим логи после запуска новой версии\n```bash\nsudo docker compose up -d \u0026\u0026 sudo docker compose logs -f -t\n```\n\n### 5. Проверка docker-compose.yml и прочих файлов\nПеред обновлениями и запусками — убедитесь, что ваши файлы **docker-compose.yml** и **.env** *(и прочие, которые могут быть в будущем)* соответствуют последним версиям из репозитория!\n\n\u003e Чтобы не писать `sudo` перед каждой командой `docker` — нужно внести пользователя, из под которого вы работаете, в группу **docker** следующей командой: `sudo usermod -aG docker \u003cusername\u003e`. А затем перезайти на сервер.\n---\n\n\u003e **Ставь ⭐** и не пропусти регулярные обновления для поддержания актуальности скрипта и оптимальной автоматизации\n\n\u003e USDT TRC20: TL6gHETnKqNWV4D6GjiKKahkBsAwcyWfo8\n\n\u003cp align=center\u003e\n    \u003ca href=\"https://t.me/grand_van\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Telegram-GrandVan-purple?logo=telegram\u0026logoColor=white\u0026labelColor=blue\" alt=\"Chat me on Telegram\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrandvan709%2Froscomvpn-geo-sync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrandvan709%2Froscomvpn-geo-sync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrandvan709%2Froscomvpn-geo-sync/lists"}