Skip to content

Instantly share code, notes, and snippets.

@pomozoff
Last active April 1, 2026 22:21
Show Gist options
  • Select an option

  • Save pomozoff/1277db00a3da70e6137fb5d4fc8c7628 to your computer and use it in GitHub Desktop.

Select an option

Save pomozoff/1277db00a3da70e6137fb5d4fc8c7628 to your computer and use it in GitHub Desktop.
OpenWrt + podkop: Russian sites direct, everything else via VLESS tunnel
#!/bin/sh
# Patch for OpenWrt + podkop:
# - Russian domains (.ru/.рф/.su + major .com) go DIRECT
# - Everything else goes through the VLESS tunnel
#
# Usage: sh apply_patch.sh
# Run AFTER configuring your outbound in podkop (LuCI → Services → Podkop).
set -e
DOMAINS_FILE="/etc/podkop/russia_domains.txt"
FIX_SCRIPT="/usr/bin/podkop_fix.sh"
PODKOP="/usr/bin/podkop"
echo "[1/4] Creating Russian domains list..."
mkdir -p /etc/podkop
cat > "$DOMAINS_FILE" << 'EOF'
ru
xn--p1ai
su
vk.com
vk.me
userapi.com
vkuseraudio.com
vkuservideo.com
vk-cdn.net
vkvideo.ru
yandex.com
yandex.net
yandex-team.ru
ya.ru
yastatic.net
yabs.yandex.net
ok.ru
odnoklassniki.ru
mycdn.me
sber.ru
sberbank.ru
sbrf.ru
sberbankdigital.ru
tinkoff.ru
tinkoff.com
alfabank.ru
vtb.ru
raiffeisen.ru
rosbank.ru
gosuslugi.ru
mos.ru
nalog.ru
nalog.gov.ru
rzd.ru
pochta.ru
ozon.ru
ozonusercontent.com
wildberries.ru
wb.ru
avito.ru
autolab.ru
hh.ru
headhunter.ru
kinopoisk.ru
ivi.ru
rutube.ru
more.tv
premier.one
2gis.ru
2gis.com
dgis.ru
drom.ru
auto.ru
kaspersky.ru
kaspersky.com
drweb.com
ntvplus.ru
ntvplus.com
lenta.ru
ria.ru
rbc.ru
kommersant.ru
interfax.ru
tass.ru
1tv.ru
vesti.ru
russia.tv
ntv.ru
ren.tv
gazprom.ru
lukoil.ru
rosneft.ru
EOF
echo " $(wc -l < "$DOMAINS_FILE") domains written."
echo "[2/4] Configuring podkop UCI..."
# Fix community_lists: must be stored as 'list', not 'option'
# (podkop uses config_list_foreach which only reads 'list' entries)
CURRENT=$(uci get podkop.main.community_lists 2>/dev/null || true)
if [ -n "$CURRENT" ]; then
uci del podkop.main.community_lists
uci add_list podkop.main.community_lists="$CURRENT"
echo " Fixed community_lists type: option → list ($CURRENT)"
else
echo " WARN: podkop.main.community_lists not set — configure your outbound in LuCI first."
fi
# Add russia_direct exclusion section (idempotent)
uci set podkop.russia_direct=section
uci set podkop.russia_direct.connection_type='exclusion'
# Replace any existing local_domain_lists entry to avoid duplicates
uci del podkop.russia_direct.local_domain_lists 2>/dev/null || true
uci add_list podkop.russia_direct.local_domain_lists="$DOMAINS_FILE"
uci commit podkop
echo " UCI committed."
echo "[3/4] Creating fix script..."
cat > "$FIX_SCRIPT" << 'FIXEOF'
#!/bin/sh
# Rewrites sing-box DNS/route rules so that:
# - russian_direct domains → real DNS → go direct (not tproxied)
# - everything else → FakeIP → tproxy → VLESS tunnel
CONFIG=/etc/sing-box/config.json
RUSSIA_DIRECT_TAG="russia_direct-local-domains-ruleset"
[ -f "$CONFIG" ] || exit 0
jq --arg rd_tag "$RUSSIA_DIRECT_TAG" '
.dns.rules = [
{"action": "reject", "query_type": "HTTPS"},
{"action": "reject", "domain_suffix": "use-application-dns.net"},
{"action": "route", "server": "dns-server", "rule_set": [$rd_tag]},
{"action": "route", "server": "fakeip-server", "rewrite_ttl": 60}
] |
.route.rules = [
{"action": "sniff", "inbound": ["tproxy-in", "dns-in"]},
{"action": "hijack-dns", "protocol": "dns"},
{"action": "route", "inbound": "tproxy-in", "outbound": "main-out", "domain": "ip.podkop.fyi"},
{"action": "route-options", "domain": "fakeip.podkop.fyi", "override_port": 8443},
{"action": "route", "inbound": "tproxy-in", "outbound": "main-out"}
]
' "$CONFIG" > /tmp/config_fixed.json && mv /tmp/config_fixed.json "$CONFIG"
logger -t podkop_fix "Applied russian-direct routing fix"
FIXEOF
chmod +x "$FIX_SCRIPT"
echo " $FIX_SCRIPT created."
echo "[4/4] Patching $PODKOP to call fix script before sing-box starts..."
if grep -q 'podkop_fix.sh' "$PODKOP"; then
echo " Already patched, skipping."
else
sed -i 's|/etc/init.d/sing-box start|/usr/bin/podkop_fix.sh\n /etc/init.d/sing-box start|' "$PODKOP"
echo " Patched."
fi
echo ""
echo "Done. Restarting podkop..."
service podkop restart
echo ""
echo "Verify:"
echo " Russian site (should be real IP): nslookup vk.com 127.0.0.42"
echo " Foreign site (should be 198.18.x): nslookup youtube.com 127.0.0.42"
echo " Tunnel check: curl https://ifconfig.me"

