먼저 오류가 발생한 리스닝 포트 확인하기

Clash를 시작할 때 포트가 사용 중이라는 오류가 뜨는 경우는 보통 커널이 로컬 리스너를 만드는 단계에서 발생합니다. 로그의 bind: address already in use는 현재 방식으로 대상 주소와 포트에 바인딩할 수 없다는 뜻입니다. Windows에서는 Only one usage of each socket address 오류가 표시되기도 합니다. 이 문제는 구독 만료나 노드 연결 여부와는 별개이므로, 노드부터 바꿔도 대개 해결되지 않습니다.

mixed-port는 하나의 포트에서 HTTP와 SOCKS 프록시 연결을 모두 받습니다. 이 글에서는 기존 포트 7890과 새 포트 17890을 예시로 사용합니다. 모두 설명을 위한 값이므로 내 PC가 반드시 7890을 사용한다거나 17890이 비어 있다고 단정할 수는 없습니다. 먼저 클라이언트 로그를 열고 오류가 난 행의 주소, 포트, 프로토콜을 확인하세요.

항목용도조치 방법
mixed-portHTTP와 SOCKS를 함께 사용하는 프록시 진입점변경 후 시스템 프록시와 앱 프록시도 업데이트
port / socks-portHTTP / SOCKS 전용 진입점혼합 진입점과 중복 설정 여부 확인
external-controller클라이언트가 커널에 연결하는 제어 인터페이스클라이언트의 제어 인터페이스 설정과 함께 변경
dns.listen커널 DNS 서비스의 리스닝 주소로그에 표시된 DNS 포트를 별도로 확인

Windows: 7890을 점유한 프로세스와 실행 경로 확인

PowerShell로 리스닝 PID 조회하기

PowerShell을 열고 다음 명령을 실행하세요. OwningProcess는 포트를 점유한 프로세스 ID이며 프로그램 이름이 아닙니다. 접근이 제한되면 관리자 권한으로 터미널을 다시 여세요. 편의상 정체를 알 수 없는 시스템 프로세스를 종료하지 마세요.

Get-NetTCPConnection -LocalPort 7890 -State Listen |
  Select-Object LocalAddress, LocalPort, State, OwningProcess

조회 결과의 PID가 1234라고 가정하고 이름, 실행 파일 경로, 시작 명령을 확인해 보겠습니다. 아래 숫자는 조회 방법을 보여 주기 위한 예시이므로 실제로는 앞서 실행한 명령에서 반환된 PID로 바꿔야 합니다.

Get-Process -Id 1234 |
  Select-Object Id, ProcessName, Path

Get-CimInstance Win32_Process -Filter "ProcessId = 1234" |
  Select-Object ProcessId, ExecutablePath, CommandLine

경로와 시작 매개변수를 보면 별도 커널을 실행한 다른 클라이언트인지, 같은 클라이언트의 백그라운드 서비스가 계속 실행 중인지 구분하는 데 도움이 됩니다. 이름이 모두 mihomo.exe여도 설치 폴더는 다를 수 있습니다. 작업 표시줄 창을 닫았다고 프로세스까지 종료된 것은 아닙니다. 트레이 메뉴에서 해당 클라이언트를 정상 종료한 다음 포트를 다시 조회하세요.

netstat으로 교차 확인하기

netstat -ano -p tcp | findstr ":7890"
tasklist /FI "PID eq 1234"

findstr는 텍스트를 필터링할 뿐이므로 원격 포트나 같은 숫자가 포함된 다른 포트도 검색될 수 있습니다. ‘로컬 주소’ 열이 실제로 :7890으로 끝나는지, 상태가 LISTENING인지 확인하세요. 일반적인 ESTABLISHED 연결만으로는 내 PC에서 7890 프록시가 리스닝 중이라고 볼 수 없습니다.

  • 127.0.0.1:7890: IPv4 루프백 주소에서 리스닝 중입니다.
  • 0.0.0.0:7890: IPv4 전체 주소에서 리스닝 중이며, 루프백 주소 바인딩과 충돌할 수 있습니다.
  • [::]:7890: IPv6 전체 주소에서 리스닝 중입니다. IPv4에도 영향을 주는지는 소켓 설정에 따라 달라집니다.

로그에 UDP 바인딩 실패가 명시되어 있다면 UDP 엔드포인트를 조회하세요. UDP에는 TCP의 LISTENING 상태가 없으므로 TCP 리스닝만 필터링하는 방식으로 판단하면 안 됩니다.

Get-NetUDPEndpoint -LocalPort 7890 |
  Select-Object LocalAddress, LocalPort, OwningProcess

