Index: nginx-1.4.7/auto/modules
===================================================================
--- nginx-1.4.7.orig/auto/modules
+++ nginx-1.4.7/auto/modules
@@ -297,6 +297,10 @@ if [ $HTTP_SSL = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_SSL_SRCS"
 fi
 
+if [ $PROXY_PROTOCOL = YES ]; then
+    have=NGX_PROXY_PROTOCOL . auto/have
+fi
+
 if [ $HTTP_PROXY = YES ]; then
     have=NGX_HTTP_X_FORWARDED_FOR . auto/have
     #USE_MD5=YES
Index: nginx-1.4.7/auto/options
===================================================================
--- nginx-1.4.7.orig/auto/options
+++ nginx-1.4.7/auto/options
@@ -47,6 +47,8 @@ USE_THREADS=NO
 NGX_FILE_AIO=NO
 NGX_IPV6=NO
 
+PROXY_PROTOCOL=NO
+
 HTTP=YES
 
 NGX_HTTP_LOG_PATH=
@@ -192,6 +194,8 @@ do
         --with-file-aio)                 NGX_FILE_AIO=YES           ;;
         --with-ipv6)                     NGX_IPV6=YES               ;;
 
+        --with-proxy-protocol)           PROXY_PROTOCOL=YES         ;;
+
         --without-http)                  HTTP=NO                    ;;
         --without-http-cache)            HTTP_CACHE=NO              ;;
 
@@ -350,6 +354,8 @@ cat << END
   --with-file-aio                    enable file AIO support
   --with-ipv6                        enable IPv6 support
 
+  --with-proxy-protocol              enable proxy protocol support
+
   --with-http_ssl_module             enable ngx_http_ssl_module
   --with-http_spdy_module            enable ngx_http_spdy_module
   --with-http_realip_module          enable ngx_http_realip_module
Index: nginx-1.4.7/auto/sources
===================================================================
--- nginx-1.4.7.orig/auto/sources
+++ nginx-1.4.7/auto/sources
@@ -36,7 +36,8 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_conf_file.h \
            src/core/ngx_resolver.h \
            src/core/ngx_open_file_cache.h \
-           src/core/ngx_crypt.h"
+           src/core/ngx_crypt.h \
+           src/core/ngx_proxy_protocol.h"
 
 
 CORE_SRCS="src/core/nginx.c \
@@ -67,7 +68,8 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_conf_file.c \
            src/core/ngx_resolver.c \
            src/core/ngx_open_file_cache.c \
-           src/core/ngx_crypt.c"
+           src/core/ngx_crypt.c \
+           src/core/ngx_proxy_protocol.c"
 
 
 REGEX_MODULE=ngx_regex_module
