--- title: APISIX 설정 및 운영 updated: 2026-03-18 --- ## 아키텍처 서울 K3s 클러스터 구성: 고객 도메인 → [[cloudflare]](DNS) → OpenWrt HAProxy (80/443) → K3s NodePort (32020/30675) → APISIX Gateway → 서비스 오사카 구성: 고객 도메인 → [[cloudflare]](DNS) → [[crowdsec-safeline|SafeLine WAF]] → APISIX(라우팅) → 고객 오리진 3개의 독립 APISIX 인스턴스. kr1의 Docker APISIX는 2026-03-15 제거 완료. ### 서울 relay (relay4wd) - 용도: 포트 포워딩 게이트웨이 - 호스트: relay4wd (AWS Lightsail, Tailscale 100.103.161.4, 공인 52.79.45.166), Docker APISIX 3.15.0 - Admin API: `http://100.103.161.4:9180` (Tailscale 100.64.0.0/10에서만 접근 가능) - Admin Key: `edd1c9f034335f136f87ad84b625c8f1` - etcd: incus-jp1 db 프로젝트 `etcd-1` (10.253.102.11:2379), prefix `/apisix-sandbox` - 설정 파일: `/opt/apisix/` (config.yaml, docker-compose.yml) - 모드: stream only (HTTP proxy 비활성화, 9080 미사용) - 방화벽: 2201-2299/tcp만 개방, SSH는 Tailscale 경유 - 2026-03-17 AWS EC2에서 Lightsail nano($5/월)로 이전 #### 포트 포워딩 (stream_routes) | 포트 | 용도 | upstream | 비고 | |------|------|----------|------| | 2201 | inbest SSH | 10.100.1.158:22 | inbest 전용 SSH 포트, OpenWrt Tailscale 광고 경유 | ### 오사카 (apisix-osaka) ``` BunnyCDN(inouter, ID 5316471) → apisix-osaka(172.233.93.180) → 백엔드 ``` - 용도: Ironclad 인프라 서비스 (ironclad.it.com, n8n, twilio 등) - 보안: SafeLine WAF + CrowdSec 연동 - upstream: incus-jp1 내부(10.253.x), K3s Traefik ### 서울 (kr2, incus 컨테이너) ``` 인터넷 → OpenWrt(:80/:443) → hp2(:9080/:9443, incus proxy device) → APISIX(10.179.99.126) → 백엔드 ``` - 용도: KR존 리버스 프록시 - upstream: K3s Traefik (192.168.9.134/214/135:443), LAN 서비스(192.168.9.x) - SSL: cert-manager wildcard `*.inouter.com` 인증서 - Admin API: `curl http://10.179.99.126:9180/apisix/admin` (incus proxy device, 192.168.9.0/24에서 접근 가능) - etcd: apisix-etcd (10.179.99.101) #### global_rules - `real-ip` — source: http_x_real_ip, trusted: 0.0.0.0/0 - `http-logger` → CrowdSec (10.253.100.240:8085, auth_header: apisix-crowdsec-log-2024) #### 라우트 및 플러그인 | 라우트 ID | 호스트 | upstream | chaitin-waf | limit-req (rate/burst) | |-----------|--------|----------|-------------|----------------------| | gitea-anvil-it-com | gitea.anvil.it.com | K3s Traefik :443 (roundrobin) | block, match: `.git/` 제외 | 50/30 | | hcv-inouter-com | hcv.inouter.com | K3s Traefik :443 (roundrobin) | block | 20/10 | | nocodb | nocodb.inouter.com | K3s Traefik :443 (roundrobin) | block | 100/50 | | nocodb-nuxt | nocodb.inouter.com | K3s Traefik :443 (roundrobin) | block | 100/50 | ### BunnyCDN Pull Zone 매핑 | Zone | Origin | 방향 | 주요 Hostnames | |---|---|---|---| | inouter (5316471) | 172.233.93.180 | → 오사카 | anvil.it.com, vault.inouter.com, n8n, kroki, tg.anvil.it.com | | actions (5330178) | 220.120.65.245 | → 서울 | actions.it.com, gitea.anvil.it.com | 참고: actions zone은 `DisableCookies: false` (쿠키 허용, 2026-03-15). Gitea 웹 로그인 세션에 필요. ### DNS 참고 - `*.anvil.it.com` 와일드카드 CNAME → `inouter.b-cdn.net` (오사카) - actions zone으로 이전한 호스트는 전용 CNAME 필수 (와일드카드 오버라이드) - `gitea.anvil.it.com` CNAME → `actions.b-cdn.net` - `hcv.inouter.com` CNAME → `k3s.inouter.com` (LAN 직접, BunnyCDN 우회) - `nocodb.inouter.com` CNAME → `k3s.inouter.com` (LAN 직접, BunnyCDN 우회) - K3s CoreDNS: `gitea.anvil.it.com` → Traefik ClusterIP (10.43.205.207) 헤어핀 방지 ## ironclad.it.com 라우트 ironclad.it.com Cloudflare DNS origin: 172.233.93.180 (osaka), zone ID: bc8761b398cc52cf731f804bd3cbf388. APISIX 라우트 ironclad-it-com → web 컨테이너 10.253.100.159:80. SSL: Google Trust Services wildcard cert (*.ironclad.it.com) in APISIX. → [[cert-manager]] ## SSL ID 규칙 APISIX SSL ID는 도메인 MD5 해시 앞 16자리 ## 플러그인 APISIX 연동: ip-restriction + geoip-restriction 플러그인 ## Twilio 라우트 APISIX 라우트 ID: twilio-jp-inouter-com → [[twilio]] ## Gitea POST 변환 [[gitea]]가 POST 미지원(AuthenticateNotImplemented, 404)하므로 APISIX에서 POST body 파라미터를 GET query string으로 변환 ## hcv.inouter.com 라우트 APISIX 서울 라우트 hcv-inouter-com → K3s Traefik (192.168.9.134/214/135:443, roundrobin, scheme https). upstream ID: hcv-inouter-com. [[vault]] UI/API 서빙. DNS: k3s.inouter.com CNAME (LAN 직접 연결, BunnyCDN 우회). BunnyCDN pull zone actions (ID 5330178)에 hostname 등록. 오사카에서 서울로 이전 (2026-03-15). ## nocodb.inouter.com 라우트 트래픽 흐름: Cloudflare DNS (A 220.120.65.245, BunnyCDN 우회) → OpenWrt(:443) → hp2(:9443, incus proxy device) → APISIX(10.179.99.126, 라우트 nocodb/nocodb-nuxt) → K3s Traefik (192.168.9.134/214/135:443, roundrobin, scheme https) → nocodb svc:8080 (namespace tools). BunnyCDN WAF가 NocoDB JS를 오탐 차단하여 CDN 우회 처리 (2026-03-15). ## CrowdSec 로그 연동 오사카/서울 양쪽 APISIX → CrowdSec (10.253.100.240:8085) http-logger로 전송. 서울은 global_rule, 오사카는 글로벌 적용. 인증: `auth_header: apisix-crowdsec-log-2024` (주의: `headers` 필드가 아님) 커스텀 파서: custom/apisix-json-logs (403 응답만 필터) 시나리오 매칭으로 반복 공격자 탐지. ## 트러블슈팅 기록 ### git push 500 에러 (2026-03-15) **증상**: `gitea.anvil.it.com`으로 git push 시 BunnyCDN에서 403 반환 (오리진 500) **원인 1 — client_body_temp 퍼미션**: - nginx가 큰 POST body(git pack ~20KB)를 `/usr/local/apisix/client_body_temp/`에 임시 파일로 쓸 때 퍼미션 거부 - 디렉토리 소유자가 `nobody`인데 APISIX는 `apisix` 사용자로 실행 - 작은 요청은 메모리 버퍼로 처리되어 정상, 큰 요청만 실패 - **수정**: `chown apisix:apisix /usr/local/apisix/client_body_temp` **원인 2 — chaitin-waf 글로벌 적용**: - `chaitin-waf`가 global_rules에 있어서 모든 요청에 WAF 검사 적용 - SafeLine detector가 git pack 바이너리를 파싱 실패 시 `mode: block`이면 500 반환 (fail-closed) - 라우트 레벨에서 match 제외를 넣어도 global_rule이 먼저 적용되어 무시됨 - **수정**: global_rules에서 `chaitin-waf` 제거, 각 라우트에 개별 적용. gitea 라우트는 `match: [{"vars": [["uri", "!", "~*", "\\.git/"]]}]`로 git 경로 WAF 제외 **교훈**: - SafeLine WAF는 바이너리 프로토콜(git pack 등)을 처리할 수 없음 → 해당 경로는 WAF에서 제외 필요 - global_rules의 WAF는 예외 처리가 어려움 → 라우트별 개별 적용이 유연함 - BunnyCDN `errorcode: 112`는 오리진 에러를 나타냄 → 실제 원인은 오리진 로그에서 확인 ### http-logger 401 에러 (2026-03-15) **증상**: 서울 APISIX http-logger가 CrowdSec으로 로그 전송 시 401 Unauthorized **원인**: http-logger 플러그인은 Authorization 헤더를 `auth_header` 필드로 설정해야 하는데, `headers.Authorization`으로 설정되어 있었음 (무시됨) **수정**: `"headers": {"Authorization": "..."}` → `"auth_header": "apisix-crowdsec-log-2024"`