← 목록
게이트웨이 2026-05-27 10KB 읽기 12분

Gateway Health Monitor — 3대 false-alarm 근본 수정

날짜: 2026-05-27 대상: /Users/ef/crowny-gateway/scripts/health-monitor.sh 범위: 반복 발생 알람 3종의 근본 원인 식별 + 수정 + 검증

개요

5/27 새벽부터 10분 간격으로 동일한 false alarm 3종이 반복 발생. 일제 진단으로 근본 원인을 식별하고 수정. 진짜 장애 1건(code/agent 백엔드 down)도 함께 복구.

진단 결과 (시작 시점)

/Users/ef/.crowny-infra/logs/health-monitor.log 10분 주기 알람:

알람빈도1차 진단
포트 충돌 :9736 — crowny-avls 대신 / 실행 중매 라운드False — PID 59072의 cwd가 / (데몬 fork 후)
SSL SAN 누락 ~170 도메인 — certbot 재발급 필요매 라운드False — 단일 fullchain.pem만 검사
외부 접속 실패: code/agent/bank.crowny.org매 라운드bank는 즉시 해결, code/agent는 진짜 백엔드 죽음

근본 원인 + 수정

1. :9736 무한 충돌 (Bug A)

원인: health-monitor.sh:378-380 에서 lsof -p $pid | grep cwd 로 작업 디렉토리 비교.

  • node 데몬은 fork 후 cwd/로 변경 → 모든 비교 FAIL
  • kill → 재시작 → 새 PID도 동일하게 cwd=/ → 10분 후 또 충돌 알람 → 무한 루프
수정 (scripts/health-monitor.sh:378-382): cwdps -o command= (cmdline 매칭)

bash# 변경 전
local cwd=$(lsof -p "$pid" 2>/dev/null | grep cwd | awk '{print $NF}')
if [ -n "$cwd" ] && ! echo "$cwd" | grep -q "$expected_dir"; then

# 변경 후
local cmdline=$(ps -p "$pid" -o command= 2>/dev/null)
if [ -n "$cmdline" ] && ! echo "$cmdline" | grep -q "$expected_dir"; then

검증:

  • PID 59072 cmdline = /opt/homebrew/bin/node /Users/ef/crowny-avls/server.js → "crowny-avls" 포함 ✓
  • 재시작 후 :9736 알람 0건 확인

2. SSL SAN false-alarm 폭주 (Bug B)

원인: check_ssl_san()crownybus.com/fullchain.pem 단일 인증서만 검사. 게이트웨이는 ssl.js 에서 crownybus.com, crownybus.com-ext, real-crowny 3개 인증서를 합쳐서 도메인별 SecureContext 로드. 비교 기준이 1/3 → 나머지 2/3에 포함된 도메인이 모두 "누락" 판정.

수정 (scripts/health-monitor.sh:337-372): certbot/live/*/fullchain.pem 전체를 순회해 SAN을 합쳐서 비교.

bashfor sub in "$live_dir"/*/; do
  cert="${sub}fullchain.pem"
  sans=$(openssl x509 -in "$cert" -noout -ext subjectAltName ...)
  cert_sans="${cert_sans}${sans}"$'\n'
done
cert_sans_sorted=$(echo "$cert_sans" | sort -u)

검증:

  • 알람 메시지에 (N개 인증서 합산) 라벨 추가 → 어떤 모드인지 명시
  • 첫 라운드: 누락 도메인 145→53개로 감소 (잔여는 진짜 SAN 미포함 — certbot 재발급 대상)

3. code/agent 백엔드 진짜 down (Bug C — 실제 장애)

원인:

  • /Users/ef/crownycode-remote/gateway.js (포트 9900) 죽음
  • /Users/ef/crownycode-remote/agent/server.js (포트 9901) 죽음
  • 게이트웨이의 Trident가 Ta(장애)로 표시 → 503 응답
  • health-monitor SERVICES 목록에 code/agent 미등록 → 자동 복구 불가
복구: 둘 다 nohup node 로 재시작.

bashcd /Users/ef/crownycode-remote && nohup node gateway.js >> .../crowny-code-9900.log 2>&1 &
cd /Users/ef/crownycode-remote/agent && nohup node server.js >> .../crowny-agent-9901.log 2>&1 &