Index: nginx-1.4.7/src/core/ngx_connection.h
===================================================================
--- nginx-1.4.7.orig/src/core/ngx_connection.h
+++ nginx-1.4.7/src/core/ngx_connection.h
@@ -63,6 +63,10 @@ struct ngx_listening_s {
     unsigned            shared:1;    /* shared between threads or processes */
     unsigned            addr_ntop:1;
 
+#if (NGX_PROXY_PROTOCOL)
+    unsigned            accept_proxy_protocol:2; /* proxy_protocol flag */
+#endif
+
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
     unsigned            ipv6only:1;
 #endif
@@ -148,6 +152,10 @@ struct ngx_connection_s {
 
     ngx_uint_t          requests;
 
+#if (NGX_PROXY_PROTOCOL)
+    ngx_uint_t          proxy_protocol;
+#endif
+
     unsigned            buffered:8;
 
     unsigned            log_error:3;     /* ngx_connection_log_error_e */
Index: nginx-1.4.7/src/core/ngx_core.h
===================================================================
--- nginx-1.4.7.orig/src/core/ngx_core.h
+++ nginx-1.4.7/src/core/ngx_core.h
@@ -77,6 +77,9 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_open_file_cache.h>
 #include <ngx_os.h>
 #include <ngx_connection.h>
+#if (NGX_PROXY_PROTOCOL)
+#include <ngx_proxy_protocol.h>
+#endif
 
 
 #define LF     (u_char) 10
Index: nginx-1.4.7/src/core/ngx_proxy_protocol.c
===================================================================
--- /dev/null
+++ nginx-1.4.7/src/core/ngx_proxy_protocol.c
@@ -0,0 +1,430 @@
+
+/*
+ * Copyright (C) Baptiste Assmann
+ * Copyright (C) Exceliance
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+#if (NGX_PROXY_PROTOCOL)
+
+int
+ngx_recv_proxy_protocol(ngx_connection_t *c, u_char *buf, ssize_t n)
+{
+    u_char *end, *p, *t;
+    size_t len;
+    ssize_t s;
+    int step = 0;
+    ngx_proxy_protocol_t pp;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "processing proxy protocol");
+
+    /* 16 is the minimal length of the proxy protocol string */
+    if (n < 18) {
+        step = 1;
+        goto fail;
+    }
+
+    s = n;
+    end = memchr(buf, '\n', n);
+    if (end == NULL) {
+        step = 2;
+        goto fail;
+    }
+
+    p = buf;
+    if (memcmp(p, "PROXY ", 6) != 0) {
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+            "incorrect proxy protocol header string");
+        step = 3;
+        goto fail;
+    }
+    p += 6;
+    s -= 6;
+    if (s <= 0) {
+        step = 4;
+        goto fail;
+    }
+
+    ngx_memzero(&pp, sizeof(ngx_proxy_protocol_t));
+
+    if (memcmp(p, "TCP4 ", 5) == 0) {
+        struct sockaddr_in *sin_src;
+        struct sockaddr_in *sin_dst;
+
+        pp.pp_proto = NGX_PP_PROTO_TCP4;
+        pp.pp_src3.ss_family = AF_INET;
+        pp.pp_dst3.ss_family = AF_INET;
+        sin_src = (struct sockaddr_in *) &pp.pp_src3;
+        sin_dst = (struct sockaddr_in *) &pp.pp_dst3;
+
+        p += 5;
+        s -= 5;
+        if (s <= 0) {
+            step = 5;
+            goto fail;
+        }
+
+        /* l3 source address */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 6;
+            goto fail;
+        }
+        len = t - p;
+        if ((sin_src->sin_addr.s_addr = ngx_inet_addr(p, len)) == INADDR_NONE) {
+            step = 7;
+            goto fail;
+        }
+        pp.pp_src3_text.data = ngx_pcalloc(c->pool, len + 1);
+        ngx_memcpy(pp.pp_src3_text.data, p, len);
+        pp.pp_src3_text.len = len;
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 8;
+            goto fail;
+        }
+
+        /* l3 destination address */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 9;
+            goto fail;
+        }
+        len = t - p;
+        if ((sin_dst->sin_addr.s_addr = ngx_inet_addr(p, len)) == INADDR_NONE) {
+            step = 10;
+            goto fail;
+        }
+// FIXME pointer shift ???
+        pp.pp_dst3_text.data = ngx_pcalloc(c->pool, len + 1);
+        ngx_memcpy(pp.pp_dst3_text.data, p, len);
+        pp.pp_dst3_text.len = len;
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 11;
+            goto fail;
+        }
+
+        /* l4 source port */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 12;
+            goto fail;
+        }
+        len = t - p;
+        pp.pp_src4 = ngx_atoi(p, len);
+        if ((pp.pp_src4 < 1024)
+                || (pp.pp_src4 > 65535)) {
+            step = 13;
+            goto fail;
+        }
+        sin_src->sin_port = htons(pp.pp_src4);
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 14;
+            goto fail;
+        }
+
+        /* l4 destination port */
+        if ( (t = (u_char *)memchr(p, '\r', s)) == NULL ) {
+            step = 15;
+            goto fail;
+        }
+        len = t - p;
+        pp.pp_dst4 = ngx_atoi(p, len);
+        if (pp.pp_dst4 > 65535) {
+            step = 16;
+            goto fail;
+        }
+        sin_dst->sin_port = htons(pp.pp_dst4);
+
+        if (p[len + 1] != '\n') {
+            step = 17;
+            goto fail;
+        }
+
+        p += (len + 2);
+        s -= (len + 2);
+
+
+        /* if we managed to get there, then we can safely replace the
+         * information in the connection structure
+         */
+
+        /* updating connection with source information provided by proxy protocol */
+        if (pp.pp_src3_text.len > c->addr_text.len) {
+            ngx_pfree(c->pool, c->addr_text.data);
+            c->addr_text.data = ngx_pcalloc(c->pool, pp.pp_src3_text.len);
+        } else {
+            ngx_memzero(c->addr_text.data, c->addr_text.len);
+        }
+        ngx_memcpy(c->addr_text.data, pp.pp_src3_text.data, pp.pp_src3_text.len);
+        c->addr_text.len = pp.pp_src3_text.len;
+
+        ngx_pfree(c->pool, c->sockaddr);
+        c->socklen = NGX_SOCKADDRLEN;
+        c->sockaddr = ngx_pcalloc(c->pool, c->socklen);
+        ngx_memcpy(c->sockaddr, sin_src, c->socklen);
+
+        if (c->sockaddr->sa_family != AF_INET) {
+            ngx_pfree(c->pool, c->sockaddr);
+            c->socklen = NGX_SOCKADDRLEN;
+            c->sockaddr = ngx_pcalloc(c->pool, c->socklen);
+        } else {
+            ngx_memzero(c->sockaddr, sizeof(struct sockaddr_in));
+            c->socklen = NGX_SOCKADDRLEN;
+        }
+        ngx_memcpy(c->sockaddr, sin_src, c->socklen);
+
+        /* updating connection with destination information provided by proxy protocol */
+        ngx_pfree(c->pool, c->local_sockaddr);
+        c->local_sockaddr = ngx_pcalloc(c->pool, NGX_SOCKADDRLEN);
+        ngx_memcpy(c->local_sockaddr, sin_dst, NGX_SOCKADDRLEN);
+
+    }
+
+#if (NGX_HAVE_INET6)
+
+     else if (memcmp(p, "TCP6 ", 5) == 0) {
+
+        struct sockaddr_in6 *sin6_src;
+        struct sockaddr_in6 *sin6_dst;
+
+        pp.pp_proto = NGX_PP_PROTO_TCP6;
+        pp.pp_src3.ss_family = AF_INET6;
+        pp.pp_dst3.ss_family = AF_INET6;
+        sin6_src = (struct sockaddr_in6 *) &pp.pp_src3;
+        sin6_dst = (struct sockaddr_in6 *) &pp.pp_dst3;
+
+        p += 5;
+        s -= 5;
+        if (s <= 0) {
+            step = 18;
+            goto fail;
+        }
+
+        /* l3 source address */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 19;
+            goto fail;
+        }
+        len = t - p;
+        if (ngx_inet6_addr(p, len, sin6_src->sin6_addr.s6_addr) != NGX_OK) {
+            step = 20;
+            goto fail;
+        }
+        pp.pp_src3_text.data = ngx_pcalloc(c->pool, len + 1);
+        ngx_memcpy(pp.pp_src3_text.data, p, len);
+        pp.pp_src3_text.len = len;
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 21;
+            goto fail;
+        }
+
+        /* l3 destination address */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 22;
+            goto fail;
+        }
+        len = t - p;
+        if (ngx_inet6_addr(p, len, sin6_dst->sin6_addr.s6_addr) != NGX_OK) {
+            step = 23;
+            goto fail;
+        }
+        pp.pp_dst3_text.data = ngx_pcalloc(c->pool, len + 1);
+        ngx_memcpy(pp.pp_dst3_text.data, p, len);
+        pp.pp_dst3_text.len = len;
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 24;
+            goto fail;
+        }
+
+        /* l4 source port */
+        if ( (t = (u_char *)memchr(p, ' ', s)) == NULL ) {
+            step = 25;
+            goto fail;
+        }
+        len = t - p;
+        pp.pp_src4 = ngx_atoi(p, len);
+        if ((pp.pp_src4 < 1024)
+                || (pp.pp_src4 > 65535)) {
+            step = 26;
+            goto fail;
+        }
+        sin6_src->sin6_port = htons(pp.pp_src4);
+
+        p += (len + 1);
+        s -= (len + 1);
+        if (s <= 0) {
+            step = 27;
+            goto fail;
+        }
+
+        /* l4 destination port */
+        if ( (t = (u_char *)memchr(p, '\r', s)) == NULL ) {
+            step = 28;
+            goto fail;
+        }
+        len = t - p;
+        pp.pp_dst4 = ngx_atoi(p, len);
+        if (pp.pp_dst4 > 65535) {
+            step = 29;
+            goto fail;
+        }
+        sin6_dst->sin6_port = htons(pp.pp_dst4);
+
+        if (p[len + 1] != '\n') {
+            step = 30;
+            goto fail;
+        }
+
+        p += (len + 2);
+        s -= (len + 2);
+
+        /* if we managed to get there, then we can safely replace the
+         * information in the connection structure
+         */
+
+        /* updating connection with source provided by proxy protocol */
+        if (pp.pp_src3_text.len > c->addr_text.len) {
+            ngx_pfree(c->pool, c->addr_text.data);
+            c->addr_text.data = ngx_pcalloc(c->pool, pp.pp_src3_text.len);
+        } else {
+            ngx_memzero(c->addr_text.data, c->addr_text.len);
+        }
+        ngx_memcpy(c->addr_text.data, pp.pp_src3_text.data, pp.pp_src3_text.len);
+        c->addr_text.len = pp.pp_src3_text.len;
+
+        ngx_pfree(c->pool, c->sockaddr);
+        c->socklen = NGX_SOCKADDRLEN;
+        c->sockaddr = ngx_pcalloc(c->pool, c->socklen);
+        ngx_memcpy(c->sockaddr, sin6_src, c->socklen);
+
+        /* updating connection with destination provided by proxy protocol */
+        if (c->sockaddr->sa_family != AF_INET6) {
+            ngx_pfree(c->pool, c->local_sockaddr);
+            c->local_sockaddr = ngx_pcalloc(c->pool, NGX_SOCKADDRLEN);
+        } else {
+            ngx_memzero(c->sockaddr, sizeof(struct sockaddr_in6));
+            c->socklen = NGX_SOCKADDRLEN;
+        }
+//        ngx_memcpy(c->local_sockaddr, sin6_dst, NGX_SOCKADDRLEN);
+//FIXME must be finished here
+
+    }
+
+#endif
+
+    else {
+        step = 31;
+        goto fail;
+    }
+
+    ngx_print_proxy_protocol(&pp, c->log);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+            "proxy_protocol, asking to remove %z chars",
+            end + 1 - buf);
+
+    return (end + 1 - buf);
+
+fail:
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+            "proxy_protocol error at step: %d", step);
+
+    return 0;
+
+}
+
+
+void
+ngx_print_proxy_protocol(ngx_proxy_protocol_t *p, ngx_log_t *log)
+{
+    switch (p->pp_proto) {
+        case NGX_PP_PROTO_TCP4:
+           ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0,
+               "proxy_protocol, proto: TCP4");
+        break;
+        case NGX_PP_PROTO_TCP6:
+           ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0,
+               "proxy_protocol, proto: TCP6");
+       break;
+   }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+       "proxy_protocol, string length: %d", ngx_proxy_protocol_string_length(p));
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
+       "proxy_protocol, src3: %s, %d", p->pp_src3_text.data, p->pp_src3_text.len);
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
+       "proxy_protocol, dst3: %s, %d", p->pp_dst3_text.data, p->pp_dst3_text.len);
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+       "proxy_protocol, src4: %d", p->pp_src4);
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+       "proxy_protocol, dst4: %d", p->pp_dst4);
+}
+
+
+int
+ngx_proxy_protocol_string_length(ngx_proxy_protocol_t *p)
+{
+    int len = 0;
+
+    /* 'PROXY ' */
+    len += (sizeof("PROXY ") - 1);
+
+    /* protocol version (TCP4 or TCP6) + space */
+    len += (sizeof("TCP0 ") - 1);
+
+    /* src3 + space */
+    len += p->pp_src3_text.len;
+    len += 1;
+
+    /* dst3 + space */
+    len += p->pp_dst3_text.len;
+    len += 1;
+
+    /* src4 */
+    if (p->pp_src4 < 10000)
+        /* 4 digits + 1 space */
+        len += (sizeof("0000 ") - 1);
+    else
+        /* 5 digits + 1 space */
+        len += (sizeof("00000 ") - 1);
+
+    /* dst4 */
+    if (p->pp_dst4 >= 10000)
+        /* 5 digits */
+        len += (sizeof("00000 ") - 1);
+    else if (p->pp_dst4 >= 1000)
+        /* 4 digits */
+        len += (sizeof("0000 ") - 1);
+    else if (p->pp_dst4 >= 100)
+        /* 3 digits */
+        len += (sizeof("000 ") - 1);
+    else if (p->pp_dst4 >= 10)
+        /* 2 digits */
+        len += (sizeof("00 ") - 1);
+    else
+        /* 1 digit */
+        len += (sizeof("0 ") - 1);
+
+    /* CRLF */
+    len += (sizeof(CRLF) - 1);
+
+    return len - 1;
+}
+
+#endif
Index: nginx-1.4.7/src/core/ngx_proxy_protocol.h
===================================================================
--- /dev/null
+++ nginx-1.4.7/src/core/ngx_proxy_protocol.h
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright (C) Baptiste Assmann
+ * Copyright (C) Exceliance
+ */
+
+
+#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_
+#define _NGX_PROXY_PROTOCOL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_PROXY_PROTOCOL)
+
+typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
+
+typedef enum {
+    NGX_PP_PROTO_TCP4 = 1,
+    NGX_PP_PROTO_TCP6
+} ngx_pp_proto;
+
+
+struct ngx_proxy_protocol_s {
+    unsigned int	    pp_proto;	/* proxy protocol related information */
+    struct sockaddr_storage pp_src3;
+    ngx_str_t		    pp_src3_text;
+    struct sockaddr_storage pp_dst3;
+    ngx_str_t		    pp_dst3_text;
+    unsigned int	    pp_src4;
+    unsigned int	    pp_dst4;
+};
+
+
+int  ngx_recv_proxy_protocol(ngx_connection_t *, u_char *, ssize_t);
+void ngx_print_proxy_protocol(ngx_proxy_protocol_t *, ngx_log_t *);
+int  ngx_proxy_protocol_string_length(ngx_proxy_protocol_t *);
+
+
+#endif
+
+#endif /* _NGX_CONNECTION_H_INCLUDED_ */
+
Index: nginx-1.4.7/src/http/modules/ngx_http_proxy_module.c
===================================================================
--- nginx-1.4.7.orig/src/http/modules/ngx_http_proxy_module.c
+++ nginx-1.4.7/src/http/modules/ngx_http_proxy_module.c
@@ -8,7 +8,9 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_http.h>
-
+#if (NGX_PROXY_PROTOCOL)
+#include <ngx_proxy_protocol.h>
+#endif
 
 typedef struct ngx_http_proxy_rewrite_s  ngx_http_proxy_rewrite_t;
 
