Skip to content

PrEvIeS/openwrt_vless

Repository files navigation

OpenWrt Mihomo Gateway Installer

Three-layer transparent gateway for OpenWrt 24.10.x / 25.04 / 25.12.x. Package manager is detected automatically (opkg on 24.10.x, apk on 25.x).

  • mihomo via nikki — VLESS+Reality transport, fake-IP DNS, rule-based routing
  • zapret via remittor — DPI bypass for YouTube / SmartTV, no VPN tunneling
  • AdGuard Home — LAN-wide ad/tracker/telemetry filter with DoH upstreams
  • Force-DNS firewall redirect — intercepts hard-coded :53 from clients

Primary documentation is Russian: README_RU.md. This page is a short orientation.


Requirements

  • OpenWrt release in SUPPORTED_RELEASES (default: 24.10.0 24.10.1 24.10.2 25.04.0 25.12.0 25.12.1 25.12.2). Extend via env: SUPPORTED_RELEASES="25.12.3" sh install.sh.
  • DISTRIB_ARCH in SUPPORTED_ARCHES (MIPS / aarch64 / arm / x86_64 / i386 variants).
  • /overlay on USB/SD/NVMe (ext4) ≥ 2 GiB — extroot must be set up before running the installer.
  • Active swap ≥ 1 GiB (1.5 GiB recommended).
  • ≥ 200 MB RAM, root SSH, working WAN.
  • Clean OpenWrt: no xray / sing-box / mihomo / passwall* / podkop running; :53 held by stock dnsmasq or free.
  • VLESS+Reality URL: vless://UUID@host:port?type=tcp&security=reality&pbk=...&fp=chrome&sni=...&sid=...&flow=xtls-rprx-vision#label.

Extroot setup is covered in README_RU.md §Подготовка.


Quick start

wget -O /tmp/install.sh https://raw.githubusercontent.com/PrEvIeS/openwrt_vless/main/install.sh
sh /tmp/install.sh

Interactive mode prompts for the VLESS URL only. Non-interactive example:

sh install.sh --non-interactive \
    --vless-url 'vless://UUID@host:443?type=tcp&security=reality&pbk=KEY&sni=www.google.com&sid=DEADBEEF&flow=xtls-rprx-vision&fp=chrome#label'

Override priority: --vless-* CLI flag > URL value > fallback default.


CLI flags

Flag Purpose
--vless-url URL Full VLESS Reality URL (required unless every field is set via --vless-* overrides)
--vless-server/port/uuid/pubkey/sid/sni/flow/fp Override individual fields
--nfqws-opt STR Custom zapret NFQWS strategy (default is a starting set, see DEFAULT_NFQWS_OPT in install.sh)
--no-zapret / --no-adguard / --no-force-dns / --no-i18n Skip a layer
--force-config Overwrite existing AdGuardHome.yaml, nikki profile and snapshot. Operator's AGH bind_port is preserved across rewrites; everything else (DNS upstreams, blocklists, theme) is reset.
--non-interactive Fail instead of prompting
-h, --help Show usage

--no-adguard requires --no-force-dns — Force DNS redirects clients to LAN_IP:53, which is empty without AGH (dnsmasq is on :54, mihomo on :1053). Installer refuses at preflight if only --no-adguard is set.


16-step pipeline

State-file /etc/openwrt-setup-state makes each step idempotent — re-running install.sh skips completed steps unless --force-config is passed.

  1. First-time setup (passwd / SSH key / TZ if not yet set)
  2. Preflight — release + architecture + package manager
  3. Preflight — extroot + swap
  4. Preflight — conflict probes (rival proxies, :53 owner, LAN iface, internet)
  5. Collect and parse VLESS URL, validate fields
  6. Pre-install state snapshot at /root/openwrt-mihomo-backup/ (chmod 700)
  7. Base packages (curl, block-mount, USB-storage kmods, …)
  8. nikki feed + mihomo packages (GitHub-releases fallback if feed DNS-blocked)
  9. zapret via remittor/update-pkg.sh
  10. adguardhome
  11. luci-theme-argon
  12. luci-app-statistics + collectd modules
  13. SQM cake (luci-app-sqm + kmod-sched-cake, queue defaults seeded only if absent)
  14. Configure: nikki profile + UCI mixin / zapret NFQWS / dnsmasq → :54 / AGH upstream / Force-DNS DNAT
  15. Service order: S50nikki → S60adguardhome → S99zapret
  16. Enable + start
  17. Self-test (ports, daemons, firewall rule) + summary

