Skip to content

Medium1992/mihomo-proxy-ros

English | Русский · Telegram · Code of Conduct

mihomo-proxy-ros

Multi-arch Docker container for MikroTik RouterOS: mihomo + byedpi + zapret + zapret2, fully ENV-driven, with a built-in sh-only WebUI that generates ready-to-paste RouterOS commands.

GitHub release Docker Pulls Docker Image Size License Platforms Telegram

✨ Features

  • 🌍 Multi-arch: ARM, ARM64, AMD64v1/v2/v3 (the latest tag bundles ARM, ARM64, AMD64v3 — for v1/v2 pull the dedicated tag)
  • 🖥 Built-in WebUI on port 80 — visual ENV editor, YAML validator, AWG/proxy/rule-set file managers, generates MikroTik terminal commands
  • 🔐 DPI bypass via ByeDPI, Zapret/nfqws, Zapret2/nfqws2 (nfqws/nfqws2 — amd64/arm64 only)
  • 🧩 Flexible routing by domain / IP / GeoSite / GeoIP / ASN, all controlled via ENV
  • 🛡 Multiple proxy links and subscriptions (including RemnaWave with HWID)
  • 🚀 WireGuard / AmneziaWG integration by dropping .conf files into a mount folder
  • 📦 Single-step automated install via MikroTik terminal snippet
  • 🛠 Multiple VETH interfaces appear as outbound proxies → mangle in RouterOS to send traffic where you want

Tested with RouterOS 7.20+. Requires the container package and device-mode container=yes.

⚡ Quickstart

  1. Enable container support on RouterOS:

    /system/device-mode/print
    /system/device-mode/update mode=advanced container=yes traffic-gen=yes
    

    You have ~5 minutes to confirm via power-cycle or physical button.

  2. Paste the install snippet into RouterOS terminal — see § RouterOS install below.

  3. Open the WebUI: http://<container-ip>:80/ Configure ENVs visually, click MikroTik commands → copy → paste back into RouterOS terminal.

  4. Or use mihomo's panel: http://<container-ip>:9090/ (UI from EXTERNAL_UI_URL).

🖥 WebUI

http://<container-ip>:80/ — local management panel served by busybox httpd from the container itself.

WebUI — overview

📸 More screenshots

WebUI — proxy providers

WebUI — proxy groups

WebUI — DPI / zapret files

WebUI — YAML / rule-sets

It does not modify the running container directly. Instead it:

  • shows every ENV that entrypoint.sh understands, grouped into logical pages (Core, Providers, DPI, Groups, Rules, Rule-sets, YAML, Tools)
  • tracks edits locally in localStorage against the original values
  • generates the exact /container/envs/add|set|remove commands you need to paste into RouterOS terminal, plus the final /container/stop+start to apply

What's also in there:

  • Proxy YAML editor with 12 protocol templates (vless-tcp/reality, vless-xhttp, vmess, trojan, ss, anytls, wireguard, amneziawg, hysteria2, tuic, ssh, vless-ws) — "Load template" fills the textarea
  • Live mihomo -t validation of proxy YAMLs before save, plus uniqueness check of name: field across all providers
  • AWG editor with full [Interface]/[Peer]/[Mihomo] template covering every key the parser understands
  • DPI files manager — upload .bin fakes to /zapret-fakebin/, edit text lists in /zapret-lists/, with filter
  • Rule-set builder — paste a payload-format list, get a RULE_SETxx_BASE64 ENV ready

All runtime artifacts (generated config, provider YAMLs, pre-rendered HTML) live in /dev/shmzero flash wear.

📁 Mount points

Path in container Purpose Format
/root/.config/mihomo/awg/ WireGuard / AmneziaWG configs → become proxy-providers *.conf
/root/.config/mihomo/proxies_mount/ Custom proxy-providers in mihomo native YAML *.yaml / *.yml
/root/.config/mihomo/rule_set_list/ Custom rule-set lists in payload format *.txt (filename = group name)
/zapret-fakebin/ Binary fake-packets used by nfqws --dpi-desync-fake-* *.bin
/zapret-lists/ Text domain / IP lists for nfqws lua scripts *.txt

You can also attach multiple VETH interfaces to the container — they show up as direct outbounds in mihomo, route to whichever you want via mangle in RouterOS. Inbound traffic to the container must enter via the first VETH only.

