Windows 가이드 추천 태그: Docker Desktop Clash host.docker.internal

Docker Desktop에서 컨테이너가 Clash를 안 탈 때:Windows 호스트 프록시와 host.docker.internal(2026)

Windows에서 브라우저·본인 앱은 Clash를 잘 타는데, Docker Desktop으로 docker run이나 Compose를 올린 애플리케이션만 여전히 직접 연결되는 경우가 많습니다. 원인은 대개 “컨테이너의 127.0.0.1이 호스트가 아니다”는 점과, 호스트 쪽 Clash가 루프백에만 열려 있거나 HTTP_PROXY·HTTPS_PROXY가 컨테이너에 전달되지 않는 것입니다. 본문은 host.docker.internal로 호스트 주소를 고정하고, NO_PROXY로 내부망·레지스트리·로컬 서비스를 예외 처리하는 순서를 한국어로 정리합니다. WSL2·localhost 글과 달리 초점은 컨테이너 브리지 네트워크와 Docker DNS입니다.

약 18분 읽기
Clash 편집부

1. 브라우저는 되는데 컨테이너만 직접 연결되는 이유

Docker Desktop으로 만든 컨테이너는 기본적으로 브리지 네트워크 위에서 독립된 네임스페이스를 가집니다. 그 안에서 127.0.0.1그 컨테이너 자신을 가리키며, Windows 호스트에서 돌아가는 Clash의 리스너와는 연결되지 않습니다. 그래서 브라우저(호스트 OS)에서는 127.0.0.1:7890 같은 주소로 HTTP 프록시가 잘 붙는데, 컨테이너 안의 curl·apt·애플리케이션 런타임은 같은 주소를 “빈 루프백”으로만 보고 실패하거나 우회 없이 바깥으로 나가는 패턴이 반복됩니다.

또 한 가지는, 컨테이너 프로세스는 Windows 시스템 프록시 설정을 자동으로 물려받지 않는다는 점입니다. 호스트에서 Clash가 “시스템 프록시”를 켠다고 해서, 이미지 안의 nodepython이 항상 동일한 경로를 쓰는 것은 아닙니다. 대부분의 CLI·라이브러리는 환경 변수(HTTP_PROXY 등)나 자체 설정 파일을 따르므로, 컨테이너 실행 시점에 명시해 주는 편이 재현성이 높습니다.

팁: “호스트에서 되는데 컨테이너에서만 안 된다”면 먼저 주소(127.0.0.1 vs 호스트)와 환경 변수 전달 여부를 나누어 보세요. 둘 다 맞으면 방화벽·바인드 주소를 의심합니다.

2. host.docker.internal으로 호스트 주소 고정하기

Docker Desktop for Windows(및 최신 Docker Engine 계열)에서는 컨테이너에서 호스트 머신을 가리키는 특수 호스트 이름으로 host.docker.internal을 제공합니다. 이 이름은 컨테이너의 /etc/hosts 등에 의해 호스트로 가는 경로로 해석되며, 127.0.0.1을 호스트 Clash에 쓰는 실수를 피하는 데 유용합니다.

실제 예로, 호스트에서 Clash의 Mixed Port가 7890이라면 컨테이너 안에서는 다음과 같이 지정하는 식이 됩니다. http://host.docker.internal:7890(프로토콜·포트는 본인 환경에 맞게 조정하세요.)

일부 사용자는 수동으로 --add-host로 같은 효과를 주기도 하지만, Desktop 환경에서는 위 이름을 쓰는 것이 문서와도 잘 맞습니다. Linux 네이티브 Docker만 쓰는 서버와 달리, 본 글은 Windows + Docker Desktop 사용자를 기준으로 합니다.

연결만 먼저 검증

환경 변수를 넣기 전에, 컨테이너 한 번으로 TCP 연결을 확인해 보세요. 예를 들어 docker run --rm -it busybox wget -qO- --timeout=5 http://host.docker.internal:7890 같은 방식은 이미지에 따라 다를 수 있으므로, 본인이 쓰는 베이스 이미지에 맞는 도구(curl, nc 등)로 호스트 IP:포트에 도달하는지부터 확인하는 것이 빠릅니다. 여기서 연결 거부가 나오면 Clash 쪽 수신 주소Windows 방화벽을 먼저 봐야 합니다.

