Cloudflare Application Services
통합 교육

Lab 실습 핵심 (DNS · TLS · WAF · Bot · Cache · LB · Rules)

엔지니어 교육용 · 발표자 덱 · 2026

Agenda

오늘 다룰 내용

시간#내용
09:30 ~ 10:00 환영 / 오리엔테이션
10:00 ~ 11:30-Cloudflare 보안 서비스 소개
-How Does Cloudflare Work
-DNS Setup
-Lab 환경 확인
1DNS
-TLS Edge / Origin
2TLS (SSL)
-SSL for SaaS 소개
11:30 ~ 13:00 점심
13:00 ~ 16:003WAF
4Bot Management
-Caching 개요
5Cache Tuning
6Load Balancer
7Rules
16:00 ~ 17:00 Magic Transit 이론 교육
참고 자료 — 발표 슬라이드

📎 Cloudflare 보안 서비스 소개

이 주제는 별도 발표 자료에서 다룹니다.
참고 자료 — 발표 슬라이드

📎 How Does Cloudflare Work

이 주제는 별도 발표 자료에서 다룹니다.
참고 자료 — 발표 슬라이드

📎 DNS Setup

이 주제는 별도 발표 자료에서 다룹니다.
참고 자료 — 발표 슬라이드

📎 Lab 환경 확인

이 주제는 별도 발표 자료에서 다룹니다.
Part I

1. DNS

실습 단계

1) Zone 설정 열기 (1/2)

Cloudflare Dashboard에서 Websites 메뉴로 이동한 후, 실습에 사용할 Zone을 선택합니다.
📌 참고
제공받은 Cloudflare 계정을 사용하는 경우, 실습용 Zone이 이미 프로비저닝되어 있어야 합니다.

1) Zone 설정 열기 (2/2)

Zone 선택

Zone 선택

2) DNS 레코드 추가 (1/2)

Zone 내에서 DNS ‣ Records를 선택하고 Add record를 클릭합니다.
📌 참고
실습 환경에 따라 이미 일부 DNS 레코드가 존재할 수 있습니다. 해당 레코드는 무시하고 아래 안내에 따라 새 레코드를 추가하면 됩니다.
Zone의 root에 lab origin 서버를 가리키는 새 A 레코드를 생성합니다. Proxy 토글이 반드시 ON 상태여야 Cloudflare가 해당 도메인에 대해 reverse proxy 역할을 수행합니다.
📌 참고
Cloudflare는 DNS 레코드에 코멘트(change request ID 등)를 추가할 수 있습니다. 운영 추적용으로 활용하시기 바랍니다.
Type: A
Name: @
IPv4 address: 20.88.188.200
Proxy: yes
Comment: Lab origin server

2) DNS 레코드 추가 (2/2)

DNS 레코드 추가

DNS 레코드 추가

3) 테스트 (1/4)

터미널을 열고 root 도메인에 대한 DNS 레코드를 조회합니다.
📌 참고
본 실습 예시에서는 logical-voyager (또는 adjective-noun) 형태의 예시 도메인을 사용합니다. 실제 실습 시에는 본인의 도메인으로 치환하시기 바랍니다.
macOS / Linux
dig logical-voyager.sxplab.com A
; <<>> DiG 9.10.6 <<>> +noquestion +nocomments adjective-noun.sxplab.com A
;; global options: +cmd
logical-voyager.sxplab.com. 300 IN  A   104.18.24.205
logical-voyager.sxplab.com. 300 IN  A   104.18.25.205

3) 테스트 (2/4)

Windows
nslookup logical-voyager.sxplab.com
Server:    127.0.2.2
Address:   127.0.2.2#53

Non-authoritative answer:
Name:    logical-voyager.sxplab.com
Address: 104.18.24.205
Name:    logical-voyager.sxplab.com
Address: 104.18.25.205

3) 테스트 (3/4)

origin 서버 20.88.188.200은 Azure에서 동작하고 있지만, 응답으로는 두 개의 Cloudflare IP 주소가 반환됩니다 (whois.com으로 소유 조직 확인 가능).
이는 Cloudflare가 해당 도메인에 대한 모든 요청에 대해 reverse proxy 역할을 수행하기 때문입니다. 사용자와의 HTTP 세션을 종료(terminate)한 후, 새로운 세션을 origin 서버로 새로 맺습니다.
마지막으로 브라우저에서 방금 생성한 도메인 이름을 입력하여 웹 애플리케이션 접속을 확인합니다. 실습용 애플리케이션의 홈페이지가 표시되어야 합니다.

3) 테스트 (4/4)

브라우저로 DNS 레코드 접근 확인

브라우저로 DNS 레코드 접근 확인

참고 자료 — 발표 슬라이드

📎 TLS Edge / Origin

