브라우저는 되는데 Docker Hub만 타임아웃되는 이유

Docker Hub 이미지 풀 타임아웃은 브라우저에서 웹사이트가 정상적으로 열리는 상황에서도 발생할 수 있습니다. 많은 사용자가 먼저 인터넷 회선이나 Clash 노드 자체를 의심하지만, 실제로는 Docker CLI와 Docker 데몬이 서로 다른 네트워크 경로를 사용한다는 점이 핵심입니다. 브라우저는 운영체제의 시스템 프록시 설정이나 브라우저 확장 프로그램을 따를 수 있지만, Docker 명령은 백그라운드에서 실행되는 Docker Engine 데몬이 담당합니다.

따라서 브라우저에서 hub.docker.com이 열리고 Clash 연결 로그에도 일부 접속이 보이더라도, 이미지 레이어를 내려받는 실제 요청이 프록시를 거치지 않을 수 있습니다. Docker Hub 로그인과 이미지 다운로드는 한 호스트에서 끝나지 않습니다. 인증 과정에는 auth.docker.io, 레지스트리 요청에는 registry-1.docker.io, 이미지 레이어에는 CDN 도메인이 사용될 수 있습니다. 이 중 한 경로라도 DIRECT로 빠지거나 Docker 데몬이 프록시 환경 변수를 읽지 못하면 context deadline exceeded, i/o timeout, net/http: request canceled 같은 오류가 나타납니다.

먼저 구분할 것: 이 글은 허용된 네트워크와 합법적인 프록시 환경에서 Docker 연결 경로를 진단하는 방법을 다룹니다. 회사·학교의 보안 정책이나 서비스 이용 약관을 위반하는 우회 설정은 권장하지 않습니다.

오류 메시지로 원인 범위 좁히기

같은 Docker Hub 오류처럼 보여도 실패한 단계에 따라 확인할 위치가 달라집니다. 재현할 때는 단순히 “안 된다”고 기록하기보다 명령어, 오류가 발생한 시간, Clash 연결 로그의 도메인과 정책 이름을 함께 남기는 것이 좋습니다. 특히 여러 이미지를 한꺼번에 받기보다 작은 공개 이미지를 사용해 한 단계씩 확인해야 로그를 읽기 쉽습니다.

증상 주로 의심할 경로 첫 점검 대상
로그인부터 실패 auth.docker.io Docker 데몬 프록시와 인증 도메인 규칙
매니페스트 조회 실패 registry-1.docker.io 레지스트리 규칙, DNS 응답, 노드 연결
레이어 다운로드 중 멈춤 Docker CDN 또는 리디렉션 주소 Clash 로그의 실제 최종 도메인과 DIRECT 여부
브라우저만 정상 Docker 데몬 전체 서비스 환경 변수, TUN 적용 여부, 방화벽

예를 들어 docker login은 성공하지만 docker pull 중 특정 레이어에서 멈춘다면 계정 문제가 아니라 다운로드 CDN 경로일 가능성이 큽니다. 반대로 모든 요청이 즉시 실패하고 Clash 로그에 Docker 관련 도메인이 전혀 나타나지 않는다면, 규칙보다 먼저 Docker 데몬이 Clash를 사용하고 있는지 확인해야 합니다.

실패 직후 수집해야 할 증거

진단을 시작하기 전에 현재 Docker 버전과 실행 환경을 확인합니다. Windows의 Docker Desktop, Linux의 systemd 서비스, macOS의 Docker Desktop은 프록시 설정 위치가 서로 다르므로 운영체제를 먼저 분리해야 합니다.

docker version
docker info
docker pull hello-world

docker version에서 Client만 출력되고 Server 쪽에 연결 오류가 있으면 Docker 데몬 자체가 실행되지 않은 상태입니다. Client와 Server 정보가 모두 출력되지만 풀만 실패한다면 네트워크 경로를 조사합니다. Linux에서는 다음 명령으로 데몬 서비스의 환경 변수와 최근 로그를 확인할 수 있습니다.