@@ -365,6 +367,17 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
       NULL },
 
+#if (NGX_PROXY_PROTOCOL)
+
+    { ngx_string("send_proxy_protocol"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.send_proxy_protocol),
+      NULL },
+
+#endif
+
 #if (NGX_HTTP_CACHE)
 
     { ngx_string("proxy_cache"),
@@ -2420,6 +2433,11 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
 
     conf->upstream.intercept_errors = NGX_CONF_UNSET;
+
+#if (NGX_PROXY_PROTOCOL)
+    conf->upstream.send_proxy_protocol = NGX_CONF_UNSET;
+#endif
+
 #if (NGX_HTTP_SSL)
     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
 #endif
@@ -2695,6 +2713,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_value(conf->upstream.intercept_errors,
                               prev->upstream.intercept_errors, 0);
 
+#if (NGX_PROXY_PROTOCOL)
+    ngx_conf_merge_value(conf->upstream.send_proxy_protocol,
+                              prev->upstream.send_proxy_protocol, 0);
+#endif
+
 #if (NGX_HTTP_SSL)
     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
                               prev->upstream.ssl_session_reuse, 1);
Index: nginx-1.4.7/src/http/ngx_http.c
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http.c
+++ nginx-1.4.7/src/http/ngx_http.c
@@ -1228,6 +1228,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 #if (NGX_HTTP_SPDY)
     ngx_uint_t             spdy;
 #endif
