Twisted web server and Autobahn WebSocket at the same time, same port - twisted

I have a server that listens for WebSocket connections on port 80, using Twisted and Autobahn. I want to have it also serve static HTML pages, for when the client doesn't want to use a WebSocket. Is it possible to do both things at the same time, using Twisted and Autobahn?

Sure, have a look here and here. You can run Twisted Web and add a Autobahn based WebSocket Twisted Web resource on a path. You can add any number of Twisted Web resources into your resource tree.
Briefly the technique is to start your WebSocketServerFactory manually by invoking startFactory(), then wrap it within a autobahn.twisted.resource.WebSocketResource resource, which you can then register with putChild anywhere within a Twisted Web hierarchy.

I think you have to add haproxy to the mix. If you want to just use twisted and autobahn then I don't think you can share the port. Having said that, I've got both my websockets and web server listening on the same external port. I had to use haproxy to do the trick, though...haproxy handle the inbound connection, then distributes the connection based upon things it pulls from its environment. Every environment is different. Basically, you get haproxy running, then make your web service and web socket listen on private, different ports. In my case I put my web socket server on 127.0.0.1:9000, and my web service on 127.0.0.1:8080. Then you create a haproxy.conf file for haproxy's configuration, in this example, something like:
global
maxconn 100
mode http
frontend myfrontend
bind *:80
acl is_websocket hdr(Upgrade) -i WebSocket
use_backend ws if is_websocket
default_backend mybackend
backend mybackend
server s3 127.0.0.1:8080
backend ws
timeout server 600s
reqrep ^Host:\ .* \0:9000
server ws1 127.0.0.1:9000
I had to remove a bunch of unrelated stuff from the haproxy.conf file, but this gets the idea across. It was important to me to have only one port visible from the outside instead of managing two.
haproxy is awesome !
-g

Related

How to redirect all request on port 80 to a docker and then pass it to my web server?

How can I put a docker between the web requests and my web server (in order to analyse and block requests)? I found morbz/docker-web-redirect docker, but it seems that it is not enough for this task.
I'd recommend using nginx as reverse proxy, or better haproxy:
https://hub.docker.com/_/haproxy/
You have to configure haproxy container to listen to port 80 on the host, then direct traffic to your proxied web server.
Haproxy ACLS might be of your interest: How to route traffic (reverse Proxy) with HAProxy based on request body

AWS Elastic Beanstalk VPC - HTTPS from ELB to instance

I'm trying to figure out the best way to manage HTTPS for an EB docker application.
At the moment I'm using the following approach.
ELB accepts HTTPS connections on 443, and forwards to HTTP port 80 on the instance.
ELB accepts HTTP connections on 80, and forwards to HTTP port 8080 on the instance.
Instance accepts HTTP connections on port 80 and forwards to docker app.
Instance accepts HTTP connections on port 8080 and redirects them to HTTPS.
This all works reasonably well. It means the docker app doesn't have to worry about redirects at all. It just listens on port 80, and does it's thing. The ELB and docker host do the rest.
My only concern with this setup, is the docker app doesn't know that it's running secure. If within my application I check for this, it'll fail.
I want to completely separate my docker app from domain names, and SSL certificates that may change, so I would prefer to continue terminating the original HTTPS connection at the ELB. I'm wondering if there is some way I can get the docker host (or ELB) to forward (re-encrypt) request in HTTPS protocol, but using a self-signed certificate, so I can keep it completely generic.
Just to be clear, this would only be between the ELB and/or docker host, and my docker app, not to the browser.
If I create a non-expiring self-signed certificate, and then register this with the web-server in the docker app (currently using Apache2, but could potentially use nginx), and then simply tell the ELB, or docker host to forward requests as HTTPS, will this work? Or would it fall over at some point because the certificate isn't trusted?
Or is there some way to be able to terminate a HTTPS connection at the docker app web-server without actually needing to pre-generate a certificate (I'm guessing no on this, as presumably it'd need to generate a certificate on the fly or something).
Is there a recommended best practice way to do this kind of thing?
A common solution when you have a load balancer terminating client connections and forwarding to backend is for the load balancer to add headers onto the backend requests to fill in any information stripped by having the load balancer there.
ELB has a page on this and uses the following headers:
X-Forwarded-For - The client IP
X-Forwarded-Proto - The scheme/protocol
X-Forwarded-Port - The incoming port.
You would generally not allow these headers directly from the client, unless they were a trusted client. I assume ELB takes care of that for you.

How to have nginx proxy websockets without continuous connection to back end server?

I currently have a server running apache httpd 2.2 serving ~1000 websocket connections. I'm trying to scale this up to around ~10K websockets on the the same hardware. I thought I'd be able to place an nginx reverse proxy on the front end, and that nginx would only connect to the backend when there was incoming traffic, and would maintain the connection to the outside world. However, right now the connection seems to continuous (i.e., once the websocket upgrade is complete, a httpd process is tied up until the connection is broken. Am I misunderstanding how nginx should do websockets proxying, or do I have something misconfigured?
NGINX supports WebSockets by creating a tunnel between the client and the backend server and so the nginx will not terminate the connections to the backend/frontend until the client/server terminates the connections.
See: https://www.nginx.com/blog/websocket-nginx/ for more info.

Where to put SSL encryption, Apache HTTP or Webapp

I'm creating an Middleware/Webapp for a REST API in Erlang with cowboy framework and Apache HTTP with ModProxy, to redirect requests from port 80 to port 80xx, since i don't wanna use custom ports to listen requests and i don't wanna run the code in root to be able to listen in port 80.
Now i wanna encrypt the connections, with SSL, using HTTPS and my question is: where is the best practice to configure SSL with certificates, keys etc, in Apache HTTP (before redirect with ModProxy) or in Cowboy framework in Erlang app, since both support SSL configuration.
Thanks in advance!
I'd put it in Apache:
If you want to add more services later, they'd automatically benefit with SSL protection.
If you need to debug something, you can tcpdump the data between Apache and your Erlang VM, which will be decrypted at that point.

Proxy Protocol on Elastic Load Balancing non-terminated SSL connection

For reasons we're not going to change, our application needs to handle the SSL connection, and not the ELB. The goal of using the Proxy Protocol is to get the client's IP address over an SSL connection.
http://aws.typepad.com/aws/2013/07/elastic-load-balancing-adds-support-for-proxy-protocol.html?ref_=9 indicates "Alternatively, you can use it if you are sending HTTPS requests and do not want to terminate the SSL connection on the load balancer. For more information, please visit the Elastic Load Balancing Guide."
Unfortunately, it appears the guide that's linked to doesn't actually elaborate on this, and the basic documentation for the Proxy Protocol ( http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/enable-proxy-protocol.html ) fails in our environment when configured as described.
Does anyone have steps or a link for this?
The proxy protocol (version 1) injects a single line into the data stream at the beginning of the connection, before SSL is negotiated by your server. You don't get this information "over" an SSL connection; you get the information prior to SSL handshaking. Your server has to implement this capability and specifically be configured so that it can accept and understand it. For an IPv4 connection, it looks like this:
PROXY TCP4 source-ip dest-ip source-port dest-port\r\n
The standard for the protocol is here:
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
Additional info in the ELB docs here:
http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/TerminologyandKeyConcepts.html#proxy-protocol
Regarding Apache support, at least at the time AWS announced support for the proxy protocol...
“neither Apache nor Nginx currently support the Proxy Protocol header inserted by the ELB”
— http://aws.typepad.com/aws/2013/07/elastic-load-balancing-adds-support-for-proxy-protocol.html?ref_=9
That is subject to change, of course, but I didn't successfully google for any Apache support of the proxy protocol. Of course, since Apache is open source, you could presumably hack it in there, though I am unfamiliar with the Apache source code.
Realizing that you don't want to change what you're doing now, I still would suggest that depending on your motivation for not wanting to change, there may still be a relatively simple solution. It's a change, but not involving SSL on ELB. What about running HAProxy behind ELB to terminate the SSL in front of Apache? Since HAProxy 1.5 can terminate SSL and appears to be able to translate the proxy protocol string from ELB into an X-Forwarded-For header, as well as generate X-SSL headers to give your application information about the client's SSL cert (perhaps that's your motivation for terminating SSL at the app server instead of on the ELB?) ... so this might be an alternative.
Otherwise, I don't have suggestions unless Apache implements support in the future, or we can find some documentation to indicate that they already have.
For the newer Network Load Balancers which allow your application servers to terminate the TLS connections, you can still get the real IP addresses of your clients and avoid all the work of configuring proxy protocol on the ELBs and in the web server config by simply configuring the target groups to use the servers' instance ids rather than their IP addresses. Regardless of which web server you use, the real IPs of the clients will show up in the logs with no translation needed.
Just to follow up on Michael - sqlbot's answer discussing the AWS support for proxy protocol on EC2 instances behind classic TCP elastic load balancers, the Apache module to use that implements the proxy protocol is mod_remoteip. Enabling it and updating the configuration properly will correct the problem of logging IP addresses of users rather than the elastic load balancer's IPs.
To enable proxy protocol on the elastic load balancer you could use these aws cli commands described in the aws documentation:
aws elb create-load-balancer-policy --load-balancer-name my-elb-name --policy-name my-elb-name-ProxyProtocol-policy --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=true
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-elb-name --instance-port 443 --policy-names my-elb-name-ProxyProtocol-policy
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-elb-name --instance-port 80 --policy-names my-elb-name-ProxyProtocol-policy
To enable use of proxy protocol in apache, in a server-wide or VirtualHost context, follow the mod_remoteip documentation such as below:
<IfModule mod_remoteip.c>
RemoteIPProxyProtocol On
RemoteIPHeader X-Forwarded-For
# The IPs or IP range of your ELB:
RemoteIPInternalProxy 192.168.1.0/24
# The IPs of hosts that may need to connect directly to the web server, bypassing the ELB (if applicable):
RemoteIPProxyProtocolExceptions 127.0.0.1
</IfModule>
You'll need to update the LogFormat wherever you have those defined (e.g. httpd.conf) to use %a rather than %h else the load balancer IP addresses will still appear.