왜 컨테이너로 Mihomo인가
Mihomo는 Clash.Meta 계열 코어로, 단일 실행 파일과 YAML 프로필만 있으면 동작합니다. 그럼에도 운영 현장에서는 동일한 이미지 태그로 여러 호스트를 맞추거나, NAS 패키지 대신 직접 compose로 버전을 고정하고 싶은 경우가 많습니다. 컨테이너는 실행 환경을 묶어 주므로 배포판별 라이브러리 차이를 줄일 수 있고, docker compose pull && up -d 한 번으로 교체 시나리오를 문서화하기 쉽습니다. 다만 커널 TUN이나 호스트 전체 트래픽 후킹은 컨테이너만으로는 제약이 크므로, 본문에서는 먼저 인바운드 프록시 포트를 중심으로 한 구성을 기본으로 두고 TUN은 별도 절에서 한정적으로 다룹니다.
구독 원문이 Clash 형식이 아니라면 Subconverter 가이드로 YAML을 맞춘 뒤, 아래 볼륨 경로에 넣으면 컨테이너 재시작 없이 파일만 갈아끼우는 운영도 가능합니다. 전체 설정 개념은 문서·설정 허브와 같이 읽으면 구조가 잡힙니다.
네트워크 모델: 브리지와 게이트웨이 역할
기본 bridge 네트워크에서는 컨테이너가 사설 대역을 받고, 포트 퍼블리시로 호스트의 0.0.0.0:포트와 연결됩니다. 호스트 위 프로세스는 127.0.0.1:매핑포트로 컨테이너 안의 mixed-port에 접근합니다. 같은 LAN의 스마트폰·PC가 쓰려면 호스트 방화벽에서 해당 TCP 포트를 허용하고, 클라이언트에는 호스트의 LAN IP와 매핑된 포트를 적어야 합니다. “컨테이너가 게이트웨이”가 되게 만들려면 라우팅·iptables·별도 브리지 설계가 필요해 난이도가 올라가므로, 대부분의 가정·소규모 서버는 명시적 HTTP(S)·SOCKS 프록시 또는 상위 라우터의 프록시 지정과 짝을 이루는 패턴이 재현성이 좋습니다.
볼륨 마운트: 무엇을 호스트에 둘까
영속화하려면 최소한 구성 파일과 런타임 데이터(GEOIP 캐시, rule-provider 다운로드 등)를 호스트 디렉터리에 두는 것이 안전합니다. 예시 구조는 다음과 같습니다.
./mihomo/config/config.yaml— 메인 프로필(또는config.yml등 실행 인자에 맞춤)./mihomo/data/— 작업 디렉터리(-d와 동일 역할)
바인드 마운트는 NAS나 클라우드 VM에서 스냅샷·백업 정책과 바로 연결되므로, 이미지를 지워도 설정이 남습니다. 권한 문제가 나면 호스트 쪽 UID/GID를 이미지 문서에 맞추거나, 읽기 전용 마운트가 필요한 파일만 분리하세요. 민감한 구독 URL이 YAML에 들어 있다면 저장소에 올리지 말고, 배포 서버에서만 두는 습관이 좋습니다.
docker-compose 예시
아래는 개념을 보여 주는 예입니다. 실제 이미지 이름·태그는 사용 중인 레지스트리에 맞게 바꾸고, 코어 인자(-d 디렉터리)는 이미지 엔트리포인트에 따라 조정합니다.
services:
mihomo:
image: metacubex/mihomo:latest
container_name: mihomo
restart: unless-stopped
volumes:
- ./mihomo/config:/etc/mihomo
- ./mihomo/data:/var/lib/mihomo
ports:
- "7890:7890" # mixed-port (example)
- "9090:9090" # external-controller (example)
# For TUN inside container (advanced; host-specific):
# cap_add:
# - NET_ADMIN
# devices:
# - /dev/net/tun
# privileged: true
주의: 공식·커뮤니티 이미지마다 설정 경로·엔트리포인트가 다릅니다. 반드시 해당 이미지 README를 확인하고, 위 경로는 예시로만 사용하세요. privileged: true는 보안 면에서 최후 수단입니다.
프로필 쪽: 인바운드와 allow-lan
컨테이너 밖에서 접속하려면 YAML에 mixed-port 또는 port·socks-port를 compose의 ports와 숫자가 일치하게 맞춥니다. LAN 기기가 붙을 가능성이 있으면 allow-lan: true를 켜고, 불필요하면 끄는 편이 안전합니다. bind-address를 * 또는 0.0.0.0에 두어 컨테이너 안에서 모든 인터페이스에 바인딩해야 호스트 포워딩이 의미 있게 이어집니다. 외부 컨트롤러를 쓰는 경우 external-controller 포트도 같이 매핑할 수 있지만, 인터넷에 노출하지 말고 방화벽·SSH 터널 뒤에 두는 것이 일반적입니다.
DNS 동작은 호스트 resolver와 엇갈리기 쉽습니다. FakeIP·로컬 DNS 리스너를 쓰는 프로필이라면 DNS 유출 방지 가이드의 점검 순서를 컨테이너 기준으로 다시 적용해 보세요. 브리지 모드에서는 “컨테이너의 127.0.0.1”과 “호스트의 127.0.0.1”이 다릅니다.
호스트·다른 기기에서 붙이기
같은 머신의 브라우저·쉘은 http_proxy=http://127.0.0.1:7890처럼 매핑된 호스트 포트를 가리키면 됩니다. 다른 PC나 TV 박스는 http://서버_LAN_IP:7890 형태로 지정합니다. 투명 프록시나 게이트웨이 수준 가로채기는 OpenWrt·라우터 쪽 글의 맥락과 겹치므로, Docker 단독으로 “집 전체”를 바꾸려면 라우터 정책까지 설계해야 합니다.
헬스 체크로는 호스트에서 curl -x http://127.0.0.1:7890 -I https://www.google.com 같은 명령을 쓰면 컨테이너 인바운드까지 경로가 한 번에 검증됩니다. 실패 시 docker logs mihomo로 기동 오류를 보고, 포트 충돌이면 호스트에서 ss -lntp로 점유 여부를 확인하세요.
컨테이너 안 TUN에 대해
호스트 전체 트래픽을 컨테이너 TUN으로내려면 NET_ADMIN·/dev/net/tun·때로는 privileged가 필요하고, Docker Desktop·일부 NAS에서는 아예 막히는 경우가 있습니다. 그럴 때는 호스트에서 TUN을 쓰는 편이 단순합니다. 즉 Linux Mihomo·systemd·TUN 글의 패턴과 본 Docker 글은 같은 YAML을 공유하되 실행 위치만 다르게 두는 관계로 이해하면 됩니다. 컨테이너는 “프록시 데몬을 격리해 돌리는 층”, bare metal systemd는 “호스트 라우팅과 한 몸인 층”에 가깝습니다.
NAS·무중단 운영 팁
이미지 업데이트 전에 config.yaml을 백업하고, docker compose up -d로 롤링하세요. 다운로드가 많은 rule-provider는 data 볼륨에 쌓이므로 디스크 정책을 정해 두면 좋습니다. 여러 스택이 같은 호스트에서 7890을 쓰면 충돌하므로, 외부에 노출하는 포트는 17890:7890처럼 호스트 쪽만 바꿔도 됩니다. 로그 로테이션은 Docker 드라이버 설정이나 외부 수집 도구로 분리하는 것이 장기적으로 깔끔합니다.
트러블슈팅 요약
- 연결 거부: 포트 매핑·프로필 포트·
bind-address·방화벽을 같은 숫자로 맞췄는지 확인합니다. - LAN에서만 안 됨:
allow-lan과 호스트 OS 방화벽 인바운드 규칙을 봅니다. - 설정이 초기화됨: 볼륨이 빈 디렉터리에 마운트됐거나, 읽기 전용으로 덮어쓰기에 실패했는지 확인합니다.
- DNS만 이상: 컨테이너와 호스트의 DNS 해석 경로를 분리해 생각하고, FakeIP와 시스템 resolver 충돌을 제거합니다.
변수는 한 번에 하나만 바꾸고 로그를 남기는 습관이 유지 보수 비용을 줄입니다. compose 파일과 YAML을 Git으로 관리할 때는 시크릿은 제외하는 정책을 권장합니다.
클라이언트 패키지: 서버에는 코어만 두고, 일상 PC·폰에서는 GUI 클라이언트를 쓰는 경우가 많습니다. 설치 파일은 공식 다운로드 허브에서 플랫폼별로 고르고, GitHub는 소스·이슈 확인용으로 쓰면 혼선이 적습니다.
정리
Docker로 Mihomo를 돌리는 핵심은 세 가지입니다. compose로 실행 명령과 재시작 정책을 고정할 것, 볼륨으로 설정과 데이터를 호스트에 남길 것, 포트 매핑으로 인바운드를 호스트·LAN에 일관되게 열 것입니다. TUN까지 한 컨테이너에 우겨 넣기보다, 요구가 “집 전체 게이트웨이”에 가깝다면 Linux 호스트·라우터 글과 역할을 나누는 편이 안정적입니다.
같은 도구를 쓰더라도 배포 층을 명확히 하면 팀원도 같은 compose와 볼륨 경로로 재현할 수 있어, 장애 때 복구가 빨라집니다.
→ Clash 클라이언트를 무료로 내려받아, 서버의 Docker 코어와 짝을 이루는 데스크톱·모바일 환경을 함께 맞춰 보세요