ผ่าน nginx/apache proxy จะใช้วิธีไหนในการดึง IP จริงของลูกค้า?
การใช้งาน nginx/apache เป็น proxy สำหรับ workerman นั้น nginx/apache จะทำหน้าที่เป็น client ของ workerman ดังนั้น IP ที่ได้จาก workerman จะเป็น IP ของเซิร์ฟเวอร์ nginx/apache ไม่ใช่ IP ที่แท้จริงของลูกค้า วิธีการในการดึง IP จริงของลูกค้าสามารถดูได้จากวิธีการด้านล่าง
หลักการ:
nginx/apache จะส่ง IP จริงของลูกค้าผ่าน http header เข้ามา เช่น ในการตั้งค่า nginx ให้เพิ่ม proxy_set_header X-Real-IP $remote_addr; ลงใน location ที่เราต้องการ จากนั้น workerman จะอ่านค่า header นี้และบันทึกลงใน $connection object (GatewayWorker สามารถบันทึกลงในตัวแปร $_SESSION ได้) และสามารถเข้าถึงค่าได้โดยการอ่านตัวแปรนั้น
หมายเหตุ:
การตั้งค่าเหล่านี้ใช้ได้กับ protocol http/https ws/wss วิธีการดึง IP ของลูกค้าใน protocol อื่นๆ จะคล้ายกัน โดย proxy server จะต้องใส่ข้อมูล IP ลงใน packet เพื่อส่งต่อ 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 header เพื่อส่งต่อ IP จริงของลูกค้า
proxy_set_header X-Real-IP $remote_addr;
}
# location / {} การตั้งค่าอื่น ๆ ของไซต์...
}
workerman อ่าน IP ของลูกค้าจาก header ที่ตั้งค่าใน 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 ขณะลูกค้า handshake websocket
* ใน callback onWebSocketConnect นี้จะได้รับค่า X_REAL_IP ผ่าน http header ที่ส่งมาจาก nginx
*/
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
/**
* ใน object ของ connection ไม่มี property realIP ดังนั้นจะต้องเพิ่ม property realIP ให้กับ connection object
* จำไว้ว่าใน php สามารถเพิ่ม property ลงใน object ได้ตามต้องการ
*/
//$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 ดึง IP ของลูกค้าจาก header ที่ตั้งค่าใน nginx
เพิ่มโค้ดด้านล่างใน Events.php
class Events
{
public static function onWebsocketConnect($client_id, $data)
{
$_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
}
// .... โค้ดอื่น ๆ ถูกตัดออก....
}
หลังจากเพิ่มโค้ดแล้วต้องรีสตาร์ท GatewayWorker
เช่นนั้นคุณจะสามารถได้รับ IP จริงของลูกค้าใน method onMessage และ onClose ใน Events.php ผ่าน $_SESSION['realIP'] ได้
หมายเหตุ: ใน Events.php method
onWorkerStart,onConnect,onWorkerStopไม่สามารถใช้$_SESSION['realIP']ได้โดยตรง