How to get remote ip from x-forwarded-for header in Phoenix
In my project hipCV there is a functionality which tracks visits for a publicly listed resume. For the server setup, I have multiple docker containers being load balanced via nginx proxy.
To track the visits, we need the real remote IP address of the request. This IP address can then be used by geoip service, to provide the location.
Since the requests to application server are being proxied, conn.remote_ip
address is of the nginx itself and not the original request. The real IP address is also being returned by ngnix, but they come through in the headers x-forwarded-for
.
So, all we need to do is to parse this information from headers. To make it simple, I wrote a small utility module which does just that.
defmodule Utils.RemoteIp do
@spec get(Plug.Conn.t()) :: binary()
def get(conn) do
forwarded_for = conn
|> Plug.Conn.get_req_header("x-forwarded-for")
|> List.first()
if forwarded_for do
forwarded_for
|> String.split(",")
|> Enum.map(&String.trim/1)
|> List.first()
else
conn.remote_ip
|> :inet_parse.ntoa()
|> to_string()
end
end
end
Module is quite simple where it takes a conn
struct as input and tries to get the value of the IP address out of x-forwarded-for
header. If it is able to find it, it returns that, otherwise the original IP address of the request is returned.
We can use this module anywhere in our controller as long as we have conn
struct.
Utils.RemoteIp.get(conn)
There you have it, now you can get the real remote ip from proxied requests without any problems.