deis/deis — pull request #2717 by Blystad (2014-12-10 15:42:48+00:00)
Title: Router add proxy protocol support

This pull requests adds support for the PROXY Protocol on port 8080, if enabled through etcd. It it slightly related to #2700.

The [PROXY Protocol](http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt) provides a way to get the clients IP address through a TCP only proxy. For my use case, Amazon ELB was [lacking websockets support](https://forums.aws.amazon.com/thread.jspa?threadID=84606) and it doesn't look like it will get it in any near future. Amazon ELB, however, supports the Proxy Protocol, and by setting the listener into TCP mode, Websockets will work fine.

The reason why I exposed port 8080 as an additional port, was because of how Amazon ELB health checks work. When sending a request to a HTTP server with Proxy protocol enabled, it first expects to get:
`PROXY TCP4 255.255.255.255. ....\r\n`, and then the request (`GET /health-check HTTP1.1\r...`).
If it doesn't get this, it will return a `400 Client error`.

## Steps to properly test it
To test this with Amazon ELB, a couple of extra steps must be done (`X` will vary, names can vary):
1. Add port 8080 (Proxy protocol) to `deis-VpcSecurityGroup-X`
2. Turn on proxy protocol support through the AWS CLI (No GUI support):
2.1 Create custom LoadBalancerPolicy: `aws elb create-load-balancer-policy --load-balancer-name deis-DeisWebE-X --policy-name EnableProxyProtocol --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=true`
2.2 Associate this with instance port 8080: `aws elb set-load-balancer-policies-for-backend-server --load-balancer-name deis-DeisWebEL-X --instance-port 8080 --policy-names EnableProxyProtocol`
3. Enable ProxyProtocol through ETCD: `etcdctl set /deis/router/proxyProtocol 1`
4. Change Aws ELB *Load Balancer port* `80` to point to *Instance port* `8080`, and *Load Balancer Protocol* from `HTTP` to `TCP`
5. Test that everything works.

To test that everything works, I've created a simple HTTP server in Go which just writes out the HTTP Headers, like so:
```
GET / HTTP/1.1
Host: http-headers.dev.mydeiscluster.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: no,en-US;q=0.8,en;q=0.6,nb;q=0.4,en-GB;q=0.2
Connection: close
X-Forwarded-For: 85.1.11.11
```
It's available here: https://github.com/Blystad/http-server-header-dump or as a `docker/deis pull blystad/http-headers-dump`

With PROXY Protocol support, X-Forwarded-For will show the correct IP. Without it, you'll see a internal IP (10.XX or similar).