무색
기술블로그
에세이
연구
소개

무색

소프트웨어로 비즈니스의 가능성을 만듭니다. 웹·앱 개발, 음성 AI, 자동화 콘텐츠 제작까지 — 기술이 필요한 곳에 무색이 있습니다.

연락처

contact@museck.com

사업자 정보

상호: 무색

대표: 배성재

사업자등록번호: 577-58-00836

인천광역시 연수구 인천타워대로 323, 에이동 8층 801-802호 AB-132 (송도동, 송도 센트로드)

© 2026 무색. All rights reserved.
개인정보처리방침·이용약관·연락처
INCHEON, KR
OpenClaw AI 게이트웨이를 홈랩에 배포한 이야기
홈랩 삽질기
2026. 1. 4.

OpenClaw AI 게이트웨이를 홈랩에 배포한 이야기

openclawnvidia-nimdockertraefiknfs

AI 에이전트 게이트웨이가 왜 필요했나

요즘 AI 에이전트를 이것저것 만들다 보면 한 가지 불편한 점이 생긴다. Telegram 봇 하나, Discord 봇 하나, 웹 챗봇 하나... 채널마다 따로 관리해야 하는 게 점점 귀찮아진다. 그래서 이번에 OpenClaw라는 오픈소스 AI 게이트웨이를 홈랩에 올려봤다. 여러 채널을 하나로 묶어서 관리할 수 있고 백엔드 AI 모델도 자유롭게 바꿔 끼울 수 있어서 꽤 마음에 들었다.

AI 백엔드로는 NVIDIA NIM 무료 티어의 Kimi K2.5 모델을 연결했다. OpenAI 호환 API를 제공해서 연동이 간단하다.

배포 구성: WSL Docker + K8s 프록시 패턴

내 홈랩 구조에서 GPU가 붙은 건 윈도우 머신뿐이라 WSL Docker에서 OpenClaw를 돌리기로 했다. 문제는 외부에서 HTTPS로 접근하게 만드는 건데, 전에 만들어둔 패턴을 그대로 쓰면 된다.

흐름을 정리하면 이렇다.

  1. K8s에 Service + Endpoints를 만들어서 WSL의 IP:포트를 가리킨다
  2. IngressRoute로 openclaw.xssh.org 도메인을 연결한다
  3. Windows portproxy로 외부 요청을 WSL 안쪽으로 포워딩한다
  4. Traefik이 TLS 종단과 라우팅을 처리한다

이 패턴은 WSL에서 돌아가는 서비스를 K8s 클러스터에 통합할 때 반복적으로 쓰는 방식이다. Service의 ClusterIP를 None으로 두고 Endpoints에 실제 IP를 넣는 것만 이해하면 어떤 서비스든 같은 방식으로 노출할 수 있다.

reverse proxy 뒤에서 WebSocket 서비스 운영하기

컨테이너를 띄우고 포트도 열었는데 Control UI에 접속하면 이런 에러가 뜬다.

disconnected (1008): pairing required

원인은 간단하다. OpenClaw가 보안상 device pairing을 요구하는데 reverse proxy를 거치면 클라이언트 IP가 실제 브라우저 IP가 아니라 Docker bridge gateway IP(172.18.0.1)로 찍힌다. OpenClaw 입장에서는 "이 IP 누구야?" 하면서 pairing을 요구하는 거다.

처음에는 dangerouslyDisableDeviceAuth 옵션을 써봤다. 이름부터 불길한데 실제로도 문제가 생겼다. device 객체 자체를 null로 만들어버려서 scope 관련 에러가 줄줄이 터졌다. 이름에 dangerously가 붙은 옵션은 역시 쓰면 안 되는 거였다.

올바른 해결 방법은 trustedProxies와 allowInsecureAuth를 조합하는 것이다.

{
  "gateway": {
    "trustedProxies": ["172.18.0.1"],
    "controlUi": {
      "allowInsecureAuth": true
    }
  }
}