이 주제는 별도 발표 자료에서 다룹니다.
HTTPS 접근 검증

2. TLS (SSL)

실습 단계

실습 시작 전, HTTPS 트래픽을 가로채는 서비스(VPN, Cloudflare WARP 등)는 모두 비활성화하시기 바랍니다.

1-a) Always Use HTTPS (1/2)

TLS 인증서를 살펴보기 전에 Zone에 HTTPS를 강제합니다. 이는 TLS를 사용하지 않는 HTTP 요청을 방지합니다.
Cloudflare Dashboard에서 Zone을 열고 SSL/TLS ‣ Edge Certificates를 선택한 뒤 Always Use HTTPS를 켭니다.

1-a) Always Use HTTPS (2/2)

Always Use HTTPS 활성화

Always Use HTTPS 활성화

1-b) Minimum TLS Version 변경 (1/2)

TLS 1.0이 Zone 기본값이지만, 호환성 목적의 설정이며 일반적으로 변경을 권장합니다. 같은 페이지에서 조금 아래로 스크롤하여 Minimum TLS Version을 TLS 1.2로 설정합니다.

1-b) Minimum TLS Version 변경 (2/2)

Minimum TLS Version 변경

Minimum TLS Version 변경

2) 서브도메인 추가 (1/4)

DNS ‣ Records로 이동하여 1단계 서브도메인을 생성합니다. 본 예시에서는 sub1을 사용합니다.
본 실습 목적상 서브도메인이 가리키는 위치는 중요하지 않습니다. 단순화를 위해 apex 도메인과 동일한 origin (20.88.188.200)을 사용합니다.

2) 서브도메인 추가 (2/4)

서브도메인 추가

서브도메인 추가

2) 서브도메인 추가 (3/4)

브라우저에서 https://sub1.logical-voyager.sxplab.com에 접속하면 정상적으로 페이지가 열려야 합니다. Universal Certificate가 이 1단계 서브도메인을 커버하기 때문입니다.
OpenSSL이 설치되어 있다면 다음 명령으로 인증서 상세 정보를 확인할 수 있습니다.
openssl s_client -connect sub1.logical-voyager.sxplab.com:443 \
  | openssl x509 -noout -ext subjectAltName
depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R4
verify return:1
depth=1 C=US, O=Google Trust Services, CN=WE1
verify return:1
depth=0 CN=adjective-noun.sxplab.com
verify return:1
X509v3 Subject Alternative Name:
    DNS:adjective-noun.sxplab.com, DNS:*.adjective-noun.sxplab.com

2) 서브도메인 추가 (4/4)

📌 참고
출력이 위와 다르다면 VPN 또는 Cloudflare WARP가 비활성화되어 있는지 확인하시기 바랍니다.
이 인증서는 Cloudflare가 자동 발급한 Universal Certificate입니다. 발급자(Issuer)가 Google인 점에 주목하시기 바랍니다.

3) 서브도메인에 또 다른 서브도메인 추가 (1/5)

방금 만든 sub1에 또 다른 서브도메인을 추가합니다. 본 예시에서는 sub2.sub1 형태로 생성합니다.

3) 서브도메인에 또 다른 서브도메인 추가 (2/5)

2단계 서브도메인 추가

2단계 서브도메인 추가

3) 서브도메인에 또 다른 서브도메인 추가 (3/5)

이 2단계 서브도메인 옆에 경고 표시가 나타나는데, Universal Certificate가 이 도메인을 더 이상 커버하지 않기 때문입니다.

3) 서브도메인에 또 다른 서브도메인 추가 (4/5)

2단계 서브도메인 인증서 경고

2단계 서브도메인 인증서 경고

3) 서브도메인에 또 다른 서브도메인 추가 (5/5)

브라우저에서 이 새 서브도메인에 접속하려고 하면 보안 연결을 수립할 수 없다는 에러가 발생합니다.
openssl s_client -connect sub2.sub1.logical-voyager.sxplab.com:443
CONNECTED(00000006)
40F8F7F201000000:error:0A000410:SSL routines:ssl3_read_bytes:
ssl/tls alert handshake failure:ssl/record/rec_layer_s3.c:908:
SSL alert number 40
---
no peer certificate available

4) Advanced Certificate 주문 (1/8)

SSL/TLS ‣ Edge Certificates로 이동하여 Order Advanced Certificate를 선택합니다.

4) Advanced Certificate 주문 (2/8)

Advanced Certificate 주문

Advanced Certificate 주문

4) Advanced Certificate 주문 (3/8)

원하는 Certificate Authority를 선택할 수 있습니다. 본 예시에서는 Google Trust Services를 사용합니다.
Certificate Hostnames 필드에 서브도메인(예: sub2.sub1)을 입력하면 전체 도메인 이름이 자동완성되며 이를 선택합니다.