+#if (NGX_PROXY_PROTOCOL)
+    ngx_uint_t             accept_proxy_protocol;
+#endif
 
     /*
      * we cannot compare whole sockaddr struct's as kernel
@@ -1283,6 +1286,10 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 #if (NGX_HTTP_SPDY)
         spdy = lsopt->spdy || addr[i].opt.spdy;
 #endif
+#if (NGX_PROXY_PROTOCOL)
+        accept_proxy_protocol = lsopt->accept_proxy_protocol
+                                || addr[i].opt.accept_proxy_protocol;
+#endif
 
         if (lsopt->set) {
 
@@ -1316,6 +1323,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 #if (NGX_HTTP_SPDY)
         addr[i].opt.spdy = spdy;
 #endif
+#if (NGX_PROXY_PROTOCOL)
+        addr[i].opt.accept_proxy_protocol = accept_proxy_protocol;
+#endif
 
         return NGX_OK;
     }
@@ -1762,6 +1772,11 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     ls->pool_size = cscf->connection_pool_size;
     ls->post_accept_timeout = cscf->client_header_timeout;
 
+#if (NGX_PROXY_PROTOCOL)
+// CLEANUP:    ls->accept_proxy_protocol = cscf->accept_proxy_protocol;
+    ls->accept_proxy_protocol = addr->opt.accept_proxy_protocol;
+#endif
+
     clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
     ls->logp = clcf->error_log;
@@ -1840,6 +1855,9 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h
 #if (NGX_HTTP_SPDY)
         addrs[i].conf.spdy = addr[i].opt.spdy;
 #endif
+#if (NGX_PROXY_PROTOCOL)
+        addrs[i].conf.accept_proxy_protocol = addr[i].opt.accept_proxy_protocol;
+#endif
 
         if (addr[i].hash.buckets == NULL
             && (addr[i].wc_head == NULL
@@ -1904,6 +1922,9 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
 #if (NGX_HTTP_SPDY)
         addrs6[i].conf.spdy = addr[i].opt.spdy;
 #endif
+#if (NGX_PROXY_PROTOCOL)
+        addrs6[i].conf.accept_proxy_protocol = addr[i].opt.accept_proxy_protocol;
+#endif
 
         if (addr[i].hash.buckets == NULL
             && (addr[i].wc_head == NULL
Index: nginx-1.4.7/src/http/ngx_http_core_module.c
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http_core_module.c
+++ nginx-1.4.7/src/http/ngx_http_core_module.c
@@ -4090,6 +4090,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             continue;
         }
 
+#if (NGX_PROXY_PROTOCOL)
+        if (ngx_strncmp(value[n].data, "accept_proxy_protocol=on", 24) == 0) {
+            lsopt.accept_proxy_protocol = 1;
+            lsopt.set = 1;
+            lsopt.bind = 1;
+            continue;
+        }
+#endif
+
         if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) {
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
             struct sockaddr  *sa;
Index: nginx-1.4.7/src/http/ngx_http_core_module.h
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http_core_module.h
+++ nginx-1.4.7/src/http/ngx_http_core_module.h
@@ -78,6 +78,11 @@ typedef struct {
 #if (NGX_HTTP_SPDY)
     unsigned                   spdy:1;
 #endif
+
+#if (NGX_PROXY_PROTOCOL)
+    unsigned                   accept_proxy_protocol:2;
+#endif
+
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
     unsigned                   ipv6only:1;
 #endif
@@ -234,6 +239,10 @@ struct ngx_http_addr_conf_s {
 
     ngx_http_virtual_names_t  *virtual_names;
 
+#if (NGX_PROXY_PROTOCOL)
+    ngx_flag_t                  accept_proxy_protocol;
+#endif
+
 #if (NGX_HTTP_SSL)
     unsigned                   ssl:1;
 #endif
Index: nginx-1.4.7/src/http/ngx_http_request.c
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http_request.c
+++ nginx-1.4.7/src/http/ngx_http_request.c
@@ -63,6 +63,9 @@ static void ngx_http_ssl_handshake(ngx_e
 static void ngx_http_ssl_handshake_handler(ngx_connection_t *c);
 #endif
 
+#if (NGX_PROXY_PROTOCOL)
+static void ngx_http_proxy_protocol(ngx_event_t *rev);
+#endif
 
 static char *ngx_http_client_errors[] = {
 
@@ -343,6 +346,14 @@ ngx_http_init_connection(ngx_connection_
     }
 #endif
 
+#if (NGX_PROXY_PROTOCOL)
+    {
+        if (hc->addr_conf->accept_proxy_protocol) {
+            rev->handler = ngx_http_proxy_protocol;
+        }
+    }
+#endif
+
     if (rev->ready) {
         /* the deferred accept(), rtsig, aio, iocp */
 