trustedProxies에 Docker bridge gateway IP를 넣으면 X-Forwarded-For 헤더를 신뢰해서 실제 클라이언트 IP를 올바르게 인식한다. allowInsecureAuth는 device pairing 과정을 건너뛰게 해준다. dangerouslyDisableDeviceAuth와 달리 device 객체는 그대로 유지되기 때문에 scope 문제도 없다.

보안 설정을 비활성화하는 옵션 중에 "dangerous"가 붙은 건 보통 부작용이 크다. 정확한 원인을 파악하고 최소한의 설정 변경으로 우회하는 게 훨씬 낫다.

NFS 권한 문제: all_squash로 UID 매핑 통일

OpenClaw를 배포하면서 동시에 NFS 공유 스토리지의 오래된 문제도 해결했다. K8s Pod, WSL, n8n 컨테이너가 전부 uid 1000으로 NFS에 접근하는데 서로 다른 환경에서 온 uid 1000이 NFS 서버에서 같은 사용자로 인식되지 않는 경우가 있었다.

해결책은 NFS 서버에 all_squash 옵션을 추가하는 거다. 이 옵션을 켜면 어떤 uid로 접근하든 전부 nobody:nogroup으로 매핑된다. 크로스 플랫폼 환경에서 uid 충돌을 원천 차단하는 셈이다.

n8n 메모리 부족과 NFS 쓰기 권한

n8n도 같이 손봤다. 메모리 제한이 512Mi로 잡혀 있었는데 워크플로우가 복잡해지면서 OOM으로 죽는 일이 잦아졌다. 1Gi로 올려서 해결.

NFS에 파일을 쓰려고 하면 권한 에러가 나는 문제도 있었다. n8n은 보안상 N8N_RESTRICT_FILE_ACCESS_TO 환경변수로 파일 접근 경로를 제한하는데 NFS 마운트 경로가 허용 목록에 없었던 거다. /shared를 추가해주니 바로 해결됐다.

정리하며

이번 작업을 한 줄로 요약하면 "AI 게이트웨이 하나 올리려다 NFS 권한까지 고쳤다" 정도가 되겠다. 홈랩이 그렇다. 뭔가 하나 건드리면 옆에 있던 문제가 같이 눈에 들어온다.

기억해둘 만한 포인트는 두 가지.

  • reverse proxy 뒤에서 WebSocket 서비스를 운영할 때는 trustedProxies에 프록시 IP를 등록해야 한다. dangerouslyDisable* 류의 옵션보다 allowInsecureAuth 같은 정밀한 대안을 찾자.
  • NFS를 크로스 플랫폼으로 공유할 때 uid 매핑 문제가 생기면 all_squash로 통일하는 게 가장 깔끔하다.

자주 묻는 질문

reverse proxy 뒤에서 WebSocket 서비스가 pairing required 에러를 내는 이유는?
프록시를 거치면 클라이언트 IP가 Docker bridge IP로 바뀌어 서비스가 신원을 확인하지 못합니다. trustedProxies에 프록시 IP를 등록하면 X-Forwarded-For 헤더를 신뢰해서 실제 IP를 올바르게 인식합니다.
NFS에서 크로스 플랫폼 UID 충돌을 해결하는 방법은?
NFS 서버에 all_squash 옵션을 추가하면 모든 접근을 nobody:nogroup으로 매핑합니다. K8s Pod, WSL, 컨테이너 등 서로 다른 환경의 uid 충돌을 원천 차단할 수 있습니다.
dangerouslyDisableDeviceAuth 옵션을 쓰면 안 되는 이유는?
device 객체 자체를 null로 만들어 scope 관련 에러가 연쇄적으로 발생합니다. 대신 trustedProxies + allowInsecureAuth 조합으로 최소한의 설정만 변경하는 것이 안전합니다.
홈랩 삽질기(11/19)
Prev

내부 AI 서비스를 Cloudflare Tunnel로 외부에 공개하기

Next

Postiz 소셜 미디어 자동화 배포: Helm OCI + Temporal 삽질기