systemctl show --property=Environment docker
journalctl -u docker --since "10 minutes ago" --no-pager

DNS가 문제인지 프록시가 문제인지 분리하려면 운영체제의 일반 네트워크 요청도 확인할 수 있습니다.

curl -I https://auth.docker.io/token
curl -I https://registry-1.docker.io/v2/

여기서 중요한 것은 curl이 성공했다는 사실만으로 Docker도 성공한다고 결론 내리지 않는 것입니다. curl은 현재 터미널의 환경 변수나 사용자 계정 설정을 사용할 수 있지만, Docker 데몬은 별도의 서비스 계정과 프로세스 환경에서 실행됩니다. 테스트 직후 Clash의 Connections 또는 Logs 화면에서 위 도메인이 어떤 규칙과 프록시 그룹으로 매칭됐는지 확인하세요.

Docker Desktop에서 Clash 프록시 연결하기

Windows와 macOS의 Docker Desktop은 일반 앱처럼 실행되지만, 실제 이미지 풀은 내부 Linux 가상 환경의 Docker Engine이 처리합니다. Windows 시스템 프록시를 켜거나 브라우저에 프록시 확장 기능을 설치하는 것만으로는 충분하지 않습니다. Docker Desktop 설정 안에 있는 프록시 항목이 데몬에 전달되는지 확인해야 합니다.

  1. Docker Desktop을 열고 Settings로 이동한 뒤 Resources 또는 버전에 따라 Proxies 항목을 찾습니다.
  2. 자동 프록시 감지가 제대로 작동하지 않으면 수동 프록시를 선택하고 Clash의 HTTP 혼합 포트 주소를 입력합니다. 일반적으로 주소는 127.0.0.1이지만 Docker Desktop 내부에서 호스트 접근 방식이 다를 수 있으므로 화면에 표시된 안내를 우선합니다.
  3. Clash의 HTTP 또는 Mixed 포트가 실제로 열려 있는지 확인합니다. SOCKS 포트만 입력하면 Docker의 HTTPS 요청이 기대대로 처리되지 않을 수 있습니다.
  4. 설정을 저장한 뒤 Docker Desktop을 완전히 종료하고 다시 실행합니다. 백그라운드 엔진이 이전 환경을 계속 유지하는 경우가 있기 때문입니다.
  5. docker pull hello-world를 다시 실행하면서 Clash 로그에 auth.docker.io와 레지스트리 요청이 나타나는지 확인합니다.

Docker Desktop과 Clash가 같은 호스트에서 실행되더라도 127.0.0.1의 의미가 항상 동일한 것은 아닙니다. 특히 WSL2, 가상 머신, 컨테이너 안에서 Docker CLI를 실행하는 경우 로컬호스트가 Windows 호스트가 아니라 현재 가상 환경을 가리킬 수 있습니다. 이때는 Clash에서 LAN 수신을 허용하고 호스트의 사설 IP를 사용해야 할 수 있지만, 외부 노출 범위를 넓히기 전에 방화벽과 접근 주소를 제한해야 합니다.

보안 주의: Clash의 외부 수신을 무조건 0.0.0.0으로 열지 마세요. Docker Desktop이나 WSL에서 접근이 필요하다면 신뢰하는 사설 네트워크와 방화벽 규칙 안에서만 제한적으로 허용하고, 외부 컨트롤러 API 포트는 인터넷에 노출하지 않아야 합니다.

Linux Docker 데몬의 프록시 설정

Linux에서는 터미널에서 export HTTP_PROXY=...를 실행하는 것만으로 Docker 데몬이 프록시를 사용하지 않습니다. 터미널의 환경 변수는 현재 셸과 그 자식 프로세스에만 적용되며, systemd가 별도로 시작한 dockerd에는 전달되지 않을 수 있습니다. 이 때문에 사용자는 프록시를 설정했다고 생각하지만 Docker는 계속 DIRECT로 연결하는 상황이 발생합니다.

