How to get client IP when using Caddy reverse proxy
kluxa
HOBBYOP

2 months ago

Hello,

I'm experiencing an issue where if I deploy the Caddy reverse proxy in front of an Express server, I can't reliably get the client IP from the x-forwarded-for header. I need the client IP for rate limiting.

When sending a request directly to the server (https://railway-proxy-test-backend.up.railway.app/headers), the client IP is the first entry in the x-forwarded-for header.

However, when sending a request via the proxy (https://railway-proxy-test.up.railway.app/api/headers), the x-forwarded-for header only contains what seems to be an internal Railway IP.

The client IP is present in the fastly-client-ip header, but according to this thread, it is recommended to use x-forwarded-for because fastly-client-ip is not stable.

$10 Bounty

4 Replies

Status changed to Awaiting Railway Response Railway 2 months ago


ilyass012
FREE

2 months ago

Looking at your actual headers, x-real-ip contains the correct client ip (41.140.199.143) in both cases, even when going through caddy. caddy is not touching that header. so just use x-real-ip instead of x-forwarded-for for your rate limiting and you're good to go


2 months ago

X-Forwarded-For is easily spoofable, so you need to tell Caddy which proxies to trust, using trusted_proxies: https://caddyserver.com/docs/caddyfile/options#trusted-proxies - since Railway proxies to services, you need to add Railway's proxy IP address (or its CIDR range) to the list of trusted proxies.


ilyass012

Looking at your actual headers, x-real-ip contains the correct client ip (41.140.199.143) in both cases, even when going through caddy. caddy is not touching that header. so just use x-real-ip instead of x-forwarded-for for your rate limiting and you're good to go

kluxa
HOBBYOP

2 months ago

Thanks for the reply. I think the x-real-ip header is inconsistent with showing the correct client IP, because when I go to https://railway-proxy-test.up.railway.app/api/headers now, the x-real-ip header contains an address from one of Fastly's public IP address ranges (which I got from running the command at https://www.fastly.com/documentation/reference/api/utils/public-ip-list/).

I added the address range to the list of trusted proxies in the Caddyfile like so:

	servers {
		trusted_proxies static private_ranges 23.235.32.0/20
	}

But x-real-ip still shows one of the Fastly public IP addresses.

I also came across this old thread where it was mentioned that x-real-ip should contain the client IP, along with a proof of concept, but when I visit that website, x-real-ip also shows a Fastly public IP.

I'm not very knowledgeable on networking but I would guess there is an issue with how Railway is forwarding client IPs.

Update: I've updated the trusted proxies list to include 100.0.0.0/8 (since IP addresses starting with 100. kept showing up) and all of Fastly's public IP address ranges, and the correct IP address is showing in the x-real-ip header now, we'll see if it stays that way.

	servers {
		trusted_proxies static private_ranges 100.0.0.0/8 23.235.32.0/20 43.249.72.0/22 103.244.50.0/24 103.245.222.0/23 103.245.224.0/24 104.156.80.0/20 140.248.64.0/18 140.248.128.0/17 146.75.0.0/17 151.101.0.0/16 157.52.64.0/18 167.82.0.0/17 167.82.128.0/20 167.82.160.0/20 167.82.224.0/20 172.111.64.0/18 185.31.16.0/22 199.27.72.0/21 199.232.0.0/16
	}

2 months ago

Ah yep if you're using additional proxies/CDN in front of Railway too, then you have to add all of those IP ranges too.


Welcome!

Sign in to your Railway account to join the conversation.

Loading...