1. 왜 컨테이너 안에 Clash를 또 두지 않을까
컨테이너마다 프록시 클라이언트를 넣으면 이미지가 무거워지고, 구독 URL·프로필 갱신·로그 위치까지 컨테이너 생명주기에 묶입니다. 팀 단위로는 보안 정책상 「한 대의 호스트에서만 출구를 관리한다」는 요구도 흔합니다. 그래서 실무에서는 호스트 OS에서 Clash(또는 mihomo)를 띄우고, 컨테이너는 그 소켓이나 HTTP 프록시 엔드포인트만 바라보게 두는 패턴이 자주 쓰입니다. 문제는 Docker가 기본적으로 브리지 네트워크를 쓰기 때문에, 컨테이너 입장에서 「호스트의 127.0.0.1」이 곧바로 호스트의 Clash가 아니라는 점입니다. 그 간극을 메우는 것이 이 글의 중심입니다.
검색으로 들어오는 분들은 「docker 프록시」「컨테이너 clash」처럼 짧은 키워드로도 찾습니다. 핵심은 컨테이너의 기본 라우팅과 애플리케이션이 프록시 환경 변수를 존중하는지를 동시에 보는 것입니다. 둘 중 하나만 맞아도 증상은 반쯤 해결되지만, 나머지 하나가 어긋나면 「curl만 되고 npm은 안 된다」처럼 보이기 쉽습니다.
2. 호스트 쪽 전제: mixed-port·allow-lan·바인드 주소
Clash 계열에서 mixed-port는 한 포트에 HTTP CONNECT와 SOCKS를 함께 받는 설정이 흔합니다. 컨테이너가 HTTP_PROXY=http://<호스트>:<포트> 형태로 붙을 때는 이 포트가 실제로 리슨 중이어야 하고, LAN·브리지 대역에서의 접속을 막지 않아야 합니다. GUI 클라이언트라면 「Allow LAN」에 해당하는 옵션을 켜 두는 식으로 정리됩니다. 바인드가 127.0.0.1에만 걸려 있으면 호스트 밖(브리지 네트워크의 컨테이너)에서 오는 SYN이 도달하지 않습니다. 반대로 0.0.0.0에 열어두면 편하지만, 사내망에서는 방화벽·ACL과 함께 범위를 제한하는 편이 안전합니다.
한 줄 정리
컨테이너가 붙을 수 있는 호스트 측 IP + mixed-port가 열려 있어야 하며, Clash 규칙·노드는 호스트에서 그대로 적용됩니다.
3. 방식 A: HTTP_PROXY·HTTPS_PROXY·ALL_PROXY 환경 변수
가장 단순한 방법은 빌드·런타임에 표준 환경 변수를 주입하는 것입니다. HTTP_PROXY와 HTTPS_PROXY는 대부분의 HTTP 클라이언트 스택이 읽습니다. ALL_PROXY는 일부 도구가 SOCKS까지 한 번에 쓰도록 붙이기도 합니다. 값은 보통 http://호스트IP:포트 형식이며, 여기서 「호스트 IP」가 플랫폼마다 달라집니다.
Docker Desktop(Mac·Windows)에서는 특수 호스트 이름 host.docker.internal이 문서화되어 있어, 컨테이너에서 호스트로의 접속에 자주 씁니다. 예를 들어 호스트 Clash의 mixed-port가 7890이면 http://host.docker.internal:7890처럼 적습니다. 리눅스 네이티브 Docker에서는 최근 버전에서 같은 이름이 지원되는 경우가 있으나, 배포판·데몬 설정에 따라 172.17.0.1(docker0 게이트웨이)이나 실제 브리지 주소를 쓰는 팀도 많습니다. 확실히 하려면 호스트에서 ip -4 addr show docker0 등으로 게이트웨이를 확인하고, 컨테이너 안에서 nc -vz <IP> <포트>로 연결성부터 보는 것이 좋습니다.
# Example: run with proxy env (adjust host and port) docker run --rm -it \ -e HTTP_PROXY=http://host.docker.internal:7890 \ -e HTTPS_PROXY=http://host.docker.internal:7890 \ -e NO_PROXY=localhost,127.0.0.1,.internal \ alpine sh -c "wget -qO- https://example.com | head"
빌드 단계에서 레지스트리나 Git이 필요하면 docker build --build-arg HTTP_PROXY=...를 병행해야 합니다. BuildKit을 쓰면 전달 방식이 조금 달라질 수 있으니, CI 로그에 프록시 관련 경고가 없는지 함께 확인하세요.
4. Docker Compose·CI에서 넣는 패턴
Compose에서는 서비스 단위 environment 블록이나 루트의 env_file로 동일한 값을 공유하기 쉽습니다. 개발자마다 호스트 IP가 다르면 .env에 PROXY_HOST=...만 두고 조합하는 방식이 실수를 줄입니다. CI 러너가 리눅스 VM이라면 host.docker.internal이 없을 수 있으므로, 그때는 러너 문서에 맞는 게이트웨이 IP나 sidecar 프록시를 정하는 편이 낫습니다.
services: app: image: node:20-bookworm environment: HTTP_PROXY: ${HTTP_PROXY:-http://172.17.0.1:7890} HTTPS_PROXY: ${HTTPS_PROXY:-http://172.17.0.1:7890} NO_PROXY: localhost,127.0.0.1,registry.internal
팀에서 구독·프로필을 표준화해 두었다면, 컨테이너 쪽은 환경 변수만 맞추면 호스트 Clash의 정책 그룹·규칙을 그대로 타게 됩니다. 규칙 우선순위 개념은 고급 라우팅 가이드와 함께 보면 디버깅이 빨라집니다.
5. NO_PROXY로 내부 레지스트리·메쉬 제외
사내 Nexus·Harbor·GitLab 같은 내부 호스트까지 프록시로내면 지연이 늘거나 TLS 상호 인증이 깨질 수 있습니다. NO_PROXY에 도메인 접미·IP 대역을 넣어 직접 경로로 빼 주는 것이 일반적입니다. 쉼표로 나열하고, 앞에 점을 붙여 접미 일치를 쓰는 관례(.corp.example.com)도 함께 기억해 두면 운영 중 수정이 줄어듭니다.
6. 환경 변수 방식의 한계: 누가 안 따를까
Go·Node·많은 CLI는 HTTP_PROXY를 잘 따르지만, 특정 바이너리는 무시하거나 자체 설정 파일만 봅니다. DNS 조회가 프록시 밖에서 먼저 일어나는 경우도 있어, fake-ip·스플릿 DNS를 호스트 Clash에서 쓰는 환경이면 컨테이너의 리졸버 설정까지 맞춰야 하는 순간이 생깁니다. 또한 환경 변수는 주로 HTTP(S) 계열에 가깝고, 임의의 TCP·UDP 포트를 통째로 터널링하는 앱에는 부족할 수 있습니다. 그럴 때는 TUN을 호스트에서 쓰거나, 아래 게이트웨이·호스트 네트워크 쪽을 검토하게 됩니다.
개발용으로는 IDE·npm·API를 도메인 규칙으로 묶어 둔 프로필을 호스트에 그대로 두고, 컨테이너만 프록시로 붙이는 구성이 자연스럽게 이어집니다.
7. 방식 B: 리눅스 게이트웨이·호스트 네트워크와 비교
「컨테이너의 기본 게이트웨이를 호스트 쪽 프록시/라우터로 보낸다」는 접근은 네트워크 관리자 친화적이지만, 단순히 Clash만으로 끝내기보다는 호스트 iptables·nftables·라우팅 테이블과 함께 설계하는 경우가 많습니다. 반면 docker run --network host는 컨테이너가 호스트의 네임스페이스를 공유하므로, 호스트에서 이미 TUN·Clash로 전역 라우팅이 잡혀 있다면 애플리케이션이 환경 변수 없이도 같은 경로를 탈 수 있습니다. 대가로 포트 충돌·격리 약화가 있어 CI·멀티 테넌트에는 신중해야 합니다.
실무에서는 먼저 방식 A로 git·npm·pip·apt가 요구하는 시나리오를 통과시키고, 특정 데몬만 예외라면 그 프로세스에 한해 호스트 네트워크나 별도 sidecar를 검토하는 순서가 부담이 적습니다. 리눅스 서버에 Clash를 상주시키는 절차는 Ubuntu·systemd 글의 흐름과 직결됩니다.
보안: mixed-port를 LAN 전체에 열면 같은 스위치에 붙은 기기도 접속할 수 있습니다. 개발 전용 Wi-Fi·로컬 방화벽으로 노출 범위를 제한하세요.
8. 실측 점검 순서
권장 순서는 다음과 같습니다. 첫째, 컨테이너 안에서 호스트 후보 IP와 포트에 대해 TCP 연결이 되는지 확인합니다. 둘째, curl -I로 외부 HTTPS 한 번, 내부 레지스트리 한 번을 나란히 찍어 NO_PROXY가 기대대로인지 봅니다. 셋째, 실패 시 호스트 Clash 로그에서 해당 연결이 어떤 규칙·아웃바운드로 나갔는지 확인합니다. 넷째, 빌드 단계와 런타임 단계 중 어디서 끊기는지 나누어 CI 로그를 재생합니다.
환경 변수가 먹었는지
env | grep -i proxy로 주입 여부를 보고, 동일 이미지에서 프록시를 뺀 대조 실험을 한 번 실행해 보세요.
DNS 이슈인지
IP로는 되는데 이름만 실패하면 리졸버 경로를 의심합니다. 호스트와 컨테이너의 /etc/resolv.conf 차이를 비교해 보세요.
정리하면, Docker가 호스트 Clash를 타고 나가게 하는 가장 현실적인 첫 수는 HTTP_PROXY 계열과 올바른 호스트 도달 주소(host.docker.internal 또는 브리지 게이트웨이)를 맞추는 것입니다. 여기에 NO_PROXY로 내부 트래픽을 분리하면 레지스트리·메쉬까지 한 번에 건드리지 않습니다. 환경 변수만으로 부족한 프로세스가 보이면 호스트 네트워크나 호스트 측 라우팅을 단계적으로 검토하면 됩니다. 같은 목적의 상용 VPN 앱들에 비해, Clash 쪽은 규칙·프로필을 파일로 관리하고 로그로 원인을 좁히기 좋아 개발자 워크플로에 잘 맞는 편입니다.
→ Clash를 무료로 내려받아 호스트에서 mixed-port·LAN 허용·프로필을 정리한 뒤, 컨테이너 환경 변수만 맞춰 Git·npm·pip 경로를 다시 점검해 보세요.
관련 읽기 · 같은 주제
주제 관련도가 높은 읽을거리 — 같은 카테고리의 Clash 실전 가이드.
Ubuntu에 Clash Meta 설치·systemd 자동 기동: deb부터 부팅까지 (2026)
Ubuntu에서 Clash Meta(mihomo) deb 설치, 설정 디렉터리 구성, systemd로 부팅 시 자동 실행·비정상 종료 시 재시작까지 한 흐름으로 정리했습니다. Linux 데스크톱·경량 서버 프록시 운용에 참고하세요.
자세히 보기Clash는 켰는데 브라우저만 직접 연결? Windows에서 보안 DNS(DoH) 끄고 시스템 프록시 맞추기 (2026)
Clash·시스템 프록시는 켰는데 Chrome·Edge만 국선·이상한 DNS처럼 보일 때, Windows 10/11·브라우저의 보안 DNS(DoH)를 끄고 mihomo의 fake-ip·로컬 DNS 흐름과 충돌을 푸는 절차입니다. Verge Rev 시스템 프록시·TUN·구독 TLS 글과…
자세히 보기Debian 12에 Clash Meta 설치: 바이너리·systemd 자동 기동·mixed-port 첫 설정 (2026)
bookworm·apt·경로와 방화벽(nft) 전제에 맞춰 mihomo 리눅스 바이너리, /etc/mihomo, systemd enable·now, journalctl, mixed-port·external-controller, 구독을 한 흐름으로 잡는 Debian 12 전용 절차입니다.…
자세히 보기