4) Advanced Certificate 주문 (4/8)

Certificate Hostnames 입력

Certificate Hostnames 입력

4) Advanced Certificate 주문 (5/8)

📌 참고
새 2단계 서브도메인만 커버하도록 하려면 기존 호스트네임은 목록에서 제거해도 됩니다. 단, 이 경우에도 검증 방법(Validation Method)은 반드시 TXT Validation으로 유지하시기 바랍니다. 도메인이 Full Setup 상태이면 Cloudflare가 TXT Validation을 통해 Domain Control Validation을 자동으로 처리합니다.
이제 새 인증서가 Pending Validation 상태로 표시됩니다.

4) Advanced Certificate 주문 (6/8)

인증서 검증 진행 중

인증서 검증 진행 중

4) Advanced Certificate 주문 (7/8)

📌 참고
Validation 완료까지 몇 분이 소요될 수 있습니다.
검증이 완료되면 브라우저에서 새 서브도메인에 다시 접속하여 정상적으로 보안 연결이 이루어지는지 확인합니다.
OpenSSL로 인증서를 다시 검사하면 새 서브도메인이 커버되는 것을 확인할 수 있습니다.
openssl s_client -connect sub2.sub1.logical-voyager.sxplab.com:443 \
  | openssl x509 -noout -ext subjectAltName
X509v3 Subject Alternative Name:
    DNS:adjective-noun.sxplab.com,
    DNS:*.adjective-noun.sxplab.com,
    DNS:sub2.sub1.adjective-noun.sxplab.com

4) Advanced Certificate 주문 (8/8)

요청 시 선택한 Google Trust Services가 발급자(Issuer)로 매칭되는 것도 확인할 수 있습니다.
참고 자료 — 발표 슬라이드

📎 Cloudflare for SaaS / SSL for SaaS 소개

이 주제는 별도 발표 자료에서 다룹니다.
HTTPS 접근 검증

3. WAF (Web Application Firewall)

실습 단계

1) WAF 배포 전 상태 확인 (1/2)

Cloudflare WAF는 별다른 설정 없이도 광범위한 보호를 즉시 제공합니다. 웹 애플리케이션의 흔한 문제 중 하나는 민감한 파일/폴더의 우발적 노출입니다.
테스트로 다음 경로에 접속해 봅니다.
https://logical-voyager.sxplab.com/.git/secrets.txt
이는 .git 버전 관리 디렉토리가 노출된 시나리오를 시뮬레이션합니다. 자격 증명이 그대로 노출됩니다.

1) WAF 배포 전 상태 확인 (2/2)

WAF 배포 전 노출된 secrets 파일

WAF 배포 전 노출된 secrets 파일

2) Cloudflare Managed Ruleset 배포 (1/3)

Cloudflare Dashboard에서 Security ‣ Settings ‣ Detection Tools로 이동하여 Cloudflare Managed Ruleset을 켭니다.
'Deploy managed ruleset' 설정 화면이 나타나며 다음을 설정할 수 있습니다.
- Execution scope: custom filter expression으로 룰셋을 특정 요청에만 적용
- Action 설정: Managed Challenge / Block / JS Challenge / Log / Interactive Challenge / Default
- 개별 룰 또는 특정 태그를 가진 룰 비활성화
- 개별 룰의 Action 오버라이드
Browse rules를 선택하면 즉시 차단되는 다양한 취약점 유형을 확인할 수 있습니다.
본 실습에서는 모든 항목을 기본값으로 유지하고 Deploy를 클릭합니다.

2) Cloudflare Managed Ruleset 배포 (2/3)

Managed Ruleset 배포

Managed Ruleset 배포

2) Cloudflare Managed Ruleset 배포 (3/3)

동일한 방식으로 OWASP Core 룰셋도 기본 설정으로 배포합니다.
룰셋에 대한 상세 내용은 Cloudflare WAF Developers Docs를 참고하시기 바랍니다.

3) Cloudflare Managed Ruleset 테스트 (1/2)

처음에 접근 가능했던 .git/secrets.txt 경로에 다시 접속해 봅니다.
https://logical-voyager.sxplab.com/.git/secrets.txt
기본 설정만으로 룰셋을 배포해도 공격이 차단되는 것을 확인할 수 있습니다.

3) Cloudflare Managed Ruleset 테스트 (2/2)

WAF 차단 페이지

WAF 차단 페이지

4) Block 이벤트 분석 (1/6)

Security > Analytics의 Events 탭으로 이동합니다. 최근 발생한 차단 이벤트가 표시됩니다 (반영까지 1분 정도 소요될 수 있음).

4) Block 이벤트 분석 (2/6)

Security Events

Security Events