🧑‍🍳 A few examples

YouTube via a single VLESS link

LINK1: "vless://uuid@server:443?type=tcp&security=reality&pbk=...#myvless"
GROUP: "youtube"
YOUTUBE_USE: "LINK1"
YOUTUBE_GEOSITE: "youtube"

Telegram via AmneziaWG (config dropped into /root/.config/mihomo/awg/tunnel1.conf)

GROUP: "telegram"
TELEGRAM_USE: "tunnel1"
TELEGRAM_GEOSITE: "telegram"
TELEGRAM_GEOIP: "telegram"
TELEGRAM_AS: "AS62041,AS59930,AS62014,AS211157,AS44907"

Discord + Google via ByeDPI strategy

BYEDPI_CMD: "--tlsrec 41+s --udp-fake 1 --oob 1 --auto=torst,redirect,ssl_err --fake -1"
GROUP: "discord,google"
DISCORD_USE: "BYEDPI"
DISCORD_GEOSITE: "discord"
DISCORD_GEOIP: "discord"
GOOGLE_USE: "BYEDPI"
GOOGLE_GEOSITE: "google"
GOOGLE_GEOIP: "google"

Route a specific LAN subnet via SOCKS5

SOCKS1: "server=192.168.88.10#port=1080#username=user#password=pass"
GROUP: "lan_socks"
LAN_SOCKS_USE: "SOCKS1"
LAN_SOCKS_SRCIPCIDR: "192.168.88.0/24"

⚙️ Environment variables

Core

ENV Default Description
TPROXY true On RoS ≥ 7.21 with arm64/amd64, the container uses NFTables. true → TProxy in (TCP+UDP); false → Redirect (TCP) + TUN (UDP).
DNS_MODE fake-ip DNS enhanced-mode.
NAMESERVER_POLICY Per-domain DNS resolver routing. Format: domain1#dns1,domain2#dns2. Docs.
SNIFFER true Domain sniffer for domain-based rules when not resolved by mihomo.
FAKE_IP_RANGE 198.18.0.0/15 fake-ip pool.
FAKE_IP_TTL 1 fake-ip cache TTL (seconds).
FAKE_IP_FILTERxx Rules list for DNS server in rule mode.

Logs & UI

ENV Default Description
LOG_LEVEL error mihomo log level: silent/error/warning/info/debug. Docs.
EXTERNAL_UI_URL MetaCube zip Source zip for the panel served on :9090. Docs.
UI_SECRET Secret for the external controller (port 9090). Empty = no auth (LAN-only setups).

Health-check

ENV Default Description
HEALTHCHECK_PROVIDER true true → checks use HEALTHCHECK_*. false → checks use GROUP_URL/XXX_URL/etc. (per-group).
HEALTHCHECK_URL https://www.gstatic.com/generate_204 Default URL.
HEALTHCHECK_URL_STATUS 204 Expected status.
HEALTHCHECK_INTERVAL 120 Interval (seconds). Docs.
HEALTHCHECK_URL_BYEDPI https://www.facebook.com URL for BYEDPI provider.
HEALTHCHECK_URL_STATUS_BYEDPI 200 Expected status for BYEDPI provider.
HEALTHCHECK_URL_ZAPRET https://www.facebook.com URL for all ZAPRET/ZAPRET2 providers.
HEALTHCHECK_URL_STATUS_ZAPRET 200 Expected status for ZAPRET/ZAPRET2 providers.

DPI engines

ENV Default Description
BYEDPI_CMDxx ByeDPI strategy. BYEDPI_CMD → outbound BYEDPI; BYEDPI_CMD1BYEDPI_1; etc. Pick strategies with byedpi-orchestrator.
ZAPRET_CMDxx Zapret/nfqws strategy. Bundled fakes in /zapret-fakebin/ (e.g. quic_initial_www_google_com.bin) and lists in /zapret-lists/ (ipset-all.txt, list-general.txt, etc.).
ZAPRET2_CMDxx Zapret2/nfqws2 strategy.
ZAPRET2_WG_CMD (default with quic_initial_vk_com blob) Dedicated nfqws2 strategy for WireGuard handshake routing.
ZAPRET_PACKETSxx 12 Number of first packets routed through the nfqws queue. xx overrides per-provider. Non-positive values = unlimited (always queued).
ZAPRET2_PACKETSxx 12 Same for nfqws2.

