docs: add readme and example of template.json

This commit is contained in:
2025-06-29 13:13:17 +03:00
parent 7e0257b272
commit 441cbd37b3
3 changed files with 415 additions and 2 deletions

4
.gitignore vendored
View File

@ -1,5 +1,5 @@
/target
/rules
/config
template.json
config/*
!config/template.json
default.json

91
README.md Normal file
View File

@ -0,0 +1,91 @@
# sbrs — sing-box rules sync
A containerized Rust utility to synchronize and self-host remote rule sets for `sing-box`.
## Core Workflow
1. **Reads** a source JSON configuration (`config/template.json`) containing remote URLs (e.g., from GitHub).
2. **Downloads** all rule files specified in the source config to a local directory (for example, `./rules`).
3. **Cleans up** stale rule files from the local directory that are no longer present in the source config.
4. **Generates** a new, client-facing configuration (`config/default.json`) where all remote URLs are rewritten to point to a self-hosted domain.
The original `template.json` is never modified by this application.
Upon container start, the utility performs an initial synchronization immediately and then sets up a cron job for subsequent, scheduled runs.
## Prerequisites
- Docker
- Docker Compose
## Usage via Docker
**1. Example of possible directory structure**
Create the following directory structure in your project root before the first run:
```
.
├── config/
│ └── template.json # Your input config with original URLs
├── rules/ # Empty directory for downloaded rule files
├── docker/
│ ├── Dockerfile
│ └── entrypoint.sh
└── docker-compose.yml
```
*Note: `config/default.json` will be generated by the application on the first run.*
**2. Configuration**
Edit `docker-compose.yml` to set the required environment variables:
- `PUID`/`PGID`: Set to your host user's ID (`id -u`) and group ID (`id -g`) to prevent volume permission issues.
- `DOMAIN`: The public domain that will serve the rule files (e.g., `rules.mydomain.com`).
- `RULE_PATH`: The path on the domain where the files are located (e.g., `/` or `/files`).
- `TZ`: The timezone for container logs (e.g., `Etc/UTC`).
- `CRON_SCHEDULE`: The schedule for the sync task.
**3. Run the Service**
```bash
# Build the image and start the service in detached mode
docker-compose up --build -d
```
The service will run the sync task immediately upon starting and then again on the schedule defined by `CRON_SCHEDULE`.
### Common Commands
```bash
# View live logs
docker-compose logs -f
# Trigger a manual sync immediately (without restarting)
docker-compose exec sbrs entrypoint.sh manual
# Stop and remove the container
docker-compose down
```
## Local Development
Requires the [Rust toolchain](https://rustup.rs/).
**1. Build**
```bash
cargo build --release
```
**2. Run**
All arguments are required.
```bash
./target/release/sbrs \
--input-config ./config/template.json \
--rules-dir ./rules \
--output-config ./config/default.json \
--domain my.server.com \
--rule-path rules
```

322
config/template.json Normal file
View File

@ -0,0 +1,322 @@
{
"log": {
"level": "error",
"timestamp": true
},
"dns": {
"cache_capacity": 16384,
"servers": [
{
"tag": "dns-remote",
"address": "tls://208.67.222.222",
"client_subnet": "{{ ansible_host }}"
},
{
"tag": "dns-local",
"address": "195.208.4.1"
},
{
"tag": "dns-block",
"address": "rcode://success"
}
],
"rules": [
{
"rule_set": [
"category-ads-all",
"adobe"
],
"server": "dns-block",
"disable_cache": true
},
{
"domain_suffix": [
"habr.com"
],
"rule_set": [
"telegram",
"google"
],
"server": "dns-remote"
},
{
"domain_suffix": [
".ru",
".su",
".ru.com",
".ru.net",
"{{ marzban_domain }}",
"wikipedia.org"
],
"domain_keyword": [
"xn--",
"ozon",
"wildberries",
"aliexpress"
],
"rule_set": [
"gov-ru",
"yandex",
"vk",
"mailru",
"duckduckgo",
"mozilla",
"category-android-app-download",
"gitlab",
"debian",
"canonical",
"torrent-clients"
],
"server": "dns-local"
},
{
"process_name": [
"qbittorrent.exe",
"thunderbird.exe",
"Obsidian.exe",
"javaw.exe"
],
"server": "dns-local"
},
{
"inbound": [
"tun-in"
],
"server": "dns-remote"
}
],
"final": "dns-local"
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "tun0",
"stack": "system",
"address": "172.19.0.1/28",
"auto_route": true,
"strict_route": true,
"sniff_override_destination": true
}
],
"outbounds": [
{
"type": "direct",
"tag": "direct"
},
{
"type": "selector",
"tag": "proxy",
"outbounds": null
},
{
"type": "urltest",
"tag": "Fastest",
"outbounds": null,
"url": "https://www.gstatic.com/generate_204",
"interval": "15m0s"
}
],
"route": {
"rules": [
{
"action": "sniff"
},
{
"protocol": "dns",
"action": "hijack-dns"
},
{
"ip_is_private": true,
"outbound": "direct"
},
{
"rule_set": [
"category-ads-all",
"adobe"
],
"action": "reject",
"method": "drop"
},
{
"domain_suffix": [
"habr.com"
],
"rule_set": [
"telegram",
"google"
],
"outbound": "proxy"
},
{
"domain_suffix": [
".ru",
".su",
".ru.com",
".ru.net",
"{{ marzban_domain }}",
"wikipedia.org"
],
"domain_keyword": [
"xn--",
"ozon",
"wildberries",
"aliexpress"
],
"ip_cidr": [
"{{ ansible_host }}"
],
"rule_set": [
"gov-ru",
"yandex",
"vk",
"mailru",
"duckduckgo",
"mozilla",
"category-android-app-download",
"gitlab",
"debian",
"canonical",
"torrent-clients"
],
"outbound": "direct"
},
{
"action": "resolve",
"strategy": "prefer_ipv4"
},
{
"rule_set": [
"geoip-ru"
],
"outbound": "direct"
},
{
"process_name": [
"qbittorrent.exe",
"thunderbird.exe",
"Obsidian.exe",
"javaw.exe"
],
"outbound": "direct"
},
{
"domain_suffix": [
"deb.home.net"
],
"outbound": "direct"
},
{
"inbound": [
"tun-in"
],
"outbound": "proxy"
}
],
"rule_set": [
{
"tag": "torrent-clients",
"type": "remote",
"format": "source",
"url": "https://raw.githubusercontent.com/FPPweb3/sb-rule-sets/main/torrent-clients.json"
},
{
"tag": "geoip-ru",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geoip/raw/rule-set/geoip-ru.srs"
},
{
"tag": "gov-ru",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-category-gov-ru.srs"
},
{
"tag": "yandex",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-yandex.srs"
},
{
"tag": "google",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-google.srs"
},
{
"tag": "telegram",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-telegram.srs"
},
{
"tag": "vk",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-vk.srs"
},
{
"tag": "mailru",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-mailru.srs"
},
{
"tag": "duckduckgo",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-duckduckgo.srs"
},
{
"tag": "mozilla",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-mozilla.srs"
},
{
"tag": "category-android-app-download",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-category-android-app-download.srs"
},
{
"tag": "adobe",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-adobe.srs"
},
{
"tag": "gitlab",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-gitlab.srs"
},
{
"tag": "debian",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-debian.srs"
},
{
"tag": "canonical",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-canonical.srs"
},
{
"tag": "category-ads-all",
"type": "remote",
"format": "binary",
"url": "https://github.com/SagerNet/sing-geosite/raw/rule-set/geosite-category-ads-all.srs"
}
],
"auto_detect_interface": true,
"override_android_vpn": true
},
"experimental": {
"cache_file": {
"enabled": true
}
}
}