# Logging real remote address with Nginx and Lua

- Link: https://www.agilicus.com/logging-real-remote-address-with-nginx-and-lua/
- Published: 2020-04-29T15:35:54+00:00
- Author: Don Bowman

A common pattern in the Cloud world is load-balancers. Your environment might have
Kubernetes with Istio feeding a set of Pods that each have a web server in them,
often based on Nginx. In this environment, the web server (Nginx) receives a header**
[X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)**
which is trusted by you since it is your front-end load-balancer. The syntax is

    ```wp-block-preformatted
    X-Forwarded-For: <client>, <proxy1>, <proxy2>
    ```

However, you may have tools that parse your access logs and assume the remote address
is **Client**, when in fact your are logging **Proxy2**. How can you fix this?

Well, one approach is to use something like Proxy Protocol and make the IP transparent
all the way through. Our team contributed this to [Envoy](https://www.envoyproxy.io/).
Another approach is to take the real client IP from the X-Forwarded-For and place
it in the log. For this you might use the [Nginx HTTP RealIP Module](https://nginx.org/en/docs/http/ngx_http_realip_module.html),
but it has the side affects of changing the client address, not just logging it.

Others may be using OpenResty which [does not support](https://github.com/openresty/lua-nginx-module/issues/1327)
the RealIP module. In this post I show you a happy medium: log (in JSON format for
easy consumption into FluentBit and ElasticSearch/Kibana) such that the downstream_remote_address
is filled in with the _real remote IP_. This does not have any other side affects
other than the access log. If you paste these snippets into your nginx config in
your various and sundry containers that run inside your cluster, it will just work.

The key blob is the **set_by_lua_block**. We introduce a new variable, **$real_remote**.
For every request, if **X-Forwarded-For** is set, we take the first component of
it and use. Else we return the original **remote_addr**.

Enjoy! If you wish to [expose](https://www.agilicus.com/secure-exposed-access-blog/)
a service from inside your facility, and still want to know the origin IP, this 
can be for you.

    ```wp-block-code
    http {
     ...
      log_format json escape=json '{'
        '"time": "$time_iso8601",'
        '"downstream_remote_address": "$real_remote",'
        '"x_forward_for": "$proxy_add_x_forwarded_for",'
        '"request_id": "$request_id",'
        '"remote_user": "$remote_user",'
        '"bytes_sent": $bytes_sent,'
        '"start_time": $request_time,'
        '"response_code": $status,'
        '"authority": "$host",'
        '"protocol": "$server_protocol",'
        '"path": "$uri",'
        '"request_query": "$args",'
        '"request_length": $request_length,'
        '"duration": $request_time,'
        '"method": "$request_method",'
        '"http_referrer": "$http_referer",'
        '"http_user_agent": "$http_user_agent"'
      '}';

     ...
        server {
          listen 5000;
      ...

          set_by_lua_block $real_remote {
            if ngx.var.http_x_forwarded_for then
              for r in ngx.var.http_x_forwarded_for:gmatch('([^,]+)') do
                return r
              end
            end
            return ngx.var.remote_addr
        }
    ...
    ```
