Emqx: Forward real client IP using a reverse proxy for websocket

Created on 13 Nov 2017  路  5Comments  路  Source: emqx/emqx

Environment

  • OS: Ubuntu Xenial 16.04.3 LTS
  • Erlang/OTP: 20 [erts-9.1]
  • EMQ: 2.2
  • Nginx: 1.10.3

Description

I'm using Nginx to proxify the websocket stream to my EMQ broker using the following configuration.
Note that nginx and EMQ are running on the same host

# Nginx config
location / {
  proxy_connect_timeout 7d;
  proxy_send_timeout 7d;
  proxy_read_timeout 7d;
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Scheme $scheme;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-Port $server_port;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass http://127.0.0.1:8083;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}

This works great, I'm able to connect to the EMQ host using the javascript client.
But, I'am expecting to see the real client IP on the EMQTT HTTP Api.
Instead, I see 127.0.0.1 (the loopback of the nginx server).

# GET http://emqtt/api/clients
{
  "currentPage": 1,
  "pageSize": 1,
  "totalNum": 1,
  "totalPage": 1,
  "result": Array[1][
    {
      "clientId": "Client-23649",
      "username": "undefined",
      "ipaddress": "127.0.0.1",
      "port": 39146,
      "clean_sess": true,
      "proto_ver": 4,
      "keepalive": 60,
      "send_msg": "undefined",
      "recv_msg": "undefined",
      "connected_at": "2017-11-13 09:21:54"
    }
  ]
}

Is it actually a real issue ?
Does the broker need the real client IP address ?
(I understand that Nginx is in charge of NAT/PAT to forward packets to the client)
Does EMQ support HTTP X-* Header ?

Enhancement

Most helpful comment

@sfowlr @franquis Merged the feature to 2.3.4 release. Now the broker supports two ways to get the real IP address of a WebSocket connection.

  1. Via 'X-Forwarded-For' and 'X-Forwarded-Port' headers

Nginx Config:

location / {
  proxy_set_header X-Forwarded-Port $server_port;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  ...
}

etc/emq.conf:

listener.ws.external.proxy_address_header = X-Forwarded-For
listener.ws.external.proxy_port_header = X-Forwarded-Port
  1. Via Proxy Protocol V1/2:

HAProxy Config:

backend emq_nodes
    mode tcp
    server emq1 192.168.1.10:8083 check-send-proxy send-proxy-v2

etc/emq.conf:

listener.ws.external.proxy_protocol = on
listener.ws.external.proxy_protocol_timeout = 3s

All 5 comments

@franquis The MQTT/WS listener still not support extracting the source address from HTTP X-* Headers. We plan to implement the feature in 2.4-beta.1, thanks.

Hi, @franquis This Feature has implemented and published at v2.3.1.

I updated to 2.3.3 using the deb package and expecting this to be patched but later realized that the ws_proxy branch still hasn't been merged. Is this still on hold for 2.4-beta1, or was it supposed to make it into the 2.3.1 release?

@sfowlr @franquis Merged the feature to 2.3.4 release. Now the broker supports two ways to get the real IP address of a WebSocket connection.

  1. Via 'X-Forwarded-For' and 'X-Forwarded-Port' headers

Nginx Config:

location / {
  proxy_set_header X-Forwarded-Port $server_port;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  ...
}

etc/emq.conf:

listener.ws.external.proxy_address_header = X-Forwarded-For
listener.ws.external.proxy_port_header = X-Forwarded-Port
  1. Via Proxy Protocol V1/2:

HAProxy Config:

backend emq_nodes
    mode tcp
    server emq1 192.168.1.10:8083 check-send-proxy send-proxy-v2

etc/emq.conf:

listener.ws.external.proxy_protocol = on
listener.ws.external.proxy_protocol_timeout = 3s

Great job ! Thanks @emqplus !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xlb0479 picture xlb0479  路  5Comments

stefano055415 picture stefano055415  路  4Comments

louisburton picture louisburton  路  4Comments

codewiget95 picture codewiget95  路  6Comments

rootqa picture rootqa  路  3Comments