@@ -364,7 +375,6 @@ ngx_http_init_connection(ngx_connection_
     }
 }
 
-
 static void
 ngx_http_wait_request_handler(ngx_event_t *rev)
 {
@@ -469,6 +479,12 @@ ngx_http_wait_request_handler(ngx_event_
     }
 
     rev->handler = ngx_http_process_request_line;
+
+#if (NGX_PROXY_PROTOCOL)
+    if (hc->addr_conf->accept_proxy_protocol)
+        rev->handler = ngx_http_proxy_protocol;
+#endif
+
     ngx_http_process_request_line(rev);
 }
 
@@ -582,6 +598,67 @@ ngx_http_create_request(ngx_connection_t
     return r;
 }
 
+#if (NGX_PROXY_PROTOCOL)
+
+static void
+ngx_http_proxy_protocol(ngx_event_t *rev)
+{
+    ssize_t                n;
+    size_t                 size = 1024;
+    u_char                 tmpbuf[size];
+    ngx_connection_t      *c;
+    ngx_http_connection_t *hc;
+
+    c = rev->data;
+    hc = c->data;
+    rev->handler = ngx_http_wait_request_handler;
+
+#if (NGX_HTTP_SPDY)
+    {
+        if (hc->addr_conf->spdy) {
+            rev->handler = ngx_http_spdy_init;
+        }
+    }
+#endif
+
+#if (NGX_HTTP_SSL)
+    {
+        if (hc->addr_conf->ssl) {
+            rev->handler = ngx_http_ssl_handshake;
+        }
+    }
+#endif
+
+    n = recv(c->fd, tmpbuf, size, MSG_PEEK);
+
+    if ((n <= 0) && (c->listening)
+            && (hc->addr_conf->accept_proxy_protocol)
+	    && (!c->proxy_protocol)) {
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_http_proxy_protocol: pp required but not found");
+        return;
+    }
+    if ((n > 0) && (c->listening)
+            && (hc->addr_conf->accept_proxy_protocol)
+	    && (!c->proxy_protocol)) {
+        ssize_t m;
+        if (!(m = ngx_recv_proxy_protocol(c, tmpbuf, n))) {
+            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_http_proxy_protocol: pp required but not found");
+            ngx_http_close_connection(c);
+            return;
+        }
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_http_proxy_protocol: pp required and found");
+
+        c->proxy_protocol = 1;
+
+        /* strip the proxy protocol string from the buffer */
+        recv(c->fd, tmpbuf, m, 0);
+    }
+
+    rev->handler(rev);
+}
+
+#endif
+
 
 #if (NGX_HTTP_SSL)
 