macOS 및 Linux: 리스닝 프로세스와 백그라운드 서비스 확인

macOS: lsof 사용하기

‘터미널’에서 다음 명령을 실행하세요. -nP는 숫자 주소와 포트를 표시해 이름 변환으로 인한 혼동을 막고, -sTCP:LISTEN은 리스닝 소켓만 표시합니다. 권한이 부족하거나 결과가 불완전하면 명령 앞에 sudo를 붙이세요.

lsof -nP -iTCP:7890 -sTCP:LISTEN
ps -p 1234 -o pid,ppid,command

COMMAND, PID, 전체 시작 명령을 확인한 뒤 해당 클라이언트 메뉴에서 정상 종료하세요. 프로세스가 곧바로 다시 나타난다면 로그인 항목, 클라이언트 백그라운드 구성 요소 또는 서비스 관리자가 관리하고 있을 수 있습니다. 먼저 해당 시작 경로를 비활성화한 다음 프로세스를 종료하세요. 강제 종료를 반복하면 감시 프로세스가 커널을 계속 재시작할 뿐입니다.

Linux: ss 사용하기

sudo ss -ltnp 'sport = :7890'
sudo ss -lunp 'sport = :7890'
ps -p 1234 -o pid,ppid,args

첫 번째 명령은 TCP 리스닝을, 두 번째 명령은 UDP 바인딩을 조회합니다. ss는 보통 배포판의 iproute2 패키지에 포함되어 있습니다. 설치되어 있지 않다면 이미 설치된 lsof로 조회할 수 있습니다. 프로세스 정보 전체를 보려면 관리자 권한이 필요할 수 있습니다.

커널이 systemd를 통해 시작된다면 실제 서비스 유닛과 ExecStart를 확인하세요. 데스크톱 클라이언트만 닫아서는 서비스가 중지되지 않을 수 있습니다. Docker 포트 공개 설정도 확인해야 합니다. 호스트의 7890을 컨테이너가 점유할 수 있으므로 현재 로그인한 사용자가 실행한 프로그램만 확인해서는 안 됩니다. 먼저 프로세스의 소속을 확인한 뒤 원래 관리하던 경로에서 중지하세요.

기존 포트를 비울지 mixed-port를 변경할지 선택

점유 프로세스를 찾았다고 바로 종료할 필요는 없습니다. 먼저 해당 프로세스를 계속 실행해야 하는지 판단하세요. 더 이상 쓰지 않는 구형 클라이언트나 중복 실행된 커널이라면 중복 인스턴스만 종료하고 하나만 남기면 됩니다. 다른 서비스가 해당 포트를 사용 중이라면 그 서비스를 중단하기보다 Clash의 프록시 진입점을 변경하는 편이 적절합니다.

  1. 현재 포트, 시스템 프록시 주소, 앱별로 따로 설정한 프록시 주소를 기록하세요.
  2. 후보 포트 17890도 7890과 같은 방법으로 조회하세요.
  3. 유지할 클라이언트와 커널 인스턴스를 확인해 두 설정을 동시에 변경하지 않도록 하세요.
  4. 실제로 적용되는 설정을 수정하고 커널을 다시 불러오거나 재시작하세요.
  5. 새 포트에서 리스닝하는지 확인한 뒤 시스템과 앱에서 사용하는 포트도 업데이트하세요.

YAML과 클라이언트 설정에서 mixed-port 변경하기

설정 파일을 직접 관리하는 경우

먼저 설정을 백업한 다음 YAML 최상위에서 기존 mixed-port 항목을 찾아 수정하세요. 파일 끝에 같은 이름의 항목을 추가하면 안 됩니다. 아래는 프록시 진입점과 관련된 일부 설정만 보여 줍니다. 기존 노드, 정책 그룹, DNS, 규칙을 유지한 채 전체 설정에 반영하세요.

# 기존 설정에 병합하세요. 전체 구독 파일이 아닙니다
mixed-port: 17890
allow-lan: false
bind-address: "127.0.0.1"

이 예시는 로컬에서만 사용하는 경우를 위한 설정입니다. 이전에 LAN에서 프록시를 공유했다면 접근 범위 설정을 그대로 복사하지 말고 리스닝 주소, 인증, 방화벽 규칙을 별도로 확인하세요. 로컬 포트 충돌을 해결하는 김에 LAN 접근을 활성화하지 마세요. 포트를 점유한 프로세스가 해제되는 것은 아닙니다.

