OpenWrt 라우터에 mihomo 커널 배포하기: 서브 라우터 우회 분리 실전 기록

프록시 커널을 PC에서 라우터로 옮기는 것은 많은 가정 네트워크의 최종 형태입니다. TV, 게임기처럼 클라이언트 설치가 어려운 기기까지 한 번에 관리할 수 있기 때문입니다. 이 글은 OpenWrt 서브 라우터에 mihomo(Clash Meta) 커널을 배포하는 전체 과정을 다룹니다. 배포 방식 선택, 바이너리 설치, 구독 설정 적용부터 TUN 트래픽 인수, procd 데몬 등록, 트래픽 분리 검증까지 단계별로 바로 따라 할 수 있는 명령어와 명확한 체크포인트를 함께 제시합니다.

mihomo 커널·TUN 인수 모드·procd 부팅 데몬·OpenWrt 23.05 테스트 환경

1. 배포 형태: 메인 라우터 직접 설치인가, 서브 라우터인가

라우터에서 프록시 커널을 구동하려면 먼저 커널을 어느 기기에 설치할지 결정해야 합니다. 두 형태는 사용 범위가 명확히 다르며, 형태 선택을 잘못하는 것이 초보자가 가장 흔하게 겪는 실패 원인입니다.

메인 라우터 직접 설치

커널이 게이트웨이에서 직접 동작하므로 내부망의 모든 트래픽이 자연스럽게 경유하고 클라이언트 쪽 설정도 필요 없습니다. 다만 결합도가 지나치게 높다는 대가가 따릅니다. 커널 다운, 규칙 오류, 메모리 부족 등 어느 한 곳이라도 문제가 생기면 온 집안이 인터넷이 끊깁니다. 또한 NAT와 암복호화가 같은 칩에서 동시에 처리되므로 연산 부담이 가장 크고, 100Mbps 이상 대역폭의 저사양 MIPS 기기는 대부분 감당하지 못합니다.

서브 라우터(단일 암 게이트웨이)

별도 기기를 하나 더 준비합니다. 사용하지 않는 TV 셋톱박스, 라즈베리 파이, 소형 x86 미니 PC 모두 가능합니다. 여기에 OpenWrt를 설치하고 메인 라우터가 있는 내부망에 연결한 뒤 같은 서브넷의 고정 IP를 부여합니다. 프록시를 거쳐야 하는 기기는 기본 게이트웨이와 DNS 서버를 이 서브 라우터로 지정하면 되고, 관리 대상이 아닌 기기는 그대로 두면 서로 영향을 주지 않습니다. 서브 라우터가 멈추면 게이트웨이를 메인 라우터로 되돌리기만 하면 10초 안에 인터넷이 복구되므로 위험이 완전히 분리됩니다.

이 글은 서브 라우터를 중심으로 설명합니다. 두 형태 모두 커널 설치와 설정 부분은 완전히 동일하며, 차이는 트래픽 진입점뿐입니다. 메인 라우터 직접 설치를 선택한 독자는 4장의 '게이트웨이 지정' 항목을 건너뛰어도 됩니다.

정리

서브 라우터의 가장 큰 가치는 성능이 아니라 되돌릴 수 있다는 점입니다. 어떤 설정 실수를 해도 10초면 원래대로 복구할 수 있는 안전망이 있는 셈입니다. 프록시 커널을 운영 네트워크에 들이기 전에 먼저 깔아두는 안전 장치입니다.

2. 커널 선택과 설치

mihomo는 원조 Clash 커널이 아카이브된 뒤 커뮤니티가 이어서 유지보수하는 분기 버전(옛 Clash.Meta)으로, 단일 파일 바이너리로 배포되어 별도 의존성 없이 OpenWrt에서 곧바로 실행할 수 있어 현재 라우터 배포용으로 가장 먼저 고려되는 커널입니다. 릴리스 산출물은 gzip으로 압축된 순수 바이너리이며 CPU 아키텍처별로 패키지가 나뉘므로, 가장 먼저 할 일은 자신의 기기 아키텍처를 정확히 파악하는 것입니다.

SSH로 라우터에 접속해 uname -m을 실행하고, 아래 표를 참고해 다운로드할 패키지를 선택합니다:

uname -m 출력값대표 기기release 파일명 키워드
aarch64라즈베리 파이 4/5, NanoPi R4S, 대다수 ARM 기기linux-arm64
armv7l라즈베리 파이 2/3(32비트 시스템), 구형 개발 보드linux-armv7
mipselMT7621 등 MIPS 라우터(K2P, 신삼 등)linux-mipsle-softfloat
x86_64소프트웨어 라우터용 미니 PC, 가상머신linux-amd64-compatible

흔히 실수하는 두 가지가 있습니다. 첫째, x86 소프트웨어 라우터는 compatible 접미사가 붙은 패키지를 선택해야 합니다. OpenWrt의 x86 빌드는 비교적 오래된 명령어 집합을 대상으로 하므로 일반 amd64 패키지는 일부 CPU에서 Illegal instruction 오류를 곧바로 일으킵니다. 둘째, MT7621 같은 MIPS 기기는 리틀 엔디언이며 대부분 하드웨어 부동소수점 유닛이 없으므로 반드시 mipsle-softfloat 패키지를 선택해야 합니다.

arm64 기기를 예로 든 전체 설치 명령은 다음과 같습니다:

opkg update
opkg install curl ca-bundle kmod-tun
curl -L -o /tmp/mihomo.gz https://github.com/MetaCubeX/mihomo/releases/download/v1.19.5/mihomo-linux-arm64-v1.19.5.gz
gunzip /tmp/mihomo.gz
mv /tmp/mihomo /usr/bin/mihomo
chmod +x /usr/bin/mihomo
mihomo -v

마지막 줄 mihomo -v가 버전 번호를 출력하면 아키텍처를 올바르게 선택한 것입니다. Illegal instruction이나 Exec format error가 뜨면 위 표를 다시 확인해 패키지를 바꿔서 시도하세요. 명령어의 버전 번호는 예시일 뿐이므로 다운로드 전에 mihomo의 releases 페이지에서 현재 안정 버전과 정확한 파일명을 확인하시기 바랍니다. kmod-tun도 이 단계에서 함께 설치되며 4장에서 사용됩니다.

정리

/tmp는 OpenWrt에서 메모리 디스크이므로 재부팅하면 초기화되며 임시 중계용으로만 적합합니다. 커널과 설정 파일은 반드시 /usr/bin, /etc/mihomo처럼 플래시 저장소에 남겨야 합니다. 플래시 용량이 32MB 미만인 기기는 먼저 extroot를 구성하거나 외부 저장소를 사용해야 합니다. 그렇지 않으면 GeoIP 데이터베이스조차 저장할 공간이 없습니다.

3. 설정 적용: 구독 다운로드와 핵심 항목

설정 디렉터리는 /etc/mihomo로 정하고, 커널을 -d /etc/mihomo 옵션으로 실행하면 이 디렉터리에 config.yaml, GeoIP 데이터베이스, 캐시 파일이 차례로 생성됩니다. 먼저 디렉터리를 만들고 구독을 내려받습니다:

mkdir -p /etc/mihomo
curl -L -o /etc/mihomo/config.yaml "구독 주소"

대부분의 서비스 업체는 Clash 계열 클라이언트가 요청할 때 YAML 설정을 바로 반환하므로, 이를 config.yaml로 저장하면 그대로 사용할 수 있습니다. 만약 base64로 인코딩된 노드 목록이 내려온다면 서버가 범용 구독 형식을 반환한 것이므로, 요청에 Clash의 User-Agent를 지정하거나 PC에서 먼저 변환한 뒤 scp로 라우터에 업로드해야 합니다. 라우터에서 직접 구독 변환 프로그램을 구동하는 방식은 유지보수 부담이 커지므로 권장하지 않습니다.

구독을 받은 뒤에는 서브 라우터 역할에 맞게 아래 핵심 항목만 수정하고 나머지는 구독 원본 그대로 둡니다:

mixed-port: 7890            # HTTP와 SOCKS 통합 진입점
allow-lan: true             # 내부망 기기 접속 허용, 서브 라우터는 반드시 켜야 함
bind-address: "*"
log-level: warning
external-controller: 0.0.0.0:9090   # 외부 제어 인터페이스
external-ui: ui             # 패널 정적 파일 디렉터리
secret: "원하는 비밀번호로 변경"
dns:
  enable: true
  listen: 0.0.0.0:1053
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  nameserver:
    - 223.5.5.5
    - 119.29.29.29
  fallback:
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
tun:
  enable: true
  stack: system
  auto-route: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

세 항목이 서브 라우터의 정상 동작을 결정합니다. allow-lan을 켜지 않으면 내부망 기기가 7890 포트에 아예 접속할 수 없고, external-controller를 0.0.0.0에 바인딩해야 PC 브라우저에서 패널에 접근할 수 있습니다. tun 항목은 다음 장에서 다룰 트래픽 인수의 핵심입니다. 수정을 마친 뒤에는 커널 내장 검사 기능으로 문법을 확인합니다:

mihomo -t -d /etc/mihomo

configuration file test is successful이 출력되면 통과입니다. 오류가 나면 구체적인 줄 번호가 함께 표시되므로 해당 줄을 찾아 수정하세요.

정리

external-controller를 내부망에 노출할 때는 반드시 secret을 설정해야 하며, 절대 공용망에 매핑해서는 안 됩니다. 9090 포트는 노드 전환, 연결 조회, 설정 변경까지 모든 권한을 가지고 있으므로 무방비로 두는 것은 네트워크 출구를 같은 서브넷의 누구에게나 넘겨주는 것과 같습니다.

4. 트래픽 인수: TUN 모드와 게이트웨이 지정

인수 방식은 TUN을 선택합니다. 이유는 라우팅 관리를 커널 내부로 흡수하기 때문입니다. 활성화하면 mihomo가 utun이라는 가상 네트워크 카드를 생성하고, auto-route가 자동으로 라우팅 규칙을 기록해 자체 발생 트래픽과 전달되어 온 TCP, UDP 트래픽을 모두 커널로 흡수합니다. iptables REDIRECT 규칙을 직접 작성하거나 UDP를 별도로 처리할 필요가 없습니다. stack은 system이 호환성이 가장 좋고, 처리량을 높이려면 gvisor로 바꿔 비교 테스트해볼 수 있습니다.

TUN을 쓰려면 커널 레벨 지원이 필요하며, 2장에서 설치한 kmod-tun이 바로 이를 위한 준비입니다. 디바이스 노드가 존재하는지 확인합니다:

ls /dev/net/tun

/dev/net/tun이 출력되면 정상입니다. 없다고 나오면 kmod-tun이 제대로 설치되지 않았거나 로드되지 않은 것이므로 재설치 후 재부팅하세요.

클라이언트 게이트웨이 지정

서브 라우터는 어떤 기기와도 직접 연결되어 있지 않으므로 트래픽이 '지정'을 통해 흘러들어와야 합니다. 권장 순서대로 세 가지 방법이 있습니다:

  1. 메인 라우터 DHCP로 배포: 메인 라우터의 DHCP 옵션에서 게이트웨이(option 3)와 DNS(option 6)를 서브 라우터 IP로 변경하면 집안 모든 기기가 무의식적으로 전환되고, 새로 연결되는 기기도 자동으로 적용됩니다.
  2. 개별 기기 수동 지정: 필요한 기기만 게이트웨이와 DNS를 변경하고 나머지는 메인 라우터에 직접 연결합니다. 서브 라우터만의 세밀한 제어 방식으로, 우선 한 기기로 테스트해보기에 적합합니다.
  3. 서브 라우터에서 DHCP 자체 구축: 메인 라우터의 DHCP를 끄고 서브 라우터가 대신 관리합니다. 제어력은 가장 강하지만 서브 라우터가 고장 나면 집안 전체가 IP를 받지 못하므로 초보자에게는 권장하지 않습니다.

시스템 단에서 확인할 것이 두 가지 더 있습니다. OpenWrt는 기본적으로 IP 포워딩이 켜져 있으며 sysctl net.ipv4.ip_forward로 값이 1인지 재확인할 수 있습니다. 방화벽 쪽에서는 '네트워크 → 방화벽 → 영역'으로 들어가 utun 장치를 lan 영역의 장치 목록에 추가해야 합니다. 그렇지 않으면 전달되어 온 트래픽이 netfilter 단계에서 차단되어, 클라이언트가 서브 라우터에는 접속되지만 어떤 웹페이지도 열리지 않는 증상이 나타납니다.

