브라우저는 되는데 docker pull만 끊기는 이유
Clash를 켠 PC에서 크롬·엣지는 유튜브·레지스트리 문서를 잘 열어도, docker pull·docker build만 i/o timeout이나 끝없는 다운로드에 가까운 증상이 나는 경우는 흔합니다. 이유는 단순합니다. 브라우저는 대개 OS에 등록한 시스템 프록시나 확장/프로필 정책을 따르지만, Docker 엔진은 별도 프로세스로 환경 변수가 비어 있으면 레지스트리에 직접 붙으려고 합니다. TUN이나 투명 프록시로 전부 잡지 않는 한, 「PC에는 Clash가 있는데 컨테이너 쪽만 공중에 떠 있다」는 이중 경험이 생깁니다. Docker Clash라고 검색해도, 실제로는 호스트(윈도·맥)에서 떠 있는 Clash의 HTTP 수신 포트로 명시적으로 보내는 편이 재현에 유리합니다.
또 Docker Desktop은 가상 머신 뒤에서 데몬이 돌기 때문에, 127.0.0.1:7890이 게스트와 호스트에서 서로 다르게 해석됩니다. 그래서 컨테이너·빌드에서 쓰는 주소는 host.docker.internal이나 리눅스 브리지 게이트웨이(흔히 172.17.0.1 등)처럼 호스트를 가리키는 쪽으로 잡는 것이 핵심입니다. WSL2 터미널에서 apt만 Clash로 보내는 시나리오와 결이 비슷하지만, 여기서는 컨테이너 런타임·도커 데몬이 주인공입니다. TUN 전역이 켜져 있어도 데몬이 안 잡히는 케이스가 있으니, HTTP_PROXY 계열을 한 겹 더 두는 팀이 많습니다.
먼저 Clash 쪽: mixed-port·Allow LAN
대부분의 Clash Meta / Mihomo GUI는 mixed-port: 7890처럼 HTTP와 SOCKS를 한 포트에서 받는 구성을 씁니다. 숫자는 본인 설정을 열어 확인하세요. Docker가 HTTP CONNECT로 붙는 경우가 많아서, 컨테이너·데몬 설정에는 http://… 스킴을 쓰는 경우가 가장 수월합니다(일부는 SOCKS5도 되지만, 문서·예제는 HTTP가 많습니다). 그리고 Allow LAN·외부 수신에 해당하는 옵션이 꺼져 있으면, 호스트가 127.0.0.1에만 바인딩되어 다른 인터페이스에서 온 Docker 브리지 연결이 거절됩니다. 이 단계는 LAN 대역 글의 맥락과 겹칩니다. 요약하면, 호스트 IP:포트에 외부(브리지)에서 붙을 수 있게 먼저 열어 두세요.
대상 URL: host.docker.internal vs 게이트웨이
Docker Desktop(Windows·macOS)은 컨테이너 안에서 host.docker.internal이 호스트 OS로 가는 특수 DNS 이름으로 동작하는 경우가 많습니다. Clash의 mixed-port가 7890이면, 컨테이너/빌드에서의 전형적인 프록시 URI는 http://host.docker.internal:7890 형태가 됩니다. Linux에서 네이티브 dockerd를 쓰는 경우엔, 배포판에 따라 host.docker.internal이 없을 수 있으니 ip route로 기본 게이트웨이를 읽어 http://172.17.0.1:7890 식으로 두는 팀이 많습니다(회사망·VPN·사용자 정의 br 는 달라질 수 있음). 어느 쪽이든, 호스트 Clash가 그 IP·포트에서 리슨하는지, 방화벽이 막지 않는지 curl -v --proxy로 먼저 확인하는 것이 좋습니다.
한 번 쓰는 명령: 환경 변수로 pull·build
터미널에서 즉시 시험하려면, HTTP_PROXY·HTTPS_PROXY·(필요 시) ALL_PROXY를 같은 HTTP URI로 맞춥니다. 대문자·소문자 둘 다 읽는 도구가 섞이므로 둘 다 넣는 편이 안전합니다. NO_PROXY에는 localhost,127.0.0.1,::1와 사내망·사설 레지스트리 도메인을 잊지 마세요(프록시로 보내면 TLS·내부 DNS가 꼬이는 대표 케이스입니다).
# Example: Docker Desktop, mixed port 7890, host.docker.internal
export HTTP_PROXY="http://host.docker.internal:7890"
export HTTPS_PROXY="http://host.docker.internal:7890"
export http_proxy="$HTTP_PROXY"
export https_proxy="$HTTPS_PROXY"
export NO_PROXY="localhost,127.0.0.1,::1,registry.internal.example"
docker pull hello-world
docker build도 빌드 시 클라이언트가 위 변수를 읽는 경우가 많아, 빌드 ARG로 넘기거나 동일 셸에서 실행합니다. 멀티 스테이지에서 RUN apt가 나가는 경우, Dockerfile 안의 ARG HTTP_PROXY·ENV HTTP_PROXY=...를 빌드 커맨드와 맞추는 팀도 있습니다(보안·공유 정책에 따라 CI 변수로만 주입).
고정 설정: ~/.docker/config.json
매번 export하기 번거롭다면, 사용자 단위 Docker 클라이언트 설정에 proxies 블록을 둡니다(경로·키 이름은 엔진 버전·문서를 확인). 일반적으로 default 섹션에 httpProxy·httpsProxy·noProxy를 넣으면, docker pull 등 클라이언트가 registry와 통신할 때 동일한 프록시를 씁니다. 이 파일은 계정마다 달라지고, 데몬이 아닌 클라이언트 측에 가깝다는 점을 기억하세요. 데몬 자체가 이미지를 받을 때 끊기면 다음 절(데스크톱·daemon.json)이 필요해질 수 있습니다.
Docker Desktop: 데몬/엔진 프록시(Windows·macOS)
Docker Desktop 설정에는 Proxy·Resources·Docker Engine JSON 등, 배포에 따라 GUI로 프록시를 넣는 화면이 있습니다. 이미지 가속이나 레지스트리 미러는 중국 등 특정 환경의 공식 문서와 함께 쓰일 때가 많고, Clash 쪽은 출구(노드)를 정해 주는 층입니다. 둘을 헷갈리지 말고, 데몬이 HTTP 프록시로 나가는지를 한 번에 맞추는 것이 “한 번에 통과”에 가깝습니다. 끄고 켤 때 Desktop 재시작이 필요한 경우가 있으니, 설정 저장 후 엔진 재시동을 잊지 마세요. Clash Windows 클라이언트를 처음 깔았다면, mixed-port·시스템 프록시는 그 가이드와 7890 점검을 함께 보면 수치가 맞기 쉽습니다.
리눅스 네이티브: /etc/docker/daemon.json
서버나 데스크톱 리눅스에 직접 dockerd를 올렸다면, /etc/docker/daemon.json에 proxies·http-proxy 관련 키(배포·버전에 따름)를 쓰거나, systemd 유닛 Environment=HTTP_PROXY=...로 도커 데몬에 주입하는 방식이 흔합니다. 루트 권한이 필요하고, 회사 보안 정책이 있을 수 있으니 운영 가이드와 맞춰 주세요. 이 경우 클라이언트만이 아니라 데몬이 pull하는 경로를 직접 여는 셈입니다.
docker compose / BuildKit
BuildKit을 켠 빌드는 빌더 컨테이너 안에서 RUN이 돌기 때문에, 호스트의 export가 그대로 안 들어가는 경우가 있습니다. 그때는 docker compose build에 --build-arg HTTP_PROXY=...를 주거나, compose 파일에 args를 정의해 스테이지마다 동일 URI를 쓰게 합니다. CI에서는 Secret으로 넣는 편이 낫고, 로컬 개발이면 .env로 빼 두고 팀원마다 같은 Clash 포트를 쓰게 정하는 것이 덜 꼬입니다. containerd·nerdctl을 쓰는 환경은 옵션 이름이 다를 수 있으니 공식 문서를 따릅니다.
TUN·규칙과 겹칠 때
호스트에서 Clash TUN이 켜져 있어도, Docker VM이나 리눅스 네트워크 네임스페이스는 항상 같은 방식으로 감싸이지는 않습니다. 규칙은 분류·GEOIP 글에서 다루듯, 출구·DNS가 흔들리면 “가끔만” 타임아웃이 납니다. 본문에서 제안한 HTTP_PROXY 고정은 명시적이라 로그에도 잘 찍힙니다. 반대로 투과형 TUN만 쓰고 싶다면, 데스크톱 쪽 TUN·라우트와 Docker 네트워크의 상호작용을 한 번 통째로 점검해야 합니다.
트러블슈팅 요약
Connection refused, 프록시 없이 직접 감
Allow LAN·바인딩·방화벽·포트 번호(7890이 아닌 7891 등)를 다시 보세요. curl로 호스트 URI가 살아 있는지 먼저 확인합니다.
TLS·인증서
회사 SSL 가로채기·백신 HTTPS 검사가 끼면 풀과 레지스트리가 따로 실패할 수 있습니다. 동일 머신의 브라우저에서도 같은가 비교하세요.
DNS만 느리다
Clash DNS와 컨테이너/호스트 해석이 갈리면 첫 연결만 지연됩니다. 로그로 실제로 나간 호스트·정책을 확인하세요.
정리
Docker pull·빌드가 Clash 뒤로 안 붙는 문제는, 대개 엔진·클라이언트가 HTTP_PROXY를 모르는 채 직접 registry로 가서 생깁니다. 호스트의 mixed-port에 http://host.docker.internal:포트(또는 게이트웨이 IP)를 맞추고, Allow LAN으로 수신을 열고, NO_PROXY로 내망·사설 레지스트리를 보호하는 네 가지를 한 세트로 두면, “컨테이너가 호스트 프록시로 나간다”는 말이 구체적 명령으로 바뀝니다. Docker Desktop·이미지 관련 UI는 미러/리소스와 출구를 구분해 쓰는 것이 덜 헷갈립니다. 비슷한 호스트 주제는 WSL2 문서가 다루는 셸·apt와 나란히 두고 보면 좋고, 클라이언트 설치는 Clash 사용 설명서와 맞닿아 있습니다. 한 번 pull·build 경로를 잡아 두면 이후 반복이 훨씬 수월해집니다. → Clash를 무료로 내려받아 위 프록시 URI를 본인 mixed-port에 맞춰 Docker 흐름에 적용해 보세요.