Gateway 아키텍처 (Gateway Architecture)

에이전트와 외부 세상을 이어주는 단일 장수명 프로세스. “모든 메시징 표면을 소유”하며, 하나의 포트에서 Slack·텔레그램·웹훅·WebChat·크론잡을 멀티플렉싱으로 처리한다. 채널별 세션 생성·분배의 실제 주체이자, 에이전트가 외부 세상과 통신하는 유일한 경로다.

핵심 설계 원칙: 포트 하나, 프로세스 하나

에이전트와 통신하는 외부 경로는 다양하다:

  • Slack 메시지 (팀원 지시)
  • 텔레그램 (모바일 접속)
  • 웹훅 (외부 서비스 이벤트 — 채널톡, 포털 등)
  • WebChat (웹 UI)
  • 크론잡 / 하트비트 (자동 스케줄)

이 모든 경로가 하나의 Gateway를 통과한다. 채널별 서버를 따로 운영하는 게 아니다.

외부 채널들
  Slack ──────┐
  텔레그램 ───┤
  웹훅 ───────┼──→ Gateway (포트 하나) ──→ 에이전트 → 응답
  WebChat ────┤      멀티플렉싱
  크론잡 ─────┘

기본 포트: 18789 (openclaw.json에서 변경 가능)

세션 라우팅의 실제 주체

agent-session-architecture에서 “채팅 컨텍스트 = 세션 1개” 원칙을 배웠다. 그 채널별 세션 생성과 분배를 실제로 수행하는 주체가 Gateway다.

  • Slack 채널a에서 메시지 → Gateway가 Slack 채널a 세션 생성 또는 기존 세션으로 라우팅
  • 텔레그램에서 메시지 → Gateway가 텔레그램 세션으로 라우팅
  • 웹훅 POST → Gateway가 hooks.mappings 설정에 따라 지정 에이전트·세션으로 전달

(출처: bbojjak-openclaw-gateway-architecture-lesson14)

데몬(Daemon) — 365일 24시간 대기

Gateway는 macOS launchd가 관리하는 데몬 프로세스.

  • 서버 시작 시 자동 실행
  • 충돌 시 launchd가 자동 재시작
  • 새벽 3시 크론잡, 주말 CS 문의, 집사의 해외 여행 중에도 계속 대기

“한 번 시작하면 꺼질 때까지 계속 돌아가는 프로세스.”

hooks.mappings — 웹훅 라우팅 설정

외부 웹훅을 특정 에이전트의 특정 세션으로 연결하는 Gateway 설정:

{
  "hooks": {
    "mappings": {
      "agent": {
        "agentId": "bbojjak",
        "sessionKey": "hook:ingress",
        "transform": "channeltalk-transform.js"
      }
    }
  }
}

/hooks/agent로 POST 요청이 오면 → bbojjak 에이전트의 hook:ingress 세션으로 전달.

보안: 인증 토큰 없이 요청 → 401 Unauthorized / 올바른 토큰 → 202 Accepted

loopback 바인딩과 외부 접근

Gateway는 기본적으로 loopback(로컬호스트) 바인딩. 같은 컴퓨터에서만 접근 가능한 안전한 기본값.

외부 접근이 필요한 경우(웹훅 수신, 원격 접속):

  • tailscale Serve — tailnet 전용 사설 접근. 신분증 인증 자동 처리.
  • tailscale Funnel — 인터넷 전체 공개. 반드시 비밀번호 필수.
인터넷 → Tailscale Funnel (HTTPS) → loopback → Gateway

Gateway는 인터넷에 직접 노출되지 않음. Tailscale이 안전한 터널.

loopback/LAN 선택의 실전 기준

yt-fastcampus-openclaw-security-3checks-2026는 bind 전략을 “문을 어디까지 열 것인가”로 설명한다.

  • loopback: 기본값. 해당 머신 내부 접근만 허용(가장 안전)
  • LAN: 같은 내부 네트워크 장치 접근 허용(편의성↑, 노출면↑)

권장 패턴은 loopback으로 시작하고, 원격 제어 필요가 확인된 뒤 LAN/터널(Tailscale)로 점진 확장하는 것이다. 즉, Gateway 설계는 기능 우선이 아니라 노출면 최소화 → 검증 후 확장 순서를 따라야 한다.

openclaw.json 통합 설정

openclaw.json에서 Tailscale 모드를 설정하면 Gateway 시작 시 자동으로 Funnel을 켜준다:

{
  "tailscale": {
    "mode": "funnel"
  }
}

tailscale funnel --bg 수동 실행의 “재시작 후 사라짐” 문제를 설정 파일 한 줄로 해결.

보안 4중 잠금

  1. Tailscale Funnel: HTTPS 기본 (TLS 인증서 자동 관리)
  2. Gateway: Bearer 인증 토큰 필수
  3. 허용된 에이전트 ID만 웹훅 호출 가능
  4. 세션 키 프리픽스 제한으로 임의 세션 접근 차단

n8n 클라우드 대비 “겹겹이 잠긴 문” 구조로 더 안전.

DM 보안 기본값 — dmPolicy=“pairing”

OpenClaw Gateway는 DM 페어링을 보안 기본값으로 채택한다. 알 수 없는 발신자는 자동 처리되지 않는다. (출처: openclaw-github-readme)

모르는 발신자 DM → Gateway → 짧은 페어링 코드 발급 + 처리 거부
                              ↓ 사용자가 approve
openclaw pairing approve <channel> <code>
                              ↓
                        로컬 허용 목록에 추가 → 이후 정상 처리

공개 DM 허용 시 명시적 opt-in 필요:

{
  "channels": {
    "telegram": { "dmPolicy": "open", "allowFrom": ["*"] }
  }
}

보안 감사: openclaw doctor — 위험하거나 잘못 설정된 DM 정책 탐지.

agent-security-design 참조 (심층 방어 원칙).

운영 함정: 포트 불일치

OpenClaw 기본 포트(18789)와 실제 Gateway 포트(44350)가 다를 때 Funnel 설정이 기본값으로 남아있으면 웹훅이 허공에 사라진다.

체크리스트:

  • Funnel 포트 = 실제 Gateway 포트 일치 확인
  • 재시작 후 Funnel 유지 → openclaw.json tailscale.mode: "funnel" 설정

실전 적용

  • OpenClaw의 뽀짝이 — Slack·텔레그램·채널톡 CS 웹훅·크론잡을 단일 Gateway로 처리
  • 채널톡 CS 파이프라인: 채널톡 → n8n → Gateway /hooks/agent → 에이전트 직접 처리

bindings — 채널→에이전트 명시 매핑

멀티에이전트 환경에서 채널별 담당 에이전트를 명시하면 Gateway가 자동 라우팅한다. (출처: bbojjak-openclaw-multichannel-session-lesson15)

{
  "bindings": [
    { "match": { "channel": "slack" }, "agentId": "뽀짝이" },
    { "match": { "channel": "telegram", "peer": { "kind": "group" } }, "agentId": "뽀야" }
  ]
}

Slack 메시지 → 뽀짝이 → Slack 답장 / 텔레그램 → 뽀야 → 텔레그램 답장. 에이전트가 채널을 판단할 필요 없음.

multichannel-session-management 참조.

관련 개념

소스