← 목록
기타 2026-06-10 13KB 읽기 15분

크라우니 회복탄력성 · 모니터링 (2026-06-10)

개요

세션독립 관리시스템(워치독), monitor.crowny.org, :9100 admin 상주화, tiomta.com 외부 :443/:80 복구 — 4개 트랙 작업 결과와 메인루프 적용 런북. 모든 검증은 비파괴(라이브 무손상).

라이브 재확인 시각 기준 상태(이 문서 작성 시점 실측):

대상상태비고
gateway :8080 (한선씨 평문)LISTEN(PID 1204) · 200apex tiomta.com Host 라우팅 200
gateway :8443 (stunnel TLS)LISTEN(PID 1202) · 200stunnel-live.conf, 로컬 tiomta TLS 200
watchdog :9201 API200 · 22개 감시 · crowny-tiomta 포함PID 14762, launchd org.crowny.watchdog
monitor :9743200 · LISTEN(PID 73285)고아 프로세스(소스/launchd 없음) — 개선본 미반영
admin :9100200(/health) · LISTEN(PID 1207)이미 상주
tiomta.com :443 (외부)000 (timeout) — 다운로컬 :443 리스너 부재. 단발 200 관측됐으나 3연속 재시도 전부 000 → 미복구 확정
tiomta.com :8443 (외부)000라우터가 8443으로 포워드 안 함
핵심: 보고서 작성 이후 라이브가 이동했다. T1(워치독 22개)·T3(admin 상주)는 이미 라이브 반영됨. T2(monitor 개선)·T4(:443 외부복구)만 미적용 → 메인루프 적용 대상.

