OpenClaw는 깔았는데 Gateway를 공인 인터페이스에 직접 붙이고 싶지 않은 팀은 Ubuntu 24.04급 VPS에서 리슨 주소 선택, systemd로 예측 가능한 재시작, Cloudflare Tunnel(또는 동급)으로 루프백만 통제된 호스트명 뒤에 두는 방법에서 막히기 쉽습니다. 본 글은 Docker 운영 가이드·멀티플랫폼 설치 가이드를 보완하는 베어메탈 + systemd + 터널 루트로, 환경 기준선·Gateway 설정 포인트·Unit 예시·ingress·증상별 분기를 정리하고, 안정적인 원격 Mac을 실행층으로 두는 대표 토폴로지와 운영 이득(빌드·에이전트 장기 안정)을 함께 제시합니다.
멀티플랫폼 글은 ‘일단 실행’에 초점을 둡니다. Docker 운영 글은 컨테이너 표준과 Compose/오케스트레이션으로 배포를 맞추려는 팀용입니다. 여기서는 베어메탈 Ubuntu 24.04에서 추상화를 최소화하고, systemd로 장애 복구와 부팅 시 자동 기동을 맡으며, Cloudflare Tunnel(또는 자체 리버스 프록시)로 TLS·접근 제어를 앱 밖으로 빼는 흐름을 다룹니다. 세 경로는 배타적이지 않습니다. 먼저 베어메탈에서 안정화한 뒤 컨테이너화해도 됩니다.
아래 여섯 가지는 티켓에서 반복되는 인지 편차입니다. 맞춘 뒤에야 이후 체크리스트가 의미 있습니다.
‘curl 성공’을 ‘운영 보안’과 동일시: 0.0.0.0에 전면 프록시 없이 바인딩하면 인증·TLS가 앱 기본값에 의존합니다. 설정이 한 번만 어긋나도 광역 스캔 대상이 됩니다.
Node 런타임과 glibc 결합을 간과: 24.04에서 오래된 프리빌드나 잘못된 NODE_OPTIONS는 ‘로컬에선 됨, systemd에선 안 됨’ 같은 거짓 양성을 만듭니다.
작업 디렉터리·권한을 /root에 임의 배치: 업그레이드나 로그 로테이션 후 권한이 바뀌면 설정을 못 읽고 systemd가 연속 재시작합니다. 로그도 묻힙니다.
헬스가 프로세스 존재만 확인: HTTP 준비 완료나 상위 모델 제어 평면 연결을 보지 않으면 LB는 계속 보내고 터널은 502를 반환해, 잘못된 층을 디버깅하게 됩니다.
터널은 살아 있는데 포트가 다름: cloudflared ingress와 Gateway 실제 리슨이 어긋나면 DNS는 되지만 루프백 포트는 맞지 않습니다.
Linux 게이트웨이를 만능 워커로 사용: Xcode·시뮬레이터·Apple Silicon 특화 작업을 VPS에 억지로 올리면 ‘OpenClaw 불안정’처럼 보이지만 실제로는 계층 배치 문제입니다.
‘루프백 + 터널’이 맞다면 이어지는 환경 기준과 명령으로 진행하면 됩니다.
설치 속도만 보지 말고 공격면·관측 가능성·롤백 경로를 한 줄에 놓고 비교하세요. 표는 리뷰용이며 포트·이미지 태그는 실제 값으로 바꿉니다.
| 축 | Gateway 공인 바인딩 | Docker / Compose 운영 | systemd + 루프백 + Tunnel |
|---|---|---|---|
| 노출 | 최대. TLS·FW가 앱 층에 집중 | publish 포트·네트워크 모드에 따름. host 네트워크 오설정 위험 | 프로세스는 127.0.0.1만. 공인 입구는 터널/엣지 |
| 인증서 | 자체 ACME 또는 수동 로테이션 | Traefik / Caddy / 클라우드 LB 전면 배치가 흔함 | Cloudflare 엣지에서 TLS 종료(또는 동급) |
| 재시작·장애 분석 | 외부 슈퍼바이저 또는 수동 | restart 정책·로그 드라이버를 별도 설계 | systemd 재시작·journal이 순서가 분명함 |
| 적합 팀 | 최소 PoC, 운영 비권장 | 컨테이너 거버넌스·이미지 공급망이 있는 조직 | 단일 VPS, 스크립트 재현성을 중시하는 중소 팀 |
운영 게이트웨이의 핵심은 ‘접속 가능 여부’가 아니라 ‘어떤 경로로 누가 허가되는가’입니다. 리슨을 루프백으로 줄이면 그 질문을 앱이 아니라 엣지로 옮깁니다.
Ubuntu 24.04 LTS 기준으로 현재 Node.js LTS 메이저(2026년 초에는 대개 22.x, 기준은 nodejs.org)를 따릅니다. nvm·fnm·NodeSource 모두 가능하나 운영에서는 마이너 버전을 고정하고 업그레이드 창을 기록합니다. 배포판 패키지의 node만으로는 보통 부족합니다.
방화벽: SSH는 키만, ufw 기본 deny incoming, Gateway 서비스 포트에는 공인 규칙을 열지 않습니다(외부는 터널만). 직접 디버깅이 필요하면 시간 제한 화이트리스트나 점프 호스트를 쓰고 변경 로그에 해제 시각을 남깁니다.
전용 사용자·경로: 예: 사용자 openclaw, 실행 상태 /var/lib/openclaw, 설정 /etc/openclaw(640/750). root와 섞지 않습니다.
고정 Node와 lockfile: package-lock.json 또는 pnpm-lock.yaml을 유지하고 운영 설치는 npm ci 등으로 메이저가 올라가지 않게 합니다.
glibc·네이티브 모듈: 대상 머신에서 클린 설치와 스모크로 dlopen 오류를 배제합니다.
타임존: timedatectl을 UTC 또는 팀 표준으로 맞춰 터널·엣지 로그와 상관시킵니다.
ufw 최소: ufw allow OpenSSH 후 ufw enable. 업무 포트는 닫고 ss -tlnp로 공인에서 Gateway가 보이지 않는지 확인합니다.
헬스 엔드포인트: 터널 전에 curl -fsS http://127.0.0.1:PORT/health(경로는 설정에 맞춤)을 Runbook에 적고 ExecStartPost·외부 프로브와 일치시킵니다.
안내: OpenClaw CLI와 설정 파일명은 상위 문서를 따릅니다. 아래 Unit·YAML의 경로·포트는 치환용 예시이며 실제 경로에 맞춘 뒤 활성화하세요.
리슨: 운영에서는 127.0.0.1:PORT를 권장합니다. 지원 시 Unix 소켓을 추가할 수 있습니다. 시크릿: 환경 파일로 주입하고 world-readable 설정에 넣지 않습니다. 로테이션은 새 토큰 작성 → 롤링 재시작 → 구 토큰 삭제 순입니다. 헬스: 프로세스 생존 + HTTP 준비 또는 모델 제어 평면 도달 중 최소 하나는 포함해야 합니다. 그렇지 않으면 터널은 ‘연결 안 됨’만 알려 줄 뿐 ‘잘못된 계층’은 알려 주지 않습니다.
[Unit] Description=OpenClaw Gateway (loopback) After=network-online.target Wants=network-online.target [Service] User=openclaw Group=openclaw WorkingDirectory=/var/lib/openclaw EnvironmentFile=-/etc/openclaw/gateway.env # ExecStart는 공식 문서의 실제 시작 명령으로 바꿉니다 ExecStart=/usr/bin/node /opt/openclaw/gateway.mjs --config /etc/openclaw/gateway.yaml Restart=on-failure RestartSec=5 LimitNOFILE=1048576 # 로그는 journal 우선, 파일이면 logrotate와 권한 설정 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
권장 순서: systemctl daemon-reload → systemctl enable --now openclaw-gateway → systemctl status로 메인 프로세스 안정 확인 → 로컬 curl 헬스 → 이후 cloudflared.
tunnel: <YOUR_TUNNEL_ID>
credentials-file: /etc/cloudflared/<YOUR_TUNNEL_ID>.json
ingress:
- hostname: claw.example.com
service: http://127.0.0.1:8787
- service: http_status:404
주의: 터널 자격 JSON은 root 또는 전용 사용자만 읽도록 합니다. 이미지 레이어나 공개 CI 로그에 넣지 마세요. Nginx/Caddy로 TLS를 끝내도 엣지 TLS·업스트림 루프백 구조는 동일하게 유지합니다.
로그 확인 순서: ① journalctl -u openclaw-gateway -b --no-pager(재시작 루프·env) ② 앱 로그 디렉터리 ③ journalctl -u cloudflared ④ curl -v를 로컬·외부에서 각각 실행해 프로세스 문제와 라우팅 문제를 분리합니다.
포트: EADDRINUSE면 ss -tlnp로 점유 프로세스 확인, 좀비 배제. 포트 변경 시 ingress·내부 프로브 동기화. 권한: EACCES는 설정·키의 owner/group과 systemd User 일치 확인. 터널: 외부 502·로컬 curl 정상이면 ingress, Cloudflare 연결, DNS 존 순. 모델: 타임아웃/401은 서버에서 벤더 베이스라인 API를 curl(시크릿은 셸 히스토리에 남기지 않음)해 이그레스 차단·토큰 만료를 배제합니다.
전형적 분리: Linux VPS에 공개 Gateway·큐·가벼운 오케스트레이션, 안정적인 원격 Mac(물리 Apple Silicon)에 Xcode 빌드·시뮬레이터·macOS 전용 툴체인. 무거운 작업은 Mac으로 넘기면 ‘게이트웨이 공개 바인딩 없음’ 정책을 유지하면서 Linux에 맞지 않는 부하를 피합니다. Mac은 주문형 실행 노드, Linux는 자체 운영 컨트롤 플레인으로 보고 SSH·큐·사설 터널로 연결합니다. 장애 도메인을 분리: 게이트웨이 장애가 Mac 빌드 캐시를 무의미하게 만들지 않게 하고, Mac 점검 창이 전체 API 입구를 멈추게 하지 않습니다.
127.0.0.1과 단일 포트로 고정해 듀얼스택 전 인터페이스 오바인드를 줄입니다.Restart=on-failure와 RestartSec=5로 로그 가독성 확보, 필요 시 StartLimitIntervalSec.localhost 대신 http://127.0.0.1:PORT로 명시해 IPv4만 바인딩할 때 ::1 불일치를 줄입니다.Linux VPS+터널만으로는 컨트롤 플레인·API 집약에는 적합하지만 iOS CI/CD, 시뮬레이터, Metal, Xcode 체인에서는 한계가 빨리 드러납니다. 헤드리스 원격의 호환성 타협이나 이미지·운영 비용 누적 중 하나를 택하게 됩니다. 무거운 작업을 전용·유지보수 창이 예측 가능한 Apple Silicon 원격 Mac에 두고 게이트웨이는 익숙한 systemd+터널을 유지하면 영향 범위가 분명해집니다. 에이전트·빌드 파이프라인을 장기 안정으로 돌리려는 팀에는 NodeMini Mac mini 클라우드 임대가 대개 더 나은 선택입니다. 컨트롤 플레인은 자체 VPS에, 실행은 Apple 생태계에 맞춘 하드웨어·임대 기간에 맡깁니다.
운영에서는 루프백만 수신하는 구성을 강력히 권장합니다. TLS와 접근 정책은 터널·리버스 프록시가 담당합니다. 공인 포트가 필요하면 화이트리스트·속도 제한·감사가 필요하며 대개 터널보다 복잡합니다. 추가 글은 OpenClaw 칼럼을 참고하세요.
서버에서 루프백으로 curl해 Gateway 준비를 확인하고, 터널 ingress·자격 증명을 점검한 뒤 상위 모델·DNS를 의심합니다. 실행 노드 주문 전 임대 가격으로 기간·리전을 맞추세요.