Index: nginx-1.4.7/src/http/ngx_http_upstream.c
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http_upstream.c
+++ nginx-1.4.7/src/http/ngx_http_upstream.c
@@ -31,6 +31,10 @@ static ngx_int_t ngx_http_upstream_reini
     ngx_http_upstream_t *u);
 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
+#if (NGX_PROXY_PROTOCOL)
+static void ngx_http_upstream_send_proxy_protocol(ngx_http_request_t *r,
+    ngx_http_upstream_t *u);
+#endif
 static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
     ngx_http_upstream_t *u);
 static void ngx_http_upstream_process_header(ngx_http_request_t *r,
@@ -1255,6 +1259,13 @@ ngx_http_upstream_connect(ngx_http_reque
 
     u->request_sent = 0;
 
+#if (NGX_PROXY_PROTOCOL)
+    if (u->conf->send_proxy_protocol && !(u->ssl && c->ssl == NULL)) {
+        ngx_http_upstream_send_proxy_protocol(r, u);
+	return;
+    }
+#endif
+
     if (rc == NGX_AGAIN) {
         ngx_add_timer(c->write, u->conf->connect_timeout);
         return;
@@ -1498,6 +1509,228 @@ ngx_http_upstream_send_request(ngx_http_
 }
 
 
+#if (NGX_PROXY_PROTOCOL)
+
+static void
+ngx_http_upstream_send_proxy_protocol(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+    size_t                   len;
+    ngx_int_t                rc;
+    ngx_connection_t        *uc;
+    ngx_connection_t        *cc;
+    ngx_chain_t             *pp_string;
+    ngx_proxy_protocol_t     pp;
+    ngx_buf_t               *b;
+    char                     port[6];
+    u_char                  *addr;
+    struct sockaddr_storage  sa_src;
+    struct sockaddr_storage  sa_dst;
+    socklen_t                addrlen = NGX_SOCKADDRLEN;
+    struct sockaddr_in      *sin_src;
+    struct sockaddr_in      *sin_dst;
+
+#if (NGX_HAVE_INET6)
+
+    struct sockaddr_in6     *sin6_src;
+    struct sockaddr_in6     *sin6_dst;
+
+#endif
+
+
+    uc = u->peer.connection;
+    cc = r->connection;
+
+    if ( !(u->conf->send_proxy_protocol) ) {
+        return;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, uc->log, 0,
+                   "http upstream send proxy protocol");
+
+    if (!u->request_sent && ngx_http_upstream_test_connect(uc) != NGX_OK) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+    uc->log->action = "sending proxy protocol to upstream";
+
+    len = 0;
+
+    if (r->connection->proxy_protocol) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, uc->log, 0,
+                   "PP: got proxy-protocol from client connection");
+
+        switch (cc->sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+
+            case AF_INET6:
+
+                pp.pp_proto = NGX_PP_PROTO_TCP6;
+                sin6_dst = (struct sockaddr_in6 *) cc->local_sockaddr;
+                sin6_src = (struct sockaddr_in6 *) cc->sockaddr;
+
+                break;
+
+#endif
+
+            default:
+                pp.pp_proto = NGX_PP_PROTO_TCP4;
+                sin_dst = (struct sockaddr_in *) cc->local_sockaddr;
+                sin_src = (struct sockaddr_in *) cc->sockaddr;
+
+        }
+
+    } else {
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, uc->log, 0,
+                   "PP: collecting information from socket fd");
+
+        getsockname(cc->fd, (struct sockaddr *) &sa_dst, &addrlen);
+
+        switch (sa_dst.ss_family) {
+
+#if (NGX_HAVE_INET6)
+
+            case AF_INET6:
+
+                pp.pp_proto = NGX_PP_PROTO_TCP6;
+                sin6_dst = (struct sockaddr_in6 *) &sa_dst;
+
+                getpeername(cc->fd, (struct sockaddr *) &sa_src, &addrlen);
+                sin6_src = (struct sockaddr_in6 *) &sa_src;
+
+                break;
+
+#endif
+
+            default:
+
+                pp.pp_proto = NGX_PP_PROTO_TCP4;
+                sin_dst = (struct sockaddr_in *) &sa_dst;
+                getpeername(cc->fd, (struct sockaddr *) &sa_src, &addrlen);
+                sin_src = (struct sockaddr_in *) &sa_src;
+        }
+
+
+    }
+
+    switch (pp.pp_proto) {
+
+#if (NGX_HAVE_INET6)
+
+        case NGX_PP_PROTO_TCP6:
+
+            /* dst3 and dst4 */
+            addr = ngx_pcalloc(r->pool, NGX_INET6_ADDRSTRLEN);
+            ngx_inet_ntop(AF_INET6, &sin6_dst->sin6_addr, addr, NGX_INET6_ADDRSTRLEN);
+            pp.pp_dst3_text.data = ngx_pcalloc(r->pool, NGX_INET6_ADDRSTRLEN);
+            pp.pp_dst3_text.len = ngx_strlen(addr);
+            ngx_memcpy(pp.pp_dst3_text.data, addr, pp.pp_dst3_text.len);
+            pp.pp_dst4 = htons(sin6_dst->sin6_port);
+
+            ngx_memzero(addr, NGX_INET6_ADDRSTRLEN);
+
+            /* src3 and src4 */
+            ngx_inet_ntop(AF_INET6, &sin6_src->sin6_addr, addr, NGX_INET6_ADDRSTRLEN);
+            pp.pp_src3_text.data = ngx_pcalloc(r->pool, NGX_INET6_ADDRSTRLEN);
+            pp.pp_src3_text.len = ngx_strlen(addr);
+            ngx_memcpy(pp.pp_src3_text.data, addr, pp.pp_src3_text.len);
+            pp.pp_src4 = htons(sin6_src->sin6_port);
+
+        break;
+
+#endif
+
+        default:
+
+            /* dst3 and dst4 */
+            addr = ngx_pcalloc(r->pool, NGX_INET_ADDRSTRLEN);
+            ngx_inet_ntop(AF_INET, &sin_dst->sin_addr, addr, NGX_INET_ADDRSTRLEN);
+            pp.pp_dst3_text.data = ngx_pcalloc(r->pool, NGX_INET_ADDRSTRLEN);
+            pp.pp_dst3_text.len = ngx_strlen(addr);
+            ngx_memcpy(pp.pp_dst3_text.data, addr, pp.pp_dst3_text.len);
+            pp.pp_dst4 = htons(sin_dst->sin_port);
+
+            ngx_memzero(addr, NGX_INET_ADDRSTRLEN);
+
+            /* src3 and src4 */
+            ngx_inet_ntop(AF_INET, &sin_src->sin_addr, addr, NGX_INET_ADDRSTRLEN);
+            pp.pp_src3_text.data = ngx_pcalloc(r->pool, NGX_INET_ADDRSTRLEN);
+            pp.pp_src3_text.len = ngx_strlen(addr);
+            ngx_memcpy(pp.pp_src3_text.data, addr, pp.pp_src3_text.len);
+            pp.pp_src4 = htons(sin_src->sin_port);
+
+    }
+
+    len += ngx_proxy_protocol_string_length(&pp);
+
+    ngx_print_proxy_protocol(&pp, uc->log);
+
+    b = ngx_create_temp_buf(uc->pool, len);
+    if (b == NULL) {
+        return;
+    }
+
+    pp_string = ngx_alloc_chain_link(uc->pool);
+    if (pp_string == NULL) {
+        return;
+    }
+
+    pp_string->buf = b;
+    pp_string->next = NULL;
+
+    b->last = ngx_cpymem(b->last, "PROXY ", sizeof("PROXY ") - 1);
+
+    switch (pp.pp_proto) {
+        case NGX_PP_PROTO_TCP4:
+            b->last = ngx_cpymem(b->last, "TCP4 ", sizeof("TCP4 ") - 1);
+        break;
+        case NGX_PP_PROTO_TCP6:
+            b->last = ngx_cpymem(b->last, "TCP6 ", sizeof("TCP6 ") - 1);
+        break;
+    }
+
+    /* src3 */
+    b->last = ngx_cpymem(b->last, pp.pp_src3_text.data, pp.pp_src3_text.len);
+    b->last = ngx_cpymem(b->last, " ", 1);
+
+    /* dst3 */
+    b->last = ngx_cpymem(b->last, pp.pp_dst3_text.data, pp.pp_dst3_text.len);
+    b->last = ngx_cpymem(b->last, " ", 1);
+
+    /* src4 */
+    ngx_memzero(port, 6);
+    sprintf(port,"%d", pp.pp_src4);
+    b->last = ngx_cpymem(b->last, port, strlen(port));
+    b->last = ngx_cpymem(b->last, " ", 1);
+
+    /* dst4 */
+    ngx_memzero(port, 6);
+    sprintf(port,"%d", pp.pp_dst4);
+    b->last = ngx_cpymem(b->last, port, strlen(port));
+
+    /* CRLF */
+    b->last = ngx_cpymem(b->last, CRLF, sizeof(CRLF) - 1);
+
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, uc->log, 0,
+            "http upstream send proxy protocol: %d -%*s-",
+            ngx_proxy_protocol_string_length(&pp),
+            ngx_proxy_protocol_string_length(&pp) - 2,
+            b->start);
+
+    rc = ngx_output_chain(&u->output, pp_string);
+
+    if (rc == NGX_ERROR) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+}
+
+#endif
+
+
 static void
 ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
     ngx_http_upstream_t *u)
