CF-Connecting-IP
The HTTP CF-Connecting-IP request header is an unofficial header carrying the address of the client connecting to Cloudflare. Cloudflare adds the header on the leg from its edge to the origin, so the value reaches the application while the browser never sees the field.
Usage
A proxied request arrives at the origin from a
Cloudflare address rather than from the visitor, so
REMOTE_ADDR and every log line built from the
connection report the edge instead of the person.
CF-Connecting-IP restores the missing
information.
The header holds exactly one address in every case, which is the practical reason to prefer the header over X-Forwarded-For. A list arriving in X-Forwarded-For needs parsing and a decision about which entry to trust, and a single value needs neither.
Cloudflare recommends reading CF-Connecting-IP rather than X-Forwarded-For for exactly this reason.
Traffic reaching the origin outside the proxy carries no CF-Connecting-IP at all. A DNS-only record resolves to the origin address directly, leaving no edge leg to add the header, and the same applies to anyone connecting to the origin address after discovering the location. Spectrum applications running over plain TCP also leave the header absent, since the field belongs to HTTP rather than to the transport.
Values
The value is a single bare IP address. IPv4 appears in dotted-quad form and IPv6 in ordinary text form without surrounding brackets. Documented examples carry no port.
CF-Connecting-IP: 203.0.113.1
CF-Connecting-IP: 2001:db8::8a2e:370:7334
IPv6 visitors reaching an IPv4 origin
An IPv6 client reaching an origin understanding only IPv4 leaves the origin with an address outside anything the software stores or compares. Cloudflare offers Pseudo IPv4 for the gap, with three settings available on all plans.
Leaving the feature off passes the real IPv6 address through unchanged.
Add Header keeps CF-Connecting-IP on the real
IPv6 address and adds CF-Pseudo-IPv4 carrying a
Class E IPv4 address hashed from the IPv6 value.
Overwrite Headers replaces CF-Connecting-IP
and X-Forwarded-For with the
pseudo IPv4 address, and preserves the real address
in CF-Connecting-IPv6. Origins needing no code
changes take this option.
Class E addresses sit in an experimental range reserved away from production internet traffic, which is what makes them safe to synthesise. Software validating addresses against public ranges rejects them, so a pseudo address occasionally fails a check written for real traffic.
Both companion headers appear only under their own
setting. CF-Connecting-IPv6 is not a routine
counterpart to CF-Connecting-IP on IPv6 traffic,
and CF-Pseudo-IPv4 arrives only where Add Header is
active.
Related headers
True-Client-IP carries an identical value under a
different name, enabled through a Cloudflare
Managed Transform, and exists for equipment already
configured to read the
alternate name. Nothing separates the two beyond the
naming.
The name is not exclusive to Cloudflare. Akamai emits
True-Client-IP as well, so an origin behind a
stacked configuration reads whichever proxy wrote
last. Cloudflare's own guidance covers the case: an
origin authenticating on True-Client-IP sets the
header on its own requests, since an unset header
accepts any value an attacker supplies.
Cloudflare appends to X-Forwarded-For rather than replacing the value, which is the detail most often stated backwards. A request arriving with no such header reaches the origin carrying the visitor address alone. A request arriving through other proxies reaches the origin with the address of the proxy connecting to Cloudflare appended to whatever came before.
Other vendors solve the same problem under their own
names. Fastly sends Fastly-Client-IP, and AWS
CloudFront sends CloudFront-Viewer-Address, which
carries a port alongside the address and needs
splitting before use.
Trusting the header
Any client sets CF-Connecting-IP on a request. An origin reachable on its own address receives whatever an attacker writes, and treating the value as authentic hands over control of rate limiting, geolocation, audit trails, and address-based access rules.
The header earns trust from the connection carrying the value rather than from the value itself. Restricting the origin to Cloudflare connections makes the field meaningful, and Cloudflare documents three approaches with different strength.
Authenticated Origin Pulls verifies a client certificate at the origin, proving the request came through Cloudflare. Available on every plan, and Cloudflare rates the approach highly. Certificate scope matters: the shared global certificate proves only a Cloudflare account sent the request, while a zone-level or per-hostname certificate proves the request came through a specific account.
Allowlisting Cloudflare address ranges at the firewall is simpler and weaker, and Cloudflare describes the approach as moderately secure and vulnerable to address spoofing. The published ranges change, so a static copy in a firewall rule drifts.
Cloudflare Tunnel removes the inbound path entirely by having the origin dial out, which earns the same high rating as Authenticated Origin Pulls.
Current ranges live at cloudflare.com/ips-v4 and
cloudflare.com/ips-v6 as plain text, and at
api.cloudflare.com/client/v4/ips as JSON needing no
authentication. Automating the refresh keeps firewall
rules aligned with the published list.
Restoring the visitor IP at the origin
Reading the header inside application code works and leaves server logs still recording Cloudflare addresses. Restoring the address at the server layer fixes logs, rate limiting, and application code together.
nginx
The real IP module rewrites the connection address
from a trusted header. Each Cloudflare range needs
its own set_real_ip_from line, and the module
ignores the header from any other source.
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
# repeat for every published Cloudflare range
real_ip_header CF-Connecting-IP;
Logging the original address without rewriting the connection uses the header variable directly.
log_format cf '$http_cf_connecting_ip - $remote_user '
'[$time_local] "$request" $status';
Apache
Apache uses mod_remoteip. The older
mod_cloudflare module is deprecated and unsupported
from Debian 9 and Ubuntu 18.04 onward.
sudo a2enmod remoteip
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 103.21.244.0/22
# repeat for every published Cloudflare range
Access logs continue recording the connection address
until the format string changes, so %h becomes %a
to log the restored client address.
LogFormat "%a %l %u %t \"%r\" %>s %O" combined
Loading the ranges from a file through
RemoteIPTrustedProxyList keeps the configuration
short where the full list runs to twenty or more
entries.
The trust list is the security control
Both modules apply the header only when the connection arrives from a listed address, which is what turns a spoofable field into a reliable one. Configuring either module with a permissive trust list, or reading the header in application code with no source check at all, reintroduces the original exposure.
Reading the address in a Worker
Workers read the header directly. The request.cf
object carries geolocation, ASN, and TLS details
about the same visitor and holds no address field, so
the header is the only route.
const clientIP = request.headers.get("CF-Connecting-IP");
Subrequests behave differently depending on the destination. A subrequest to another Cloudflare zone arrives carrying a Cloudflare address rather than the visitor address, which is deliberate. A subrequest to an origin outside Cloudflare carries the visitor address as normal.
Example
A visitor on 203.0.113.1 requests a page through
Cloudflare. The origin receives the connection from a
Cloudflare address while the header carries the
visitor.
GET /account HTTP/1.1
Host: www.example.re
CF-Connecting-IP: 203.0.113.1
X-Forwarded-For: 203.0.113.1
CF-Ray: 8a1b2c3d4e5f6789-AMS
The same request arriving through another proxy ahead of Cloudflare carries the proxy's address in CF-Connecting-IP, since the proxy is the client connecting to Cloudflare, while X-Forwarded-For preserves the whole chain.
CF-Connecting-IP: 198.51.100.101
X-Forwarded-For: 203.0.113.1,198.51.100.101
Crawler verification
Origins left unrestored record every request as arriving from a Cloudflare address, which collapses crawler traffic and visitor traffic into the same handful of addresses. Log analysis separating Googlebot from other clients stops working, and address-based rate limiting throttles every client at once rather than per visitor.
Verifying a crawler calls for a reverse DNS lookup on the connecting address, so the check depends on the restored value. Running the lookup against a Cloudflare address returns a Cloudflare hostname and marks genuine Googlebot traffic as unverified.
See also
- Cloudflare: HTTP request headers
- Cloudflare: Restoring original visitor IPs
- X-Forwarded-For
- X-Real-IP
- Forwarded
- Cf-Ray
- User-Agent
- HTTP headers