OpenWrt + podkop: Russian sites direct, everything else via VLESS tunnel

A patch script for OpenWrt routers running podkop that configures split-routing:

  • Russian domains (.ru, .рф, .su + major .com Russian services) → go direct
  • Everything else → routed through your VLESS tunnel

Background

podkop stores community_lists as a UCI option instead of list, but internally uses config_list_foreach which silently skips option entries. This means the community list ruleset is never loaded into sing-box, breaking all routing. This patch fixes that and sets up proper split-routing.

Prerequisites

  1. OpenWrt with podkop installed
  2. Your VLESS outbound configured in LuCI → Services → Podkop (server, UUID, TLS/REALITY settings)

Usage

# Copy script to the router
scp apply_patch.sh root@192.168.1.1:/tmp/

# SSH into the router and run
ssh root@192.168.1.1
sh /tmp/apply_patch.sh

What the patch does

  1. Creates /etc/podkop/russia_domains.txt — Russian TLD suffixes (.ru, .рф, .su) plus explicitly listed major Russian .com/.net services (VK, Yandex, Sber, Tinkoff, Ozon, etc.)

  2. Fixes UCI community_lists type — changes option community_lists 'russia_inside' to list community_lists 'russia_inside' so podkop's config_list_foreach actually reads it

  3. Adds a russia_direct exclusion section in podkop pointing to the domains file

  4. Creates /usr/bin/podkop_fix.sh — rewrites sing-box's DNS and route rules on every podkop start:

    • Russian domains → real DNS → real IPs → not intercepted by tproxy → direct
    • All other domains → FakeIP catch-all → tproxy → sing-box → VLESS tunnel
  5. Patches /usr/bin/podkop to call the fix script before sing-box launches

How the routing works

vk.com      →  real DNS (87.240.x.x)   →  not tproxied  →  DIRECT
yandex.ru   →  real DNS (5.255.x.x)    →  not tproxied  →  DIRECT
youtube.com →  FakeIP  (198.18.0.x)    →  tproxy        →  VLESS tunnel
google.com  →  FakeIP  (198.18.0.x)    →  tproxy        →  VLESS tunnel

Only traffic to 198.18.0.0/15 (FakeIP range) is intercepted by nft and redirected to sing-box's tproxy port. Russian domains get real IPs that fall outside this range, so they bypass the tunnel entirely.

Adding more Russian domains

echo "example.ru" >> /etc/podkop/russia_domains.txt
service podkop restart

The .ru TLD suffix already covers millions of Russian sites. Add entries only for Russian services on non-.ru domains.

Verify after install

# Russian site → should return a real IP (e.g. 87.240.x.x), not 198.18.x.x
nslookup vk.com 127.0.0.42

# Foreign site → should return a FakeIP (198.18.x.x)
nslookup youtube.com 127.0.0.42

# Tunnel check → should return your VPS IP, not your ISP IP
curl https://ifconfig.me
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment