How to get proxy value of nginx-key X-Real-IP in Ratchet websocket

2k Views Asked by At

i'm setting up a websocket application with ratchet websockets. My setup is the following: I (have to) use an nginx server as an reverse proxy forwarding requests to my websocket ratchet server:

    location /websocket {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_redirect off;
    }

Within my websocket app i need to get the value ($remote_addr) of X-Real-IP for IP filtering. Because i have to use this proxy solution i will always get the ip 127.0.0.1 as the remote ip when using the function stream_socket_get_name.

As far as i have investigated this problem ratchet starts a stream_socket_server and then starts to listen for incomming connections. These connections are already streams and not http-requests so i'm not able to use something like $_SERVER etc.

Does anybody know how to retrieve this value?

Regards

Marcus

2

There are 2 best solutions below

0
On

Each ConnectionInterface object that is passed in the on methods contains a Guzzle RequestInterface object with the HTTP headers from the initial request:

$conn->WebSocket->request->getHeader('X-Real-IP');
0
On

I had the same issue, but even more complicated because I had 2 proxy servers in front of a load balancer and then another proxy, and then another one for the websocket... I spent some time to pass the headers properly, but things will get interesting when you proxy your WebSocket server...

I will share the function I made to get the real IP of the visitor inside the Ratchet server application, even if behind CloudFlare:

/**
     * Get the real visitor IP
     * @author nboros
     * @param Ratchet WebSocket $conn
     * @return string $ip
     */
    function GetRealUserIp($conn) {

        $HTTP_X_REAL_IP         = $conn->WebSocket->request->getHeader('X-Real-IP');
        $HTTP_X_FORWARDED_FOR   = $conn->WebSocket->request->getHeader('X-Forwarded-For');
        $HTTP_CF_CONNECTING_IP  = $conn->WebSocket->request->getHeader('CF_CONNECTING_IP');
        $REMOTE_ADDR            = $conn->remoteAddress;

        if(filter_var($HTTP_X_REAL_IP, FILTER_VALIDATE_IP))
        {
            $ip = $HTTP_X_REAL_IP;
        } 
        elseif(filter_var($HTTP_X_FORWARDED_FOR, FILTER_VALIDATE_IP))
        {
            $ip = $HTTP_X_FORWARDED_FOR;
        } 
        elseif(filter_var($HTTP_CF_CONNECTING_IP, FILTER_VALIDATE_IP))
        {
            $ip = $HTTP_CF_CONNECTING_IP;
        } 
        else
        {
            $ip = $REMOTE_ADDR;
        }

        return $ip;
    }

I normally cal the function in the "onOpen()" callback:

$this->GetRealUserIp($conn);

Makre sure you are passing one of the headers: X-Real-IP, X-Forwarded-For in NGINX.

Also add the CloudFlare IP's:

# CloudFlare IPs
# List from: https://www.cloudflare.com/ips-v4
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 199.27.128.0/21;

# List from: https://www.cloudflare.com/ips-v6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;

real_ip_header X-Real-IP;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

And the pass the headers:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

I really hope this will help someone else in need, and if you think there is room for improvement do advise!

Cheers!