Laravel: get accurate IP from `Request`

I am using the default Laravel Fly configuration and the IPs that I get from $request->ip() are not accurate. They are showing the IP of the Fly proxy. This is causing problems with throttling, as it’s based on IP, and sessions have incorrect IPs.

How can I configure my Laravel app to use the IP of the client that made the request?

You can use the value of the Fly-Client-IP header.

Hi Leo, thanks. I am aware of this header, but how do I configure Laravel to use this header?

I already have the TrustProxies middleware and this line in my Dockerfile: && sed -i 's/protected \$proxies/protected \$proxies = "*"/g' app/Http/Middleware/TrustProxies.php, but it’s still showing the IP of the proxy

It seems like this was possible to be configured in the old TrustProxies:

@fideloper-fly is this something you could help with? I see you wrote the original TrustProxies :slight_smile:

I just gave this a shot in a fresh Laravel app and it seems to be a problem there as well:

laravel new test-ips

Then made these changes to web.php

Route::get('/', function (Request $request) {
    dd(
        $_SERVER,
        $request->ip(),
        $request->ips(),
        $request->isFromTrustedProxy(),
    );
    return view('welcome');
});

fly deploy and it shows:

image

$request->ip() is showing the IP of the proxy

Sadly, I don’t think the underlying Symfony classes allow you to set any old header for that area (You used to be able to!!!).

So perhaps some custom handling there is required. It looks like Symfony recommends over-writing the $_SERVER variable set (haha :sweat_smile:): How to Configure Symfony to Work behind a Load Balancer or a Reverse Proxy (Symfony Docs)

That’s a bit annoying but totally possible to do in Laravel’s public/index.php file.

@Yaeger Are any of those 2 IP addresses the correct one? (Is it just picking the wrong IP, or are those 2 IP’s totally wrong?)

$request->ip() is returning the IP address of the proxy (137.66.23.103). $request()->ips() is returning:

[
    0 => '137.66.23.103', // <- Proxy IP
    1 => '217.100.236.74', // <- My actual IP
]

Yea this is what I’m trying right now :skull: It feels really nasty.

I have this now at the top of my public/index.php:

if (isset($_SERVER["HTTP_FLY_CLIENT_IP"])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_FLY_CLIENT_IP"];
    $_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER["HTTP_FLY_CLIENT_IP"];
}

This seems to work. Just tried it on a toy project. Will try prod now. If you have any better suggestions still, I’d be all ear.

One think that I was thinking: can’t this be done in Nginx? If it can be done in Nginx, it would be possible to adjust the Fly Laravel configuration. This way it would work out of the box when running fly launch. It’s a bit annoying that I know have to remember to make this change to public/index.php:

  1. It’s easy to forget.
  2. It’s nasty.
  3. It’s Fly specific. I kinda liked that I had to make zero changes to my Laravel app to make it work with Fly.

That’s a good point, perhaps (via SO)

proxy_hide_header X-Forwarded-For;
add_header X-Forwarded-For $http_fly_client_ip;

?

(EDIT: whoops I think that’s setting RESPONSE headers, not headers going into PHP-FPM!)

More correct might be:

	location ~ \.php$ {
			include snippets/fastcgi-php.conf;
			fastcgi_param  HTTP_X_FORWARDED_FOR $http_fly_client_ip;
			fastcgi_pass unix:/var/run/php/php-fpm.sock;
	}

I’ll give it a shot!

1 Like

Works like a charm! @fideloper-fly Should I make a PR on the Fly CLI?

Great!

I’m working on that already! I’m asking if there’s an security concerns there (I dont think so, assuming you only run this Nginx config within Fly)

1 Like

Perfect, thanks :+1:

That’s been deemed safe enough #shipit :chipmunk:

1 Like