2 months ago
Hey,
As I didn't manage to find way to whitelist IPs, I created custom guard that was extracting client ip from headers: x-forwarded-for, x-real-ip. but yestearday it stopped working, probably something was changed on railways side.
11 Replies
2 months ago
Our edge proxy sets the X-Real-IP header with the client's remote IP on every HTTP request, as documented in our Specs & Limits. We are not aware of any recent changes to this behavior. Could you share what values you're seeing in those headers now, and confirm whether you're using a CDN like Cloudflare in front of your service? A CDN would replace the original client IP with its own edge IP.
Status changed to Awaiting User Response Railway • about 2 months ago
Status changed to Awaiting Railway Response Railway • about 2 months ago
Railway
Our edge proxy sets the `X-Real-IP` header with the client's remote IP on every HTTP request, as documented in our [Specs & Limits](https://docs.railway.com/networking/public-networking/specs-and-limits). We are not aware of any recent changes to this behavior. Could you share what values you're seeing in those headers now, and confirm whether you're using a CDN like Cloudflare in front of your service? A CDN would replace the original client IP with its own edge IP.
2 months ago
{
"host": "ss4a-production.up.railway.app",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
"accept": "*/*",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9,ka;q=0.8",
"cdn-loop": "Fastly;wasm=\"nmAGrHE1kxft6MktQsNYgofI2aVnVS3bEq8aDmtWxc_G8BOrNh_M8A21WTHcqviVfrYv6rrggmluBr9naoJ3XmXxsn__5DAA\"",
"priority": "u=1, i",
"sec-ch-ua": "\"Chromium\";v=\"146\", \"Not-A.Brand\";v=\"24\", \"Google Chrome\";v=\"146\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-forwarded-for": "157.52.106.31",
"x-forwarded-host": "ss4a-production.up.railway.app",
"x-forwarded-proto": "https",
"x-railway-edge": "railway/europe-west4-drams3a",
"x-railway-request-id": "iselANRLRRWa4x7c5nX1uw",
"x-real-ip": "157.52.106.31",
"x-request-start": "1774345988865"
}Status changed to Open Railway • about 2 months ago
2 months ago
look at your own headers you have "cdn-loop: fastly" in there, which means fastly is sitting in front of your railway service and that's why x-real-ip and x-forwarded-for are showing a fastly edge ip instead of your real client ip. you're not using cloudflare but you are going through fastly. check if you intentionally set that up, or if it got added somewhere in your config without you noticing , that's your culprit
ilyass012
look at your own headers you have "cdn-loop: fastly" in there, which means fastly is sitting in front of your railway service and that's why x-real-ip and x-forwarded-for are showing a fastly edge ip instead of your real client ip. you're not using cloudflare but you are going through fastly. check if you intentionally set that up, or if it got added somewhere in your config without you noticing , that's your culprit
2 months ago
I have railway managed domain, and nothing in between, 1 web app that directly calls API.
2 months ago
Railway partnered with Fastly to bring DDoS protection to every public service on Railway. All traffic routes through their global network. That's why the x-real-ip is a fastly IP. Right now x-forwarded-for (first/leftmost IP) is the most reliable option. Although, your JSON dump shows "157.52.106.31" as the only string in the x-forwarded-for header, your backend framework might be parsing/mutating the headers to grab the last proxy IP. So I suggest you try to fix that.
You might also have to set app.set('trust proxy', 1) (you may need to increase the number to 2 depending on Railway's internal proxy hops).
For more info, refer to this issue: https://station.railway.com/questions/which-header-should-i-rely-on-for-real-c-d78a6f96#xms3
darseen
Railway partnered with Fastly to bring DDoS protection to every public service on Railway. All traffic routes through their global network. That's why the `x-real-ip` is a fastly IP. Right now `x-forwarded-for` **(first/leftmost IP)** is the most reliable option. Although, your JSON dump shows `"157.52.106.31"` as the only string in the `x-forwarded-for` header, your backend framework might be parsing/mutating the headers to grab the last proxy IP. So I suggest you try to fix that. You might also have to set `app.set('trust proxy', 1)` (you may need to increase the number to `2` depending on Railway's internal proxy hops). For more info, refer to this issue: <https://station.railway.com/questions/which-header-should-i-rely-on-for-real-c-d78a6f96#xms3>
2 months ago
Following your guidance, I tried X-Forwarded-For[0] but it was also incorrect — it's still not the user's real IP, it's still Fastly's IP.
2 months ago
I'm seeing exactly the same behavior on my side.
A few hours ago, I was consistently getting my real client IP in X-Forwarded-For (e.g. 190.xxx.xxx.xxx), but now it only shows Fastly IPs (140.248.x.x / 157.52.x.x), and the real IP is completely missing from all headers.
So in my case, reading X-Forwarded-For doesn't solve it anymore — it just returns the edge IP.
2 months ago
Also, for all the HTTP/1.1 responses from the server (backend), they are coming in the format of transfer_encoding: chunked, whereas before it was Content-length type, so it is breaking our client side. How can we switch to Content-length type again?
Status changed to Awaiting User Response brody • about 2 months ago
2 months ago
Hey,
This has been fixed, no action is needed on your end.
We are sorry for introducing this regression and will be more diligent about changes to the behavior of headers going forward.
brody
Hey, This has been fixed, no action is needed on your end. We are sorry for introducing this regression and will be more diligent about changes to the behavior of headers going forward.
2 months ago
Thanks
Status changed to Awaiting Railway Response Railway • about 2 months ago
Status changed to Solved blackoctop • about 2 months ago