T1 — 세션독립 서비스 관리(워치독) 고도화 [라이브 반영 완료]

  • 커버 서비스 18→22. 누락 4건 추가(모두 node server.js, 실측 LIVE):
  • crowny-tiomta :9878 /Users/ef/crowny-tiomta health=/api/health(200) → tiomta.com
  • crowny-mpti :9907 /Users/ef/crowny-mpti health=/api/health(200) → mpti.tiomta.com
  • crowny-amti :9813 /Users/ef/crowny-amti health=/(200; /api/health 404 → 루트) → amti.crowny.org
  • crowny-abti :9811 /Users/ef/crowny-abti health=/(200; /api/health 000 → 루트) → abti.crowny.org
  • 지수 백오프: 재기동 후 헬스 실패 시 backoffStep++ → 다음 재시작 20/40/80/160/300s(상한)로 지연,
  • 정상화 시 즉시 리셋. (관측된 crowny-dex 매 사이클 재시작 루프 해결.) 인터벌 10s 유지. maxRestarts=5/5분 상한.
    • startAPI(:9201) EADDRINUSE 핸들러: 'listen EADDRINUSE :9201 → Node 전체 크래시' 방어(API만 비활성, 감시 지속).
    • status()에 backoffStep/nextRestartIn 노출 → /status·/history 가시화.
    • 한선씨 동반본 서비스감시.한선(포트프로브/백오프지연/서비스점검/재기동 4함수) 컴파일+실행 검증
    (백오프 0→0,1→20,3→80,9→300 JS 일치). 패턴 학습 완료(intent: 서비스감시_포트프로브_지수백오프재기동).

    현재 라이브: /Users/ef/crowny-infra/crowny-stack.yaml에 crowny-tiomta 포함 확인, 워치독 PID 14762가 22개 감시 중 → 보고서의 '핫리로드 없음' 블로커는 해소됨(launchd 재기동이 이미 일어남). 관련 파일: watchdog.js, crowny-stack.yaml(buildWatchdogServices=22), 서비스감시.한선.


    T2 — monitor.crowny.org 현황 + 개선 + 워치독 연동 [미적용 → 런북]

    현황(개선 전)

    라이브 :9743은 crownyc(한선씨) 프로세스로 200이나:
    1. 소스 .한선 부재 + launchd 미등록 = 고아 프로세스(/tmp/crowny-monitor.toau 디스크 소실).
    2. UI가 구형 다크테마(#0f1117/파랑) — 클로드 밸런스 아님.
    3. 금융 6~7개 서비스만 모니터(전 서비스 아님).
    4. 워치독 복구 정보 전무.

    개선

    /Users/ef/crowny-gateway/한선게이트웨이/모니터개선.한선 (순수 한선씨 15KB, 빌드 .toau 동반).
    • 클로드 밸런스 디자인(kraft #F4F2EC, 카드 #FBFAF7, 코랄 #D97757, Georgia, ✳, TOAU △○▽●).
    • 전 서비스 실시간 상태: gateway-status.json(38서비스) up/down 카드 + Ti/Om/Ta pill.
    • 워치독 자가복구: watchdog-status.json에서 recovered/ti/ta/rate/마지막점검 + 미복구(failed 28건) 목록.
    • 신규 엔드포인트: /api/services /api/recovery /api/status(Ti/Om/Ta 요약) /health.
    • 데이터 소스: /Users/ef/.crowny-infra/logs/{gateway-status.json, watchdog-status.json}.

    검증

    그림자 포트 :19743(라이브 :9743 무단종료 없이) 컴파일+기동+헤드리스. 4 엔드포인트 JSON OK: /api/status={ti:38}, /api/services=38(up38), /api/recovery={rate:53.3, failed 28}, /health=200. 검증 후 그림자 종료, 라이브 :9743 내내 200.

    한선씨 함정 3건(우회 적용)

    1. 읽기()는 9MB+ append-only 로그 선두 ~9KB만 → tail 불가 → 정형 JSON 소스 사용.
    2. 글자() 바이트 재조립이 한글 멀티바이트 경계에서 NUL(0x00) 손상.
    3. Content-Length=글자수()는 한글 본문 잘림 → Connection:close만.

    런북 (메인루프 — 자가복구 안전망 하)

    bash# :9743 현재 고아 프로세스. 동일포트 순차교체(비파괴 불가).
    cd /Users/ef/CrownyOS/crownyc
    ./hanseonc_high /Users/ef/crowny-gateway/한선게이트웨이/모니터개선.한선 \
      > /Users/ef/crowny-gateway/한선게이트웨이/모니터개선.toau
    OLD=$(lsof -nP -iTCP:9743 -sTCP:LISTEN -t); kill $OLD; sleep 1
    nohup /Users/ef/CrownyOS/crownyc/crownyc run \
      /Users/ef/crowny-gateway/한선게이트웨이/모니터개선.toau \
      > /Users/ef/.crowny-infra/logs/crowny-monitor.log 2>&1 &
    sleep 2; curl -s http://127.0.0.1:9743/api/recovery | head -c 120
    # 영속화: crowny-stack.yaml에 crowny-monitor 추가(command=위 nohup) → 워치독 :9743 TCP 프로브 감시.
    # 포트는 crowny-ports.sh로 등록됨(monitor.crowny.org→9743).
    


    T3 — :9100 admin(관리자.한선) 상주 서버화 [라이브 반영 완료 · :9100 현재 200]

    3가지 수정:

    1. 진입점 분기(~L291): 무조건 단위검증() → ADMIN_SELFTEST=="1"일 때만 단위검증(),
    그 외 관리자수신부(관리자수신포트). = 상주화 핵심.
    1. 포트 환경변수화: 수신포트결정() — 환경변수("GW_ADMIN_PORT") 정수 파싱, 미설정/<=0 → 9100.
    함정: 한선씨 환경변수()(ENV_GET op448, crownyc.c:10028)는 미설정 시 정수 -1 반환("-1"). → (a) n<=0 가드로 흡수, (b) ADMIN_SELFTEST를 포함()으로 보면 "-1"이 "1" 부분포함해 오탐 → ==동등비교로.
    1. 인증서리로드() 재작성: 기존 curl POST :9100/certs/renew = 자기참조 데드락 →
    stunnel(stunnel-live.conf)에 pkill -HUP graceful reload. 라이브 stunnel(PID 53275)에 실제 HUP 전달 검증, :8443 유지.

    런처(게이트웨이기동.sh L87)는 이미 GW_ADMIN_PORT=9100 + ADMIN_SELFTEST 미설정 → 수정 소스가 자동 상주 분기. cert-manager.sh 계약(ADMIN_API=:9100, GET /status→200, POST /certs/renew→200) 충족.

    런북 (즉시 적용 — 위험변경: 게이트웨이 재기동 동반)

    bashbash /Users/ef/crowny-gateway/한선게이트웨이/게이트웨이재기동.sh
    curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:9100/health   # 200
    curl -s http://127.0.0.1:9100/status                                    # engine:hanseon, port:9100
    curl -s -o /dev/null -w "%{http_code}\n" -X POST http://127.0.0.1:9100/certs/renew  # 200(stunnel HUP)
    
    현재 :9100은 이미 200(상주 확인). 다음 재기동 사이클에 수정본이 안정 상주.

    T4 — tiomta.com 외부접속 :443/:80 복구 [미적용 → 최우선 런북]

    외부경로 결론

    • tiomta.com → 공인 112.144.147.144 = 이 호스트 egress IP. LAN 192.168.219.153, 라우터 192.168.219.1(en1).
    DNS는 hosting.kr(mode:hosting), A레코드 공인IP 직지정.
    • 외부 :443/:80 = 000(timeout)(refused 아님) → 라우터가 공인 443/80을 내부로 포워드하나 내부 LISTEN 부재.
    • 현재 라이브: stunnel :8443 + crownyc :8080만. :443/:80 비어있음(재확인됨).
    • 로컬 :8080 H 라우팅 정상(apex Host→200), apex TLS도 ext 마스터 cert(SAN tiomta.com/www 포함) 종단 가능.
    → 백엔드·라우팅·인증서 모두 준비됨. 막힌 건 외부 :443/:80 종단 LISTEN 뿐.

    openclaw 정체(무관)

    ai.openclaw.gateway/-gemini/-sonnet = crowny-genesis(/Users/ef/crowny-genesis/dist/index.js) AI 게이트웨이. :18789/:18790/:18791(+내부18793) bind. :443/:80 절대 안 건드림. 양보협상 불필요.

    권한

    macOS는 <1024 비루트 bind 제한 없음. 레거시 node가 동일 사용자 ef로 :443/:80 bind해 동작 = 증거. sudo 불필요.

    준비물(비파괴 생성 완료 · 검증됨)

    • stunnel_conf_gen.py live443 모드 추가(live 모드 출력 byte-identical 회귀확인).
    • stunnel-live-443.conf(697줄 · 25KB 확인됨): master[https443]+SNI슬레이브97, accept=0.0.0.0:443→connect 127.0.0.1:8080.
    stunnel 5.78 바이너리 로드 OK. apex는 슬레이브 미존재→마스터 ext cert fallback(SAN 유효).
    • :80 리다이렉트는 게이트웨이통합.한선GW_PORT=80 GW_REDIRECT=1 지원(L469~476, 301).

    런북 (메인루프 전용 · 자가복구 안전망 하 · 기존 :8080/:8443 무손상)

    bashcd /Users/ef/crowny-gateway/한선게이트웨이
    
    # [1] 충돌 사전점검
    lsof -nP -iTCP:443 -sTCP:LISTEN; lsof -nP -iTCP:80 -sTCP:LISTEN   # 현재 둘 다 free
    
    # [2] :443 stunnel 2차 인스턴스 기동(foreground=no 자체 데몬화)
    /opt/homebrew/bin/stunnel /Users/ef/crowny-gateway/한선게이트웨이/stunnel-live-443.conf
    sleep 1; lsof -nP -iTCP:443 -sTCP:LISTEN; tail -5 /tmp/stunnel-live-443.log
    
    # [3] :80 → 301 리다이렉트 한선씨 인스턴스
    export PATH="/Users/ef/CrownyOS/crownyc:$PATH"; export CROWNY_STD="/Users/ef/Downloads/CrownyTVM/std"
    /Users/ef/CrownyOS/crownyc/hanseonc_high \
      /Users/ef/crowny-gateway/한선게이트웨이/게이트웨이통합.한선 > /tmp/gwlive.toau
    GW_PORT=80 GW_REDIRECT=1 nohup /Users/ef/CrownyOS/crownyc/crownyc run /tmp/gwlive.toau \
      > /tmp/gw80.log 2>&1 &
    echo $! > /tmp/gw80.pid; sleep 1; lsof -nP -iTCP:80 -sTCP:LISTEN
    
    # [4] 검증 (로컬 → 외부)
    curl -sk --resolve tiomta.com:443:127.0.0.1 https://tiomta.com:443/ -o /dev/null -w "local443=%{http_code}\n"
    curl -s  --resolve tiomta.com:80:127.0.0.1  http://tiomta.com:80/  -o /dev/null -w "local80=%{http_code}(301)\n"
    curl -sk --max-time 10 https://tiomta.com/ -o /dev/null -w "EXTERNAL443=%{http_code}\n"
    curl -s  --max-time 10 http://tiomta.com/  -o /dev/null -w "EXTERNAL80=%{http_code}(301)\n"
    
    # [4-대안A] 외부 여전히 000이면: 라우터 포워드 타겟이 8443일 가능성.
    curl -sk --max-time 10 https://tiomta.com:8443/ -o /dev/null -w "ext8443=%{http_code}\n"
    #  → 8443=200이면 라우터 타겟=8443(이미 :8443 라이브가 받음, [2] 불필요). 라우터를 443→443으로 변경 권장.
    #  → 8443=000이면 라우터 포워드 자체 부재 → 라우터 admin에서 공인443→192.168.219.153:443 추가 필요.
    
    # [5] 영속화 (검증 통과 후) — 게이트웨이기동.sh "go" stunnel 기동 직후 + 재기동.sh 정리 루프에 80/443 추가.
    
    # [롤백] (외부영향 즉시 제거 · 라이브 :8443/:8080 무손상)
    pkill -f stunnel-live-443.conf; [ -f /tmp/gw80.pid ] && kill -TERM "$(cat /tmp/gw80.pid)"
    
    # [충돌처리] :443 선점 시 stunnel bind 실패('Address already in use') → 즉시 [롤백] 후 선점 PID 정체 파악.
    #  openclaw(:18789~91)는 :443 미사용이라 무관.
    

    잔여 블로커

    라우터 포워드 타겟(공인443→내부443 vs →8443)은 호스트 내부에서 확정 불가 → 외부 curl([4]/[4-대안A])로만 판별. pf NAT는 sudo 비번 필요로 미확인이나 라우터단 포워딩이라 호스트 pf 무관.


    메인루프 즉시 적용 우선순위

    1. T4 — tiomta.com :443 외부복구 (최우선, 사용자 외부접속 차단 상태). 런북 [1]→[2]→[3]→[4].
    외부 000 지속 시 [4-대안A]로 라우터 타겟 판별 → 라우터 설정 또는 8443 유지 결정.
    1. T2 — monitor :9743 개선본 교체(고아 프로세스 → 영속화). 동일포트 순차교체.
    2. T3 — admin :9100: 이미 200 상주. 다음 게이트웨이 재기동 사이클에 안정화(능동 조치 불요, 모니터만).
    3. T1 — 워치독 22개: 이미 라이브 반영(PID 14762). 추가 조치 불요.

    관련 파일

    • /Users/ef/crowny-gateway/한선게이트웨이/모니터개선.한선 · 모니터개선.toau
    • /Users/ef/crowny-gateway/한선게이트웨이/stunnel-live-443.conf (697줄)
    • /Users/ef/crowny-gateway/한선게이트웨이/stunnel_conf_gen.py (live443 모드)
    • /Users/ef/crowny-gateway/한선게이트웨이/관리자.한선 · 게이트웨이통합.한선 · 게이트웨이기동.sh · 게이트웨이재기동.sh
    • /Users/ef/crowny-infra/crowny-stack.yaml (워치독 22서비스 SSOT) · watchdog.js
    • 서비스감시.한선 (T1 한선씨 동반)
    • 로그/데이터: /Users/ef/.crowny-infra/logs/{watchdog.log, gateway-status.json, watchdog-status.json}