👉 Please read the Code of Conduct before participating in the project.
mihomo-proxy-ros is a multi-architecture Docker container based on Mihomo, byedpi, zapret(nfqws; only amd64 and arm64) and zapret2(nfqws2; only amd64 and arm64)
supporting platforms ARM, ARM64, AMD64v1, AMD64v2, and AMD64v3.
The latest tag includes ARM, ARM64, and AMD64v3.
If you have AMD64v1 or AMD64v2, you need to pull the corresponding tag.
If you find this project useful, you can support it via donation:
USDT(TRC20): TWDDYD1nk5JnG6FxvEu2fyFqMCY9PcdEsJ
https://boosty.to/petersolomon/donate
The repository contains an interactive automated installation script for RouterOS MikroTik,
which also If set installs and runs standalone dnsproxy from AdGuardHome dnsproxy from AdGuardHome.
- 🌍 Multi-architecture: ARM, ARM64, AMD64v1-v3
- ⚙️ Automated installation via MikroTik terminal using the script at the end of this description
- 🔐 DPI bypass via ByeDPI (You can change the strategy in the container’s ENVs. For selecting strategies, there is an option called byedpi-orchestrator.)
- 🔐 DPI bypass using Zapret (nfqws) (amd64 and arm64 only) — strategies must be selected separately from the container according to the instructions from the author of zapret
- 🔐 DPI bypass using Zapret2 (nfqws2) (amd64 and arm64 only) — strategies must be selected separately from the container according to the instructions from the author of zapret2
- 🌐 DNSProxy: multi-resolve from multiple DNS servers, supports all DNS protocols (Optional)
- 🧩 Flexible routing and management of domain, IP, and AS pools via ENVs
- 🛡️ Ability to add multiple proxy links and subscriptions (including RemnaWave subscriptions with HWID) via ENVs
- 🚀 Integration of multiple WG, AWG VPNs by copying config files into the mount folder
During execution, the user is prompted to:
- Enter a single proxy link:
vless://,vmess://,ss://,trojan:// - If available — a subscription link:
Enter sublink http(s)://... URL
The script automatically performs:
- Router configuration
- Mangle and routing setup
- Container installation
- Domain pool formation for resources routed through proxies
This makes the project significantly simplify the setup process,
making it convenient even for inexperienced users,
and provides a flexible, ready-to-use proxy solution.
After installation, you can flexibly configure resource routing on the router itself by modifying the resources in the existing script or creating new ones (DNS_FWD, IPList),
as well as adding new links and other parameters via environment variables (ENV) for flexible routing and container logic configuration of mihomo-proxy-ros.
| ENVs | Default | Description |
|---|---|---|
DNS_MODE |
fake-ip |
DNS server operation mode DOCs |
NAMESERVER_POLICY |
— | Specifies which domains should be resolved by which DNS servers DOCs. ENV example: domain1#dns1,domain2#dns2 |
SNIFFER |
true |
Domain sniffer. Applied when routing by domains, when the domain is resolved not by mihomo |
FAKE_IP_RANGE |
198.18.0.0/15 |
Fake-IP pool range DOCs |
FAKE_IP_TTL |
1 |
Lifetime of FakeIP record in DNS cache in seconds DOCs |
FAKE_IP_FILTER |
— | Comma-separated list of domains excluded from Fake-IP DOCs. When running the script, www.youtube.com is set due to YouTube specifics on TVs via BYEDPI and the need to modify MSS |
FAKE_IP_FILTER_MODE |
blacklist |
Fakeip filter operation mode DOCs |
EXTERNAL_UI_URL |
link | Web interface link (zip archive) DOCs |
LOG_LEVEL |
error |
mihomo log level (silent, error, warning, info, debug) DOCs |
HEALTHCHECK_URL |
https://www.gstatic.com/generate_204 |
Health-check URL |
HEALTHCHECK_URL_STATUS |
204 |
Expected health-checked status DOCs |
HEALTHCHECK_INTERVAL |
120 |
Health-check interval in seconds DOCs |
HEALTHCHECK_URL_BYEDPI |
https://www.facebook.com |
Health-check URL for BYEDPI proxy provider |
HEALTHCHECK_URL_STATUS_BYEDPI |
200 |
Expected health-check status DOCs for BYEDPI proxy provider |
HEALTHCHECK_URL_ZAPRETI |
https://www.facebook.com |
Health-check URL for ZAPRET proxy provider |
HEALTHCHECK_URL_STATUS_ZAPRET |
200 |
Expected health-check status DOCs for ZAPRET proxy provider |
HEALTHCHECK_URL_ZAPRET2 |
https://www.facebook.com |
Health-check URL for ZAPRET2 proxy provider |
HEALTHCHECK_URL_STATUS_ZAPRET2 |
200 |
Expected health-check status DOCs for ZAPRET2 proxy provider |
HEALTHCHECK_PROVIDER |
true |
If true — health checks use HEALTHCHECK_URL, HEALTHCHECK_INTERVAL, HEALTHCHECK_URL_STATUS. If false — health checks use GROUP_URL, XXX_URL, GROUP_URL_STATUS, XXX_URL_STATUS, GROUP_INTERVAL, XXX_INTERVAL |
BYEDPI_CMD |
— | Enables BYEDPI DPI bypass strategy only for TCP traffic going through mihomo (Clash Meta kernel); when set, the BYEDPI proxy outbound appears |
BYEDPI_CMD_UDP |
Same as BYEDPI_CMD |
Enables BYEDPI DPI bypass strategy only for UDP through mihomo and additionally starts a socks5 proxy on port :1090 that handles both TCP and UDP via byedpi |
ZAPRET_CMD |
— | The Zapret(nfqws) strategy; when set, the ZAPRET proxy outbound appears. The container includes .bin files for fakes from the zapret-discord-youtube repository. The paths for using them are @/zapret-fakebin/quic_initial_www_google_com.bin, @/zapret-fakebin/tls_clienthello_4pda_to.bin, @/zapret-fakebin/tls_clienthello_max_ru.bin, @/zapret-fakebin/tls_clienthello_www_google_com.bin |
ZAPRET2_CMD |
— | The Zapret2(nfqws2) strategy; when set, the ZAPRET2 proxy outbound appears |
LINK0, LINK1... |
— | Proxy links vless://, vmess://, ss://, trojan://... For each proxy link, a separate proxy provider is created |
SUB_LINK0, SUB_LINK1... |
— | Subscriptions of type http(s)://... For each subscription, a separate proxy provider is created. Supports setting HWID individually for each subscription |
SUB_LINKxx_PROXY |
DIRECT |
Specifies through which proxy the subscription should be fetched. Example: SUB_LINK1_PROXY with value proxies1 → the subscription will be downloaded via the proxy proxies1 |
SUB_LINKxx_HEADERS |
— | Specification of headers for the subscription request with special headers. Example format: header1=value1#header2=value2. Example with x-hwid: x-hwid=xxx#x-device-os=xxx#x-ver-os=xxx#x-device-model=xxx#user-agent=xxx |
SOCKS0, SOCKS1... |
— | SOCKS5 proxies . Each defined SOCKS5 proxy gets its own separate proxy-provider. ENV examples: server=192.168.88.3#port=1080#username=admin#password=admin#tls=true#fingerprint=chrome#skip-cert-verify=false#udp=false#ip-version=ipv4 or shorter server=192.168.88.3#port=1080#username=admin#password=admin All SOCKS5 config parameters are separated by # instead of the usual YAML/JSON syntax. |
GROUP |
— | Comma-separated list of proxy groups, e.g., telegram,youtube,google,ai,geoblock will create proxy groups TELEGRAM,YOUTUBE,GOOGLE,AI,GEOBLOCK. A proxy group is created only if at least one of the _GEOSITE, _GEOIP, _AS ENVs exists for it |
XXX_TYPE |
select |
Proxy group type . XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,youtube,... → YOUTUBE_TYPE |
GROUP_URL |
https://www.gstatic.com/generate_204 |
Proxy health check URL used when HEALTHCHECK_PROVIDER=false and XXX_TYPE is url-test, fallback, or load-balance |
XXX_URL |
ENV GROUP_URL |
Sets the proxy health check URL for a specific proxy group when HEALTHCHECK_PROVIDER=false |
GROUP_URL_STATUS |
204 |
Expected status code for proxy health check used when HEALTHCHECK_PROVIDER=false and XXX_TYPE is url-test, fallback, or load-balance |
XXX_URL_STATUS |
ENV GROUP_URL_STATUS |
Sets the expected status code for proxy health check for a specific proxy group when HEALTHCHECK_PROVIDER=false |
GROUP_INTERVAL |
60 |
Proxy health check interval in seconds, used when HEALTHCHECK_PROVIDER=false and XXX_TYPE is url-test, fallback, or load-balance |
XXX_INTERVAL |
ENV GROUP_INTERVAL |
Sets the proxy health check interval for a specific proxy group when HEALTHCHECK_PROVIDER=false |
GROUP_TOLERANCE |
20 |
Difference for selecting the best proxy in ms, used for XXX_TYPE url-test |
XXX_TOLERANCE |
ENV GROUP_TOLERANCE |
Setting difference for selecting the best proxy for the proxy group |
GROUP_STRATEGY |
consistent-hashing |
Load balancing strategy, used for XXX_TYPE load-balance |
XXX_STRATEGY |
ENV GROUP_STRATEGY |
Setting load balancing strategy for the proxy group |
XXX_USE |
(all providers) in order LINKs, SUB_LINKs, WG,AWG, BYEDPI, DIRECT |
Comma-separated list of proxy providers to be used in the specified order for the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,youtube,... → YOUTUBE_USE with value BYEDPI,LINK1 will leave two proxy providers for the YOUTUBE group, with BYEDPI first and LINK1 second |
XXX_FILTER |
— | Proxy group filter, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,youtube,... → YOUTUBE_FILTER with value RU|BYEDPI will leave proxies with the RF flag emoji and name BYEDPI for the YOUTUBE group |
XXX_EXCLUDE |
— | Proxy group exclude filter, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,youtube,... → YOUTUBE_EXCLUDE with value RU|BYEDPI will exclude proxies with the RF flag emoji and name BYEDPI from the YOUTUBE group |
XXX_EXCLUDE_TYPE |
— | Proxy group filter by type, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,youtube,... → YOUTUBE_EXCLUDE_TYPE with value vmess|direct will exclude vmess and direct type proxies from the YOUTUBE group |
XXX_GEOSITE |
— | Comma-separated list of geosite for proxy group XXX. Actually creates a rule-set in rms format and corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,geoblock,... → GEOBLOCK_GEOSITE with value intel,openai,xai will load domain lists for intel,openai,xai resources and route them to the GEOBLOCK proxy-group |
XXX_GEOIP |
— | Comma-separated list of geoip for proxy group XXX. Actually creates a rule-set in rms format and corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,geoblock,... → GEOBLOCK_GEOIP with value netflix will load IP pools for netflix and route them to the GEOBLOCK proxy-group |
XXX_AS |
— | Comma-separated list of AS for proxy group XXX. Actually creates a rule-set in rms format and corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,telegram,... → TELEGRAM_AS with value AS62041,AS59930,AS62014,AS211157,AS44907 will load IP pools for AS62041,AS59930,AS62014,AS211157,AS44907 and route them to the TELEGRAM proxy-group |
XXX_DOMAIN |
— | Comma-separated list of domains for proxy group XXX. Actually creates corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,telegram,... → TELEGRAM_DOMAIN with value telegram.org,telegram.com will route the specified domains to the TELEGRAM proxy-group |
XXX_SUFFIX |
— | Comma-separated list of domain suffixes for proxy group XXX. Actually creates corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,telegram,... → TELEGRAM_SUFFIX with value telegram.org,telegram.com will route the specified domains and their subdomains to the TELEGRAM proxy-group |
XXX_KEYWORD |
— | Comma-separated list of domain keywords for the proxy-group named XXX. Automatically creates corresponding rules that route matching domains to the proxy-group XXX. The group name XXX is taken from the GROUP environment variable (comma-separated list). Example: GROUP=...,telegram,... + TELEGRAM_KEYWORD=telegram,tg → all domains containing telegram or tg will be routed to the TELEGRAM proxy-group |
XXX_IPCIDR |
— | Comma-separated list of IP-CIDR for proxy group XXX. Actually creates corresponding routing rules to the proxy group, where XXX is the proxy group name set in the GROUP ENV. For example, for GROUP ...,telegram,... → TELEGRAM_IPCIDR with value 91.108.4.0/22,91.108.56.0/22 will route the specified subnets to the TELEGRAM proxy-group |
XXX_SRCIPCIDR |
— | Comma-separated list of SRC-IP-CIDR for the proxy group XXX. Actually creates corresponding routing rules that send traffic from these source IPs/subnets to the proxy group XXX. XXX is the proxy group name you specify in the ENV variable GROUP. Example: if GROUP contains ...,socks,..., then the variable SOCKS_IPCIDR with value 192.168.88.37/32,192.168.88.65/32 will route all traffic from these subnets to the proxy-group named SOCKS. |
XXX_PRIORITY |
— | Priority of proxy group XXX in terms of rule order in rules. For example, YOUTUBE_PRIORITY with value 1 and TELEGRAM_PRIORITY with value 2 will create rules in rules in order: first YOUTUBE, then TELEGRAM |
WG, AWG configs need to be mounted to the container folder
/root/.config/mihomo/awg/, proxy providers will be created in the number of config files with their filenames.
Any proxy can be formatted in a
.yamlfile according to the documentation and mounted in the folder/root/.config/mihomo/proxies_mount/.
Multiple VETH interfaces can be added to the container; they will appear as proxy outbounds in mihomo. You can choose which interface to send traffic through, and then, in RouterOS, use mangle to route it as desired, but traffic must be sent to the mihomo container only through the first interface in the list.
First, make sure you have the container package installed and that the necessary device-mode functions are enabled.
/system/device-mode/printEnable device-mode if necessary. Follow the instructions after executing the command below. You have 5 minutes to reboot the power supply or briefly press any button on the device (I recommend using any button).
/system/device-mode/update mode=advanced container=yesTranslated with DeepL.com (free version)
🧩 Installation is done directly via MikroTik terminal —
just copy and paste the snippet below into the RouterOS terminal,
then the script automatically downloads from the repository and starts installation.
: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 ]
}
}
If you find this project useful, you can support it via donation:
USDT(TRC20): TWDDYD1nk5JnG6FxvEu2fyFqMCY9PcdEsJ
https://boosty.to/petersolomon/donate