3. Clash(Windows): 수신 주소·Mixed Port·Allow LAN

컨테이너가 host.docker.internal로 호스트에 도달하려면, 호스트의 Clash가 루프백에만 소켓을 열고 있으면 안 됩니다. 127.0.0.1에만 바인드되어 있으면 가상 네트워크에서 오는 연결을 받지 못합니다. GUI에서는 Allow LAN·유사 옵션을 켜고, 설정 파일에서는 allow-lan·bind-address 등을 코어 문서에 맞게 확인하세요.

포트 번호가 혼동되기 쉬우므로, 실제로 mixed-port인지 http-port·socks-port만 쓰는지 UI나 로그로 한 번 더 확인하십시오. Mixed Port·LAN·방화벽 글과 직접 연결되는 부분이라, 호스트 쪽을 먼저 안정화한 뒤 컨테이너 설정을 맞추면 원인 분리가 쉬워집니다.

주의: LAN 허용은 같은 물리망의 다른 기기에서도 프록시 포트에 접근할 수 있게 할 수 있습니다. 신뢰하는 환경에서만 켜고, 카페·공용 Wi‑Fi에서는 끄는 것이 좋습니다.

4. HTTP_PROXY·HTTPS_PROXY·ALL_PROXY

많은 HTTP 클라이언트와 패키지 매니저는 대문자·소문자 환경 변수를 모두 읽습니다. 컨테이너에 넣을 때는 일관되게 다음처럼 맞추는 경우가 많습니다.

  • HTTP_PROXY=http://host.docker.internal:7890
  • HTTPS_PROXY=http://host.docker.internal:7890
  • ALL_PROXY=socks5://host.docker.internal:7891 — SOCKS를 쓰는 경우에만, 포트는 본인 설정에 맞게

docker run 예시는 다음과 같습니다(포트는 예시입니다).

docker run --rm -e HTTP_PROXY=http://host.docker.internal:7890 \ -e HTTPS_PROXY=http://host.docker.internal:7890 \ -e NO_PROXY=localhost,127.0.0.1,::1 \ your-image:tag

Git·npm·pip 등은 도구별로 별도 설정을 두는 경우가 있어, 환경 변수만 바꿨는데도 따라오지 않으면 각 도구의 설정 우선순위를 확인하세요. 개념·CLI 전반은 설정 가이드·튜토리얼과 함께 보면 구조가 잡힙니다.

5. NO_PROXY로 내부망·레지스트리·로컬 예외

프록시를 켜면 사이드 이펙트로 가장 먼저 터지는 것이 내부 서비스·사설 IP·도커 네트워크 간 통신입니다. 예를 들어 docker run으로 레지스트리에서 이미지를 받을 때, 회사 내부 registry.example.local을 프록시로 보내면 실패하거나 느려질 수 있습니다. 반대로 공용 레지스트리(registry-1.docker.io 등)는 환경에 따라 프록시를 경유하는 편이 안정적일 때도 있습니다.

그래서 NO_PROXY(또는 no_proxy)에 다음을 빠짐없이 넣는 습관이 중요합니다.

  • localhost, 127.0.0.1, ::1
  • 사내 도메인 접미사·내부 DNS 이름(예: .corp.local)
  • 사설 대역(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 등) — 팀 정책에 맞게 최소화
  • 같은 Compose 스택에서 서로 호출하는 서비스 이름(db, redis 등)

NO_PROXY 문법은 클라이언트마다 미세하게 다를 수 있으므로, 문제가 되는 도구의 문서를 한 번 확인하세요. “이미지 풀만 실패한다”면 레지스트리 호스트만 예외에 넣는 것부터 시도해 볼 수 있습니다.

6. Docker Compose·빌드(docker build) 단계

Compose에서는 서비스별 environment 또는 env_file로 동일한 변수 묶음을 재사용할 수 있습니다. 여러 개발자가 같은 저장소를 쓸 때는 .env.example에 호스트 이름이 host.docker.internal으로 고정돼 있는지, 포트가 Mixed Port와 일치하는지 확인하는 것이 좋습니다.

