How to Get the Real Client IP Through Nginx/Apache Proxy?
When using nginx/apache as a proxy for Workerman, nginx/apache acts as a client to Workerman. Therefore, the client IP obtained on Workerman will be the IP of the nginx/apache server, not the actual client IP. To obtain the real client IP, you can refer to the methods below.
Principle:
Nginx/apache passes the real client IP through the HTTP header. For example, in the nginx configuration, add proxy_set_header X-Real-IP $remote_addr; in the location block. Workerman reads this header value and saves it in the $connection object (GatewayWorker can save it in the $_SESSION variable), which can be directly accessed when needed.
Note:
The following configuration is applicable to http/https and ws/wss protocols. For other protocols, the method of obtaining the client IP is similar, requiring the proxy server to insert a segment of IP data into the packet that transparently passes the real client IP.
Nginx configuration is as follows:
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";
# This part uses http headers to transparently pass the real client IP
proxy_set_header X-Real-IP $remote_addr;
}
# location / {} Other site configurations...
}
Workerman reads the client IP from the header set by nginx
<?php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('websocket://0.0.0.0:7272');
/**
* The callback onWebSocketConnect during the websocket handshake of the client
* Obtain the X_REAL_IP value from the http header set by nginx in the onWebSocketConnect callback
*/
$worker->onWebSocketConnect = function(TcpConnection $connection, $request){
/**
* The connection object does not have a realIP attribute by default, here we dynamically add a realIP attribute to the connection object
* Remember that PHP objects can have properties added dynamically, you can also use your preferred property name
*/
//$connection->realIP = $_SERVER['HTTP_X_REAL_IP']; // Usage in workerman v4
$connection->realIP = $request->header('x-real-ip'); // Usage in workerman v5
};
$worker->onMessage = function(TcpConnection $connection, $data)
{
// When using the real client IP, directly use $connection->realIP
$connection->send($connection->realIP);
};
Worker::runAll();
GatewayWorker gets the client IP from the header set by nginx
Add the following code to Events.php
class Events
{
public static function onWebsocketConnect($client_id, $data)
{
$_SESSION['realIP'] = $data['server']['HTTP_X_REAL_IP'];
}
// .... Other code omitted....
}
After adding the code, you need to restart GatewayWorker.
This way, you can obtain the real client IP in the onMessage and onClose methods in Events.php through $_SESSION['realIP'].
Note:
$_SESSION['realIP']cannot be used directly inonWorkerStart,onConnect, andonWorkerStopmethods in Events.php.