port: 17890 또는 socks-port: 17890 항목이 있는지도 확인하세요. 전용 진입점과 혼합 진입점은 같은 주소와 TCP 포트에 중복 바인딩할 수 없습니다. 혼합 진입점만 사용한다면 클라이언트가 전용 진입점에 의존하지 않는지 확인한 후 해당 전용 포트 항목을 제거하거나 커널 설정에 따라 0으로 지정해 비활성화하세요.

mihomo를 직접 실행한다면 터미널에서 설정을 확인할 수 있습니다. 여기서는 현재 디렉터리에 있는 실제 파일 이름이 config.yaml이고 커널 명령이 mihomo라고 가정합니다.

mihomo -t -f config.yaml

-t는 설정을 테스트하는 옵션이며 프록시 리스너가 정상적으로 생성됐다는 뜻은 아닙니다. 테스트 후에는 평소 사용하는 실행 경로에서 파일을 불러오고 시작 로그를 확인하세요. 클라이언트가 별도로 다운로드하거나 생성한 실행 설정은 이 파일과 다를 수 있으므로, 실제로 사용하지 않는 사본만 테스트해서는 안 됩니다.

그래픽 클라이언트에서 설정을 관리하는 경우

먼저 클라이언트 설정에서 ‘혼합 포트’, ‘Mixed Port’ 또는 ‘프록시 포트’ 항목을 찾아보세요. 클라이언트와 버전에 따라 메뉴 이름은 다를 수 있습니다. 이 표현들은 항목을 찾기 위한 예시이지, 모든 클라이언트에 공통으로 적용되는 메뉴 경로가 아닙니다. 항목을 수정하고 저장한 뒤 클라이언트 안내에 따라 커널을 다시 불러오세요. 구독 원문만 수정하면 클라이언트가 생성한 포트 설정에 반영되지 않을 수 있습니다.

  • 화면에 포트 설정이 있는 경우: 우선 화면에서 변경하고, 실행 로그에 새 포트가 표시되는지 확인하세요.
  • 화면에 해당 항목이 없는 경우: 클라이언트에서 로컬 덮어쓰기 또는 설정 병합을 지원하는지 확인한 뒤 해당 설정의 최상위에 mixed-port를 지정하세요.
  • 구독 새로고침 후 7890으로 돌아가는 경우: 덮어쓰기되는 구독 캐시를 직접 수정했는지 확인하고, 변경 내용을 클라이언트가 지원하는 영구 설정 경로로 옮기세요.
  • 저장 후에도 기존 포트에서 리스닝하는 경우: 현재 선택된 설정, 실행 파일 경로, 클라이언트 설정 우선순위를 확인한 뒤 올바른 커널 인스턴스를 재시작하세요.

수정하기 전에 시스템 프록시를 끄면 아직 리스너가 없는 동안 시스템이 해당 주소에 계속 접속하는 상황을 막을 수 있습니다. 새 포트가 정상적으로 시작된 뒤 다시 켜세요. 클라이언트가 시스템 프록시를 자동으로 설정하더라도 시스템 설정 화면에서 최종 값이 올바른지 확인하세요.

시스템 프록시, 브라우저, 명령줄을 새 포트에 맞추기

커널 포트를 17890으로 바꿨는데 시스템 프록시가 계속 7890에 연결되면 ‘포트 충돌은 해결됐지만 웹페이지가 열리지 않는’ 문제가 발생할 수 있습니다. 로컬 HTTP 프록시 주소는 127.0.0.1:17890로 변경해야 합니다. 혼합 포트는 SOCKS 연결도 받지만, 입력 형식과 프록시 유형은 앱의 요구 사항을 따라야 합니다.

위치확인 경로 또는 방법새 값 예시
Windows 11‘설정’ → ‘네트워크 및 인터넷’ → ‘프록시’ → ‘수동 프록시 설정’ → ‘편집’주소 127.0.0.1, 포트 17890
최근 버전의 macOS‘시스템 설정’ → ‘네트워크’ → 현재 네트워크의 ‘세부사항’ → ‘프록시’웹 프록시와 보안 웹 프록시의 주소 및 포트 확인
Firefox 자체 프록시 설정‘설정’ → ‘일반’ → ‘네트워크 설정’ → ‘설정’시스템 프록시를 사용하거나 수동 프록시 포트를 업데이트
명령줄 프로그램HTTP_PROXY, HTTPS_PROXY, ALL_PROXY 및 도구 자체 설정 확인새 포트로 변경하고 필요하면 새 터미널을 여세요

