· 故障排查 · 预计阅读 12 分钟
Clash 启动报端口被占用:定位占用进程与修改 mixed-port
在 Windows、macOS 与 Linux 上用 netstat、lsof、ss 找出占用 7890 等端口的进程,并说明修改端口后系统代理与浏览器设置的同步调整。
先读日志:确认端口、地址与错误类型
Clash 或 Clash Meta(现称 mihomo)启动时出现端口绑定失败,首先要确认失败的是哪个监听器。7890 常被配置为本地代理入口,但它不是固定要求,也不是远端节点的服务端口。修改本地入口通常不需要改订阅中的节点地址、密码或代理规则。
在客户端的日志页面查找 listen、bind、address already in use 等关键词,记录完整的本地地址与端口。例如下面的日志表示 TCP 的 IPv4 回环地址绑定失败:
listen tcp 127.0.0.1:7890: bind: address already in use
Windows 也可能显示 Only one usage of each socket address。如果显示的是 permission denied 或 An attempt was made to access a socket in a way forbidden by its access permissions,则还要检查权限、安全策略或系统保留端口,不能直接判定为另一个 Clash 进程占用。
| 配置字段 | 用途 | 绑定失败后的影响 |
|---|---|---|
mixed-port | HTTP 与 SOCKS5 共用入口 | 使用该入口的应用无法连接代理 |
port / socks-port | 独立 HTTP / SOCKS 入口 | 对应协议的代理入口不可用 |
external-controller | 控制 API,常见示例为 9090 | 客户端面板可能无法连接内核 |
dns.listen | 内置 DNS 的监听地址 | 相关 DNS 查询可能失败 |
排查对象是“协议 + 本地地址 + 端口”,不只是一个数字。
127.0.0.1:7890、0.0.0.0:7890与[::]:7890的监听范围不同;通配地址和双栈监听可能与更具体的地址冲突。
Windows:用 netstat 与 PowerShell 定位进程
查询监听记录,再核对 PID
打开 PowerShell,先运行以下命令。第一条用于快速查看,第二条按本地 TCP 端口精确筛选。查看其他进程的完整信息时,可能需要以管理员身份运行终端。
netstat -ano -p tcp | findstr ":7890"
Get-NetTCPConnection -LocalPort 7890 -State Listen -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, State, OwningProcess
netstat 的末列是进程标识 PID。注意 findstr 也可能匹配远端地址或 78900 等字符串,因此要确认“本地地址”列确实是 7890,且状态为 LISTENING。TIME_WAIT 是连接状态,不应据此随意结束进程。
假设查询得到 PID 为 4321,继续查看进程名、可执行文件路径与命令行。这里的 4321 只是演示,执行前必须换成实际查询结果。
tasklist /FI "PID eq 4321"
Get-CimInstance Win32_Process -Filter "ProcessId = 4321" |
Select-Object Name, ExecutablePath, CommandLine
如果进程是另一个代理客户端启动的 mihomo,优先从那个客户端的托盘菜单退出,或关闭其后台服务。仅关闭窗口不一定停止内核。如果 PID 属于系统服务或不认识的软件,先核对路径和用途,不要直接执行强制结束命令。
没有监听记录,但仍提示绑定失败
- 检查日志是否实际指向 7891、9090 或另一个端口,而不是 7890。
- 检查客户端是否在失败后反复重启内核,查询时恰好处于进程退出的间隙。
- 如果日志明确写 UDP,使用
Get-NetUDPEndpoint -LocalPort 7890查看,不要只查 TCP。 - 如果错误属于访问权限限制,可运行下方命令查看 IPv4 TCP 排除端口范围。端口落在范围内时,选择其他可用端口通常比删除系统保留范围更稳妥。
netsh interface ipv4 show excludedportrange protocol=tcp
macOS:用 lsof 查看监听者与后台服务
在“终端”运行下面的命令。-nP 禁止把地址和端口转换成名称,-sTCP:LISTEN 只显示监听套接字,便于区分本地服务与普通出站连接。
sudo lsof -nP -iTCP:7890 -sTCP:LISTEN
结果中的 COMMAND 是进程名,PID 是进程标识,NAME 显示监听地址。若看到 *:7890,说明它不是只绑定某一个指定的本地接口。接着查询完整命令行,识别内核由哪个客户端或启动项拉起:
ps -p 4321 -o pid,ppid,user,command
如果确认是旧客户端残留,先正常退出对应应用;仍未停止时,可以在“活动监视器”中选中已确认的进程并尝试退出。命令行操作可对实际 PID 发送 kill -TERM 4321,让进程有机会正常清理。不要把 kill -9 当作第一步。
若刚退出就出现新 PID,通常存在自动拉起机制。可到 macOS 13 及后续版本的“系统设置”→“通用”→“登录项”(部分版本名称为“登录项与扩展”)核对后台项目;通过 Homebrew 安装的服务还应检查 brew services list。应从对应服务入口停用,而不是反复结束子进程。
Ubuntu 与 Linux:用 ss 定位 systemd 和重复内核
Ubuntu 优先使用 ss 查询 TCP 监听状态。加上 sudo 后,通常能看到其他用户进程的 PID 与程序名;省略权限可能只看到套接字而看不到进程。
sudo ss -ltnp 'sport = :7890'
sudo ss -lunp 'sport = :7890'
第一条查看 TCP,第二条查看 UDP。TCP 输出里的 LISTEN 表示监听,UDP 通常显示 UNCONN,两者状态名称不同。在安装了 lsof 的系统上,也可以使用与 macOS 相同的 sudo lsof -nP -iTCP:7890 -sTCP:LISTEN。
桌面客户端与 systemd 同时运行
常见冲突是服务器部署遗留的 systemd 服务已经占用 7890,桌面客户端又尝试启动另一份内核。如果 PID 是 4321,可先查看命令行和所属服务,再决定保留哪一套:
ps -p 4321 -o pid,ppid,user,args
sudo systemctl status 4321
systemctl status 可以根据 PID 查询所属单元;若确认它属于名为 mihomo.service 的自建服务,而且现在要使用桌面客户端,可停止该服务:
sudo systemctl stop mihomo.service
sudo ss -ltnp 'sport = :7890'
服务名必须以本机实际结果为准。如果以后也不需要开机启动,再执行 sudo systemctl disable mihomo.service;单独执行 disable 不会停止当前进程。用户级服务则使用 systemctl --user 操作。对于启用了自动重启的服务,直接杀掉内核往往只会触发再次启动。
若监听者显示为容器相关进程,还应核对容器的宿主机端口映射。不要为了释放一个代理端口而停止整个容器运行环境;可以调整对应容器的映射,或给本地代理换一个入口。
修改 mixed-port:区分界面设置与实际生效配置
如果占用者是必须保留的程序,可以将 Clash 的本地入口从 7890 改为 17890。17890 只是本篇示例,不保证在你的设备上空闲;修改前先用前面的命令查询这个新端口。
图形客户端优先在设置中修改
不同客户端的界面名称并不统一,通常可在“设置”中的“端口”“代理端口”或“内核设置”找到入口。先确认当前显示的是混合端口,而不是控制器端口。客户端可能把设置写入生成配置,并覆盖订阅文件中的同名字段,因此不要只改下载到本地的订阅 YAML。
独立运行 mihomo 时修改根层级字段
对于直接读取配置文件的内核,编辑启动参数 -f 指定的文件;若使用工作目录 -d,则核对该目录中的实际配置文件。下面是入口字段的修改示例,不是包含节点和规则的完整配置:
mixed-port: 17890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
mixed-port写在 YAML 根层级,前面不要加general:,也不要缩进到dns:下。- 若原配置还有
port、socks-port等独立入口,逐项检查是否仍占用冲突端口。只修改混合端口不会自动修改其他入口。 - 修改根层级入口后,按客户端要求重新应用配置或重启内核;仅切换代理节点不能保证监听器更新。
- 订阅更新可能覆盖直接编辑的内容。支持覆写或合并功能的客户端,应在持久化设置或覆写层保存本地端口。
独立部署可用 mihomo -t -f /etc/mihomo/config.yaml 检查配置能否解析,路径按实际部署调整。配置测试通过并不代表运行时端口一定可用,最终仍要检查启动日志与监听状态。
同步系统代理、浏览器与终端端口
把内核改为 17890 后,如果应用仍连接 127.0.0.1:7890,现象通常会从“内核启动失败”变成“代理服务器拒绝连接”。需要同步的是所有手动填写过旧端口的位置,而不只是客户端界面。
| 使用方式 | 需要核对的位置 |
|---|---|
| Windows 系统代理 | “设置”→“网络和 Internet”→“代理”→“手动设置代理” |
| macOS 系统代理 | “系统设置”→“网络”→当前连接→“详细信息”→“代理” |
| Ubuntu GNOME | “设置”→“网络”→“网络代理”,核对手动代理端口 |
| Firefox 独立代理 | “设置”→“常规”→“网络设置”→“设置” |
| 浏览器代理扩展 | 当前情景模式中的 HTTP / SOCKS5 服务器地址和端口 |
| 终端及开发工具 | 代理环境变量、Git 配置、IDE 与包管理器的独立代理设置 |
由客户端管理系统代理时,可在确认新入口监听成功后,将“系统代理”关闭再开启,让客户端重新写入地址。Firefox 若选择“使用系统代理设置”,一般不必再单独填端口;若选择手动代理,则需要自行更新。
在 Linux 或 macOS 的当前 shell 中,可按需要更新环境变量。https_proxy 使用 http:// 并不矛盾:这里表示应用通过 HTTP 代理建立 HTTPS 隧道,而不是把目标网站降为 HTTP。
export http_proxy=http://127.0.0.1:17890
export https_proxy=http://127.0.0.1:17890
export all_proxy=socks5h://127.0.0.1:17890
这些命令只影响当前 shell 及其后续子进程,已打开的应用不会自动更新。还要检查 shell 启动文件里是否保存了旧值。Git 可先用 git config --show-origin --get-regexp '.*proxy.*' 查看来源,再针对实际作用域修改,避免只改全局配置而遗漏仓库配置。
TUN 模式通过虚拟网卡接管流量,与显式 HTTP/SOCKS 入口不是同一机制。启用 TUN 不会释放已被占用的端口;如果配置仍要求监听 7890,该监听器仍可能报错。也不要因为 TUN 下部分应用可用,就忽略旧系统代理设置。
恢复验证:监听、请求与重启后持久性
- 确认监听进程。用系统对应的查询命令检查 17890,确认监听者是打算保留的内核,并核对回环地址或通配地址。
- 发送显式代理请求。使用下面的命令绕过“应用是否遵循系统代理”的不确定性,分别验证 HTTP 与 SOCKS5 入口。
- 检查客户端连接记录。确认测试请求进入内核,再查看规则命中与出口。能连接本地入口不等于远端节点一定可用。
- 验证日常应用。重新打开浏览器或终端,检查是否仍引用 7890。
- 验证重启与订阅更新。重启客户端后再看一次端口;更新订阅后确认持久化设置没有被覆盖。
curl --noproxy "" --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 20 -I https://example.com/
curl --noproxy "" --proxy socks5h://127.0.0.1:17890 --connect-timeout 5 --max-time 20 -I https://example.com/
Windows PowerShell 中建议把上面的 curl 明确写为 curl.exe,避免旧版 PowerShell 的同名别名产生参数差异。--noproxy "" 用于排除绕过代理设置的干扰,5 秒与 20 秒分别是连接超时和总请求超时,不是速度测试结果。
若返回连接被拒绝,继续检查本地监听与端口;若已经连接代理但后续超时,转向规则、节点、DNS 与目标站点可达性排查。若报错端口其实是控制 API 的 9090,则应同步修改控制器地址及客户端连接参数,而不是反复改 mixed-port。按“日志定位 → 查进程 → 处理重复服务或换端口 → 同步应用 → 验证”的顺序,能将本地绑定故障与后续网络故障分开处理。