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 처리 방식은 서비스 초기에 공통 유틸로 정리해두는 것이 좋습니다.