검증:

  • 9900/9901 LISTEN 확인
  • 30초 후 Trident 자동 복구 탐색 → 게이트웨이 경유 200 OK

작업 후 상태

  • :9736 알람: 12:19:29 이후 0건 ✓
  • SSL SAN 알람: "3개 인증서 합산" 모드 동작, 잔여 누락 도메인 53개 (진짜 미포함 — 추후 certbot 작업)
  • code/agent: 게이트웨이 경유 200 OK ✓
  • 36 서비스 중 28~31 UP (점진 복구 중 — enterprise/downloads/market 등 자동복구 진행)

잔여 이슈 → 후속 4작업 진행

(1) code/agent SERVICES 등록 — 완료

scripts/health-monitor.sh:56-57 에 두 줄 추가:
bash"code|9900|http://127.0.0.1:9900/health|node|false|$NODE /Users/ef/crownycode-remote/gateway.js"
"agent|9901|http://127.0.0.1:9901/health|node|false|$NODE /Users/ef/crownycode-remote/agent/server.js"
검증: gateway-status.json"code":"up", "agent":"up" 표시. 서비스 수 36→38.

(2) SSL SAN 51개 certbot 재발급 — Plan 완료 (실 발급은 사용자 승인 후)

핵심 발견: 누락 53개 중 51개가 정상 도메인, 10개는 yaml 설정 오류(pay, crns, crowny-dist, remote*, 티옴타작업소 등 도메인 suffix 누락).

선결조건 발견: 누락 51개 중 44개가 NXDOMAIN — hosting.kr DNS A 레코드 부재.

  • HTTP-01 챌린지는 도메인이 게이트웨이 IP로 resolve되어야 가능. NXDOMAIN 상태에선 챌린지 실패.
  • 우선 hosting.kr 패널에서 와일드카드 *.crowny.org, *.tiomta.com, *.crownybus.com A 레코드 추가 필요 (가장 빠른 방법).
추천 전략: crownybus.com-ext 확장 (10→59 SAN), main(93) 한계여유 확보.
bashsudo certbot certonly \
  --config-dir /Users/ef/crowny-data/certs/certbot \
  --webroot --webroot-path /Users/ef/crowny-gateway/webroot \
  --cert-name crownybus.com-ext --key-type ecdsa \
  --allow-subset-of-names --expand --dry-run \
  $(xargs -a /tmp/missing-sans.txt -I D printf '%s\n' '-d D')

위험: hosting.co.kr NS의 간헐적 CAA SERVFAIL (Phase 4 이슈) — crowny.org. CAA 0 issue "letsencrypt.org" 선제 추가 권장.

(3) 외부 접속 점검 실패 — 진단 완료

근본 원인: 라우터(192.168.219.1) NAT 포트포워딩 부재 또는 끊김.
  • 호스트: 80/443/8080/8443 모두 LISTEN 정상 (PID 27394 게이트웨이)
  • LAN IP: 192.168.219.153, 공인 IP: 112.144.147.144 (KT)
  • 외부 IP의 80/443에 즉시 Connection refused (filtering이면 timeout이 나야 함)
  • DNS 해석 OK, 호스트 LISTEN OK → 라우터 NAT가 단일 후보
사용자 수동 조치: http://192.168.219.1 관리 페이지에서
  • 외부 80 → 192.168.219.153:80 매핑
  • 외부 443 → 192.168.219.153:443 매핑
  • 활성/대상 IP 일치 확인 (DHCP 변경 시 어긋남)
보조 발견: agent.crowny.org는 DNS A 레코드 자체가 없음 — hosting.kr 패널 추가 필요.

(4) health-monitor 한선씨 동반본 포팅 — 완료

scripts/health-monitor.한선 에 추가:
  • 함수 트림(s) — 개행/공백 제거 (한선씨 네이티브)
  • 함수 포트충돌검사() — bash의 check_port_conflicts 한선씨 등가
  • 함수 SSL_SAN검사() — bash의 check_ssl_san 한선씨 등가
  • 메인 루프에 두 함수 호출 추가
  • 가져오기 "문자열.한선" 추가
