我经常遇到在服务器上部署的容器需要用到代理的情况,给容器配置代理,最常见的是使用HTTP_PROXY环境变量,但是这个变量并不是所有App都认的,有些跑在容器里面的App根本不鸟这个变量,这时候就有点蛋疼了。
今天分享一个利用mihomo让容器全部无感透明代理的思路,这套配置简洁、优雅、易于使用,且适用所有容器内的App,不管容器内跑的是Java还是Node.js亦或者其它的什么东西,都能够直接连上mihomo的节点实现代理访问互联网。
其实sing-box也可以做到同样的效果,只要代理软件支持TUN,且具备自动接管路由表的能力,都可以用这种配置方式,只是我不想搓sing-box的json配置文件,太麻烦了,想比较之下mihomo的yaml配置文件搓起来简单点。。
新建compose文件:
mkdir /opt/mihomo && cd /opt/mihomo && nano docker-compose.yml
写入如下内容:
services:
mihomo:
image: metacubex/mihomo:latest
container_name: mihomo
restart: always
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
volumes:
- ./mihomo_config:/root/.config/mihomo
ports:
- "19090:9090" # 外部控制面板(可选)
- "8080:8080" # 如果应用容器有自己的端口要暴露,端口必须映射在这里
# 你的实际应用容器,这里的容器仅为演示代理效果
my_app:
image: nicolaka/netshoot:latest
container_name: my_app
network_mode: "service:mihomo" # 共享mihomo代理容器的网络栈
depends_on:
- mihomo
command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]
这套配置的核心就这一行:network_mode: "service:mihomo",让我简单解释一下其作用。在Docker中,默认情况下每个容器都有自己独立的“网络空间”(Network Namespace),里面有独立的网卡、路由表和iptables规则。
但是当你配置network_mode: "service:mihomo"时,等于把应用容器(App)强行塞进了代理容器(Proxy)的“网络空间”里。此时:它们共享同一张虚拟网卡,共享同一套路由表。
当代理软件在容器内开启TUN模式时,它会在这个“网络空间”创建一个虚拟网卡,并把默认路由指向虚拟网卡。由于应用容器也在这个“网络空间”里,所以理所当然它的流量也会被路由表直接导向虚拟网卡。
在这个模式下,你可能会遇到一些“坑点”,这里我也简单说一下。
1.端口映射(Ports)必须声明在“代理容器”上:一旦配置了network_mode: "service:mihomo",你的应用容器(本文示例:my_app)就已经失去了独立网络主权,它无法再声明自己的端口。假设你的应用是一个Web服务(比如NGINX监听8080端口),你必须把-"8080:8080"写在mihomo容器的ports列表里。
2.容器间通信名字变了:一旦容器加入了代理的“网络空间”,它就失去了在Docker默认网桥上的“独立姓名”,容器间通过服务名(如nginx、postgres)互相寻址的机制就会失效。在默认情况下,其他Docker容器可以通过http://my_app:8080访问该应用,但现在my_app在Docker默认网络中相当于“隐身”了。你应该将所有的内部互访全部改写为127.0.0.1(本地回环)例如对于本文的示例而言,应修改为:http://127.0.0.1:8080
其实我之前有一篇文章介绍过GlueTun这个项目,其采用的是与本文一样的方式,只是这个GlueTun不太适合在中国内地使用,它支持的几乎全部都是收费的VPN,对于我们平时常用的代理协议是全部都不支持。
那么现在让我们继续对mihomo进行配置,新建一个目录用于存放mihomo的配置文件和其它资源(如:控制面板文件、rule-set文件)
mkdir mihomo_config
新建mihomo的配置文件:
nano mihomo_config/config.yaml
这是我的示例配置:
mixed-port: 7890
allow-lan: true
tcp-concurrent: true
find-process-mode: strict
mode: rule
log-level: info
ipv6: false
keep-alive-interval: 30
unified-delay: true
profile:
store-selected: true
store-fake-ip: false
external-controller: 0.0.0.0:9090
external-controller-cors:
allow-origins:
- '*'
allow-private-network: true
secret: "89641937"
external-ui: "./ui"
external-ui-name: zashboard
external-ui-url: "https://github.com/Zephyruso/zashboard/archive/refs/heads/gh-pages.zip"
tun:
enable: true
stack: mixed
auto-route: true
auto-redirect: false
auto-detect-interface: true
dns-hijack:
- any:53
strict-route: true
mtu: 1500
dns:
enable: true
cache-algorithm: arc
prefer-h3: false
use-hosts: true
use-system-hosts: true
listen: 127.0.0.1:6868
ipv6: false
enhanced-mode: redir-host
default-nameserver:
- 8.8.8.8
- 1.1.1.1
nameserver:
- https://cloudflare-dns.com/dns-query
- https://dns.google/dns-query
proxy-server-nameserver:
- https://cloudflare-dns.com/dns-query
- https://dns.google/dns-query
direct-nameserver:
- https://dns.google/dns-query
- https://cloudflare-dns.com/dns-query
respect-rules: true
sniffer:
enable: true
force-dns-mapping: true
parse-pure-ip: true
sniff:
HTTP:
ports:
- 80
- 8080-8880
override-destination: true
TLS:
ports:
- 443
- 8443
proxies:
- name: proxy1
type: anytls
server: 8.9.6.4
port: 8443
password: "hidden"
client-fingerprint: chrome
udp: true
idle-session-check-interval: 30
idle-session-timeout: 30
min-idle-session: 5
sni: "anytls.example.com"
alpn:
- h2
skip-cert-verify: false
proxy-groups:
- name: PROXY
icon: https://cdn.jsdelivr.net/gh/Koolson/Qure@master/IconSet/Color/Hijacking.png
type: select
proxies:
- proxy1
rule-providers:
geosite-youtube:
type: http
behavior: domain
format: mrs
url: https://github.com/MetaCubeX/meta-rules-dat/raw/meta/geo/geosite/youtube.mrs
path: ./rule-sets/youtube.mrs
interval: 86400
proxy: proxy1
rules:
- DOMAIN-SUFFIX,ipinfo.io,PROXY
- RULE-SET,geosite-youtube,PROXY
- MATCH,DIRECT
该配置并非最佳实践,里面包含一些无用或者多余的配置项,但并不会影响实际使用。此配置是根据我的这篇文章随便改了下而来的,又不是不能用。
在rules这块,兜底走的是MATCH,DIRECT(直连)而非MATCH,PROXY(代理)是因为我将其部署在境外的服务器上,境外本来就没有GFW这种垃圾东西(伊朗和俄罗斯这种国家除外),自然没有必要将所有流量都走代理,能直连就尽量直连。我更多的是为了解决服务器自身IP太脏,被Youtube等流媒体平台拉黑的问题,当然具体怎么使用取决于你自己的网络环境。
启动:
docker compose up -d
测试一下应用容器内是否成功走了代理:
补充一点内容,本文提供的mihomo配置文件内启用了zashboard控制面板:
http://serverip:19090/ui/zashboard/
密码:89641937
如果要使用这个控制面板,请根据如图所示进行配置(修改主机的IP地址为你的服务器公网IP,端口19090):
荒岛

















