프록시 수신 포트와 제어 포트 구분하기
Clash 또는 Clash Meta(mihomo) 커널을 사용하는 클라이언트를 실행할 때 로그에 address already in use가 표시되면, 커널이 수신하려는 주소와 포트를 다른 프로세스가 이미 사용 중일 가능성이 큽니다. 오류에 나온 프로토콜, 주소, 포트를 확인한 뒤 어떤 프로그램을 종료하거나 어떤 설정 항목을 변경할지 결정하세요. '시작 실패'만 보고 구독을 계속 바꾸는 것으로는 대개 로컬 포트 충돌을 해결할 수 없습니다.
listen tcp 127.0.0.1:7890: bind: address already in use
listen tcp 127.0.0.1:9090: bind: address already in use
두 줄은 서로 다른 기능을 나타냅니다. 7890은 프록시 접속 포트, 9090은 제어 인터페이스 포트로 자주 사용되지만 모든 클라이언트에서 고정적으로 쓰이는 값은 아닙니다. 현재 설정과 시작 로그를 기준으로 판단하세요.
| 항목 | 용도 | 충돌 시 나타나는 증상 |
|---|---|---|
mixed-port | 하나의 포트에서 HTTP 및 SOCKS 프록시 연결 수신 | 앱에서 로컬 프록시에 연결할 수 없음 |
port | 별도의 HTTP 프록시 수신 포트 | 해당 HTTP 주소를 사용하는 요청 실패 |
socks-port | 별도의 SOCKS 프록시 수신 포트 | 해당 SOCKS 주소를 사용하는 요청 실패 |
external-controller | 클라이언트나 대시보드에서 호출하는 제어 API 주소 | 대시보드 연결, 상태 조회 또는 정책 전환 실패 |
Windows: 수신 포트로 점유 프로세스 찾기
1단계: TCP 수신 포트와 PID 확인
PowerShell을 열고 다음 명령을 실행하세요. 예시는 로컬에서 수신 대기 중인 7890 및 9090만 조회하므로 원격의 같은 포트로 연결된 일반 세션은 포함되지 않습니다. 권한이 부족하거나 프로세스 정보가 충분하지 않으면 터미널을 관리자 권한으로 실행하세요.
Get-NetTCPConnection -State Listen -LocalPort 7890,9090 -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, OwningProcess
출력에서 7890의 OwningProcess 값이 14620이라고 가정해 보겠습니다. 다음 명령으로 프로세스 이름, 실행 파일 경로, 시작 인수를 확인할 수 있습니다. 14620은 예시 값이므로 실행할 때는 해당 PC에서 실제로 확인한 PID를 사용하세요.
Get-Process -Id 14620 | Select-Object Id, ProcessName, Path
Get-CimInstance Win32_Process -Filter "ProcessId = 14620" |
Select-Object ProcessId, ExecutablePath, CommandLine
2단계: 커널이 중복 실행 중인지 확인
- 이전 프록시 클라이언트: 시스템 트레이 메뉴에서 기존 클라이언트를 종료한 다음 사용할 클라이언트를 실행하세요.
- 같은 클라이언트의 백그라운드 서비스: 먼저 클라이언트에서 커널이나 서비스를 중지한 뒤 정상적으로 종료하세요. 하위 프로세스만 강제 종료하면 자동으로 다시 실행될 수 있습니다.
- 다른 개발 도구 또는 서비스: 해당 프로그램은 계속 수신하도록 두고 Clash에 다른 미사용 포트를 지정하세요.
- 정체를 알 수 없는 시스템 프로세스: 포트를 비우려고 무작정 강제 종료하지 말고, 먼저 어떤 서비스인지 확인하세요.
명령 프롬프트에서 다음 명령을 실행해도 됩니다. findstr :7890은 원격 주소나 78900처럼 비슷한 포트까지 검색할 수 있습니다. '로컬 주소'의 포트가 정확히 7890인지, 상태가 LISTENING인지 확인해야 합니다.
netstat -ano -p tcp | findstr :7890
tasklist /FI "PID eq 14620"
로그에 UDP 바인딩 실패가 명시되어 있다면 Get-NetUDPEndpoint -LocalPort 7890으로 해당 포트의 점유 상태를 확인하세요. TCP와 UDP는 서로 다른 포트 공간을 사용하므로 숫자가 같다는 이유만으로 충돌이라고 단정할 수 없습니다.
macOS 및 Linux: 수신 주소와 서비스 확인
macOS에서는 lsof로 TCP 수신 상태를 확인할 수 있고, Linux에서는 ss로 소켓과 프로세스를 조회할 수 있습니다. 아래 명령은 상태만 확인하며 서비스를 중지하지 않습니다. 출력이 비어 있다면 시작 실패로 클라이언트가 이미 종료되었는지도 확인하세요.
sudo lsof -nP -iTCP:7890 -sTCP:LISTEN
sudo lsof -nP -iTCP:9090 -sTCP:LISTEN
sudo ss -ltnp 'sport = :7890'
sudo ss -ltnp 'sport = :9090'
ps -p 14620 -o pid,ppid,user,args
수신 주소를 특히 주의해서 확인하세요. 127.0.0.1:7890은 IPv4 로컬 루프백 주소입니다. 0.0.0.0:7890은 모든 IPv4 인터페이스에서 수신한다는 뜻이며, 다른 프로그램이 같은 포트의 특정 IPv4 주소에 바인딩하지 못하게 할 수 있습니다. [::]:7890은 IPv6 주소입니다. IPv4 연결도 함께 허용되는지는 시스템과 소켓 설정에 따라 달라집니다.
프로세스가 systemd 또는 다른 서비스 관리자에 의해 실행 중이라면 해당 서비스에서 중지하거나 설정을 변경하세요. kill만 실행하면 서비스 관리자가 프로세스를 즉시 다시 시작해 '종료했는데 포트가 또 점유됨' 현상이 생길 수 있습니다. 호스트에서 확인된 프로세스가 컨테이너 포트 전달용이라면 컨테이너 내부만 보지 말고 포트 매핑도 확인하세요.
mixed-port 변경: 미사용 포트를 확인한 뒤 영구 설정 수정
기존 포트를 다른 프로그램에 양보해야 한다면 혼합 프록시 포트를 7890에서 17890으로 변경할 수 있습니다. 17890은 이 글의 예시일 뿐입니다. 먼저 앞의 명령으로 사용 가능한지 확인하세요. 조회 결과가 비어 있어도 조회 당시 해당 유형의 수신 프로세스가 없었다는 뜻일 뿐이며, 실제 바인딩 성공 여부는 재시작 후 확인해야 합니다.
그래픽 클라이언트와 YAML 파일에서 수정하기
- 클라이언트 설정에서 '포트', '혼합 포트' 또는 'Mixed Port'를 찾으세요. 검색창이 있다면
mixed-port를 검색하면 됩니다. - 클라이언트에 전역 포트 설정이 있다면 해당 메뉴에서 변경하는 것이 우선입니다. 클라이언트마다 메뉴 위치가 다르므로 특정 버전의 '설정' 경로를 모든 클라이언트에 적용되는 방법으로 간주하지 마세요.
- mihomo를 직접 실행한다면 시작 옵션
-f가 가리키는 설정 파일을 수정하세요. 서비스로 실행하는 경우에는 서비스에서 실제로 사용하는 옵션과 작업 디렉터리도 확인해야 합니다. - 클라이언트가 구독으로 실행 설정을 생성하는 경우, 클라이언트가 지원하는 영구 오버라이드나 설정 병합 기능을 사용하세요. 그래야 구독을 업데이트해도 포트가 원래 값으로 되돌아가지 않습니다.
mixed-port: 17890
allow-lan: false
external-controller: 127.0.0.1:9090
이 세 항목으로 구독 설정 전체를 덮어쓰지 마세요. 기존 설정에서 해당 부분만 수정하고 프록시, 정책 그룹, 규칙, DNS, 인증 설정은 유지하세요. mixed-port는 최상위 항목이므로 proxies나 proxy-groups 안에 들여쓰면 안 됩니다. 같은 매핑에서 동일한 키를 두 번 선언하지 마세요.
설정에 port: 7890 또는 socks-port: 7890도 있다면 혼합 포트만 바꾸어도 기존 포트에서 계속 수신을 시도할 수 있습니다. 필요한 항목을 각각 변경하거나 별도 수신 포트를 비활성화하세요. 여러 포트 항목에 충돌하는 주소와 TCP 포트를 중복 지정하지 않도록 합니다.
external-controller 변경: 대시보드 연결 주소도 함께 수정
오류가 9090을 가리킨다면 혼합 포트는 17890으로 유지하고, 제어 인터페이스를 사용 가능한 것으로 확인된 19090으로 옮길 수 있습니다. 제어 인터페이스는 브라우저의 일반 프록시 요청을 처리하지 않으므로 시스템 프록시 포트까지 19090으로 바꾸면 안 됩니다.
mixed-port: 17890
allow-lan: false
external-controller: 127.0.0.1:19090
기존 설정에 secret이 있다면 그대로 유지하고 외부 대시보드에도 같은 키를 입력하세요. 별도의 대시보드를 사용한다면 API 주소를 http://127.0.0.1:19090으로 변경합니다. 일부 데스크톱 클라이언트는 제어 포트와 키를 자체 관리합니다. 생성된 파일을 직접 수정하면 화면과 커널의 연결이 끊길 수 있으므로, 이 경우 클라이언트에서 지원하는 설정을 이용하세요.
- 프록시 포트는 정상인데 대시보드가 연결되지 않음: 제어 주소와 키, 클라이언트가 이전 포트에 계속 연결 중인지 먼저 확인하세요.
- 대시보드에는 상태가 표시되지만 브라우저 요청은 실패함: 혼합 포트와 앱의 프록시 설정을 추가로 확인하세요. 대시보드가 연결된다고 프록시 포트도 정상이라고 볼 수는 없습니다.
- 원격에서 대시보드에 접속해야 한다면 수신 주소, 접근 제어, 방화벽 규칙을 별도로 설계해야 합니다. 충돌을 해결한다는 이유만으로 모든 인터페이스에서 접속을 허용하지 마세요.
allow-lan: false는 프록시 포트의 LAN 접속을 제한하는 설정이지, 제어 API의 바인딩 주소와 인증을 대신하지 않습니다. 제어 인터페이스를 로컬에서만 사용한다면 루프백 주소를 유지하는 것이 가장 명확한 경계 설정입니다.
포트 변경 후 시스템 프록시와 앱 설정 동기화
포트를 옮길 때는 두 가지를 해야 합니다. 커널이 새 포트에서 수신하도록 하고, 호출하는 쪽도 새 포트에 연결하도록 변경해야 합니다. 전자만 완료하고 브라우저가 이전 포트인 7890에 계속 접속하면 '커널은 정상 작동하지만 웹 페이지가 열리지 않는' 상황이 발생합니다.
| 호출하는 쪽 | 확인할 설정 |
|---|---|
| Windows 시스템 프록시 | '설정' → '네트워크 및 인터넷' → '프록시'에서 수동 프록시 주소와 포트 확인 |
| macOS 시스템 프록시 | '시스템 설정' → '네트워크' → 현재 네트워크 서비스 → '세부사항' → '프록시' |
| 브라우저 프록시 확장 프로그램 | 확장 프로그램에 수동으로 저장된 HTTP 또는 SOCKS 주소와 포트 |
| 터미널 및 스크립트 | HTTP_PROXY, HTTPS_PROXY, ALL_PROXY 및 명령줄 옵션 |
| 별도 제어 대시보드 | 혼합 프록시 포트가 아닌 제어 API 주소, 포트, 키 |
시스템 설정 경로는 운영체제 버전에 따라 달라질 수 있습니다. 클라이언트가 시스템 프록시를 관리한다면 클라이언트의 '시스템 프록시'를 껐다가 다시 켜 새 포트를 적용한 뒤 실제 값도 확인하세요. 별도로 프록시를 설정한 브라우저, IDE, 다운로드 도구는 시스템 설정을 자동으로 따르지 않을 수 있습니다.
터미널에서 프록시를 명시하면 이전 환경 변수를 물려받는 문제를 피할 수 있습니다. 아래 예시는 새 혼합 포트에 HTTP 프록시 방식으로 연결합니다. Windows에서는 curl.exe를, macOS와 Linux에서는 curl을 사용할 수 있습니다.
curl.exe --proxy http://127.0.0.1:17890 --noproxy "" --connect-timeout 5 --max-time 15 -I https://example.com/
여기서 5초는 연결 제한 시간이고 15초는 전체 요청 제한 시간이지, 속도 측정 결과가 아닙니다. 현재 네트워크와 정책에서 접속을 허용하는 주소를 테스트에 사용하세요. HTTP 상태 코드가 반드시 200일 필요는 없습니다. 응답과 로그를 함께 확인해 요청이 프록시를 통과했는지가 중요합니다. TLS 인증서 오류, 원격 서버의 거부, 로컬 연결 거부는 서로 다른 단계의 문제입니다.
점유 프로세스가 보이지 않는데도 바인딩에 실패하는 경우
주소 충돌이 아니라 권한 제한인 경우
Windows의 access permissions와 Unix 계열 시스템의 permission denied는 일반적인 포트 충돌로 간주하면 안 됩니다. Windows에서는 일부 포트 범위를 시스템이나 가상화 구성 요소가 예약할 수 있으므로 아래의 읽기 전용 명령으로 확인하세요. 선택한 포트가 예약 범위에 포함되면 예약되지 않은 미사용 포트를 우선 사용하세요.
netsh interface ipv4 show excludedportrange protocol=tcp
netsh interface ipv6 show excludedportrange protocol=tcp
7890을 사용하려고 시스템 예약 범위를 바로 삭제하지 마세요. Linux에서 1024 미만의 포트를 수신하려면 일반적으로 적절한 권한이나 capability가 필요합니다. 하지만 7890과 17890은 낮은 포트 범위에 속하지 않으므로 보안 정책과 서비스 로그를 함께 확인해 원인을 파악해야 합니다.
이전 프로세스가 자동 재시작되거나 설정 파일을 잘못 수정한 경우
점유 프로세스의 PID가 계속 바뀐다면 시작 프로그램, 백그라운드 서비스, 다른 클라이언트의 자동 복구 기능을 확인하세요. PID는 그대로인데 로그에 이전 포트가 계속 표시된다면 시작 옵션, 설정 병합 순서, 클라이언트의 전역 포트 오버라이드를 점검해야 합니다. 구독 파일에서 7890을 바꾸었다고 해서 실제 실행 설정까지 바뀌는 것은 아닙니다.
오류가 cannot assign requested address라면 바인딩 IP가 현재 기기에 실제로 할당되어 있는지도 확인하세요. 예를 들어 네트워크를 바꾼 뒤 이전 LAN 주소가 더 이상 존재하지 않을 수 있습니다. 이는 다른 프로그램이 포트를 먼저 점유한 문제와 다릅니다.
수정 결과 확인: 수신, 요청, 재시작 점검
- 수신 프로세스 확인: 17890과 제어 포트를 다시 조회하고, 포트가 열려 있다는 사실만 보지 말고 해당 프로세스의 경로가 사용할 클라이언트나 커널에 속하는지 확인하세요.
- 요청 경로 확인: 프록시를 명시한 명령으로 요청을 보내고, 클라이언트의 연결 기록에 해당 연결이 나타나는지 확인하세요. 규칙 적용 여부와 출구 정책도 점검합니다.
- 설정 유지 확인: 클라이언트를 재시작하고 구독을 한 번 업데이트한 뒤 포트가 이전 값으로 되돌아가지 않는지 확인하세요. 시스템 프록시와 외부 대시보드가 다시 연결되는지도 점검합니다.
프록시를 명시한 요청은 성공하지만 일반 브라우저에서 실패한다면 시스템 프록시, 브라우저 확장 프로그램, 앱 자체 설정을 계속 확인하세요. 요청이 커널에 도달했지만 DNS 조회나 원격 연결에서 실패한다면 DNS, 노드, 규칙을 점검해야 합니다. 로컬 수신 포트를 계속 바꿀 필요는 없습니다.
포트 충돌은 전체 바인딩 오류 확인, 프로토콜과 주소에 따른 점유자 조회, 중복 서비스를 중지하거나 수신 포트를 변경한 뒤 모든 호출 측 설정을 동기화하는 순서로 처리하면 됩니다. 이렇게 하면 필요한 백그라운드 서비스는 유지하면서 '포트는 바꿨지만 앱은 이전 주소에 연결하는' 추가 장애를 예방할 수 있습니다.