├── .gitignore ├── Dockerfile ├── LICENSE ├── docker-compose.yaml ├── config.yaml ├── README.md ├── entrypoint.sh └── cn_cidr.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/.DS_Store 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | ARG TZ="Asia/Shanghai" 4 | 5 | WORKDIR /mihomo 6 | 7 | RUN echo "Starting..." && \ 8 | apk add --no-cache nftables ca-certificates tzdata git && \ 9 | cp /usr/share/zoneinfo/${TZ} /etc/localtime && \ 10 | echo ${TZ} > /etc/timezone && \ 11 | mkdir /mihomo/config && \ 12 | git clone -b gh-pages --single-branch https://github.com/MetaCubeX/metacubexd.git /mihomo/config/ui && \ 13 | apk del tzdata git && \ 14 | rm -rf /var/cache/apk/* 15 | 16 | COPY --from=metacubex/mihomo:latest /mihomo /mihomo/mihomo 17 | COPY entrypoint.sh /entrypoint.sh 18 | 19 | ENTRYPOINT ["/bin/sh", "/entrypoint.sh"] 20 | CMD ["/mihomo/mihomo", "-d", "/mihomo/config"] 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 ATP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | mihomo: 3 | image: mihomo:latest 4 | # build: 5 | # context: . 6 | # dockerfile: Dockerfile 7 | container_name: mihomo 8 | restart: unless-stopped 9 | cap_add: 10 | - NET_ADMIN 11 | networks: 12 | mihomovlan: # macvlan name 13 | ipv4_address: 192.168.2.2 # container (gateway) ip address 14 | environment: 15 | QUIC: "false" # allow quic (udp 443) 16 | CONTAINER_PROXY: "false" # forward the container's own traffic to tproxy 17 | BYPASS_CN: "false" # bypass cn ip to mihomo kernel (valid only in redir-host mode; fake-ip mode requires DNS routing) 18 | volumes: 19 | - './config.yaml:/mihomo/config/config.yaml' 20 | - './cn_cidr.txt:/mihomo/config/cn_cidr.txt' 21 | 22 | networks: 23 | mihomovlan: 24 | name: mihomovlan 25 | driver: macvlan 26 | driver_opts: 27 | parent: eth0 # modify it to match your network interface name 28 | ipam: 29 | config: # modify the following content to match your network env 30 | - subnet: "192.168.2.0/24" 31 | ip_range: "192.168.2.64/26" 32 | gateway: "192.168.2.1" 33 | 34 | # if you already have a macvlan 35 | # networks: 36 | # yourvlan: 37 | # external: true 38 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | ########################################## 2 | ## Mihomo (Clash.Meta) documentation: ## 3 | ## https://wiki.metacubex.one/config/ ## 4 | ########################################## 5 | # mixed-port: 7890 6 | # redir-port: 7892 7 | # Do not modify lines from 8 to 14 8 | tproxy-port: 7893 9 | allow-lan: true 10 | bind-address: '*' 11 | iptables: 12 | enable: false 13 | routing-mark: 255 14 | external-ui: ui 15 | external-controller: 0.0.0.0:9090 16 | # secret: "" 17 | mode: rule 18 | log-level: info 19 | ipv6: false 20 | profile: 21 | store-selected: true 22 | # TCP keep alive interval 23 | keep-alive-interval: 15 24 | keep-alive-idle: 15 25 | use-hosts: true 26 | hosts: 27 | 'localhost': 127.0.0.1 28 | geox-url: 29 | geosite: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite-lite.dat 30 | geoip: https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip-lite.dat 31 | geodata-mode: true 32 | geo-auto-update: true 33 | geo-update-interval: 72 34 | dns: 35 | enable: true 36 | prefer-h3: true 37 | ipv6: false 38 | listen: 0.0.0.0:1053 # Do not modify this address 39 | enhanced-mode: redir-host # or fake-ip 40 | # fake-ip-range: 198.18.0.1/16 41 | # fake-ip-filter: 42 | # - '*.lan' 43 | # - localhost.ptlogin2.qq.com 44 | default-nameserver: 45 | - 223.6.6.6 46 | - 119.29.29.29 47 | nameserver: # Default DNS for non-CN websites, use unpolluted DNS for redir-host mode. 48 | - https://dns.alidns.com/dns-query 49 | - https://doh.pub/dns-query 50 | nameserver-policy: 51 | "geosite:cn,private": # DNS for CN websites 52 | - https://dns.alidns.com/dns-query 53 | - tls://dot.pub 54 | 55 | proxies: 56 | # ... 57 | 58 | proxy-groups: 59 | # ... 60 | 61 | rules: 62 | # ... 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mihomo Transparent Proxy Docker 2 | 3 | A simple Mihomo (formerly known as Clash.Meta) transparent proxy Docker image. 4 | 5 | You can build and deploy this image on your local Linux device, such as a Raspberry Pi or NAS, as a bypass gateway. It supports both TCP and UDP redirection using nftables, with the option to block QUIC (UDP 443) traffic and bypass forwarding CN IPs to the Mihomo kernel. Since it runs within a Docker container, there's no need to worry about affecting the host network. 6 | 7 | ## Getting started 8 | 9 | *\* Unless you need network isolation, this is not a recommended practice for general use. Running in a Docker container may incur some network overhead.* 10 | 11 | By default, the gateway itself (docker container) does not forward traffic to TPROXY. If you are using the redir-host mode and do not have a clean DNS server that can be directly connected to, consider setting `CONTAINER_PROXY` to `true` within the `docker-compose.yaml` file. 12 | 13 | ### Requirements 14 | 15 | - AMD64 or ARM64 (AArch64) based Linux devices 16 | - Docker and Compose V2 installed 17 | 18 | ### Building 19 | 20 | Download or clone this repository to your local machine, and then build the image using the following command: 21 | 22 | ``` 23 | docker build -t mihomo:latest . 24 | ``` 25 | 26 | If you encounter network issues during the build process, try using the host network mode: 27 | 28 | ``` 29 | docker build --network=host -t mihomo:latest . 30 | ``` 31 | 32 | ## Usage 33 | 34 | Configure `docker-compose.yaml` file: 35 | 36 | ```docker 37 | services: 38 | mihomo: 39 | image: mihomo:latest 40 | # build: 41 | # context: . 42 | # dockerfile: Dockerfile 43 | container_name: mihomo 44 | restart: unless-stopped 45 | cap_add: 46 | - NET_ADMIN 47 | networks: 48 | mihomovlan: 49 | ipv4_address: 192.168.2.2 50 | environment: 51 | QUIC: "true" # allow quic (udp 443) 52 | CONTAINER_PROXY: "false" # forward the container's own traffic to tproxy 53 | BYPASS_CN: "false" # bypass cn ip to mihomo kernel (valid only in redir-host mode; fake-ip mode requires DNS routing) 54 | volumes: 55 | - './config.yaml:/mihomo/config/config.yaml' 56 | - './cn_cidr.txt:/mihomo/config/cn_cidr.txt' 57 | 58 | networks: 59 | mihomovlan: 60 | name: mihomovlan 61 | driver: macvlan 62 | driver_opts: 63 | parent: eth0 # modify this to match your network interface name 64 | ipam: 65 | config: # modify the following content to match your local network env 66 | - subnet: "192.168.2.0/24" 67 | ip_range: "192.168.2.64/26" 68 | gateway: "192.168.2.1" 69 | ``` 70 | 71 | If you need to connect to an IPv6 server, modify the networks config as follows: 72 | ``` 73 | networks: 74 | mihomovlan: 75 | name: mihomovlan 76 | driver: macvlan 77 | driver_opts: 78 | parent: eth0 79 | enable_ipv6: true 80 | ipam: 81 | config: 82 | - subnet: "192.168.2.0/24" 83 | ip_range: "192.168.2.64/26" 84 | gateway: "192.168.2.1" 85 | - subnet: "2001:db8:1::/64" 86 | ``` 87 | 88 | !!! Configure `config.yaml` of mihomo before you start the container. Please refer to the comments in the configuration for modifications. 89 | 90 | After configuring the `config.yaml` file, to start the container: 91 | 92 | ``` 93 | docker compose up 94 | ``` 95 | 96 | If there are no errors, press Ctrl + C to stop the container. Then restart it in the background: 97 | 98 | ``` 99 | docker compose up -d 100 | ``` 101 | 102 | You can download the latest [CN IP list](https://github.com/misakaio/chnroutes2/blob/master/chnroutes.txt) and replace the `cn_cidr.txt` file with it (the filename cannot be changed). After updating the `config.yaml` or `cn_cidr.txt`, simply restart the Docker container for the changes to take effect: 103 | 104 | ``` 105 | docker compose restart 106 | ``` 107 | 108 | *\* Setting up a crontab scheduled task for automatic updating and restarting is usually a good idea.* 109 | 110 | Finally, change the gateway and DNS server on your PC or phone to the Docker container's IP address. (e.g., 192.168.2.2). 111 | 112 | If everything is correct, you should be able to browse the internet now. You can conveniently manage mihomo via the built-in [web dashboard](https://github.com/MetaCubeX/metacubexd) accessible at http://192.168.2.2:9090. 113 | 114 | ## Credits 115 | 116 | - [Dreamacro/clash](https://github.com/Dreamacro/clash) 117 | - [MetaCubeX/mihomo](https://github.com/MetaCubeX/mihomo) 118 | - [misakaio/chnroutes2](https://github.com/misakaio/chnroutes2) 119 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Reference documentation: 3 | # https://www.kernel.org/doc/Documentation/networking/tproxy.txt 4 | # https://guide.v2fly.org/app/tproxy.html 5 | 6 | # configs 7 | MIHOMO_PORT=7893 8 | MIHOMO_DNS_PORT=1053 9 | MIHOMO_MARK=0xff 10 | TPROXY_MARK=0x1 11 | ROUTE_TABLE=100 12 | 13 | CN_IP_FILE="/mihomo/config/cn_cidr.txt" 14 | 15 | NFT_DIR="/mihomo/nftables" 16 | MAIN_NFT="$NFT_DIR/clash.nft" 17 | PRIVATE_NFT="$NFT_DIR/private.nft" 18 | CHNROUTE_NFT="$NFT_DIR/chnroute.nft" 19 | 20 | DEFAULT_IFACE=$(ip route | awk '/^default/ {print $5; exit}') 21 | [ -z "$DEFAULT_IFACE" ] && DEFAULT_IFACE="eth0" 22 | 23 | RESERVED_IPS="0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4" 24 | 25 | setup_nftables() { 26 | nft flush ruleset 27 | set -e 28 | 29 | # Generate nftables rules 30 | mkdir -p "$NFT_DIR" 31 | 32 | # private.nft 33 | cat > "$PRIVATE_NFT" <> "$PRIVATE_NFT" 43 | done 44 | sed -i '$ s/,$//' "$PRIVATE_NFT" 45 | 46 | cat >> "$PRIVATE_NFT" < "$CHNROUTE_NFT" <> "$CHNROUTE_NFT" 63 | sed -i '$ s/,$//' "$CHNROUTE_NFT" 64 | 65 | cat >> "$CHNROUTE_NFT" < "$MAIN_NFT" <> "$MAIN_NFT" 83 | 84 | cat >> "$MAIN_NFT" <> "$MAIN_NFT" 93 | 94 | cat >> "$MAIN_NFT" <> "$MAIN_NFT" <> "$MAIN_NFT" <> "$MAIN_NFT" 140 | 141 | # Masquerade non-tproxy traffic going out of default interface 142 | cat >> "$MAIN_NFT" <