왜 터미널이 아니라 systemd인가

Linux에서 Mihomo(Clash Meta) 계열 코어는 단순히 바이너리 하나를 실행하면 됩니다. 그러나 SSH 세션이 끊기면 같이 종료되거나, 예기치 않은 패닉·OOM 이후에 사람이 다시 켜 주지 않으면 프록시가 비는 문제가 생깁니다. 데스크톱에서 GUI 래퍼를 쓰지 않고 코어만 돌리거나, 소형 서버·홈랩에 상시 게이트웨이를 두려면 init 시스템이 프로세스 수명을 관리하는 편이 안전합니다. systemd는 서비스 단위로 의존 관계·재시작 정책·로그 수집을 표준화하므로, Windows·macOS용 GUI 튜토리얼과 달리 「Linux + 서비스화」라는 검색 의도에 직접 맞는 접근입니다.

이 글은 배포판별 패키지 설치법을 나열하기보다, 공식·커뮤니티에서 받은 단일 바이너리를 기준으로 흔한 경로(/usr/local/bin)와 설정 디렉터리를 잡고 유닛 파일을 만드는 흐름을 설명합니다. 네트워크 정책·서비스 약관·관할 법규는 환경마다 다르므로, 허용된 용도와 본인 책임 범위 안에서만 적용하시기 바랍니다. 용어와 기본 개념은 Clash 사용 문서와 함께 보는 것을 권장합니다.

1단계: 디렉터리·바이너리·계정 정리

서비스로 올리기 전에 실행 파일 위치설정 루트(-d로 넘기는 디렉터리)를 고정하는 것이 좋습니다. 예시는 다음과 같습니다(경로는 취향에 맞게 바꿔도 됩니다).

  • 바이너리: /usr/local/bin/mihomo — 릴리스 아카이브에서 받은 실행 파일 이름이 clash-meta 등이면 그 이름을 그대로 두되, ExecStart와 일치시키면 됩니다.
  • 설정 디렉터리: /etc/mihomo — 그 안에 config.yaml, ruleset·프로바이더 캐시 등을 둡니다.
  • 런타임에 쓰는 사용자: mihomo 같은 전용 시스템 유저를 만들고, 위 디렉터리 소유권을 맞춥니다. root로 장시간 돌리는 것보다 권한 분리가 유지보수에 유리합니다.

전용 계정을 만들었다면 대략 다음과 같은 명령으로 권한을 맞출 수 있습니다. 배포판에 따라 useradd 옵션은 조금씩 다를 수 있습니다.

sudo useradd --system --home /etc/mihomo --shell /usr/sbin/nologin mihomo
sudo chown -R mihomo:mihomo /etc/mihomo
sudo chmod 750 /etc/mihomo
sudo install -o root -m 0755 mihomo /usr/local/bin/mihomo

TUN 모드·특수 포트·캡처 권한이 필요한 구성이라면, 이 단계에서 capabilities나 별도 그룹 정책을 함께 설계해야 합니다. 단순 HTTP/SOCKS 리스너만 쓰는 경우가 가장 단순하고, 유닛 파일도 짧게 유지할 수 있습니다.

2단계: systemd 유닛 파일 작성

배포판 관례에 따라 /etc/systemd/system/mihomo.service에 아래와 비슷한 내용을 둡니다. ExecStart-d 인자는 실제 설정 경로로 바꿉니다.

[Unit]
Description=Mihomo (Clash Meta) proxy core
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=mihomo
Group=mihomo
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576

# Optional: send logs to journal (default if no file logging in app)
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

After=network-online.target는 부팅 직후 DNS·라우팅이 준비되기 전에 코어가 먼저 떠서 구독 URL을 가져오지 못하는 상황을 줄이는 데 도움이 됩니다. 완전한 보장은 아니므로, 여전히 실패하면 잠시 뒤 systemctl restart mihomo로 한 번 더 올리거나, 아래에서 설명하는 지연 타이머를 고려합니다.

Restart=on-failure는 비정상 종료 시에만 재시작합니다. 설정 오류로 즉시 다시 죽는 루프를 막고 싶다면 StartLimitIntervalSec·StartLimitBurst를 추가하는 방법도 있습니다. 반대로 「어떤 이유로든 항상 살아 있게」가 목표면 Restart=always를 검토할 수 있으나, 잘못된 YAML로 무한 재시작하는 경우 진단이 어려워질 수 있어 운영 성숙도에 맞게 선택하세요.

3단계: 등록·기동·확인

유닛을 저장한 뒤 데몬 리로드와 등록을 수행합니다.

sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
systemctl status mihomo.service

active (running)이면 기본적으로는 정상입니다. mixed-portport로 리슨하는지는 설정 파일과 ss -tlnp 등으로 확인합니다. 포트가 이미 다른 프로세스에 잡혀 있으면 기동 직후 실패할 수 있는데, 이때는 로그로 포트 충돌과 노드 타임아웃을 가르는 글과 함께 journalctl 출력을 보면 원인 분리가 빨라집니다.

4단계: 로그는 journalctl과 앱 설정을 함께

위 예시는 표준 출력·에러를 저널로 보냅니다. 운영자는 다음처럼 따라가면 됩니다.