Proxy providers

ENV Default Description
LINK0, LINK1, … Single proxy URL: vless://, vmess://, ss://, trojan://, vpn://. Each creates a proxy-provider.
SUB_LINK0, SUB_LINK1, … Subscription URL (http(s)://...). One proxy-provider per sub, supports per-sub HWID via headers.
SUB_LINKxx_PROXY DIRECT Which proxy is used to fetch the subscription. Example: SUB_LINK1_PROXY=proxies1.
SUB_LINKxx_HEADERS Custom HTTP headers for the sub request. Format: key1=val1#key2=val2. HWID example: x-hwid=...#x-device-os=...#x-ver-os=...#x-device-model=...#user-agent=....
SUB_LINK_INTERVAL 3600 Default refresh interval (s) for all subs.
SUB_LINKxx_INTERVAL inherits SUB_LINK_INTERVAL Override interval per sub.
SUB_LINKxx_FILTER Provider-level filter regex — keep only nodes whose name matches. Multiple patterns separated by |.
SUB_LINKxx_EXCLUDE_FILTER Provider-level exclude-filter regex.
SUB_LINKxx_EXCLUDE_TYPE Provider-level exclude-type — list of Adapter Type (case-insensitive) via |. Example: vmess|direct.
SUB_LINKxx_ADDITIONAL_PREFIX Goes into override.additional-prefix — fixed prefix for every node name.
SUB_LINKxx_ADDITIONAL_SUFFIX Goes into override.additional-suffix — fixed suffix for every node name.
SOCKS0, SOCKS1, … SOCKS5 proxy. Format: server=ip#port=1080#username=#password=#tls=#fingerprint=#skip-cert-verify=#udp=#ip-version=. Docs.
XXX_DIALER_PROXY Override dialer-proxy — route this provider's connections through another group. Example: LINK1_DIALER_PROXY=YouTube.

Proxy groups

GROUP declares the set of named groups. For each group XXX (uppercased), prefix-ENV variants below are honored.

💡 In addition to user-defined groups, three "system" groups are hardwired in entrypoint: GROUP_* (defaults for every group), GLOBAL_* (the special GLOBAL group) and DNS_* (a dedicated group for DNS resolution). All three accept the same prefix ENVs as the table below.

ENV Default Description
GROUP Comma-separated list of proxy groups. telegram,youtube,google,ai,geoblock → groups TELEGRAM, YOUTUBE, GOOGLE, AI, GEOBLOCK. A group is created only if it has at least one resource (XXX_*) or XXX_USE.
XXX_TYPE select Group type: select / url-test / fallback / load-balance / relay.
XXX_USE all providers in order: LINKs, SUB_LINKs, WG/AWG, BYEDPI, DIRECT Subset of providers to include. Example: YOUTUBE_USE=BYEDPI,LINK1.
XXX_PROXIES Explicit proxies (specific nodes, not providers), comma-separated. Alternative/addition to XXX_USE.
XXX_FILTER Provider name filter regex. Example: RU|BYEDPI.
XXX_EXCLUDE Exclude regex.
XXX_EXCLUDE_TYPE Exclude by type. Example: vmess|direct.
XXX_DNS DNS resolver for this group's domain rules. Example: https://dns.google/dns-query#disable-qtype-65=true&disable-ipv6=true.
XXX_ICON URL for the group's icon.
XXX_HIDDEN false Hide the group from mihomo's WebUI.
GROUP_URL / XXX_URL https://www.gstatic.com/generate_204 Per-group health-check URL when HEALTHCHECK_PROVIDER=false and XXX_TYPE is url-test/fallback/load-balance.
GROUP_URL_STATUS / XXX_URL_STATUS 204 Expected status for the above.
GROUP_INTERVAL / XXX_INTERVAL 60 Check interval (seconds).
GROUP_TOLERANCE / XXX_TOLERANCE 20 URL-test tolerance in ms.
GROUP_STRATEGY / XXX_STRATEGY consistent-hashing Load-balance strategy.

Routing rules (per group)

Each entry creates an automatic rule targeting the group XXX. XXX_GEOSITE/GEOIP/AS also build a rule-set in .mrs format from the meta-rules-dat repo.

ENV Description
XXX_GEOSITE Comma-separated geosite names. Example: GEOBLOCK_GEOSITE=intel,openai,xai.
XXX_GEOIP Comma-separated geoip. Example: GEOBLOCK_GEOIP=netflix.
XXX_AS AS numbers. Example: TELEGRAM_AS=AS62041,AS59930,AS62014,AS211157,AS44907.
XXX_DOMAIN Exact DOMAIN matches.
XXX_SUFFIX DOMAIN-SUFFIX matches.
XXX_KEYWORD DOMAIN-KEYWORD matches.
XXX_IPCIDR IP-CIDR ranges.
XXX_SRCIPCIDR SRC-IP-CIDR — route by source. Example: SOCKS_SRCIPCIDR=192.168.88.37/32,192.168.88.65/32.
XXX_DSCP Marks this group's traffic with a DSCP value (0–63). Example: YOUTUBE_DSCP=10.
XXX_PRIORITY Position of this group's rules in the rules list. Lower = earlier. Shared priority space with RULESxx. Default ≥1000.

Custom rule-sets

ENV Description
RULE_SETxx_BASE64 <base64>#<name><base64> is base64-encoded payload list. Creates a rule-set + group <name> with priority ≥2000. The WebUI's Rule-sets → New base64 builds these for you.
RULESxx Raw mihomo rule where xx is the priority. Example: RULES1=AND,((NETWORK,udp),(DST-PORT,443)),REJECT drops QUIC first.

🛠 RouterOS install

First, enable container support (if not enabled already):

/system/device-mode/print
/system/device-mode/update mode=advanced container=yes traffic-gen=yes

You have ~5 minutes to confirm via power-cycle or briefly pressing any physical button on the device.

Then paste the snippet below into RouterOS terminal:

:global currentVersion [/system resource get version];
:global currentMinor [:pick $currentVersion ([:find $currentVersion "."] + 1) ([:find $currentVersion "."] + 3)];
:global r
:global statusPackage false
:global statusDeviceMode [/system/device-mode/get container]

:if ([:len [/system/package/find name=container available=no disabled=no]] >0) do={
:set statusPackage true
} else={
:put "Please check the installation of the container package"
}
:if ($statusDeviceMode=false) do={
:put "Please check /system/device-mode/print container enable"
}
:if ($currentMinor >= 21) do={
:put "Current version RouterOS 7.$currentMinor"
:set r [/tool fetch url=https://raw.githubusercontent.com/Medium1992/mihomo-proxy-ros/refs/heads/main/script21.rsc mode=https output=user as-value]
}
:if ($currentMinor = 20) do={
:put "Current version RouterOS 7.$currentMinor"
:set r [/tool fetch url=https://raw.githubusercontent.com/Medium1992/mihomo-proxy-ros/refs/heads/main/script.rsc mode=https output=user as-value]
}
:if ($currentMinor < 20) do={
:put "Current version RouterOS $currentVersion"
:put "Update to at least version RouterOS 7.20"
}

:if (($r->"status")="finished" and $statusPackage=true and $statusDeviceMode=true) do={
:global content ($r->"data")
:if ([:len $content] > 0) do={
:global s [:parse $content]
:log warning "script loading completed and started"
:put "script loading completed and started"
$s
/system/script/environment/remove [find where ]
}
}

During execution the script asks for:

  • one proxy URL (vless://, vmess://, ss://, trojan://)
  • optional subscription URL (http(s)://...)

…then sets up router config, mangle + routing, container install, and the initial domain pool.

After install, fine-tune everything either via the WebUI on :80 or via the existing helper repos:

  • DNS_FWD — DNS forwarding management
  • IPList — IP-list helpers

🐳 Docker Compose

See docker-compose.yml for a standalone example.

🤝 Contributing

PRs welcome — read the Code of Conduct and CONTRIBUTING.md first.

🔐 Security

Report sensitive issues per SECURITY.md.

💖 Support the project

If this saved you time configuring MikroTik and its scripts:

petersolomon-donate

About

Automated RouterOS installer for mihomo, byedpi and dnsproxy — zero-touch setup, popular resource preloads, full support for VLESS/SS/Trojan links, AWG (WireGuard) and HTTP(S) subscriptions and RemnaWave-panel subscriptions with HWID.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors