feat: перевод CI на Gitea Actions и автообновление по cron
build / build (push) Successful in 18s

Вместо GitHub Actions — .gitea/workflows/build.yml: проверка, тесты, сборка,
валидация настоящими Xray и sing-box, публикация в ветку release и релиз
через Gitea API (tools/gitea-release.sh). Ни gh CLI, ни GitHub-only экшенов.

Для серверов — tools/update-geosite.sh: сверяет sha256 до закачки и выходит
молча, если файл не менялся, проверяет сумму до подмены, подменяет атомарно и
дёргает перезапуск только когда файл реально обновился. Едет в dist/, поэтому
на сервере нужен один базовый URL. В README — cron и systemd timer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-08-07 14:21:38 +03:00
co-authored by Claude Opus 5
parent f905a76caf
commit c05f6aa0d7
7 changed files with 488 additions and 161 deletions
+162 -17
View File
@@ -4,7 +4,10 @@
тесты утечек DNS/WebRTC, GeoIP-базы и скоринг прокси/VPN.
Собирается в несколько форматов. Основной — `geosite.dat` (protobuf v2ray/Xray) для 3x-ui.
Сборка идёт автоматически при каждом изменении `data/` и раз в сутки по расписанию.
CI на Gitea Actions пересобирает всё при каждом изменении `data/` и раз в сутки по расписанию.
> Во всех примерах ниже `gitea.example.com/mrleo1nid/ipcheck-domains` — замените на адрес
> своего инстанса и репозитория.
## Категории
@@ -18,16 +21,18 @@
## Скачать
Ветка `release` обновляется при каждой сборке ссылки стабильны:
Ветка `release` перезаписывается при каждой сборке, ссылки стабильные:
```
https://raw.githubusercontent.com/mrleo1nid/ipcheck-domains/release/<путь>
https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release/<путь>
```
| Файл | Для чего |
| --- | --- |
| `ipcheck.dat` | Xray / v2ray / 3x-ui — кладётся рядом со штатным `geosite.dat` |
| `geosite.dat` | то же самое, но именем по умолчанию — если хотите заменить штатный файл |
| `ipcheck.dat.sha256sum` | контрольная сумма, по ней работает автообновление |
| `update-geosite.sh` | скрипт обновления для cron (см. ниже) |
| `sing-box/<категория>.srs` | sing-box, скомпилированный rule-set |
| `sing-box/<категория>.json` | sing-box, исходный rule-set |
| `mihomo/<категория>.mrs` | mihomo, бинарный rule-provider |
@@ -36,17 +41,18 @@ https://raw.githubusercontent.com/mrleo1nid/ipcheck-domains/release/<путь>
| `txt/<категория>.txt` | просто домены, по одному на строку |
| `json/<категория>.json` | структурированный список с типами правил |
| `adguard/<категория>.txt` | AdGuard Home / uBlock — если нужно блокировать, а не роутить |
| `metadata.json` | время сборки, счётчики, sha256 |
| `metadata.json`, `SHA256SUMS` | время сборки, счётчики, суммы по всем файлам |
Плюс каждая сборка публикуется как GitHub Release с датой в теге.
Плюс каждая сборка публикуется как релиз Gitea с датой в теге — там же лежит
`ipcheck-domains-all.tar.gz` со всем содержимым `dist/` разом.
## 3x-ui
Файл кладётся туда же, где лежат `geoip.dat` и `geosite.dat` панели. Обычно это
`/usr/local/x-ui/bin` (панель, установленная скриптом) или `/usr/local/share/xray`:
Файл кладётся туда же, где у панели лежат `geoip.dat` и `geosite.dat`. Обычно это
`/usr/local/x-ui/bin` (установка скриптом) или `/usr/local/share/xray`:
```bash
curl -fsSL -o /usr/local/x-ui/bin/ipcheck.dat https://raw.githubusercontent.com/mrleo1nid/ipcheck-domains/release/ipcheck.dat
curl -fsSL -o /usr/local/x-ui/bin/ipcheck.dat https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release/ipcheck.dat
```
Дальше в панели: **Xray Settings → Routing Rules → Add Rule**, поле `domain`:
@@ -70,6 +76,123 @@ ext:ipcheck.dat:ipcheck
После замены файла Xray нужно перезапустить (в 3x-ui — **Restart Xray**).
## Автообновление на сервере
Xray читает `.dat` только при старте, поэтому обновление — это «скачать файл и
перезапустить сервис». Этим занимается [`update-geosite.sh`](tools/update-geosite.sh):
- сначала тянет `.sha256sum` и, если сумма совпала с локальным файлом, **молча выходит**
ни лишней закачки, ни лишнего перезапуска Xray;
- проверяет контрольную сумму скачанного файла **до** подмены;
- подменяет файл атомарно (`mv` в пределах каталога), старый сохраняет в `.bak`;
- перезапускает сервис только если файл действительно изменился;
- пишет в stdout только когда что-то произошло, так что cron не будет слать письма впустую.
### Установка
```bash
curl -fsSL -o /usr/local/bin/update-geosite.sh https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release/update-geosite.sh
chmod +x /usr/local/bin/update-geosite.sh
```
Проверьте вручную — первый запуск скачает файл и перезапустит панель:
```bash
BASE_URL=https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release \
DEST=/usr/local/x-ui/bin/ipcheck.dat \
RESTART_CMD='x-ui restart' \
/usr/local/bin/update-geosite.sh
```
Второй запуск подряд должен отработать молча и мгновенно — значит сравнение сумм работает.
### Вариант 1: cron
`crontab -e` от root, одна строка (04:17 ночи, чтобы не совпадать с чужими крон-джобами):
```cron
17 4 * * * BASE_URL=https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release DEST=/usr/local/x-ui/bin/ipcheck.dat RESTART_CMD='x-ui restart' /usr/local/bin/update-geosite.sh >> /var/log/ipcheck-update.log 2>&1
```
Или, если не хочется длинной строки, положите настройки в `/etc/default/ipcheck`:
```bash
BASE_URL=https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release
DEST=/usr/local/x-ui/bin/ipcheck.dat
RESTART_CMD=x-ui restart
```
```cron
17 4 * * * . /etc/default/ipcheck && /usr/local/bin/update-geosite.sh >> /var/log/ipcheck-update.log 2>&1
```
Скрипт не экспортирует переменные сам — при таком варианте добавьте в файл
`export BASE_URL DEST RESTART_CMD` последней строкой.
### Вариант 2: systemd timer
Точнее cron: `Persistent=true` догоняет пропущенный запуск после перезагрузки,
`RandomizedDelaySec` размазывает нагрузку, а логи идут в journald.
`/etc/systemd/system/ipcheck-geosite.service`:
```ini
[Unit]
Description=Обновление ipcheck.dat для Xray
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
Environment=BASE_URL=https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release
Environment=DEST=/usr/local/x-ui/bin/ipcheck.dat
Environment=RESTART_CMD=x-ui restart
ExecStart=/usr/local/bin/update-geosite.sh
```
`/etc/systemd/system/ipcheck-geosite.timer`:
```ini
[Unit]
Description=Ежедневное обновление ipcheck.dat
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
```
```bash
systemctl daemon-reload
systemctl enable --now ipcheck-geosite.timer
systemctl start ipcheck-geosite.service # разовая проверка
journalctl -u ipcheck-geosite.service -n 20
```
### Если 3x-ui в Docker
Путь указывайте внутрь примонтированного тома, а перезапуск делайте через docker:
```bash
DEST=/var/lib/x-ui-bin/ipcheck.dat RESTART_CMD='docker restart 3x-ui' /usr/local/bin/update-geosite.sh
```
### Переменные скрипта
| Переменная | По умолчанию | Значение |
| --- | --- | --- |
| `BASE_URL` | ссылка на ветку `release` | база, откуда качать |
| `DEST` | `/usr/local/x-ui/bin/ipcheck.dat` | куда положить файл |
| `NAME` | имя файла из `DEST` | имя файла в репозитории |
| `RESTART_CMD` | пусто | что выполнить после успешного обновления |
| `TIMEOUT` | `30` | таймаут curl, секунды |
Коды возврата: `0` — обновлено или уже актуально, `1` — ошибка (не скачалось,
не совпала сумма, не удался перезапуск).
## sing-box
```json
@@ -81,14 +204,17 @@ ext:ipcheck.dat:ipcheck
"type": "remote",
"tag": "ipcheck",
"format": "binary",
"url": "https://raw.githubusercontent.com/mrleo1nid/ipcheck-domains/release/sing-box/ipcheck.srs",
"download_detour": "direct"
"url": "https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release/sing-box/ipcheck.srs",
"download_detour": "direct",
"update_interval": "1d"
}
]
}
}
```
Здесь cron не нужен — sing-box обновляет rule-set сам.
## Clash / mihomo
```yaml
@@ -97,7 +223,7 @@ rule-providers:
type: http
behavior: domain
format: yaml
url: "https://raw.githubusercontent.com/mrleo1nid/ipcheck-domains/release/clash/ipcheck.yaml"
url: "https://gitea.example.com/mrleo1nid/ipcheck-domains/raw/branch/release/clash/ipcheck.yaml"
path: ./ruleset/ipcheck.yaml
interval: 86400
@@ -105,7 +231,7 @@ rules:
- RULE-SET,ipcheck,PROXY
```
Для `.mrs` укажите `behavior: domain` и `format: mrs`.
Для `.mrs` укажите `behavior: domain` и `format: mrs`. Обновление тоже своё, по `interval`.
## Как добавить домен
@@ -131,26 +257,45 @@ example.com @ads # атрибут — попадёт в .dat как geosit
Нужен только Python 3.10+, зависимостей нет:
```bash
python tools/build.py
python3 tools/build.py
```
Результат — в `dist/`. Проверка исходников без сборки (синтаксис, дубликаты,
домены, уже покрытые родительским суффиксом, циклические `include`):
```bash
python tools/build.py --check
python3 tools/build.py --check
```
Тесты сборщика:
```bash
python3 -m unittest discover -s tools -t tools
```
`.srs` и `.mrs` собираются, только если в `PATH` есть `sing-box` и `mihomo`
без них остальные форматы всё равно соберутся. Пути можно указать явно:
без них остальные форматы всё равно соберутся. Скачать их вместе с `xray`:
```bash
python tools/build.py --sing-box ./bin/sing-box --mihomo ./bin/mihomo
sh tools/fetch-tools.sh ./bin
```
Сборщик проверяет сам себя: после записи `geosite.dat` он разбирает файл обратно
и сверяет с исходником. В CI дополнительно поднимается настоящий Xray с правилом
`ext:geosite.dat:ipcheck` — если файл не читается, сборка падает.
`ext:ipcheck.dat:ipcheck` — если файл не читается, сборка падает.
## CI
[`.gitea/workflows/build.yml`](.gitea/workflows/build.yml): проверка → тесты →
сборка → валидация настоящими Xray и sing-box → публикация в ветку `release`
релиз в Gitea.
Раннеру нужен образ с `python3`, `curl`, `unzip`, `tar`, `git` (например
`catthehacker/ubuntu:act-latest`); если чего-то нет, первый шаг доставит пакеты сам.
Публикация идёт под автоматическим токеном `${{ github.token }}`. Если у раннера
нет прав на push в репозиторий или на создание релизов — заведите секрет
`RELEASE_TOKEN` с правами `repo:write`, workflow предпочтёт его.
## Лицензия