Files
obsidian/infra/apisix.md
kappa fb5a34ebcc edge gateway: "APISIX = SafeLine WAF 전용" 표현 정정
kappa 피드백 + kubectl 실측 기반 정정. 이전 기록의 "SafeLine WAF 전용 리버스
프록시" 또는 "SafeLine WAF 전용" 표현은 오해의 소지가 있음.

실측 사실 (2026-04-10 kubectl get svc + ApisixRoute + HTTPRoute):
- APISIX (svc apisix-gateway): MetalLB VIP 192.168.9.50, gateway 80/443 +
  admin 9180. 독립 LoadBalancer. Deployment replica 2.
  ApisixRoute 1건: juiceshop/juiceshop → juiceshop.keepanker.cv → juiceshop
  svc (chaitin-waf plugin 으로 SafeLine 통합 테스트)
- Traefik (svc traefik): MetalLB VIP 192.168.9.53, 80/443.
  HTTPRoute 14건 (argocd/gitea/grafana/n8n/nocodb/sftpgo/openmemory/searxng/
  kroki/safeline-mgt/vault-ui + api/namecheap + api/vultr + bunnycdn-mcp)
  + 5 legacy IngressRoute (vlogs/outline/vault-mcp/vault-mcp-http/bunnycdn-mcp)

→ **두 gateway 는 동등한 병렬 독립 LoadBalancer**. APISIX 는 Traefik 뒤의
리버스 프록시가 아니라 자체 MetalLB VIP 를 가진 별개 외부 인입 채널.
"SafeLine WAF 전용" 이 아니라, 2026-03-25 메인 라우팅이 Traefik 으로 이전된
이후 현재 APISIX route 가 SafeLine 테스트용 1건만 남은 상태일 뿐 — 범용
gateway 로 언제든 새 route 추가 가능.

정정 대상:
- infra/apisix.md — 서울 섹션 헤더/용도/축소 문구
- infra/infra-hosts.md — 게이트웨이 한 줄 요약
- infra/k3s-migration.md — 게이트웨이 열 + Phase 0 + Namespace 표
- infra/gateway-api.md — 전환 이력 2026-03-25 줄
- infra/crowdsec-safeline.md — waf-kr BunnyCDN Pull Zone 섹션 머리말

부수적으로 2026-04-10 에 발견된 heimdall kubectl 부재 문제 해결
(kubectl + helm + kubeconfig 복원) + tofu cloud-init 자동화 추가 —
commit bd5e4cb (ops-agents-tofu).
2026-04-10 00:36:29 +09:00

