Cloudflare
NGINX
ingress controller
client IP restoration
web server configuration

How to restore original client IP from Cloudflare with NGINX ingress controller

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When Cloudflare proxies traffic, your Kubernetes ingress often sees Cloudflare edge addresses instead of real visitor addresses. That breaks IP-based rate limits, audit logs, and geolocation logic unless real IP handling is configured correctly. This guide shows a reliable setup for NGINX Ingress Controller and how to verify it end to end.

Core Topic Sections

Understand header flow before changing config

Cloudflare forwards client information through headers such as:

  1. CF-Connecting-IP
  2. X-Forwarded-For
  3. X-Real-IP in some paths

NGINX must trust Cloudflare source ranges and then rewrite remote address fields using those headers. If trust is too broad, IP spoofing risk increases. If trust is too narrow, you keep seeing Cloudflare edge addresses.

Configure NGINX Ingress controller ConfigMap

For ingress-nginx, real IP behavior is usually controlled in the controller ConfigMap.

Example values:

yaml
1apiVersion: v1
2kind: ConfigMap
3metadata:
4  name: ingress-nginx-controller
5  namespace: ingress-nginx
6data:
7  use-forwarded-headers: "true"
8  enable-real-ip: "true"
9  real-ip-header: "CF-Connecting-IP"
10  proxy-real-ip-cidr: "173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"

Update CIDR list from Cloudflare official published ranges periodically.

Decide between CF-Connecting-IP and X-Forwarded-For

For Cloudflare-only front doors, CF-Connecting-IP is usually simpler and less ambiguous. X-Forwarded-For can contain chains from multiple proxies and requires careful parsing.

Practical rule:

  1. Cloudflare as single external proxy, prefer CF-Connecting-IP.
  2. Multi-proxy path with known chain model, X-Forwarded-For may be better.

Consistency across logging, WAF, and app frameworks matters more than header preference alone.

Apply and roll out controller config safely

After changing ConfigMap, ensure controller picks up new values. Some deployments hot-reload, others need rollout restart.

bash
kubectl apply -f ingress-configmap.yaml
kubectl rollout restart deployment ingress-nginx-controller -n ingress-nginx
kubectl rollout status deployment ingress-nginx-controller -n ingress-nginx

Do this in controlled windows if IP-based policies affect production traffic.

Verify at ingress and app layers

Verification should happen at two levels.

Ingress logs:

bash
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=200 | grep -i "GET /"

Application echo endpoint:

python
1from flask import Flask, request
2
3app = Flask(__name__)
4
5@app.get("/debug/ip")
6def debug_ip():
7    return {
8        "remote_addr": request.remote_addr,
9        "x_forwarded_for": request.headers.get("X-Forwarded-For"),
10        "cf_connecting_ip": request.headers.get("CF-Connecting-IP")
11    }

Confirm remote_addr matches expected client address when request enters through Cloudflare.

Secure trust boundary to prevent spoofing

Do not trust all source addresses for real IP rewriting. Trust only Cloudflare networks. Otherwise, a direct caller can inject fake CF-Connecting-IP or X-Forwarded-For values.

Hardening steps:

  1. Restrict service exposure so traffic must pass through Cloudflare.
  2. Restrict trusted proxy CIDRs to Cloudflare ranges.
  3. Optionally enforce origin access controls at network edge.

These controls prevent bypass and preserve log integrity.

Keep Cloudflare range updates operationalized

Cloudflare ranges can change. Treat updates as routine maintenance:

  1. Track range source in infrastructure docs.
  2. Use scheduled review or automation pipeline to update ConfigMap.
  3. Test in staging before production apply.

Stale CIDR lists are a common reason real IP restoration breaks silently.

Troubleshooting checklist

If still seeing proxy IPs:

  1. Confirm correct controller namespace and ConfigMap name.
  2. Confirm controller actually reads that ConfigMap.
  3. Check header availability at ingress layer.
  4. Validate Cloudflare proxy mode is enabled on the DNS record.

Troubleshooting is usually a mismatch between intended config and active controller runtime.

Common Pitfalls

  • Trusting 0.0.0.0/0 for real IP and enabling header spoofing paths.
  • Using wrong ConfigMap key names for the ingress-nginx version in use.
  • Forgetting controller restart where hot reload is not active.
  • Assuming X-Forwarded-For format is always single-hop and stable.
  • Not updating Cloudflare CIDR ranges over time.

Summary

  • Cloudflare proxying hides client addresses unless ingress real IP logic is configured.
  • Configure trusted source CIDRs and choose a consistent real IP header.
  • Verify both ingress logs and application-level observed address.
  • Lock trust boundaries to prevent spoofing.
  • Keep Cloudflare range management as an operational maintenance task.

Course illustration
Course illustration

All Rights Reserved.