4) Block 이벤트 분석 (3/6)

화면의 각 옵션을 살펴봅니다. 차단을 발생시킨 Service를 확인할 수 있으며, 스크롤하면 트리거된 룰, 소스 IP 등의 상세 정보가 나옵니다.
Activity Log의 항목을 펼치면 Ruleset, 특정 Rule ID, 요청 상세 정보 등 더욱 풍부한 정보가 제공됩니다. WAF 트리거 분석에 매우 유용합니다.

4) Block 이벤트 분석 (4/6)

Activity Log 상세

Activity Log 상세

4) Block 이벤트 분석 (5/6)

해당 룰에 대해 필터를 추가하여 동일 룰과 관련된 모든 이벤트를 한 번에 확인할 수 있습니다.

4) Block 이벤트 분석 (6/6)

룰별 필터 적용

룰별 필터 적용

5) Custom Rule 생성 (1/11)

본격적인 실습 전에 Cloudflare Rule Operators Docs를 가볍게 살펴보시기 바랍니다.
Custom Rule은 사용자가 정의한 룰에 따라 Zone으로 들어오는 요청을 필터링하고 Block, Managed Challenge 등의 액션을 수행할 수 있게 합니다.
본 실습에서는 AcmeCorp Contact 페이지 접근 시 Managed Challenge를 제시하는 단순한 룰을 만듭니다.
Security ‣ Security rules ‣ Create rule ‣ Custom rules로 이동합니다.

5) Custom Rule 생성 (2/11)

Custom Rule 생성

Custom Rule 생성

5) Custom Rule 생성 (3/11)

다음과 같이 설정합니다.
- Name: "Challenge Contact Requests"와 같이 식별 가능한 이름
- Field: URI Path
- Operator: equals
- Value: /contact/
- Choose action: Managed Challenge

5) Custom Rule 생성 (4/11)

Custom Rule 설정 화면

Custom Rule 설정 화면

5) Custom Rule 생성 (5/11)

Deploy 후 Contact 페이지로 이동하면 Managed Challenge가 표시됩니다.
📌 참고
Managed Challenge가 보이지 않으면 시크릿/프라이빗 탭이나 다른 브라우저로 시도하시기 바랍니다.

5) Custom Rule 생성 (6/11)

Managed Challenge 화면

Managed Challenge 화면

5) Custom Rule 생성 (7/11)

일반적으로 최신 브라우저의 실제 사용자는 자동으로 통과되어 요청한 페이지로 리다이렉트됩니다. 인간 인증을 요구받으면 체크박스를 클릭합니다.

5) Custom Rule 생성 (8/11)

Challenge 통과 후 Contact 페이지

Challenge 통과 후 Contact 페이지

5) Custom Rule 생성 (9/11)

curl로 동일 요청을 시도하면 어떤 결과가 나오는지도 확인해 보시기 바랍니다.
브라우저 개발자 도구의 Network 탭에서 Cookies를 확인하면, Challenge 통과 시 cf_clearance 쿠키가 발급되어 반복적인 Challenge를 방지하는 것을 볼 수 있습니다. 이 쿠키 때문에 동일 브라우저에서는 다시 Challenge가 보이지 않을 수 있으니, 다른 브라우저나 시크릿 모드를 활용하시기 바랍니다.

5) Custom Rule 생성 (10/11)

cf_clearance 쿠키

cf_clearance 쿠키

5) Custom Rule 생성 (11/11)

Custom Rule의 다양한 use case는 Common use cases for custom rules를 참고하시기 바랍니다.

6) Rate Limiting Rule 생성 (1/10)

Managed Ruleset과 Custom Rule을 배포했으니, 이제 Advanced Rate Limiting으로 AcmeCorp 애플리케이션을 더 강화합니다.
Security ‣ Security rules ‣ Create Rule에서 Rate limiting rules를 선택합니다.

6) Rate Limiting Rule 생성 (2/10)

Rate Limiting Rule 생성

Rate Limiting Rule 생성

6) Rate Limiting Rule 생성 (3/10)

목표: brute force 공격을 방지하기 위해 분당 5회로 요청 제한합니다.
설정 값:
- Field: URI Path
- Operator: Contains
- Value: /services/safes/
- Characteristics: IP
- When Rate exceeds...: 5 requests / 1 minute
- Action: Block (Response Type: Default)
- Behavior: Block for the selected duration → 1 minute

6) Rate Limiting Rule 생성 (4/10)

Rate Limiting 설정 완료

Rate Limiting 설정 완료

6) Rate Limiting Rule 생성 (5/10)

