← 목록
기타 2026-07-24 4KB 읽기 4분

크라우니메일 v3 — 트래픽 보호(레이트리밋) + 실용량 API 장착

개요

크라우니메일서버.한선(v3, :9610)에 in-memory 고정윈도우 레이트리밋 게이트와 실용량(/api/storage) API를 추가했다. 라이브(맥 :9610, VPS)는 무접촉 — 소스와 /tmp/메일v3.toau 컴파일 산출물만 갱신, 재기동은 메인 세션 몫.

무엇을 했는지

A. 레이트리밋

  • libs/레이트리밋.한선은 top-level에 데모 실행문(56~65행: 리밋DB생성→규칙등록→
요청확인→리밋현황 출력)이 있어 가져오기 시 데모가 기동마다 실행됨 (한선씨-가드레일.md "가져오기는 top-level 문을 실행한다" 함정 해당) → import 금지. 또한 그 lib는 "현재카운트"만 증가하고 시간창 리셋 로직이 없어 "분당 N회" 요구사항에 구조적으로 미달.
  • 대신 crowny-gateway/게이트웨이Q/그림자/게이트웨이정책코어_perip.한선
_레이트리밋판정(리셋시각 방식 고정윈도우, per-key 분리) 검증패턴을 참고해 메일서버 로컬에 이식 + 보강:
  • 키 512개 캡 + LRU(최고령) 슬롯 재사용 (게이트웨이 원본엔 없던 보강)
  • 게이트웨이 원본은 date +%s fork로 epoch를 얻지만, 메일서버는 이미
  • 현재시간()(ms) 내장함수를 다른 곳에서 쓰고 있어 fork 없이 그대로 사용
  • 원장(해시체인 WAL)에는 기록하지 않음 — 고빈도 오염 방지(요구사항대로)
  • 클라이언트 키: X-Forwarded-For 첫 값(게이트웨이 경유), 없으면 "direct".
  • 규칙: 전역 API 120/분·키, POST /api/auth/login 10/분·키(브루트포스 방어),
  • POST /api/mail/send 20/분·키, 정적/HTML(/,/login,/demo) 60/분·키.
    • 초과 시 429 Too Many Requests + Retry-After 헤더 + JSON
    {"error":"rate limited","retryAfter":N} (_429응답() 신규 헬퍼).
    • GET /api/ratelimit/status — admin 역할만: totalRequests/passed/blocked/activeKeys/capacity.

    B. 실용량 API

    • GET /api/storage(세션 필요): 체계("df -m ...") 파싱(usedMB/availMB,
    quotaGB:15 고정) + 원장 파일 합계 바이트(cat 원장_*.psv | wc -c, ledgerBytes). 60초 캐시(_스토리지새로고침()) — 매 요청 fork 금지.
    • GET /api/policy를 세션 필요 구간에서 공개 라우트 구간으로 이동(정적 정책 표,
    민감정보 없음).

    관련 파일

    • /Users/ef/crowny-mail/크라우니메일서버.한선 (2157→2371줄, +214줄)
    • /tmp/메일v3.toau — 갱신된 컴파일 산출물(라이브 미교체, 메인 세션 몫)
    • 참고 패턴: /Users/ef/crowny-gateway/게이트웨이Q/그림자/게이트웨이정책코어_perip.한선
    (_레이트리밋판정)
    • 미사용(재사용 불가로 판단): /Users/ef/CrownyOS/crownyc/libs/레이트리밋.한선

    검증 (전부 실측, PORT=19613 MAIL_DATA=/tmp/mail-rl-test/)

    • CROWNY_STRICT=1 ./hanseonc_high 컴파일 경고 0건 — PASS
    • 로그인 11연타 → 11번째 429 ({"error":"rate limited","retryAfter":61}) — PASS
    • 일반 API(/api/stats) 121연타(동일 키) → 121번째 429 — PASS
    • 429 유발 후 다른 XFF 키는 즉시 정상(200) — 키별 격리 확인 — PASS
    • /api/mail/send 21연타(동일 키) → 21번째 429 — PASS
    • admin(kps) → /api/ratelimit/status 200, non-admin(rental) → 403 — PASS
    • /api/storage 실수치 반환(usedMB/availMB/quotaGB/ledgerBytes) — PASS
    • /api/policy 무세션 200 — PASS
    • 기존 회귀: 로그인//api/mail/list//api/mail/send//api/chain/verify 정상 — PASS
    • 강제 kill 후 재기동 → 원장 리플레이 47건(유저5/메일42) 그대로 복원,
    /api/ratelimit/status는 0에 가깝게 리셋(레이트리밋 휘발, 원장 무영향 확인) — PASS
    • 테스트 프로세스 kill 완료, 원본 라이브(:9610) 무접촉

    잔여 이슈

    • /tmp/메일v3.toau가 최신 소스 반영본이나 라이브(:9610, VPS)는 아직 구버전
    바이너리로 서빙 중 — 교체는 메인 세션이 결정.
    • 레이트리밋 상태는 프로세스 재기동 시 완전 휘발(의도된 설계) — 다중 인스턴스
    간 공유는 없음(단일 프로세스 전제, 게이트웨이 앞단이 로드밸런싱 안 하는 현재 배포 구조와 일치).