5. 부팅 자동 실행: procd에 맡기기

OpenWrt의 서비스 관리자는 procd이며, init 스크립트 하나만 작성하면 부팅 시 자동 실행과 크래시 시 재기동 기능을 모두 얻을 수 있습니다. /etc/init.d/mihomo 파일을 새로 만들고 아래 내용을 입력합니다:

#!/bin/sh /etc/rc.common
# mihomo 커널 데몬 스크립트
START=99
STOP=10
USE_PROCD=1

start_service() {
    procd_open_instance mihomo
    procd_set_param command /usr/bin/mihomo -d /etc/mihomo
    procd_set_param respawn 3600 5 5
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}

respawn 줄의 세 숫자는 순서대로 임계값, 간격, 재시도 횟수를 의미합니다. 프로세스가 종료되면 5초 후 다시 기동하고, 1시간 안에 5회 넘게 반복해서 크래시하면 재시도를 포기한다는 뜻입니다. stdout과 stderr는 syslog로 리다이렉트되므로 이후 logread로 커널 로그를 확인할 수 있습니다. 실행 권한을 부여하고 활성화합니다:

chmod +x /etc/init.d/mihomo
/etc/init.d/mihomo enable
service mihomo start

enable을 실행하면 /etc/rc.d에 S99로 시작하는 심볼릭 링크가 생성되어 라우터를 재부팅해도 커널이 자동으로 실행됩니다. 구독 갱신도 간단히 자동화할 수 있습니다. crontab에 매주 새벽 config.yaml을 다시 다운로드한 뒤 service mihomo restart를 실행하는 작업을 등록해두면 노드 목록을 항상 최신 상태로 유지할 수 있습니다.

6. 검증 및 문제 해결 체크리스트

배포가 끝났다고 트래픽 분리가 제대로 되는 것은 아닙니다. 아래 순서대로 하나씩 확인하고, 각 단계마다 명확한 판단 기준을 두세요:

  1. 프로세스 실행 확인

    pgrep mihomo에 결과가 출력되고 /etc/init.d/mihomo status가 running으로 표시되어야 합니다. 최초 실행 시 GeoIP 데이터베이스를 /etc/mihomo로 자동 다운로드하므로 해당 디렉터리에 쓰기 권한과 충분한 여유 공간이 있는지 확인하세요.

  2. 로그 확인

    logread -e mihomo에서 반복되는 오류가 없어야 합니다. 같은 줄의 오류가 계속 반복된다면 대개 설정 또는 네트워크 문제이므로 오류 메시지를 따라 원인을 찾으세요.

  3. 패널 접속 확인

    브라우저에서 http://서브라우터IP:9090/ui를 열고 secret을 입력하면 실시간 연결 상태를 볼 수 있어야 합니다. external-ui가 가리키는 ui 디렉터리에는 먼저 metacubexd나 zashboard의 빌드 결과물을 풀어 넣어야 합니다.

  4. DNS 인수 확인

    클라이언트에서 nslookup www.google.com 서브라우터IP를 실행했을 때 fake-ip 모드에서 198.18.x.x 대역 주소가 반환되면, 조회가 커널을 통과했으며 우회 경로로 유출되지 않았음을 의미합니다.

  5. 출구 확인

    클라이언트에서 IP 조회 사이트를 열면 노드의 출구 주소가 표시되어야 합니다. 이어서 중국 본토 사이트를 방문해 직접 연결로 정상 속도가 나오는지 확인하면 트래픽 분리가 성립된 것입니다.

자주 발생하는 문제와 해결책:

여기까지 마치면 자가 복구, 되돌리기, 필요에 따른 트래픽 인수가 모두 가능한 서브 라우터 배포가 완료됩니다. 이후 유지보수는 두 가지만 신경 쓰면 됩니다. mihomo의 버전 업데이트 주기를 챙기는 것과 /etc/mihomo 디렉터리를 정기적으로 백업하는 것입니다. 이 디렉터리에는 모든 설정과 데이터베이스가 들어 있으므로 기기를 교체할 때는 디렉터리 전체를 옮기기만 하면 됩니다.

Clash 다운로드