Index: nginx-1.4.7/src/http/ngx_http_upstream.h
===================================================================
--- nginx-1.4.7.orig/src/http/ngx_http_upstream.h
+++ nginx-1.4.7/src/http/ngx_http_upstream.h
@@ -188,6 +188,10 @@ typedef struct {
     unsigned                         intercept_404:1;
     unsigned                         change_buffering:1;
 
+#if (NGX_PROXY_PROTOCOL)
+    ngx_flag_t                       send_proxy_protocol;
+#endif
+
 #if (NGX_HTTP_SSL)
     ngx_ssl_t                       *ssl;
     ngx_flag_t                       ssl_session_reuse;
Index: nginx-1.4.7/auto/cc/gcc
===================================================================
--- nginx-1.4.7.orig/auto/cc/gcc
+++ nginx-1.4.7/auto/cc/gcc
@@ -168,7 +168,7 @@ esac
 
 
 # stop on warning
-CFLAGS="$CFLAGS -Werror"
+CFLAGS="$CFLAGS"
 
 # debug
 CFLAGS="$CFLAGS -g"
Index: nginx-1.4.7/auto/cc/icc
===================================================================
--- nginx-1.4.7.orig/auto/cc/icc
+++ nginx-1.4.7/auto/cc/icc
@@ -115,7 +115,7 @@ case "$NGX_ICC_VER" in
 esac
 
 # stop on warning
-CFLAGS="$CFLAGS -Werror"
+CFLAGS="$CFLAGS "
 
 # debug
 CFLAGS="$CFLAGS -g"