Skip to content

Build SingBox Configs #114

Build SingBox Configs

Build SingBox Configs #114

Workflow file for this run

name: Build SingBox Configs
on:
schedule:
- cron: "*/10 * * * *"
timezone: "Europe/Moscow"
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Build configs
run: |
# НУЖНЫЕ ИСХОДНИКИ (4 источника)
SOURCES=(
"https://raw.githack.com/igareck/vpn-configs-for-russia/main/Vless-Reality-White-Lists-Rus-Mobile.txt"
"https://raw.githack.com/igareck/vpn-configs-for-russia/main/WHITE-CIDR-RU-all.txt"
"https://raw.githack.com/igareck/vpn-configs-for-russia/main/WHITE-CIDR-RU-checked.txt"
"https://raw.githack.com/igareck/vpn-configs-for-russia/main/WHITE-SNI-RU-all.txt"
)
# Функция создания конфига с правильным количеством ключей
make_config_with_rules() {
OUTPUT_FILE=$1
RUSSIAN_KEYS=$2
NON_RUSSIAN_KEYS=$3
CONFIG_NAME=$4
# Очищаем от пустых строк
RUSSIAN_KEYS=$(echo "$RUSSIAN_KEYS" | grep -v '^$' | sed '/^[[:space:]]*$/d')
NON_RUSSIAN_KEYS=$(echo "$NON_RUSSIAN_KEYS" | grep -v '^$' | sed '/^[[:space:]]*$/d')
# Считаем количество русских ключей (безопасно)
RU_COUNT=$(echo "$RUSSIAN_KEYS" | grep -c . 2>/dev/null | tr -d '\n\r\t ' | xargs)
RU_COUNT=${RU_COUNT:-0}
RU_COUNT=$((RU_COUNT + 0))
echo "Building $OUTPUT_FILE ($CONFIG_NAME)"
echo " - Source RU keys: $RU_COUNT"
# Определяем логику формирования набора ключей
if [ "$RU_COUNT" -ge 10 ]; then
# Если русских 10 или больше - берем 10 случайных русских
FINAL=$(echo "$RUSSIAN_KEYS" | shuf | head -n 10)
echo " - Strategy: >=10 RU keys, taking 10 random RU keys"
elif [ "$RU_COUNT" -ge 6 ]; then
# Если русских 6-9 - берем всех русских + добиваем нерусскими до 10
TARGET_TOTAL=10
NEED_NON_RU=$((TARGET_TOTAL - RU_COUNT))
FINAL="$RUSSIAN_KEYS"
if [ "$NEED_NON_RU" -gt 0 ]; then
NONRU_TO_ADD=$(echo "$NON_RUSSIAN_KEYS" | shuf | head -n "$NEED_NON_RU" 2>/dev/null || true)
if [ -n "$NONRU_TO_ADD" ]; then
FINAL=$(printf "%s\n%s\n" "$FINAL" "$NONRU_TO_ADD" | grep -v '^$')
fi
fi
echo " - Strategy: $RU_COUNT RU keys (6-9), adding $NEED_NON_RU non-RU to reach 10 total"
elif [ "$RU_COUNT" -ge 4 ]; then
# Если русских 4-5 - берем всех русских + добиваем нерусскими до 7
TARGET_TOTAL=7
NEED_NON_RU=$((TARGET_TOTAL - RU_COUNT))
FINAL="$RUSSIAN_KEYS"
if [ "$NEED_NON_RU" -gt 0 ]; then
NONRU_TO_ADD=$(echo "$NON_RUSSIAN_KEYS" | shuf | head -n "$NEED_NON_RU" 2>/dev/null || true)
if [ -n "$NONRU_TO_ADD" ]; then
FINAL=$(printf "%s\n%s\n" "$FINAL" "$NONRU_TO_ADD" | grep -v '^$')
fi
fi
echo " - Strategy: $RU_COUNT RU keys (4-5), adding $NEED_NON_RU non-RU to reach 7 total"
elif [ "$RU_COUNT" -ge 1 ]; then
# Если русских 1-3 - берем всех русских + добиваем нерусскими до 5
TARGET_TOTAL=5
NEED_NON_RU=$((TARGET_TOTAL - RU_COUNT))
FINAL="$RUSSIAN_KEYS"
if [ "$NEED_NON_RU" -gt 0 ]; then
NONRU_TO_ADD=$(echo "$NON_RUSSIAN_KEYS" | shuf | head -n "$NEED_NON_RU" 2>/dev/null || true)
if [ -n "$NONRU_TO_ADD" ]; then
FINAL=$(printf "%s\n%s\n" "$FINAL" "$NONRU_TO_ADD" | grep -v '^$')
fi
fi
echo " - Strategy: $RU_COUNT RU keys (1-3), adding $NEED_NON_RU non-RU to reach 5 total"
else
# Если русских ключей НЕТ (RU_COUNT = 0) - берем 5 нерусских ключей
TARGET_TOTAL=5
FINAL=$(echo "$NON_RUSSIAN_KEYS" | shuf | head -n "$TARGET_TOTAL" 2>/dev/null || true)
echo " - Strategy: No RU keys, taking $TARGET_TOTAL non-RU keys"
# Если нерусских меньше 5 - берем сколько есть
NONRU_AVAILABLE=$(echo "$NON_RUSSIAN_KEYS" | grep -c . 2>/dev/null | tr -d '\n\r\t ' | xargs)
NONRU_AVAILABLE=${NONRU_AVAILABLE:-0}
NONRU_AVAILABLE=$((NONRU_AVAILABLE + 0))
if [ "$NONRU_AVAILABLE" -lt "$TARGET_TOTAL" ]; then
echo " - Warning: Only $NONRU_AVAILABLE non-RU keys available (less than $TARGET_TOTAL)"
fi
fi
# Убираем пустые строки и перемешиваем финальный список
FINAL=$(echo "$FINAL" | grep -v '^$' | shuf)
# Безопасное получение числовых значений
FINAL_COUNT=$(echo "$FINAL" | grep -c . 2>/dev/null | tr -d '\n\r\t ' | xargs)
FINAL_COUNT=${FINAL_COUNT:-0}
FINAL_COUNT=$((FINAL_COUNT + 0))
RU_IN_FINAL=$(echo "$FINAL" | grep -Ei 'russia' | grep -c . 2>/dev/null | tr -d '\n\r\t ' | xargs)
RU_IN_FINAL=${RU_IN_FINAL:-0}
RU_IN_FINAL=$((RU_IN_FINAL + 0))
NONRU_IN_FINAL=$((FINAL_COUNT - RU_IN_FINAL))
echo " - Total nodes: $FINAL_COUNT"
echo " - Russian nodes: $RU_IN_FINAL"
echo " - Non-Russian nodes: $NONRU_IN_FINAL"
# Отправляем запрос к API
jq -n --arg input "$FINAL" '{
core: "singbox",
input: $input,
options: {
addTun: true,
addSocks: true,
genClashSecret: false,
useExtended: false
}
}' \
| curl -sS -X POST "https://api.web2core.workers.dev/" \
-H "Content-Type: application/json" \
--data-binary @- \
> "$OUTPUT_FILE"
}
# Создаем конфиги: по 2 конфига на каждый источник (основной и b)
for i in "${!SOURCES[@]}"; do
SOURCE_NUM=$((i + 1))
SOURCE_URL="${SOURCES[$i]}"
echo "=========================================="
echo "Processing source $SOURCE_NUM: $SOURCE_URL"
echo "=========================================="
# СКАЧИВАЕМ ТОЛЬКО ЭТОТ ИСТОЧНИК для основного конфига
KEYS=$(curl -s "$SOURCE_URL" | tr -d '\r' | grep -E '^(vless|vmess|trojan)://' | grep -Evi 'raw' || true)
UNIQUE_KEYS=$(echo "$KEYS" | grep -v '^$' | sort -u)
TOTAL_KEYS=$(echo "$UNIQUE_KEYS" | grep -c . 2>/dev/null || echo "0")
echo "Total unique keys in source: $TOTAL_KEYS"
# Разделяем на RU и NON-RU для этого источника
RUSSIA=$(echo "$UNIQUE_KEYS" | grep -Ei 'russia' | shuf || true)
NON_RUSSIA=$(echo "$UNIQUE_KEYS" | grep -Evi 'russia' | shuf || true)
RU_COUNT_TOTAL=$(echo "$RUSSIA" | grep -c . 2>/dev/null || echo "0")
NONRU_COUNT_TOTAL=$(echo "$NON_RUSSIA" | grep -c . 2>/dev/null || echo "0")
echo "RU keys in source: $RU_COUNT_TOTAL"
echo "Non-RU keys in source: $NONRU_COUNT_TOTAL"
# Создаем основной конфиг
make_config_with_rules "config_${SOURCE_NUM}.json" "$RUSSIA" "$NON_RUSSIA" "source${SOURCE_NUM}_main"
# Для _b конфига берем другие ключи (если возможно)
# Перемешиваем заново, чтобы получить другой набор
RUSSIA_B=$(echo "$UNIQUE_KEYS" | grep -Ei 'russia' | shuf || true)
NON_RUSSIA_B=$(echo "$UNIQUE_KEYS" | grep -Evi 'russia' | shuf || true)
# Создаем backup конфиг
make_config_with_rules "config_${SOURCE_NUM}_b.json" "$RUSSIA_B" "$NON_RUSSIA_B" "source${SOURCE_NUM}_backup"
echo ""
done
# ---------------- PATCH URLTEST НА 1 МИНУТУ ДЛЯ ВСЕХ КОНФИГОВ ----------------
patch_interval() {
FILE=$1
INTERVAL=$2
if [ -f "$FILE" ]; then
echo "Patching $FILE -> interval=$INTERVAL"
jq --arg interval "$INTERVAL" '
(.outbounds[] | select(.type=="urltest") | .interval) = $interval |
(.outbounds[] | select(.type=="urltest") | .tolerance) = 100
' "$FILE" > tmp.json && mv tmp.json "$FILE"
else
echo "Warning: $FILE not found, skipping patch"
fi
}
# Применяем патч 1 минута для ВСЕХ конфигов
for file in config_*.json; do
patch_interval "$file" "1m"
done
# Выводим список созданных файлов
echo "=========================================="
echo "Created configs:"
ls -la config_*.json
# Проверяем, что файлы не пустые
echo "=========================================="
echo "Config sizes:"
for file in config_*.json; do
if [ -f "$file" ]; then
SIZE=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo "0")
echo "$file: $SIZE bytes"
if [ "$SIZE" -lt 100 ]; then
echo " WARNING: $file is too small, might be invalid!"
fi
fi
done
- name: Commit configs
run: |
git config user.name "github-actions"
git config user.email "actions@github.com"
git add config_*.json
git commit -m "auto update sing-box configs (dynamic keys based on RU count)" || exit 0
git push
- name: Upload to Yandex Disk via WebDAV
env:
YA_LOGIN: ${{ secrets.YANDEX_NAME }}
YA_PASS: ${{ secrets.YANDEX_TOKEN }}
run: |
# Кодируем логин:пароль в base64
AUTH_HEADER=$(echo -n "$YA_LOGIN:$YA_PASS" | base64)
# Создаём папку
curl -s -X MKCOL "https://webdav.yandex.ru/SingBox_Configs/" \
-H "Authorization: Basic $AUTH_HEADER" || true
# Загружаем все файлы config_*.json
for file in config_*.json; do
if [ -f "$file" ]; then
echo "Uploading $file..."
curl -s -T "$file" "https://webdav.yandex.ru/SingBox_Configs/$file" \
-H "Authorization: Basic $AUTH_HEADER"
fi
done
echo "All configs uploaded to Yandex Disk"