한선씨 토큰화 주의사항 발견:
  • ${var} 셸 변수 보간이 한선씨 토크나이저에 식별자로 잡힘 → xargs로 회피
  • 다른 라이브러리에 정의된 함수(예: 시작확인)가 가져오기에도 호출 안 될 때가 있음 → 포함() >= 0 비교로 동등 처리
검증:
  • 컴파일 성공: 706KB toau, 25,218 큐브
  • 단위 테스트: 한선씨 측 SSL_SAN 검사가 53개 누락 도메인 동일 감지

작업 후 최종 상태

항목상태
:9736 무한 충돌 알람✓ 해결 (cmdline 매칭)
SSL SAN false-alarm 폭주✓ 해결 (3개 인증서 합산)
code/agent 백엔드 down✓ 복구 + 자동복구 등록
code/agent 게이트웨이 경유✓ 200 OK
한선씨 동반본 포팅✓ 충돌검사·SSL SAN 검사 추가
SSL SAN 진짜 누락 51개✅ certbot 발급 완료 — ext 인증서 11→61 SAN
외부 접속 실패 0/5✅ 라우터 룰 ON + 와일드카드 DNS 적용 → 5/5 회복

후속 작업 결과 (추가)

certbot 재발급 — 완료

  • DNS 와일드카드 *.crowny.org/*.tiomta.com/*.crownybus.com 추가 (사용자) → 44개 NXDOMAIN 일괄 해소
  • 라우터 80→8080, 443→8443 포트포워딩 룰 ON 확인 (사용자)
  • certbot dry-run 61 SAN 성공 → 실 발급 성공 (만료 2026-08-25)
  • 게이트웨이 재시작 시 새 ext 인증서 SNI 매핑 자동 적용 (docs.crowny.org subjectAltName matched)
주의 발견: 게이트웨이의 /certs/renew/reload admin API는 SNI 컨텍스트 재빌드를 안 함. SIGHUP는 메인 프로세스 종료만 시켜 launchd가 자동 재기동. 새 인증서 적용엔 완전 재시작이 필요. 추후 ssl.js의 contexts 재로드 메소드 추가가 깔끔.

일제 진단 결과 (154 도메인)

분류개수
🟢 정상 (외부 200)52
🟡 DNS OK / upstream 미가동90 (대부분 운영 안 하는 서비스)
🔴 NXDOMAIN (yaml placeholder 11)11 (gateway.yaml 정리 대상)
⚫ 잘못된 IP0
진짜 hosting.kr A 레코드 추가 필요한 도메인: 0개 (와일드카드로 다 커버).

academy / finance 확인

  • academy.crowny.org: 백엔드 :9865 LISTEN 활성, 외부/내부 200 OK
  • finance.crowny.org: PID 92591 node proxy.js :9754, 5시간 39분 안정 가동, 외부/내부 200 OK

gateway.yaml 정리 권장 (suffix 없는 placeholder 11)

book-agent  →  book-agent.crowny.org (진짜 도메인 의도?)
cif-editor  →  cif-editor.crowny.org
crns        →  crns.crowny.org
crowny-dist →  dist.crowny.org
cycle       →  cycle.crowny.org
pay         →  pay.crowny.org
remote      →  remote.crowny.org
remote-agent → remote-agent.crowny.org
remote-pty  →  remote-pty.crowny.org
reward-ui   →  reward-ui.crowny.org
value       →  value.crowny.org
티옴타작업소 → xn--... (Punycode IDN 변환)

각 항목별로 suffix 추가하면 와일드카드 DNS로 즉시 해결되고, 다음 certbot 갱신 시 SAN에 자동 포함됨.

관련 파일

  • /Users/ef/crowny-gateway/scripts/health-monitor.sh (수정)
  • /Users/ef/crowny-gateway/lib/ssl.js (참조)
  • /Users/ef/crowny-data/certs/certbot/live/ (3개 인증서 디렉토리)
  • /Users/ef/.crowny-infra/logs/health-monitor.log (검증)
  • /Users/ef/crownycode-remote/gateway.js (재시작)
  • /Users/ef/crownycode-remote/agent/server.js (재시작)