发现端口被占用时,应先留下可追溯记录,而不是立刻结束该进程。适用条件是:Clash 因地址或路径无法绑定而启动失败,或启动前查询发现代理端口、外部控制端口、Unix socket、named pipe 已被监听,需要先弄清占用方是谁,再决定改配置还是退出旧实例。
先锁定 Clash 真正会占用的对象
记录必须对准配置里的监听,而不是本机所有高位端口。代理端口与 bind-address 成对出现:* 表示所有 IP,具体 IPv4 或 IPv6 只绑一处。allow-lan 为 true 时其他设备会使用这些代理端口,但占用方仍是「谁在该地址上监听」,与 lan-allowed-ips、lan-disallowed-ips 无关——后两者只过滤客户端来源,默认白名单为 0.0.0.0/0 与 ::/0,黑名单优先。外部控制示例为 127.0.0.1:9090,TLS 示例为 127.0.0.1:9443,且使用 TLS 时必须同时存在 external-controller。external-controller-unix 与 external-controller-pipe 要把路径和管道名一并列入。清单应包含:地址或路径、端口或管道、来自哪一条配置键。
不要用 find-process-mode 去查找占用端口的进程。该选项控制的是 Clash 是否为路由规则匹配进程:always 强制匹配所有进程,strict 由内核判断是否开启,off 不匹配并推荐在路由器上使用。它记录的是走代理的客户端进程,不是占用监听套接字的服务进程。把两者分开,才不会在路由器上打开 always 却仍然不知道谁占了控制端口。
记录哪些字段才算可追溯
对每个冲突的地址或路径,应记下:进程标识、可执行文件或服务名、完整命令行(用来分辨另一份内核、旧实例或其他面板)、监听的准确元组,以及它与配置键的对应关系。若占用的是 Unix socket 或 named pipe,资料写明从这两类入口访问 API 不会验证 secret,记录时更要写清路径和进程归属,避免误判成密钥配错。external-ui 只是静态资源目录,不额外监听端口;secret、authentication、skip-auth-prefixes 也不占用端口。这些项可以在备注中标明「已排除」,但不要当成占用方。external-doh-server 是在已有 RESTful API 端口上开启路径(资料示例为 /dns-query),冲突仍落在 API 监听上,不必当成第三条独立 TCP 端口去结束进程。
判断「可以先不结束进程」的依据包括:占用方名称无法确认为多余的 Clash 实例;命令行显示它服务于其他面板、系统服务或开发服务器;管道或 socket 名称与当前配置接近,但无法证明是无主残留。此时结束进程可能中断别人的 API 或代理。记录本身已经足以支持下一步:给当前 Clash 改端口或改 bind-address。
不结束进程时的操作与失败时下一步
具体操作分三步。第一,按配置列出监听清单。第二,在系统中查出占用这些元组的进程并写下标识,不做终止。第三,对照是否为第二个 external-controller 实例。只有在记录已经能证明那是自己的旧内核之后,才在维护窗口有序退出那一个实例,而不是对未知进程直接结束。若无法确认,优先改当前配置的代理端口、bind-address 或 external-controller 端口,让新实例改绑空闲地址。
失败时下一步:查询不到进程时,检查是否把 bind-address 理解错(* 与单一 IP 看到的占用网卡不同),以及是否把 CORS 或 external-doh-server 当成了独立端口。若只有 Unix 或 pipe 冲突,下一步查路径是否被旧实例持有,而不是结束恰好使用邻近 TCP 端口的无关程序。需要日志辅助时,将 log-level 设为 warning 或 error,用来确认失败的是哪一个地址;不要用 mode、store-selected 或 GEO 更新去「清占用」。记录保存之后,再决定是改配置还是退出已确认的旧实例。