Deploy 후 테스트합니다.
이번 예시에서 contains를 사용한 이유는, equals는 명시적 매칭이므로 /contact 정책이 redirect로 인해 /contact/가 되는 경우 매칭되지 않을 수 있기 때문입니다. contains는 더 유연합니다.
curl 테스트 (macOS / Linux)
for i in {1..10}; do
  curl -svo /dev/null \
    "https://logical-voyager.sxplab.com/services/safes/" 2>&1 \
    | grep "< HTTP.* "
done
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429

6) Rate Limiting Rule 생성 (6/10)

PowerShell 테스트 (Windows)
for (($i = 0); $i -lt 10; $i++) {
  try {
    $Response = Invoke-WebRequest -Uri "https://logical-voyager.sxplab.com/services/safes/"
    $StatusCode = $Response.StatusCode
  } catch {
    $StatusCode = $_.Exception.Response.StatusCode.value__
  }
  "#$i - $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $StatusCode"
}
5개의 정상 200 응답 이후, 6번째 요청부터 HTTP 429 (Too Many Requests)가 반환되며 Rate Limit이 적용됩니다. 다른 페이지에서는 429가 발생하지 않는 것도 확인해 보시기 바랍니다.
📌 참고
curl 사용이 어렵다면 브라우저에서 페이지를 빠르게 새로고침해도 임계치가 낮아 테스트가 가능합니다.

6) Rate Limiting Rule 생성 (7/10)

Rate Limit 적용 화면

Rate Limit 적용 화면

6) Rate Limiting Rule 생성 (8/10)

1분 대기 후 다시 시도하면 정상 접근됩니다.

6) Rate Limiting Rule 생성 (9/10)

Rate Limit 해제 후 정상 접근

Rate Limit 해제 후 정상 접근

6) Rate Limiting Rule 생성 (10/10)

Rate Limiting 상세 옵션은 Advanced rate limiting documentation을 참고하시기 바랍니다.
1000개 동시 요청

4. Bot Management

실습 단계

1) Definite Bot 대응 템플릿 룰 배포

Cloudflare Dashboard에서 Security ‣ Security rules ‣ Templates로 이동합니다.
Rules template에서 "bots"로 검색한 뒤 Mitigate definite bot traffic 템플릿의 Preview template을 클릭합니다.
준비된 룰이 자동으로 채워진 Custom Rules 화면이 나타납니다. 다른 실습에 영향을 주지 않도록 존재하지 않는 경로로 한정합니다.
- 마지막 URI Path 조건의 Operator를 contains로 설정
- Value를 /hellobots로 설정
- Action: Block (기본값)
Deploy합니다.

2) 룰 테스트 (1/3)

/hellobots 엔드포인트에 대해 HTTP 헤더를 검사합니다.
curl
curl -I "https://logical-voyager.sxplab.com/hellobots"
< HTTP/2 403
< date: Thu, 26 Oct 2023 14:27:56 GMT
< content-type: text/html; charset=UTF-8
< content-length: 4512
< server: cloudflare
< cf-ray: 81c362047fbe45a0-LHR

2) 룰 테스트 (2/3)

PowerShell
Invoke-WebRequest -Uri "https://logical-voyager.sxplab.com/hellobots" -method HEAD
Invoke-WebRequest: Response status code does not indicate success: 403 (Forbidden).

2) 룰 테스트 (3/3)

curl과 PowerShell 명령은 모두 자동화 도구로 인식되어 룰이 트리거되고 차단됩니다.

3) 차단 이벤트 분석

Security ‣ Analytics에서 차단을 트리거한 요청을 확인합니다. 어떤 룰이 차단을 일으켰는지 확인합니다.
이벤트가 즉시 보이지 않거나 더 좁은 시간 범위로 보고 싶다면 Previous 30 minutes로 전환합니다.
참고 자료 — 발표 슬라이드

📎 Caching 개요

이 주제는 별도 발표 자료에서 다룹니다.
Part II

5. Cache Tuning

실습 단계

📌 참고
대부분의 예시는 curl을 사용하지만, 브라우저 및 PowerShell 예시도 함께 제공됩니다. 편한 도구를 활용하시기 바랍니다.

1) 기본 동작 분석 (1/2)

curl 또는 PowerShell로 HTTP 응답 헤더를 확인합니다.
curl
curl -I "https://logical-voyager.sxplab.com/services/luggages/"
< HTTP/2 200
< date: Thu, 26 Oct 2023 07:42:38 GMT
< content-type: text/html
< x-origin: origin-1
< cf-cache-status: DYNAMIC
< server: cloudflare
< cf-ray: 81c110540d6823ab-LHR

1) 기본 동작 분석 (2/2)

여기서 주목할 헤더는 cf-cache-status입니다. 값이 DYNAMIC이라는 것은 이 리소스가 캐시 대상이 아니며 origin에서 직접 가져왔다는 의미입니다.
curl이 없다면 브라우저 Developer Tools (F12)의 Network 탭에서 동일하게 확인할 수 있습니다. 이때 Disable cache 체크박스로 브라우저 캐시를 비활성화하시기 바랍니다.

2) /services/luggages 용 Cache Rule 생성 (1/3)

Caching ‣ Cache Rules에서 Create rule을 선택합니다.
- Name: "Cache HTML on Luggages Page" 등 식별 가능한 이름
- Field: URI Path
- Operator: equals
- Value: /services/luggages/
- Cache status: Eligible for cache
추가 설정으로 다음을 커스터마이즈할 수 있습니다.
- Edge TTL: Cloudflare 네트워크에 캐시되는 시간
- Browser TTL: 방문자 브라우저에 캐시되는 시간
- Cache Key: 캐시 키 구성 요소 커스터마이즈
- Serve Stale Content: 백그라운드 재검증 중 stale 콘텐츠 서빙
- Respect Strong ETags: 재검증을 위한 strong ETag 사용
- Origin Error Page Pass-thru: origin 에러 페이지 통과
Edge TTL 우측에서 + Add Setting을 클릭하고 Ignore cache-control header and use this TTL을 선택, 30초로 설정합니다.

2) /services/luggages 용 Cache Rule 생성 (2/3)

Cache Rule 설정

Cache Rule 설정

2) /services/luggages 용 Cache Rule 생성 (3/3)

기타 값은 기본값으로 두고 Deploy합니다.
이로써 /services/luggages/ 경로의 모든 콘텐츠가 캐시 대상이 되며, origin의 cache-control 헤더는 무시되고 Cloudflare 엣지에서 30초간 캐시됩니다.

3) Cache Rule 테스트 (1/2)

curl -I "https://logical-voyager.sxplab.com/services/luggages/"
< HTTP/2 200
< x-origin: origin-2
< cf-cache-status: MISS
< server: cloudflare
cf-cache-status가 MISS로 변경된 것이 보입니다. 캐시 대상이지만 캐시에 없어서 origin에서 가져왔다는 의미입니다.
즉시 다시 실행해 봅니다.
< HTTP/2 200
< x-origin: origin-2
< cf-cache-status: HIT
< age: 19

3) Cache Rule 테스트 (2/2)

HIT이 발생했고 캐시에서 서빙된 것이 19초 전임을 age 헤더로 알 수 있습니다.
30초 이상 기다린 뒤 다시 시도하면 다음과 같이 REVALIDATED 상태가 보입니다.
< cf-cache-status: REVALIDATED
다른 페이지를 시도해보면 여전히 cf-cache-status가 DYNAMIC인 것을 볼 수 있습니다.

4) 범위 확장 (1/7)

적절히 활용된 캐싱은 성능 향상과 origin 부하 감소에 큰 도움이 됩니다. 위 룰을 확장하여 /services/ 하위 전체를 커버해 봅니다.
기존 룰을 수정합니다.
- Field: URI Path 유지
- Operator: contains
- Value: /services/
기타 값은 그대로 두고 Save합니다.
/services/arrows/ 등 다른 페이지로 테스트하여 cache HIT을 확인합니다.
curl -I "https://logical-voyager.sxplab.com/services/arrows/"
< HTTP/2 200
< x-origin: origin-2
< cf-cache-status: HIT
< age: 3

4) 범위 확장 (2/7)

이번엔 캐시 룰에 매칭되지만 존재하지 않는 페이지에 접근해 봅니다.
curl -I "https://logical-voyager.sxplab.com/services/doesnotexist/"
< HTTP/2 404
< cf-cache-status: MISS

4) 범위 확장 (3/7)

재실행:
< HTTP/2 404
< cf-cache-status: HIT
< age: 73
여기서 이상한 점을 발견할 수 있습니다.
- 404 응답인데 cache HIT이 발생합니다.
- age 값이 우리가 설정한 TTL(30초)보다 큽니다.
Cache by status code 문서에 따르면 404 에러 코드의 기본 TTL은 3분(180초)입니다.
이를 수정하려면 룰에서 404 응답에 대한 default 동작을 override해야 합니다.
먼저 캐시를 purge합니다. Caching ‣ Configuration ‣ Custom Purge로 이동합니다.

4) 범위 확장 (4/7)

캐시 Purge

캐시 Purge

4) 범위 확장 (5/7)

Purge 방법은 Cache Purge Dev Docs를 참고하시기 바랍니다.
다시 Cache Rules로 돌아와 Status code TTL을 설정합니다.
- 기존 Edge TTL 섹션에서 Add status code setting 선택
- Scope: Single Code
- Status code: 404
- Duration: 10초

4) 범위 확장 (6/7)

Status code TTL 설정

Status code TTL 설정

4) 범위 확장 (7/7)

저장 후 재테스트하면 age가 0~10 사이일 때 HIT, 10초가 지나면 EXPIRED, 그 직후에 다시 HIT이 나타납니다.
상태 코드별 캐시 동작을 이해하는 것은 중요하며, 404 페이지가 캐시되는 시나리오는 흔한 운영 이슈입니다.
Part II

6. Load Balancer

실습 단계

본 실습에서는 공유 origin (legacy LB 뒤의 2대 origin 서버)을 다시 사용합니다.
Origin 1:   52.191.5.18
Origin 2:   52.170.37.97
Legacy LB:  20.88.188.200   ← 본 실습에서는 사용하지 않음
Cloudflare Load Balancer를 두 origin 서버 앞에 두어 legacy LB를 대체합니다.
📌 참고
각 origin 서버는 응답에 X-Origin 헤더를 추가하므로 어느 origin이 응답했는지 추적할 수 있습니다.
curl --head 52.191.5.18
curl --head 52.170.37.97

1) Load Balancer 생성 (1/2)

Dashboard의 Zone에서 Traffic ‣ Load Balancing으로 이동하여 새 Load Balancer를 생성합니다.
LB용 새 호스트네임으로 기존 zone에 lb 접두어를 추가합니다. Session Affinity와 Adaptive Routing은 일단 OFF로 둡니다.

1) Load Balancer 생성 (2/2)

Load Balancer 생성

Load Balancer 생성

2) Origin Pool 생성 (1/2)

다음 단계에서 Origin Pool 추가가 요청되면 Create a pool을 선택합니다.
Pool 이름을 입력하고 Endpoint Steering을 Random으로 설정한 뒤 두 origin을 추가합니다.
Name      IP             Weight
origin-1  52.191.5.18    1
origin-2  52.170.37.97   1
페이지 하단에서 Health Check Regions을 Western North America로 설정합니다 (origin이 위치한 리전).

2) Origin Pool 생성 (2/2)

Origin Pool 생성

Origin Pool 생성

3) Monitor 생성 (1/4)

다음 페이지에서 Attach monitor, Create a Monitor를 선택합니다.
본 실습에서는 단순 HTTP monitor를 생성합니다.

3) Monitor 생성 (2/4)

HTTP Monitor 생성

HTTP Monitor 생성

3) Monitor 생성 (3/4)

Monitor 첨부 시 기본값으로 Save하고 다음 단계로 진행합니다.

3) Monitor 생성 (4/4)

Monitor 첨부

Monitor 첨부

4) Traffic Steering

Pool이 하나뿐이므로 Traffic Steering은 Off로 유지합니다.
나머지 설정을 건너뛰고 Save and Deploy로 마무리합니다.

5) 테스트 (1/3)

LB로 여러 요청을 보내 random 분산이 되는지 확인합니다.
while true; do
  curl -s --head https://lb.logical-voyager.sxplab.com | grep -i x-origin
done
X-Origin: origin-2
X-Origin: origin-2
X-Origin: origin-1
X-Origin: origin-1
...

5) 테스트 (2/3)

브라우저에서는 페이지를 여러 번 새로고침하면 다른 origin이 응답하는 것을 확인할 수 있습니다.

5) 테스트 (3/3)

LB 응답 확인

LB 응답 확인

6) Origin 하나 비활성화

Load Balancing 메인 페이지로 돌아가 Manage Pools에서 생성한 origin pool을 펼치고 origin 하나를 비활성화합니다. origin 장애를 시뮬레이션하는 단계입니다.

7) 재테스트

테스트하면 모든 트래픽이 활성화된 origin 하나로 라우팅되는 것을 확인할 수 있습니다.
X-Origin: origin-2
X-Origin: origin-2
X-Origin: origin-2
...

8) Session Affinity 구성 (1/2)

Origin pool에서 두 origin을 모두 활성화하고 메인 Load Balancing 페이지로 돌아가 생성한 LB의 Edit을 클릭합니다.
Session Affinity를 활성화하고 By Cloudflare cookie and Client IP fallback을 선택합니다.
이렇게 하면 동일 브라우저(쿠키)나 동일 클라이언트(IP)의 모든 요청이 동일 origin으로 처리됩니다. 자세한 내용은 Session Affinity 문서를 참고하시기 바랍니다.

8) Session Affinity 구성 (2/2)

Session Affinity 설정

Session Affinity 설정

9) 재테스트

동일 브라우저의 모든 요청이 일관되게 동일 origin으로 서빙됩니다. 다른 브라우저에서는 다른 origin이 응답할 수 있지만, 같은 브라우저 내에서는 항상 같은 origin이 응답합니다.
Part II

7. Rules (Transform / Redirect)

실습 단계

1) 모든 응답에 헤더를 추가하는 Transform Rule (1/7)

Transform Rules는 Cloudflare 글로벌 네트워크에서 요청/응답의 URI path, query string, HTTP 헤더를 조정합니다.
본 실습에서는 공통 보안 헤더 X-Frame-Options을 모든 응답에 추가합니다. 이후 Managed Transforms로 더 간단히 수행하는 방법도 확인합니다.
Rules ‣ Overview로 이동하여 Response Header Transform Rules 섹션의 Create rule을 클릭합니다.

1) 모든 응답에 헤더를 추가하는 Transform Rule (2/7)

Response Header Transform Rule 생성

Response Header Transform Rule 생성

1) 모든 응답에 헤더를 추가하는 Transform Rule (3/7)

미리 정의된 템플릿이 보입니다.

1) 모든 응답에 헤더를 추가하는 Transform Rule (4/7)

Transform Rule 템플릿

Transform Rule 템플릿

1) 모든 응답에 헤더를 추가하는 Transform Rule (5/7)

본 실습에서는 템플릿 대신 직접 룰을 작성합니다.
- Rule name: "Add X-Frame-Options" 등 식별 가능한 이름
- If incoming requests match...: All incoming requests
- Then...: Add
- Header name: X-Frame-Options
- Value: SAMEORIGIN
원하면 다른 임의의 헤더도 추가할 수 있습니다.

1) 모든 응답에 헤더를 추가하는 Transform Rule (6/7)

Transform Rule 작성

Transform Rule 작성

1) 모든 응답에 헤더를 추가하는 Transform Rule (7/7)

Deploy합니다.

2) 응답 헤더 검증

curl -I "https://logical-voyager.sxplab.com/services/luggages/"
HTTP/2 200
date: Fri, 24 Jan 2025 04:36:50 GMT
content-type: text/html
x-origin: origin-1
cf-cache-status: DYNAMIC
x-frame-options: SAMEORIGIN
some-other-header: Hello
server: cloudflare
방금 정의한 x-frame-options 헤더 및 기타 헤더가 응답에 포함된 것이 확인됩니다.

3) Managed Transforms로 보안 헤더 추가 (1/5)

이제 한 번에 더 많은 보안 헤더를 추가하는 방법을 살펴봅니다.
먼저 방금 배포한 룰을 Disable합니다. Rules ‣ Overview → Response Header Transform Rules → Manage Response Header Transform Rules로 이동합니다.

3) Managed Transforms로 보안 헤더 추가 (2/5)

Managed Transforms 진입

Managed Transforms 진입

3) Managed Transforms로 보안 헤더 추가 (3/5)

Managed Transforms 탭으로 전환합니다. 다양한 공통 시나리오에 대한 옵션이 제공됩니다. HTTP response headers 섹션에서 Add security headers를 활성화합니다.

3) Managed Transforms로 보안 헤더 추가 (4/5)

Add security headers 활성화

Add security headers 활성화

3) Managed Transforms로 보안 헤더 추가 (5/5)

다시 curl로 확인하면 x-xss-protection, x-content-type-options 등 새 헤더가 추가된 것이 보입니다.
HTTP/2 200
x-origin: origin-1
cf-cache-status: DYNAMIC
referrer-policy: same-origin
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
server: cloudflare

4) URL Rewrite Rule 추가 (1/4)

URL은 그대로 두면서 다른 콘텐츠를 서빙하고 싶은 경우가 있습니다. /services/arrows로 요청이 들어오면 /services/luggages 페이지를 보여주도록 구성해 봅니다.
Rules ‣ Overview의 URL Rewrite Rules 섹션에서 Create rule을 선택합니다.
- Rule name: "Show Luggages Page on Arrows URL"
- If incoming requests match...: Custom filter expression
- Field: URI Path
- Operator: equals
- Value: /services/arrows/
- Then...: Rewrite to...
- Static: services/luggages/

4) URL Rewrite Rule 추가 (2/4)

URL Rewrite Rule 작성

URL Rewrite Rule 작성

4) URL Rewrite Rule 추가 (3/4)

Deploy합니다.
브라우저에서 /services/arrows/로 접속하면 URL은 arrows로 유지된 채 Luggages 페이지의 내용이 표시됩니다. 이는 HTTP redirect가 아니라 동일 URL에 대해 다른 콘텐츠가 반환되는 방식입니다.

4) URL Rewrite Rule 추가 (4/4)

URL Rewrite 결과

URL Rewrite 결과

5) (선택) 추가 룰 작성

Rules의 다양한 옵션을 탐색해 보시기 바랍니다. 예시: /services/calculators/로 들어오는 요청을 AcmeCorp 홈페이지로 redirect하는 룰을 만들 수 있는지 시도해 보시기 바랍니다.