Linux 데스크톱 환경에는 공통 시스템 프록시 메뉴가 없습니다. GNOME, KDE, 앱마다 설정을 따로 관리할 수 있습니다. Windows의 시스템 프록시와 WinHTTP 프록시도 별도 설정입니다. netsh winhttp show proxy로 WinHTTP 프록시를 확인할 수 있지만, WinHTTP를 재설정한다고 모든 브라우저 문제가 해결되는 것은 아닙니다.

아래 PowerShell 명령은 현재 세션의 HTTP 프록시 환경 변수만 변경하며 모든 앱의 설정을 바꾸지는 않습니다. HTTPS 대상에 로컬 HTTP 프록시로 터널을 연결할 때 프록시 주소는 http://를 사용해도 됩니다. 대상이 HTTPS라는 이유로 로컬 진입점을 TLS로 바꿀 필요는 없습니다.

$env:HTTP_PROXY = "http://127.0.0.1:17890"
$env:HTTPS_PROXY = "http://127.0.0.1:17890"

macOS 및 Linux 셸에서는 다음과 같이 임시로 설정할 수 있습니다.

export http_proxy=http://127.0.0.1:17890
export https_proxy=http://127.0.0.1:17890

이전에 ALL_PROXY, Git의 http.proxy 또는 편집기에 내장된 프록시를 설정했다면 해당 설정도 별도로 확인하세요. 환경 변수 처리 방식은 도구마다 다르며, 이미 실행 중인 앱은 환경 변수를 바꿔도 새 값을 자동으로 읽지 않는 경우가 많습니다.

리스닝, 요청, 재시작으로 변경 사항 확인하기

먼저 로컬 리스닝을 확인한 다음 요청 테스트

앞서 안내한 포트 조회를 다시 실행해 7890을 17890으로 바꾸고, 준비한 커널이 해당 포트에서 리스닝하는지 확인하세요. 그런 다음 프록시를 명시하는 옵션으로 요청을 보내 시스템 프록시 설정이 적용됐는지와 무관하게 테스트하세요. Windows에서는 curl.exe를 사용하면 일부 PowerShell 환경에서 같은 이름의 별칭이 매개변수 해석에 영향을 주는 일을 피할 수 있습니다.

# Windows
curl.exe --noproxy "" --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 -I https://example.com

# macOS / Linux
curl --noproxy "" --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 -I https://example.com

여기서 5초는 연결 시간 제한, 15초는 전체 요청 시간 제한입니다. 성능 측정값이 아닙니다. --noproxy ""는 이번 요청에서 프록시 우회 목록을 비우는 옵션입니다. 응답 결과는 노드, 규칙, DNS, 대상 사이트 상태에 따라 달라질 수 있습니다.

  • 연결이 즉시 거부되는 경우: 새 포트에서 리스닝 중인지, 주소가 올바른지, 커널이 종료되지 않았는지 먼저 확인하세요.
  • 로컬 진입점에는 연결되지만 요청 시간이 초과되는 경우: 커널 로그에서 노드 연결, 규칙 일치, DNS 오류를 계속 확인하세요.
  • 프록시를 지정한 요청은 성공하지만 브라우저에서 실패하는 경우: 브라우저 자체 프록시, 이전 시스템 프록시 포트, 확장 프로그램 설정을 집중적으로 확인하세요.
  • 명령줄 요청은 성공했지만 예상한 노드를 사용하지 않는 경우: 실제 적용된 규칙과 정책 선택을 확인하세요. 요청이 성공했다는 사실만으로 트래픽이 프록시 노드를 통과했다고 볼 수는 없습니다.

마지막으로 재시작과 구독 업데이트 확인

클라이언트를 종료한 뒤 다시 시작하고 17890에서 계속 리스닝하는지 확인하세요. 평소처럼 구독을 업데이트한 다음 포트가 7890으로 돌아가지 않았는지도 확인합니다. 재시작 후 포트를 다른 프로세스가 점유한다면 매번 임시로 숫자만 바꾸지 말고 다른 클라이언트의 시작 프로그램과 백그라운드 서비스를 확인하세요.

TUN 모드도 별도로 판단해야 합니다. TUN은 시스템 네트워크 트래픽을 가로채는 기능이지, 앱이 반드시 mixed-port를 사용한다는 뜻은 아닙니다. TUN을 켠 뒤 웹페이지가 열려도 기존 시스템 프록시 포트가 수정됐다고 볼 수 없습니다. 클라이언트에 따라 혼합 진입점 충돌로 일부 기능이 시작되지 않을 수도 있습니다. 최종 확인 때 로그, 로컬 리스닝, 요청 경로를 각각 점검하세요.