Routing rules in mihomo profile (first match wins):

  1. LAN / RFC1918 → DIRECT
  2. YouTube domain-suffix list → YOUTUBE selector (default VLESS-REALITY)
  3. geosite:ru-available-only-inside (yandex.net, kinopoisk-ru.clstorage, cdnvideo.ru …) → DIRECT
  4. .ru / .рф / .su / geoip:RUDIRECT
  5. geosite:ru-blocked (runetfreedom antifilter + re:filter) → PROXY
  6. MATCHFINAL selector (default VLESS-REALITY)

geosite.dat / geoip.dat are pre-downloaded from runetfreedom/v2ray-rules-dat before mihomo first start (chicken-and-egg: empty caches block startup DNS).


Routing rule lists (runetfreedom)

Source: runetfreedom/russia-v2ray-rules-dat, release branch — community-curated v2fly-format geosite.dat + geoip.dat, refreshed daily by upstream CI from antifilter + re:filter.

geosite category Routes to Coverage
ru-available-only-inside DIRECT (before .ru / GEOIP) RU-only services: Yandex / Kinopoisk / Okko / Wink, CDN domains .yandex.net, cdnvideo.ru, kinopoisk-ru.clstorage.net.com/.net of Russian infra not caught by .ru TLD.
ru-blocked PROXY → VLESS-Reality (after .ru / GEOIP) Domains blocked in RU — antifilter + re:filter (~10⁴ entries).
geoip:RU DIRECT IP-block fallback.

Files live in /etc/nikki/run/{geosite,geoip}.dat (~66 + ~21 MiB). Auto-update every 24h via geo-update-interval. Force refresh without restart:

SECRET=$(uci get nikki.mixin.api_secret)
curl -X POST -H "Authorization: Bearer $SECRET" http://127.0.0.1:9090/configs/geo

To use a different rules repo, edit geox-url in /etc/nikki/profiles/main.yaml. v2fly-format protobuf is required (Xray / sing-box format is binary-compatible).

Note: runetfreedom/russia-v2ray-custom-routing-list is not what we use — that repo doesn't ship a mihomo-compatible build (release/mihomo/*.list URLs return 404).


IPv6 behavior

The installer targets IPv4-only routing. What this means in practice:

  • mihomo fake-IP works only for A records. AAAA responses are passed through without fake-IP, so v6 destinations are not matched against the geosite / YouTube / geoip rules.
  • zapret is pinned to disable_ipv6=1 in UCI, the nfqws hook only inspects v4 traffic.
  • Force-DNS redirect is v4 only (ip nat DNAT, no ip6nat rule).

Net effect: if a LAN client has working IPv6 to a blocked destination, the browser will prefer v6 (Happy Eyeballs) and bypass VLESS entirely. Recommendation: disable IPv6 on the LAN side in LuCI → Network → Interfaces → LAN — set IPv6 assignment length to disabled and turn off the RA/DHCPv6 services.

A proper --ipv6 {bypass,drop,route} policy flag is tracked on the roadmap.


Failure modes

Phase Exit Behavior
Preflight refuse (release / arch / pkg / extroot / conflicts / VLESS URL) 2 nothing written, fix environment and re-run
Error after snapshot (mutations begun) 1 installer prints sh uninstall.sh hint, no auto-rollback
Self-test FAIL 1 per-check report printed, state kept, run uninstall.sh to revert

No --force flag, no retry loops, no auto-rollback.


Post-install (manual)

  1. Open the AdGuard Home wizard at http://<LAN_IP>:3000 — set admin port to :8080, DNS bind to all interfaces :53, create a password.
  2. If YouTube is slow or blocked, tune the zapret strategy:
    service zapret stop
    /opt/zapret/blockcheck.sh
    # → update NFQWS_OPT in LuCI → Services → Zapret

Uninstall

sh uninstall.sh
# or, for full cleanup:
sh uninstall.sh --remove-packages --remove-state --purge-config --restore-crontab

UCI values are restored symbolically from snapshot.env. --purge-config additionally removes /etc/config/{nikki,zapret,adguardhome} (default keeps them with enabled=0 for reinstall). extroot and swap are never touched.


License

MIT. Third-party packages keep their upstream licenses (mihomo / nikki / zapret / AdGuard Home).

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages