Cloudflare Tunnel 환경에서 실제 방문자 IP를 처리하는 방법
Cloudflare Tunnel로 서비스를 노출하면 origin 서버가 보는 접속 IP가 실제 방문자 IP가 아닐 수 있습니다. 모든 요청이 터널 또는 프록시에서 온 것처럼 보이면 rate limit, 방문 통계, IP 차단 같은 기능이 부정확해집니다.
왜 실제 IP가 안 보이나
Cloudflare Tunnel 구조는 대략 다음과 같습니다.
[방문자]
→ [Cloudflare Edge]
→ [cloudflared Tunnel]
→ [origin server]origin 서버 입장에서는 TCP 연결의 출발지가 방문자가 아니라 터널 또는 내부 프록시입니다. 실제 방문자 IP는 HTTP 헤더로 전달됩니다.
우선 확인할 헤더
Cloudflare는 실제 방문자 IP를 다음 헤더에 담아 전달합니다.
| 헤더 | 용도 |
|---|---|
CF-Connecting-IP |
Cloudflare가 전달하는 실제 방문자 IP. 가장 우선적으로 사용 |
X-Forwarded-For |
여러 프록시를 거친 IP 체인 |
X-Real-IP |
일부 프록시 환경에서 사용하는 단일 IP |
Cloudflare를 신뢰할 수 있는 경로로만 origin에 접근하게 했다면 CF-Connecting-IP를 우선 사용하는 것이 가장 단순합니다.
애플리케이션에서 처리하기
Next.js 같은 앱에서는 요청 헤더에서 IP를 추출하는 공통 함수를 두는 것이 좋습니다.
export function clientIpFromHeaders(headers: Headers): string {
const cf = headers.get('cf-connecting-ip');
if (cf) return cf.trim();
const forwarded = headers.get('x-forwarded-for');
if (forwarded) return forwarded.split(',')[0].trim();
return headers.get('x-real-ip') || 'unknown';
}이 함수를 rate limit, 로그인 보호, 방문 통계 등 IP 기반 로직에서 일관되게 사용합니다.
nginx에서 처리하기
nginx 앞단에서 real_ip_header CF-Connecting-IP를 설정하면 애플리케이션은 remote_addr 기준으로 실제 IP를 볼 수 있습니다.
다만 이 방식은 신뢰할 프록시 범위를 정확히 지정해야 합니다. Cloudflare IP 대역과 내부 터널 네트워크를 과도하게 넓게 신뢰하면 헤더 위조 위험이 생길 수 있습니다.
운영 환경에서는 Cloudflare IP ranges를 정기적으로 확인하고, origin이 외부에서 직접 접근되지 않도록 제한하는 것이 좋습니다.
검증 방법
서로 다른 네트워크에서 방문자 IP 확인용 API를 호출해 봅니다.
- 사무실 Wi-Fi
- 휴대폰 LTE/5G
- VPN 또는 다른 네트워크
각 요청이 서로 다른 IP로 기록되면 정상입니다. 모두 같은 내부 IP로 보인다면 아직 프록시 IP를 보고 있는 것입니다.
주의할 점
IP 기반 보안은 절대적인 인증 수단이 아닙니다. 특히 프록시 헤더는 신뢰 경계가 잘못 설정되면 위조될 수 있습니다. 따라서 IP는 rate limit과 보조 보안 신호로 사용하고, 인증·권한 검증을 대체해서는 안 됩니다.
듀오랩스가 보는 관점
Cloudflare Tunnel은 배포와 보안을 단순하게 만들어주지만, 프록시 구조를 이해하지 않으면 로그와 보안 정책이 왜곡될 수 있습니다. 실제 방문자 IP 처리 방식은 서비스 초기에 공통 유틸로 정리해두는 것이 좋습니다.
우리 서비스에 적용할 계획이 있으신가요?
클라우드 구축·배포 운영 살펴보기 →함께 읽기
- Cloudflare Tunnel로 Vercel을 연결하면 안 되는 이유Vercel 배포는 성공했습니다. 프로젝트명.vercel.app 으로 접속하면 잘 뜹니다.
- 새 서브도메인이 특정 브라우저에서만 안 열릴 때: DNS 캐시 점검법새 서브도메인을 추가한 직후 “Safari에서는 열리는데 Chrome에서는 안 열린다” 같은 일이 생길 수 있습니다. 이럴 때 바로 서버 장애나 DNS 설정 오류라고 판단하기 쉽지만, 실제 원인은 로컬 또는 브라우저 DNS 캐시인 경우가 많습니다.
- Cloudflare를 붙였는데 한국에서 오히려 느려진 이유한국 사용자를 대상으로 운영 중인 데모 사이트에서 응답 지연을 점검했습니다. 도메인은 Cloudflare 프록시를 거치게 해뒀고, 원본 IP와 오리진을 보호하기 위해 켜둔 상태였습니다. 그러다 사이트를 손보는 중에 "버튼이 한 박자 늦게 눌리는 것 같다"는 얘기가 나왔고, 확인해 보니 앱 코드가 아니라 이 프록시 경로가…
- Cache-Control: immutable인데 왜 Cloudflare는 계속 DYNAMIC이었을까요?CDN을 붙이고 응답 헤더에 긴 캐시 시간을 설정했는데도 CF-Cache-Status가 계속 DYNAMIC으로 표시되는 경우가 있습니다. 저희도 파일 제공 기능을 점검하면서 같은 상황을 만났습니다.
- 한국에서 Cloudflare 엣지가 서울이 아닐 때: 무료 플랜의 POP 배정이미지 엣지 캐시를 손보고 나서 얼마나 빨라졌는지 재고 있었습니다. 캐시에서 나오면 156ms, 오리진까지 가면 622ms. 4배 차이니까 좋아하고 있었는데, 156ms라는 숫자가 자꾸 걸렸습니다.