journalctl -u mihomo.service -f
journalctl -u mihomo.service --since "1 hour ago"

코어 자체의 log-level과 파일 로깅 옵션을 YAML에서 켜 두었다면, 디스크 용량·로테이션(logrotate 등)까지 계획하는 것이 좋습니다. 장시간 debug는 I/O 부하가 커지므로, 문제 재현 구간에만 올렸다가 평시에는 info 전후로 내리는 습관이 안전합니다. 로그에 찍힌 bind·dial tcp 패턴이 다음 조치를 가르는지는 앞서 인용한 진단 글과 같은 맥락입니다.

5단계: 구독 갱신·리로드와 systemd 연계

Mihomo는 설정에 따라 프로필·프로바이더를 주기적으로 원격에서 당겨오는 기능을 갖습니다. profile-update-interval 등을 현실적인 값으로 두면, 별도 크론 없이도 구독이 갱신되는 경우가 많습니다. 다만 부팅 직후 네트워크가 늦게 올라오는 환경에서는 첫 갱신이 실패하고, 이후 주기까지 기다려야 할 수 있습니다. 이럴 때는

  • 네트워크가 안정된 뒤 systemctl restart mihomo.service로 한 번 더 기동하거나,
  • 별도 mihomo-wait-net.service처럼 ExecStartPre=/bin/sleep …를 쓰는 소형 유닛을 얹는 패턴(환경에 따라 비추천일 수 있음),
  • systemd timer로 매 시간·매일 짧은 health 체크 후 systemctl try-restart mihomo를 호출

같은 선택지가 있습니다. 운영 규모가 커지면 timer가 명시적이어서 감사·장애 대응에 유리합니다.

구독 파일을 외부 스크립트로만 갱신하는 구조라면, 파일을 덮어쓴 뒤 코어에 설정 리로드를 걸어야 트래픽이 끊기지 않는 경우가 많습니다. 코어 버전별로 REST API·시그널 지원이 다를 수 있으므로, 사용 중인 빌드 문서를 확인하고 curl로 API를 호출하거나, 안전하게 systemctl reload mihomo(ExecReload를 유닛에 정의한 경우) 같은 경로를 택하세요. ExecReload를 쓰지 않았다면 reload 대신 짧은 restart가 사실상의 운영 절차가 됩니다.

6단계: 바이너리 업그레이드 절차

코어를 새 버전으로 바꿀 때는 실행 중인 파일을 덮어쓰지 않도록 먼저 서비스를 멈추는 흐름이 일반적입니다.

sudo systemctl stop mihomo.service
sudo install -o root -m 0755 ./mihomo-new /usr/local/bin/mihomo
sudo systemctl start mihomo.service

변경 후 systemctl statusjournalctl -u mihomo -b로 기동 로그를 확인합니다. 메이저 업그레이드 후 YAML 키가 바뀌는 경우가 있으므로, 릴리스 노트와 Clash Meta(Mihomo) 업그레이드 가이드를 함께 보는 것이 좋습니다. 검증된 클라이언트 패키지와 코어 조합을 유지하려면 공식 다운로드 페이지에서 배포 채널을 정리해 두는 편이 이후 장비 확장에도 도움이 됩니다.

보안·권한·TUN에 대한 짧은 메모

서비스 유닛에는 NoNewPrivileges=true, PrivateTmp=true, ProtectSystem=strict 등 강화 옵션을 붙일 수 있지만, 설정 경로 읽기·쓰기·캐시 디렉터리에 맞게 ReadWritePaths를 정확히 열어 주지 않으면 오히려 기동 실패를 유발합니다. TUN·iptables·nft와 연동하는 고급 구성은 capabilities와 네트워크 네임스페이스 이해가 필요하므로, 본문 범위를 넘어서면 별도 문서·위키를 참고하는 것이 낫습니다.

정리

Linux에서 Mihomo를 systemd 서비스로 묶으면 부팅 후 자동 기동·비정상 종료 시 재시작·저널 기반 로그 조회라는 세 가지가 한 번에 정리됩니다. 구독은 코어 내장 주기와 timer·수동 재시작을 조합해 네트워크 타이밍에 맞추고, 장애 시에는 포트 충돌과 업스트림 실패를 로그 키워드로 나누면 대응이 단순해집니다. GUI 클라이언트가 없는 서버 환경에서도 동일한 패턴을 재사용할 수 있다는 점이 이 접근의 장점입니다.

기억할 점: systemd는 프로세스를 살려 주는 도구일 뿐, 잘못된 YAML·만료된 구독·노드 장애를 자동으로 「고쳐 주지」는 않습니다. 유닛은 안정적인 실행 틀을 제공하고, 원인 분석은 여전히 로그와 설정 검증이 담당합니다.

데스크톱에서는 래퍼 앱이 편할 때가 많지만, 게이트웨이·CI 러너·원격 박스처럼 항상 켜 두어야 하는 Linux에는 systemd 한 줄기가 여전히 가장 예측 가능한 선택입니다. 규칙·DNS·프로토콜을 한 트리에서 다루는 Clash 계열의 장점은, 서비스화한 뒤에도 동일하게 유지됩니다.

→ Clash를 무료로 내려받아, Linux 코어 운영과 데스크톱 클라이언트를 함께 맞춰 보세요