빌드 단계는 런타임과 네트워크가 다릅니다. docker buildRUN apt-get·npm install이 프록시를 타야 한다면 --build-arg HTTP_PROXY=...를 쓰거나 BuildKit 환경 변수 전달 방식을 맞춰야 합니다. 런타임에만 HTTP_PROXY를 넣어두고 빌드가 실패하는 경우가 흔합니다.

docker build \ --build-arg HTTP_PROXY=http://host.docker.internal:7890 \ --build-arg HTTPS_PROXY=http://host.docker.internal:7890 \ -t myapp:local .

CI와 로컬이 달라지면 같은 Dockerfile이라도 결과가 달라질 수 있으므로, 팀에서 “빌드 시 프록시 필요 여부”를 문서화해 두면 재현성이 올라갑니다.

7. DNS·Docker embedded DNS에 대한 짧은 메모

컨테이너가 이름 해석을 할 때는 호스트의 Clash DNS와 독립적으로 동작하는 경우가 많습니다. 프록시 TCP는 통과하는데 특정 도메인만 실패하면, 컨테이너 내부의 /etc/resolv.confDocker embedded DNS(보통 127.0.0.11)를 함께 봐야 합니다. TUN 모드·전역 라우팅을 쓰는 경우에는 호스트 쪽 라우팅과 겹쳐 증상이 달라질 수 있어, TUN·라우팅 글의 순서를 참고하는 편이 안전합니다.

이 글의 범위는 “HTTP(S) 프록시 환경 변수로 호스트 Clash에 붙는 것”이 우선입니다. DNS까지 Clash 쪽으로 일원화하려면 호스트 리스너 주소·포트를 컨테이너에 전달하는 별도 설계가 필요하고, 127.0.0.1 함정이 다시 등장하므로 host.docker.internal 또는 호스트 게이트웨이 IP를 명시하는 방식을 검토하세요.

8. 증상별로 어디를 볼까

아래는 Docker Desktop에서 Windows Clash를 쓸 때 자주 보는 패턴입니다.

증상 가능성이 큰 원인 먼저 할 일
컨테이너에서 127.0.0.1:포트 연결 거부 호스트 Clash가 아닌 컨테이너 루프백 host.docker.internal 또는 호스트 경로로 변경
호스트 IP로도 연결 거부 Clash가 루프백에만 바인드 Allow LAN·bind-address·방화벽
이미지 풀만 실패 레지스트리가 프록시 경로에서 막힘 NO_PROXY에 레지스트리 호스트 추가 또는 프록시 허용
빌드만 실패·런타임은 정상 빌드 단계에 프록시 미전달 --build-arg·BuildKit 설정
내부 서비스 이름으로만 실패 Compose 서비스명이 프록시로 보내짐 NO_PROXY에 서비스 이름·도메인 추가

표에 없는 “호스트 전체 인터넷이 끊김” 류는 Clash와 무관한 라우팅·다른 VPN·TUN 충돌을 의심합니다. 해당 증상은 본 글보다 TUN 점검 글을 따르는 편이 빠릅니다.

9. 요약

Docker Desktop으로 올린 컨테이너가 Clash를 타지 않는 문제는, 네트워크 스택이 호스트와 분리되어 있다는 점과, HTTP_PROXY·HTTPS_PROXY가 컨테이너에 전달되지 않는 점을 동시에 맞추면 대부분 해소됩니다. 127.0.0.1 대신 host.docker.internal로 호스트 쪽 리스너를 가리키고, 호스트에서는 Allow LAN과 방화벽을 정리한 뒤, NO_PROXY로 내부망·레지스트리·로컬 서비스를 예외 처리하세요. 같은 Windows에서 WSL2 터미널만 문제라면 WSL2·localhost 글의 순서가 더 적합합니다.

설치 패키지는 소스 저장소가 아니라 공식 다운로드 페이지를 우선하는 것이 버전·업데이트 경로가 분명합니다. 오픈 소스 저장소는 빌드와 이슈 추적용으로 두면 혼선이 적습니다.

Clash를 무료로 내려받아 Windows에서 안정적으로 연 뒤, Docker 컨테이너에는 host.docker.internal과 프록시 환경 변수를 맞춰 보세요