312 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: APISIX 설정 및 운영
updated: 2026-04-04
---
## 아키텍처
서울 K3s 클러스터 구성: 고객 도메인 → [[cloudflare]](DNS) → OpenWrt HAProxy (80/443) → Traefik MetalLB 192.168.9.53 → K3s 서비스 → pods
오사카 구성: 고객 도메인 → [[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, Debian 12), Docker APISIX 3.15.0, SSH: admin (포트 2222, Vault CA 인증서)
- 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 미사용)
- 방화벽: 22/tcp + 2201-2299/tcp + 443/tcp 개방, SSH는 Tailscale 경유 포트 2222
- 22 → iptables REDIRECT → 9022 (SFTPGo용, privileged 포트 우회)
- 443 → iptables REDIRECT → 8443 (Teleport용, privileged 포트 우회)
- 2026-03-17 AWS EC2에서 Lightsail nano($5/월)로 이전
- **주의**: config.yaml의 stream_proxy.tcp에 privileged 포트(1-1023)를 넣으면 비특권 컨테이너에서 bind 실패로 크래시. 2026-03-27 포트 22 추가로 장애 발생, 제거하여 복구
#### 포트 포워딩 (stream_routes)
| 포트 | 용도 | upstream | 비고 |
|------|------|----------|------|
| 9022 (외부 22) | SFTPGo SFTP | 192.168.9.55:22 | K3s MetalLB → SFTPGo, iptables 22→9022 리다이렉트 |
| 2201 | inbest SSH | 10.100.1.158:22 | inbest 전용 SSH 포트, OpenWrt Tailscale 광고 경유 |
| 2202 | Gitea SSH | 192.168.9.54:22 | K3s MetalLB → Gitea SSH |
| 8443 (외부 443) | Teleport | 192.168.9.52:443 | K3s MetalLB → Teleport proxy, iptables 443→8443 리다이렉트 |
### 오사카 (apisix-osaka)
```
BunnyCDN(iron-jp, ID 5555247) → apisix-osaka(172.233.93.180) → 백엔드
```
- 용도: Ironclad 인프라 서비스 (ironclad.it.com, n8n, twilio 등)
- Docker: APISIX 3.15.0 (waf-apisix) + etcd v3.5.11 (waf-etcd)
- 보안: SafeLine WAF + CrowdSec 연동
- upstream: incus-jp1 내부(10.253.x), K3s Traefik
### 서울 (K3s 새 클러스터, apisix 네임스페이스) — 독립 외부 인입 게이트웨이
```
외부 → OpenWrt HAProxy(:9080/:9443) → MetalLB 192.168.9.50(80/443) → APISIX(replica 2) → K3s 서비스
```
- 용도: **Traefik(VIP 192.168.9.53)과 동등한 병렬 독립 LoadBalancer gateway**. "SafeLine WAF 전용" 이 아니라, 2026-03-25 에 메인 HTTP 라우팅을 Traefik 으로 이전한 이후 현재 APISIX 에는 `juiceshop.keepanker.cv` 1건만 남아 있고 그것이 chaitin-waf 플러그인으로 SafeLine 통합 테스트 용도라 **결과적으로 현재만** SafeLine 테스트 전용처럼 보일 뿐 — 언제든 새 ApisixRoute 추가 가능한 범용 gateway.
- 클러스터: K3s 새 클러스터 (Supabase PostgreSQL 백엔드, kr2+kr1+hp2)
- 배포: K3s apisix 네임스페이스, **Deployment replica 2** (2026-04-04 HA 업그레이드)
- APISIX: 3.15.0-ubuntu
- SafeLine WAF 연동: `plugin_attr.chaitin-waf``safeline-detector:8000` (10.43.253.244)
- global_rules: `http-logger` (CrowdSec 로그 전송) + `limit-req` (rate 20, burst 10). **`chaitin-waf`는 global_rule에 없음** — 라우트별 적용 (2026-03-15 git push 500 사건 이후). 두 global_rule 모두 GatewayProxy CR(`spec.plugins`)로 선언되어 ingress controller가 관리.
- 서비스: apisix-gateway LoadBalancer 192.168.9.50 (80→9080, 443→9443)
- etcd: **K3s 내부 apisix-etcd StatefulSet 3 replicas** (Bitnami etcd 차트, Longhorn PVC 5Gi × 3), prefix `/apisix`. ClusterIP `apisix-etcd.apisix.svc.cluster.local:2379`. 외부 통합 etcd로 잠시 이전했다가(2026-04-06) Patroni와의 장애 격리 + 네트워크 단순화를 위해 K3s 내부로 복귀(2026-04-08).
- Admin API: `apisix-admin` ClusterIP :9180 (`adminKey: edd1c9f034335f136f87ad84b625c8f1`). admin allow IPs: `127.0.0.1/24`, `10.42.0.0/16`(pod), `10.43.0.0/16`(svc), `192.168.9.0/24`(LAN), `100.64.0.0/10`(Tailscale)
- HAProxy: OpenWrt에서 :9080→192.168.9.50:80, :9443→192.168.9.50:443 (MetalLB)
- 2026-03-25 메인 HTTP 라우팅을 Traefik 으로 이전. APISIX route 축소되어 현재 juiceshop 1건만 (SafeLine chaitin-waf 통합 테스트). **APISIX 자체는 여전히 독립 외부 LoadBalancer gateway — MetalLB VIP 별도 유지**
- 2026-04-08 ApisixRoute CRD 사용을 위해 ingress controller 복구 + K3s 내부 etcd 복귀
#### plugin_metadata (GatewayProxy CR로 관리)
chaitin-waf 플러그인은 `plugin_attr`(config.yaml)이 아닌 **`plugin_metadata`(etcd)**에서 detector 노드를 읽음. 옛날에는 etcd에 직접 PUT했으나, 2026-04-08부터 ingress controller가 destructive sync로 미관리 객체를 1분마다 삭제하므로 **반드시 GatewayProxy CR의 `spec.pluginMetadata`로 선언**해야 함. helm values의 `gatewayProxy.pluginMetadata` 항목 참고.
#### 등록된 라우트 / TLS (ApisixRoute / ApisixTls CRD)
모든 라우트와 SSL은 K8s CRD로 선언됨. ingress controller가 watch하여 APISIX admin API로 push.
| Kind | Name | Namespace | 설명 |
|------|------|-----------|------|
| ApisixRoute | juiceshop | juiceshop | `juiceshop.keepanker.cv` → juiceshop:3000, plugins.chaitin-waf (block) |
| ApisixTls | wildcard-keepanker-cv | apisix | `*.keepanker.cv` + `keepanker.cv`, secret `wildcard-keepanker-cv-tls` (cert-manager 발급) |
⚠️ **etcd 직접 등록 금지** (1분 이내 controller가 삭제). 모든 신규 객체는 CRD로 선언해야 함.
#### real_ip 설정 (2026-04-08 patch 반영)
⚠️ **helm values로는 반영 안 됨** — APISIX helm chart의 nginx.http.realIpFrom/realIpHeader 옵션이 K3s에 배포된 차트(2.13.0) 구조에서 `nginx_config.http`로 전달이 안 됨. 그래서 `cm/apisix` 직접 patch가 필요하고, helm upgrade 시 reset됨.
현재 적용 값 (cm/apisix `config.yaml`):
```yaml
nginx_config:
http:
real_ip_header: "X-Forwarded-For"
real_ip_from:
- 0.0.0.0/0 # BunnyCDN/OpenWrt/K3s 모든 hop 신뢰 (Tailnet+LAN+CDN 경유)
real_ip_recursive: "on"
access_log_format: '$remote_addr - $remote_user [$time_local] $http_host \"$request\" $status $body_bytes_sent $request_time \"$http_referer\" \"$http_user_agent\" $upstream_addr $upstream_status $upstream_response_time \"$upstream_scheme://$upstream_host$upstream_uri\" xff=\"$http_x_forwarded_for\" xrip=\"$http_x_real_ip\"'
```
→ access log의 첫 필드 `$remote_addr`이 X-Forwarded-For에서 추출한 진짜 클라이언트 IP가 됨. 끝에 `xff="..." xrip="..."` 디버그 필드 추가.
적용 절차:
```bash
kubectl get cm apisix -n apisix -o jsonpath='{.data.config\.yaml}' > /tmp/apisix-config.yaml
# /tmp/apisix-config.yaml 편집 (real_ip_*, access_log_format)
kubectl create cm apisix --from-file=config.yaml=/tmp/apisix-config.yaml -n apisix --dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deploy/apisix -n apisix
```
⚠️ **Vector parse_apisix 정규식과 짝**: APISIX log format을 변경할 때마다 `vector` helm values의 parse_apisix 정규식도 같이 업데이트해야 [[victorialogs|VictoriaLogs]]에 구조화 필드가 정상 추출됨. 현재 정규식은 `xff/xrip` 필드를 optional 그룹으로 처리.
#### 이전 사유 (2026-03-25)
- Ingress Controller 2.0 초기 시도에서 GatewayProxy 모드 + ApisixRoute CRD 연동 실패 (당시 helm values에 v1.x 형식의 `config.apisix.serviceName` 사용 → 차트 1.x 스키마와 불일치)
- Gateway API HTTPRoute에 플러그인 개별 적용 방법이 없음 → ApisixRoute CRD 필요
- global_rules를 Ingress Controller가 덮어쓰려는 충돌 발생
- → Traefik으로 메인 라우팅 교체, APISIX는 SafeLine WAF 연동 전용으로 유지
#### Ingress Controller 복구 (2026-04-08)
`apisix-ingress-controller` Helm release는 살아있었으나 Deployment가 수동 삭제된 상태였음. helm values를 chart 1.1.2 (controller v2.0.1) 스키마에 맞게 재작성 후 `helm upgrade`로 복구.
값 수정 핵심:
```yaml
gatewayProxy:
createDefault: true # GatewayProxy CR 자동 생성
provider:
type: ControlPlane
controlPlane:
service:
name: apisix-admin
port: 9180
auth:
type: AdminKey
adminKey:
value: "edd1c9f034335f136f87ad84b625c8f1"
config:
disableGatewayAPI: false # Gateway API + ApisixRoute 양쪽 다 지원
kubernetes:
ingressClass: apisix
```
검증 결과: GatewayProxy 모드에서도 ApisixRoute CRD(v2)는 정상 동작함. 옛 메모의 "GatewayProxy 모드에서 ApisixRoute CRD 미지원"은 틀렸음 — 잘못된 helm values 때문이었음. ApisixRoute에 `ingressClassName: apisix`만 명시하면 controller가 자동으로 admin API에 push.
ApisixRoute 예시 (라우트별 chaitin-waf):
```yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: <name>
namespace: <ns>
spec:
ingressClassName: apisix
http:
- name: rule1
match:
hosts: [<host>]
paths: ["/*"]
backends:
- serviceName: <svc>
servicePort: <port>
plugins:
- name: chaitin-waf
enable: true
config:
mode: block
append_waf_resp_header: true
```
WAF가 문제 시 `plugins` 항목만 빼면 즉시 비활성화됨.
#### Destructive sync 주의사항 (v2.x controller)
새 controller는 **CRD/GatewayProxy로 선언되지 않은 모든 APISIX 객체를 1분마다 자동 삭제**함. 영향:
| 객체 | 관리 방법 |
|------|----------|
| routes | `ApisixRoute` CRD (또는 HTTPRoute) |
| upstreams | `ApisixUpstream` CRD |
| ssls | `ApisixTls` CRD |
| consumers | `ApisixConsumer` CRD |
| plugin_metadata | `GatewayProxy.spec.pluginMetadata` (helm values) |
| global_rules | `GatewayProxy.spec.plugins` (helm values) |
⚠️ **etcd 직접 PUT은 임시 디버깅 외에는 금지.** 1분 안에 삭제됨. 옛 운영 메모에 있는 `etcdctl put` 예제는 모두 deprecated.
#### K3s 내부 etcd 복귀 (2026-04-08)
기존: 외부 통합 etcd 클러스터(192.168.9.100/10.100.2.214/10.253.101.233, prefix `/apisix/seoul`) — Patroni DCS와 etcd 공유.
복귀 후: K3s 내부 `apisix-etcd` StatefulSet 3 replicas (Bitnami etcd, Longhorn PVC 5Gi × 3, ClusterIP `apisix-etcd.apisix.svc:2379`, prefix `/apisix`).
이유:
- **장애 격리**: Patroni 이슈가 APISIX 라우팅에 영향 주지 않게
- **네트워크 단순화**: K3s 내부 통신만으로 충분
- **운영 일관성**: helm 한 곳에서 etcd + apisix + ingress controller 관리
helm values 핵심:
```yaml
etcd:
enabled: true
replicaCount: 3
persistence:
enabled: true
size: 5Gi
```
업그레이드 시 주의:
- Bitnami etcd 차트의 pre-upgrade hook은 기존 etcd 멤버 list를 시도함. 멤버가 없는 상황에서는 무한 retry 실패 → `helm upgrade --no-hooks` 사용 또는 helm rollback 후 재시도
- helm upgrade 전 release values nesting 점검 필수: `apisix.admin.allow.ipList`(O) vs `admin.allow.ipList`(X), `apisix.nginx.http.realIpFrom`(O) vs `nginx.http.realIpFrom`(X), `service.http.containerPort`(O) vs `gateway.http.containerPort`(X). 잘못된 nesting은 차트가 조용히 무시함.
- 이전 후 ingress controller는 자동으로 모든 K8s CRD 객체를 새 etcd에 재push (rollout restart로 즉시 동기화 가능)
- 외부 통합 etcd의 stale `/apisix/seoul/*` 키는 수동 삭제 (postgresql-ha.md의 etcd cleanup 명령 참고)
### BunnyCDN Pull Zone 매핑 (2026-04-09 API 실측)
| Zone | ID | Origin | 방향 | Hostnames (전수) |
|---|---|---|---|---|
| iron-kr | 5555227 | 220.120.65.245 | → 서울 (OpenWrt → Traefik) | `iron-kr.b-cdn.net`, actions.it.com, n8n.inouter.com, jarvis.inouter.com, telegram-webhook.inouter.com, vault.inouter.com, outline.inouter.com (사용자 6 + 시스템 1 = 7) |
| iron-jp | 5555247 | 172.233.93.180 | → 오사카 (osaka-gw APISIX) | `iron-jp.b-cdn.net`, anvil.it.com, n8n.anvil.it.com, tg.anvil.it.com, linode.actions.it.com (사용자 4 + 시스템 1 = 5) |
| iron-kr-waf | 5555224 | 220.120.65.245:9443 | → 서울 (HAProxy :9443 → K3s APISIX SafeLine WAF) | `iron-kr-waf.b-cdn.net`, juiceshop.keepanker.cv |
| iron-git | 5584382 | 220.120.65.245 | → 서울 (gitea, **미들웨어 미장착**) | `iron-git.b-cdn.net`, gitea.inouter.com |
| i-gate | 5557897 | 172.233.93.180 | (미사용 슬롯) | `i-gate.b-cdn.net` |
참고:
- iron-kr `IgnoreQueryStrings: true` / iron-jp `IgnoreQueryStrings: false` — 동일 미들웨어 풀존이지만 캐시 키 정책이 다름
- iron-kr / iron-jp `BlockNoneReferrer: true`, iron-git 는 `false` (git smart HTTP 호환)
- 모든 zone `EdgeRules: []` (Edge Rules 미사용, 모든 분기는 미들웨어 64811 안)
- Edge Script 64811 `crowdsec-bouncer-middleware` 는 **iron-jp + iron-kr 두 풀존**에만 attach. iron-git 은 의도적 우회 (git pack 바이너리 보호 불가).
- gitea.inouter.com 은 더 이상 iron-kr 가 아니라 iron-git 풀존 소속 (분리됨)
### DNS 참고
- `*.inouter.com` 와일드카드 CNAME → `iron-jp.b-cdn.net` (오사카)
- iron-kr zone 호스트는 전용 CNAME 필수 (와일드카드 오버라이드)
- `gitea.inouter.com` CNAME → `iron-kr.b-cdn.net`
- `hcv.inouter.com` CNAME → `k3s.inouter.com` (LAN 직접, BunnyCDN 우회)
- `nocodb.inouter.com` CNAME → `k3s.inouter.com` (LAN 직접, BunnyCDN 우회)
- K3s CoreDNS: `gitea.inouter.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.inouter.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"`
## jarvis.inouter.com 라우트
jarvis.inouter.com → APISIX(오사카) → jarvis(10.100.2.162:18789). OpenClaw 게이트웨이 웹 UI 및 webhook 엔드포인트. enable_websocket: true.
## telegram-webhook.inouter.com 라우트
telegram-webhook.inouter.com → APISIX(오사카) → jarvis(10.100.2.162:8787). 텔레그램 봇 webhook 수신. Cloudflare proxied, *.inouter.com 와일드카드 SSL.