¿Cómo obtener la verdadera IP del cliente a través de un proxy nginx/apache?

Al usar nginx/apache como proxy para Workerman, nginx/apache actúa realmente como el cliente de Workerman, por lo que la IP del cliente obtenida en Workerman es la IP del servidor nginx/apache y no la IP real del cliente. Para obtener la verdadera IP del cliente, puedes referirte a los métodos a continuación.

Principio:

nginx/apache transmite la verdadera IP del cliente a través de los encabezados http, por ejemplo, en la configuración de nginx, se agrega en location proxy_set_header X-Real-IP $remote_addr;. Workerman lee este valor del encabezado y lo guarda en el $connection objeto (GatewayWorker puede guardarlo en la variable $_SESSION), y luego se puede utilizar directamente para leer la variable.

Nota:

La siguiente configuración es aplicable a los protocolos http/https ws/wss. Para otros protocolos, el método para obtener la IP del cliente es similar, se necesita que el servidor proxy inserte una porción de datos de IP dentro del paquete de datos para transmitir la verdadera IP del cliente.

La configuración de nginx es similar a la siguiente:

server {
  listen 443;

  ssl on;
  ssl_certificate /etc/ssl/server.pem;
  ssl_certificate_key /etc/ssl/server.key;
  ssl_session_timeout 5m;
  ssl_session_cache shared:SSL:50m;
  ssl_protocols SSLv3 SSLv2 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;

  location /wss
  {
    proxy_pass http://127.0.0.1:8282;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    # Esta parte utiliza los encabezados http para transmitir la verdadera IP del cliente
    proxy_set_header X-Real-IP $remote_addr;
  }

  # location / {} Otras configuraciones del sitio...
}

Workerman lee la IP del cliente desde el encabezado configurado por nginx

<?php

use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('websocket://0.0.0.0:7272');

/**
 * Callback onWebSocketConnect al realizar el handshake del websocket del cliente
 * En el callback onWebSocketConnect se obtiene el valor X_REAL_IP del encabezado http de nginx
 */
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
    /**
     * El objeto connection en sí no tiene la propiedad realIP, aquí se agrega dinámicamente una propiedad realIP al objeto connection
     * Recuerda que en php los objetos pueden tener propiedades agregadas dinámicamente, también puedes usar cualquier nombre de propiedad que prefieras
     */
    //$connection->realIP = $_SERVER['HTTP_X_REAL_IP']; // Uso de workerman v4
    $connection->realIP = $request->header('x-real-ip'); // Uso de workerman v5
};
$worker->onMessage = function(TcpConnection $connection, $data)
{
    // Al usar la verdadera IP del cliente, simplemente se usa $connection->realIP
    $connection->send($connection->realIP);
};
Worker::runAll();

GatewayWorker obtiene la IP del cliente del encabezado configurado por nginx

Agrega el siguiente código a Events.php

class Events
{
   public static function onWebsocketConnect($client_id, $data)
   {    
        $_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
   }
   // .... Omitir otros códigos....
}

Después de agregar el código, es necesario reiniciar GatewayWorker.

De esta manera, se puede obtener la verdadera IP del cliente a través de $_SESSION['realIP'] en los métodos onMessage y onClose de Events.php.

Nota: En Events.php, onWorkerStart, onConnect, onWorkerStop no pueden usar directamente $_SESSION['realIP'].