Docker 컨테이너의 트래픽을 Clash 또는 Mihomo 프록시로 보내려면 컨테이너 안에 프록시 클라이언트를 설치하는 것만으로는 충분하지 않습니다. Docker bridge 네트워크에서 호스트로 들어오는 패킷을 어디서 가로챌지, 응답 패킷을 어떻게 되돌릴지, DNS 요청과 프록시 서버 자체의 연결을 어떻게 제외할지 함께 설계해야 합니다. 이 가이드에서는 Linux 게이트웨이에서 컨테이너의 TCP·UDP 트래픽을 처리하는 두 가지 투명 프록시 방식을 설명하고, 적용 전에 확인할 방화벽·라우팅 조건과 장애 진단 절차를 정리합니다.
먼저 네트워크 구조와 적용 범위 정하기
일반적인 Docker bridge 네트워크에서 컨테이너가 외부 주소에 연결하면 패킷은 컨테이너의 가상 인터페이스에서 호스트의 브리지 인터페이스로 이동한 뒤 호스트의 라우팅 및 방화벽 규칙을 통과합니다. 이 트래픽은 호스트 프로세스가 직접 만든 연결과 달리 대부분 FORWARD 경로를 따릅니다. 따라서 호스트의 로컬 프로그램에 적용한 규칙이나 OUTPUT 체인만으로는 컨테이너 트래픽을 가로챌 수 없습니다.
먼저 실제 인터페이스와 주소 대역을 확인합니다. 아래 예시에서는 Docker 브리지가 br-app, 컨테이너 대역이 172.20.0.0/16, 호스트의 외부 인터페이스가 ens3라고 가정합니다. 이 값은 예시일 뿐이므로 자신의 호스트에서 확인한 값으로 바꿔야 합니다.
ip -br address docker network ls docker network inspect app-net ip route
docker network inspect 결과에서 브리지 이름과 서브넷을 확인하고, ip -br address에서 외부 인터페이스 및 호스트 주소를 찾습니다. 여러 Docker 네트워크가 있다면 네트워크별 브리지 이름과 CIDR을 따로 기록하세요. Docker가 자동으로 만드는 docker0만 대상으로 삼으면 사용자 정의 bridge 네트워크의 패킷은 처리되지 않을 수 있습니다.
- REDIRECT 방식: TCP 연결을 Mihomo의
redir-port로 보내는 구성이 비교적 단순합니다. 먼저 TCP만 투명 프록시로 검증하려는 경우 적합합니다. - TPROXY 방식: TCP와 UDP를 함께 처리할 수 있지만, 방화벽 마킹과 정책 라우팅이 필요합니다. 커널 지원과 Mihomo의
tproxy-port설정을 함께 확인해야 합니다. - 일반 프록시 환경 변수: 애플리케이션이 HTTP 또는 SOCKS 프록시를 지원한다면 먼저 이 방법을 고려할 수 있습니다. 투명 프록시보다 라우팅과 DNS 동작을 추적하기 쉽습니다.
Mihomo 리스너와 기본 설정 준비
컨테이너가 호스트의 Mihomo에 도달할 수 있어야 하며, Mihomo는 투명 프록시용 포트에서 패킷을 받아야 합니다. redir-port는 일반적으로 TCP 리다이렉션에 사용하고, TPROXY 구성은 tproxy-port를 사용합니다. 두 방식을 모두 설정할 수 있지만, 실제로 필요한 리스너만 열어 두면 문제 원인을 좁히기 쉽습니다.
mixed-port: 7890 redir-port: 7892 tproxy-port: 7893 allow-lan: true bind-address: 0.0.0.0 mode: rule log-level: info
allow-lan과 바인딩 주소는 컨테이너 네트워크에서 호스트 리스너로 접속할 수 있도록 하는 설정입니다. 호스트에서 127.0.0.1에만 바인딩하면 컨테이너에서 도달하지 못할 수 있습니다. 반대로 0.0.0.0으로 열 경우 방화벽으로 접근 범위를 제한하세요. 특히 관리용 mixed-port와 외부 컨트롤러 포트를 인터넷 전체에 노출하지 않아야 합니다.
Mihomo가 Docker 컨테이너 안에서 실행된다면, 포트를 게시하는 것만으로 투명 프록시가 완성되지는 않습니다. 컨테이너에 필요한 네트워크 권한과 호스트 측 라우팅 구조가 추가로 필요합니다. 처음 구성할 때는 호스트 네트워크에서 Mihomo를 실행하고 Docker bridge 트래픽을 호스트 리스너로 전달하는 방식이 경로를 확인하기 쉽습니다. 어느 방식이든 프록시 노드 서버의 IP와 포트, 컨테이너 및 호스트의 관리 대역은 가로채기 대상에서 제외해야 합니다.
REDIRECT로 컨테이너 TCP 연결 전달하기
REDIRECT 방식은 Docker 브리지에서 외부로 나가는 TCP 패킷을 호스트의 redir-port로 바꿉니다. 아래 규칙은 예시 네트워크의 트래픽만 대상으로 하고, 사설 네트워크와 Mihomo의 프록시 서버 주소를 제외하는 형태입니다. 실제 환경에서는 직접 연결해야 하는 내부망 CIDR과 노드 주소를 빠짐없이 지정하세요.
# 예시값: 브리지 br-app, 컨테이너 대역 172.20.0.0/16 # 프록시 노드 주소 203.0.113.10은 실제 주소로 교체 iptables -t nat -N MIHOMO_DOCKER 2>/dev/null || true iptables -t nat -F MIHOMO_DOCKER iptables -t nat -A MIHOMO_DOCKER -d 203.0.113.10/32 -j RETURN iptables -t nat -A MIHOMO_DOCKER -d 10.0.0.0/8 -j RETURN iptables -t nat -A MIHOMO_DOCKER -d 172.16.0.0/12 -j RETURN iptables -t nat -A MIHOMO_DOCKER -d 192.168.0.0/16 -j RETURN iptables -t nat -A MIHOMO_DOCKER -d 127.0.0.0/8 -j RETURN iptables -t nat -A MIHOMO_DOCKER -p tcp -j REDIRECT --to-ports 7892 iptables -t nat -C PREROUTING -i br-app -s 172.20.0.0/16 -j MIHOMO_DOCKER 2>/dev/null || \ iptables -t nat -A PREROUTING -i br-app -s 172.20.0.0/16 -j MIHOMO_DOCKER
이 규칙은 TCP만 처리합니다. 컨테이너에서 보내는 UDP, QUIC, 일부 게임 트래픽은 이 규칙으로 프록시되지 않습니다. 또한 사설 주소를 모두 제외하는 정책이 항상 옳은 것은 아닙니다. 내부 서비스까지 프록시해야 하는 환경이라면 필요한 대역만 제외하거나 내부 도메인 및 IP 규칙을 별도로 설계하세요. 호스트 자신이 만든 연결은 PREROUTING을 통과하지 않으므로 위 규칙에 잡히지 않습니다.
Docker는 자체 방화벽 체인을 관리하고, 시스템의 iptables가 nftables 백엔드를 사용할 수도 있습니다. 규칙이 있어도 카운터가 증가하지 않는다면 실제 패킷이 br-app으로 들어오는지 확인하고, Docker의 체인 순서와 사용 중인 방화벽 백엔드를 살펴보세요. Docker 정책에 맞춰 필터링해야 할 때는 DOCKER-USER 체인을 검토할 수 있지만, NAT 리다이렉션 규칙과 필터 규칙의 역할은 서로 다릅니다. 한 체인에 규칙을 추가했다고 다른 단계의 처리가 자동으로 바뀌지는 않습니다.
TPROXY로 TCP·UDP와 정책 라우팅 구성하기
TPROXY는 목적지 주소를 단순히 바꾸는 대신 원래 목적지 정보를 보존한 채 로컬 프록시 소켓으로 패킷을 전달합니다. 따라서 Mihomo에 tproxy-port가 설정되어 있어야 하고, 패킷에 표시를 붙인 다음 해당 표시가 있는 패킷을 로컬로 라우팅해야 합니다. 이 과정 중 하나라도 빠지면 방화벽 카운터가 증가해도 연결이 타임아웃될 수 있습니다.
# 로컬 라우팅 테이블과 정책 규칙 ip rule add fwmark 0x1/0x1 table 100 2>/dev/null || true ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null || true # 표시할 트래픽을 위한 mangle 체인 iptables -t mangle -N MIHOMO_TPROXY 2>/dev/null || true iptables -t mangle -F MIHOMO_TPROXY # 로컬 및 사설 목적지는 우회 iptables -t mangle -A MIHOMO_TPROXY -d 127.0.0.0/8 -j RETURN iptables -t mangle -A MIHOMO_TPROXY -d 10.0.0.0/8 -j RETURN iptables -t mangle -A MIHOMO_TPROXY -d 172.16.0.0/12 -j RETURN iptables -t mangle -A MIHOMO_TPROXY -d 192.168.0.0/16 -j RETURN iptables -t mangle -A MIHOMO_TPROXY -d 203.0.113.10/32 -j RETURN iptables -t mangle -A MIHOMO_TPROXY -p tcp -j TPROXY --on-port 7893 --tproxy-mark 0x1/0x1 iptables -t mangle -A MIHOMO_TPROXY -p udp -j TPROXY --on-port 7893 --tproxy-mark 0x1/0x1 iptables -t mangle -A PREROUTING -i br-app -s 172.20.0.0/16 -j MIHOMO_TPROXY
이 예시는 개념을 설명하기 위한 최소 구성입니다. 정책 라우팅 테이블은 재부팅 후 유지되도록 시스템의 네트워크 설정 또는 시작 서비스에 반영해야 합니다. ip rule과 라우팅 테이블이 중복으로 등록되지 않도록 적용 절차를 멱등적으로 구성하고, IPv6를 사용하는 환경에서는 IPv4 규칙만으로 충분하다고 가정하지 마세요. IPv6를 프록시하지 않을 계획이라면 컨테이너의 IPv6 경로가 의도치 않은 우회 통로가 되지 않는지도 점검해야 합니다.
Linux 커널과 iptables 확장 모듈이 TPROXY를 지원해야 합니다. 규칙 추가 단계에서 TPROXY 타깃이나 관련 모듈 오류가 나오면 먼저 커널 지원과 iptables 백엔드를 확인하세요. 컨테이너 트래픽을 호스트에서 전달하는 경우 IP 포워딩도 필요할 수 있습니다.
sysctl net.ipv4.ip_forward sysctl -w net.ipv4.ip_forward=1 ip rule show ip route show table 100
ip_forward를 켜는 것은 라우팅을 허용하는 설정이지, 특정 트래픽을 자동으로 안전하게 제한하는 방화벽 정책은 아닙니다. 호스트를 게이트웨이로 사용하는 범위에 맞춰 포워딩 정책을 구성하고, 방화벽 기본 정책이 컨테이너의 반환 패킷을 막지 않는지 확인하세요.
DNS, 내부 대역, 프록시 루프 관리
DNS는 투명 프록시에서 별도로 설계해야 합니다. Docker의 기본 DNS 전달은 컨테이너에서 호스트의 Docker DNS 서비스로 향할 수 있으며, 목적지 주소가 로컬 또는 사설 주소라면 위에서 설정한 제외 규칙에 의해 프록시되지 않습니다. 반대로 UDP 53을 무조건 가로채면 컨테이너가 사용하는 로컬 DNS 경로를 깨뜨리거나, DNS 요청이 Mihomo와 Docker DNS 사이에서 반복되는 문제가 생길 수 있습니다.
- 컨테이너가 Docker 내장 DNS를 사용한다면 실제 DNS 목적지와 포트가 무엇인지 패킷 캡처로 확인한 뒤 처리 방법을 정합니다. 로컬 전달 경로를 유지하거나, 명시적으로 접근 가능한 Mihomo DNS 리스너를 사용하도록 컨테이너 네트워크를 구성할 수 있습니다.
- Mihomo DNS를 사용한다면 DNS 리스너 주소와 포트가 컨테이너에서 접근 가능한지 확인하고, 해당 DNS 포트로 향하는 트래픽을 다시 투명 프록시 규칙에 넣지 않도록 제외합니다.
- 내부 도메인이 있다면 내부 DNS 서버와 사내 CIDR을 프록시 대상에서 제외하거나, Mihomo 규칙과 DNS 설정에서 내부 이름이 올바르게 해석되도록 분리합니다.
- UDP 연결이 필요하다면 REDIRECT만으로 처리된다고 가정하지 말고 TPROXY 및 Mihomo의 UDP 지원을 점검합니다. 애플리케이션이 QUIC 연결에 실패할 때 TCP로 재시도하는지 여부도 확인하세요.
리다이렉트 루프의 대표 원인은 프록시 노드로 향하는 연결까지 다시 프록시 리스너로 보내는 것입니다. 프록시 노드의 IP 주소와 포트를 미리 확인해 가로채기 규칙에서 제외하고, 주소가 자주 바뀌는 환경이라면 노드 IP 변경 시 방화벽 예외도 함께 갱신해야 합니다. 로컬 DNS, Docker 브리지 게이트웨이, 호스트 관리 주소도 목적에 맞게 제외하세요. 한편 owner 조건은 호스트 프로세스의 소유자를 기준으로 하므로, 전달되는 컨테이너 패킷을 제외하는 일반적인 수단으로 사용할 수 없습니다.
연결 문제 진단과 자주 묻는 질문
문제를 진단할 때는 컨테이너의 라우팅, 호스트의 방화벽 규칙, Mihomo 리스너, 프록시 노드 연결 순으로 경로를 나눠 확인합니다. 먼저 컨테이너 안에서 DNS 해석과 기본 연결을 확인하고, 다음으로 호스트에서 방화벽 카운터 및 패킷을 확인한 뒤, Mihomo의 연결 목록과 로그를 비교하세요.
docker exec app-container ip route docker exec app-container getent hosts example.com ss -lntup iptables -t nat -vnL PREROUTING iptables -t mangle -vnL PREROUTING tcpdump -ni br-app host 203.0.113.10
- 방화벽 규칙 카운터가 계속 0이면 잘못된 브리지 인터페이스나 CIDR을 사용했는지, 패킷이 실제로 해당 인터페이스를 통과하는지 확인합니다.
- 카운터는 증가하지만 연결이 실패하면 리스너의 바인딩 주소와 포트, Mihomo 로그, 정책 라우팅 테이블을 차례로 확인합니다.
- IP 주소로는 연결되지만 도메인으로 실패하면 DNS 서버 접근 경로, 컨테이너의 DNS 설정, UDP 53 제외 규칙을 검토합니다.
- 일부 사이트만 실패하면 내부 대역 제외와 프록시 노드 주소 예외, IPv6 우회 여부를 확인합니다.
REDIRECT와 TPROXY 중 무엇을 선택해야 하나요?
TCP만 먼저 프록시하고 싶다면 REDIRECT가 단순한 출발점입니다. UDP까지 투명하게 처리하거나 원래 목적지 정보를 보존해야 한다면 TPROXY를 검토하세요. 다만 TPROXY는 정책 라우팅과 커널 지원까지 필요하므로, 먼저 최소 범위에서 동작을 검증해야 합니다.
컨테이너 연결이 반복되거나 프록시 노드에도 접속할 수 없는 이유는 무엇인가요?
프록시 노드의 연결이 다시 가로채져 리스너로 되돌아오는 루프일 수 있습니다. 노드 IP를 제외 규칙에 추가하고, 적용 전후에 연결 목적지와 방화벽 카운터를 확인하세요. 노드 주소가 DNS 이름으로만 관리된다면 실제 연결 IP가 바뀌는 경우도 고려해야 합니다.
DNS도 반드시 투명 프록시해야 하나요?
반드시 그렇지는 않습니다. 컨테이너가 사용하는 DNS 경로가 안정적이고 정책에 맞다면 그대로 유지할 수 있습니다. DNS 요청을 가로채려면 Docker DNS의 전달 구조와 Mihomo DNS 리스너를 먼저 확인하고, 루프와 DNS 누출 가능성을 함께 점검하세요.
방화벽 규칙을 재부팅 후에도 유지하려면 어떻게 하나요?
배포판에서 사용하는 방화벽 관리 도구에 규칙을 통합하거나, Docker 네트워크가 준비된 뒤 규칙을 적용하는 시스템 서비스로 관리할 수 있습니다. 규칙 적용 순서와 중복 실행을 고려하고, 재부팅 후 브리지 이름이 바뀌지 않았는지 확인하세요. 운영 중인 호스트에서는 변경 전 복구 절차도 준비하는 것이 좋습니다.
Docker 투명 프록시는 단순히 포트를 열어 두는 작업이 아니라, 컨테이너의 패킷이 지나가는 경로와 DNS·예외 정책을 함께 맞추는 구성입니다. 우선 테스트용 bridge에서 TCP REDIRECT 또는 TPROXY 중 하나만 적용하고, Mihomo 로그와 방화벽 카운터로 동작을 확인한 다음 필요한 대역과 프로토콜을 단계적으로 확장하세요. 구성이 안정되면 사용 중인 Linux 방화벽 관리 방식에 맞춰 규칙을 영구화하고, Clash/Mihomo 클라이언트와 설정을 준비해 실제 게이트웨이에 적용할 수 있습니다.
Clash로 트래픽을 완전히 제어하세요
Windows, macOS, Linux, Android, iOS 지원. 유연한 규칙, 간단한 설정.