systemd 기반 배포판에서는 Docker 서비스용 drop-in 디렉터리를 만들고 프록시 변수를 지정합니다.

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf

파일에는 실제 Clash가 수신하는 주소와 포트를 넣습니다. 아래 포트는 예시이므로 자신의 Clash 설정에 맞게 바꿔야 합니다.

[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1"

저장한 다음 systemd를 다시 읽고 Docker를 재시작합니다.

sudo systemctl daemon-reload
sudo systemctl restart docker
systemctl show --property=Environment docker
docker pull hello-world

systemctl show에 프록시가 표시되어도 실제 연결이 성공한다는 뜻은 아닙니다. Clash 로그에 요청이 기록되는지, Docker Hub 도메인이 올바른 프록시 그룹으로 들어가는지, 이미지 레이어가 끝까지 내려오는지를 함께 확인해야 합니다. 프록시 주소가 127.0.0.1인데 Clash가 컨테이너나 다른 사용자 세션 안에서 실행 중이라면 해당 주소가 Docker 데몬이 접근할 수 있는 위치인지도 확인하세요.

Clash 규칙과 DNS를 점검하는 순서

Docker Hub 관련 도메인을 발견했다고 해서 곧바로 DOMAIN-SUFFIX,docker.io,Proxy 한 줄만 추가하는 것은 충분하지 않을 수 있습니다. 인증, 레지스트리, 리디렉션 CDN이 서로 다른 도메인을 사용할 수 있기 때문입니다. 우선 실제 로그에 나타난 FQDN을 기준으로 좁은 규칙을 만들고, 테스트가 끝난 뒤 필요하지 않은 광범위한 규칙은 정리하는 편이 안전합니다.

  • 인증: auth.docker.io 요청이 어떤 정책에 매칭되는지 확인합니다.
  • 레지스트리: registry-1.docker.io가 인증 도메인과 같은 안정적인 그룹을 사용하는지 비교합니다.
  • Hub 웹 도메인: hub.docker.com은 브라우저 확인에는 유용하지만 이미지 레이어 다운로드의 전부를 대표하지 않습니다.
  • CDN: 풀 중 새로 등장하는 호스트를 기록하고, 무관한 전체 CDN을 한꺼번에 프록시로 보내지 않습니다.

DNS 모드도 놓치기 쉬운 원인입니다. Fake-IP와 Redir-Host 동작이 Docker Desktop, WSL2, Linux 네트워크와 충돌하면 도메인은 해석되지만 실제 연결이 비정상적으로 반복될 수 있습니다. 진단 중에는 DNS 모드를 한 번에 여러 개 바꾸지 말고, 현재 모드와 변경 시각을 기록하면서 한 가지씩 비교하세요. Clash 연결 로그에 도메인 대신 예상하지 못한 IP만 표시되면 DNS 모드와 호스트명 보존 설정을 먼저 살펴보는 것이 좋습니다.

실전 팁: 규칙을 수정한 뒤에는 기존 연결이 캐시에 남아 있을 수 있습니다. Clash에서 관련 연결을 지우고 Docker Desktop 또는 Docker 서비스를 재시작한 다음, 작은 이미지로 다시 재현하면 이전 결과와 새 결과를 구분하기 쉽습니다.

타임아웃을 재현하고 수정하는 최종 체크리스트

설정을 여러 곳에서 동시에 바꾸면 어떤 변경이 효과가 있었는지 알 수 없게 됩니다. 다음 순서를 지키면 문제를 재현하면서 원인을 단계적으로 좁힐 수 있습니다.

  1. 환경 확인: Windows Docker Desktop, macOS Docker Desktop, Linux systemd, WSL2 중 현재 Docker 데몬이 어디에서 실행되는지 기록합니다.
  2. 단일 이미지 테스트: 큰 이미지 대신 hello-world처럼 작은 공개 이미지를 사용해 기본 연결을 확인합니다.
  3. 로그 비교: 풀을 실행하는 순간 Clash 로그에서 인증·레지스트리·CDN 도메인과 매칭 정책을 확인합니다.
  4. 프록시 위치 수정: Docker Desktop 설정 또는 systemd drop-in에 실제 데몬이 읽는 HTTP/HTTPS 프록시를 지정합니다.
  5. 규칙 최소화: 로그에 확인된 도메인부터 안정적인 그룹으로 보내고, DOMAIN-KEYWORD,docker처럼 지나치게 넓은 규칙은 피합니다.
  6. 한 번에 하나만 변경: DNS 모드, TUN, 프록시 포트, 규칙을 동시에 바꾸지 말고 변경 후 매번 같은 이미지로 결과를 비교합니다.

수정 후 인증은 성공하지만 레이어에서 계속 멈춘다면 CDN 연결을 별도로 관찰합니다. 반대로 로그에 인증 도메인조차 나타나지 않는다면 규칙을 더 추가하기보다 Docker 데몬이 지정한 프록시 주소에 접근할 수 있는지 확인해야 합니다. curl 결과와 Docker 결과가 다를 때는 거의 항상 실행 주체, 환경 변수, 가상 네트워크 경계 중 하나가 다릅니다.

자주 묻는 질문

브라우저에서 Docker Hub가 열리면 Docker도 정상이어야 하지 않나요?

그렇지 않습니다. 브라우저는 시스템 프록시를 사용하지만 Docker 이미지는 Docker 데몬이 별도로 다운로드합니다. Docker Desktop의 프록시 설정이나 Linux systemd 환경 변수가 빠져 있으면 브라우저만 정상이고 Docker는 DIRECT 연결을 시도할 수 있습니다.

Docker 프록시에 Clash SOCKS 포트를 입력해도 되나요?

환경에 따라 가능하지만 Docker Desktop과 Docker Engine은 일반적으로 HTTP 또는 HTTPS 프록시 주소를 입력하는 방식이 가장 단순합니다. SOCKS 포트만 지정했을 때는 데몬 버전과 프록시 구현에 따라 동작하지 않을 수 있으므로, 우선 Clash의 HTTP 혼합 포트를 사용하고 실제 연결 로그를 확인하세요.

auth.docker.io만 규칙에 넣으면 충분한가요?

대부분의 경우 충분하지 않습니다. 인증과 레지스트리, 이미지 레이어가 서로 다른 호스트를 사용할 수 있습니다. auth.docker.ioregistry-1.docker.io를 확인한 뒤, 실제 풀 과정에서 새로 나타나는 CDN 도메인을 로그로 확인해야 합니다.

TUN 모드를 켜면 Docker 프록시 설정이 필요 없나요?

TUN 모드가 Docker Desktop이나 Linux의 모든 트래픽을 반드시 동일하게 처리한다고 단정할 수 없습니다. 가상 머신, WSL2, 컨테이너 네트워크, 서비스 계정의 라우팅이 개입하기 때문에 TUN은 보조 수단으로 보고 Docker 데몬의 프록시 설정과 Clash 로그를 함께 검증하는 것이 안전합니다.

일반적인 시스템 프록시 도구는 브라우저 중심으로 설계되어 Docker 데몬, WSL2, CDN 리디렉션까지 한 번에 설명하지 못하고 설정 위치도 플랫폼마다 달라 초보자가 원인을 놓치기 쉽습니다. Clash 공식 사이트는 Docker Hub 인증·레지스트리·레이어 다운로드를 분리해 로그와 명령어를 함께 확인하도록 안내하며, 운영체제별 설정 차이도 한 흐름에서 비교할 수 있습니다. 같은 문제를 다시 겪지 않도록 안정적인 Clash 클라이언트를 준비하고 싶다면 다운로드 페이지에서 환경에 맞는 버전을 확인해 보세요.