Nginx/Apache 프록시를 통해 클라이언트의 실제 IP를 얻는 방법은 무엇인가요?

Nginx/Apache를 Workerman의 프록시로 사용할 때, Nginx/Apache는 사실 Workerman의 클라이언트 역할을 합니다. 따라서 Workerman에서 얻는 클라이언트 IP는 Nginx/Apache 서버의 IP일 뿐 실제 클라이언트의 IP가 아닙니다. 클라이언트의 실제 IP를 얻는 방법은 아래를 참조하세요.

원리:

Nginx/Apache는 클라이언트의 실제 IP를 HTTP 헤더를 통해 전달합니다. 예를 들어 Nginx 구성에서 location에 proxy_set_header X-Real-IP $remote_addr;을 추가합니다. Workerman은 이 헤더 값을 읽어 $connection 객체에 저장하고, (GatewayWorker는 $_SESSION 변수에 저장할 수 있습니다) 사용할 때 변수값을 직접 읽어오면 됩니다.

주의:

아래 설정은 http/https ws/wss 프로토콜에 적합합니다. 다른 프로토콜에서도 클라이언트 IP를 얻는 방법은 비슷하며, 프록시 서버가 데이터 패킷에 클라이언트의 실제 IP를 전달하는 데이터를 삽입해야 합니다.

Nginx 설정은 다음과 비슷합니다:

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";
    # 이 부분은 HTTP 헤더를 이용해 클라이언트의 실제 IP를 전달하는 것입니다.
    proxy_set_header X-Real-IP $remote_addr;
  }

  # location / {} 사이트의 다른 설정...
}

Workerman이 Nginx에서 설정한 헤더에서 클라이언트 IP를 읽는 방법

<?php

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

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

/**
 * 클라이언트 WebSocket 핸드셰이크 시의 콜백 onWebSocketConnect
 * onWebSocketConnect 콜백에서 Nginx를 통해 HTTP 헤더의 X_REAL_IP 값을 얻습니다.
 */
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
    /**
     * connection 객체에는 realIP 속성이 없습니다. 여기서 connection 객체에 동적으로 realIP 속성을 추가합니다.
     * PHP 객체는 동적으로 속성을 추가할 수 있으며, 원하는 속성명을 사용할 수 있습니다.
     */
    //$connection->realIP = $_SERVER['HTTP_X_REAL_IP']; // workerman v4 사용법
    $connection->realIP = $request->header('x-real-ip'); // workerman v5 사용법
};
$worker->onMessage = function(TcpConnection $connection, $data)
{
    // 클라이언트의 실제 IP를 사용할 때는 직접 $connection->realIP를 사용하면 됩니다.
    $connection->send($connection->realIP);
};
Worker::runAll();

GatewayWorker가 Nginx에서 설정한 헤더에서 클라이언트 IP를 가져오는 방법

Events.php에 아래 코드를 추가합니다.

class Events
{
   public static function onWebsocketConnect($client_id, $data)
   {    
        $_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
   }
   // .... 다른 코드는 생략합니다....
}

코드를 추가한 후 GatewayWorker를 재시작해야 합니다.

이제 Events.php의 onMessageonClose 메소드에서 $_SESSION['realIP']를 통해 클라이언트의 실제 IP를 얻을 수 있습니다.

주의: Events.php의 onWorkerStart, onConnect, onWorkerStop에서는 $_SESSION['realIP']를 직접 사용할 수 없습니다.