How to access event machine websockets through Thin/nginx? - ruby

I have an event-machine websocket application (using the em-websocket gem) and it runs fine. The problem is that I need to deploy it using port 80 through nginx (can't compile it with tcp proxy module). Is it possible to use a simple nginx proxy_pass pointing to a thin server and have the thin server to pass the requests to my websocket server?

From what I understand you can't proxy websocket traffic with a proxy_pass.
Since web sockets are done over HTTP 1.1 connections (where the handshake and upgrade are completed), your backend needs to support HTTP 1.1, and from what I have researched, they break the HTTP 1.0 spec...
I've seen some people try to do the same thing with socket.io and HAProxy (see links). I would guess that you could try to swap out the socket.io with em-websockets and expect similar results.
1: http://www.letseehere.com/reverse-proxy-web-sockets
2: HAProxy + WebSocket Disconnection

Related

Cloudflare blocking websocket connection

I have a node js web app that has a websocket server. When I connect to it from the same domain, the websocket connects but when I try to connect from a different domain it does not work. Is there any cloudflare settings that could be blocking this?
Changed minimum TLS version from1.3 to 1 because websockets use lower TLS version

Can I have my cloudrun server receive http/2 requests?

Can I have Google send http/2 requests to my server in cloud run?
I am not sure how google would know my server supports it since google terminates the SSL on the loadbalancer and sends http to the stateless servers in cloud run.
If possible, I am thinking of grabbing a few pieces from webpieces and creating a pure http/2 server with no http1.1 for microservices that I 'know' will only be doing http/2.
Also, if I have a pure http/2 server, is there a way that google translates from http1 requests to http/2 when needed so I could host websites as well?
The only info I could find was a great FAQ that seems to be missing the does it support http/2 on the server side(rather than client)...
https://github.com/ahmetb/cloud-run-faq
thanks,
Dean
Cloud Run container contract requires your application to serve on an unencrypted HTTP endpoint. However, this can be either HTTP/1 or HTTP/2.
Today, gRPC apps work on Cloud Run and gRPC actually uses HTTP/2 as its transport. This works because the gRPC servers (unless configured with TLS certificates) use the H2C (HTTP/2 unencrypted cleartext) protocol.
So, if your application can actually serve traffic unencrypted using h2c protocol, the traffic between Cloud Run load balancer <=> your application can be HTTP/2, without ever being downgraded to HTTP/1.
For example, in Go, you can use https://godoc.org/golang.org/x/net/http2/h2c package to automatically detect and upgrade http2 connections.
To test if your application implements h2c correctly, you need to locally run:
curl -v --http2-prior-knowledge http://localhost:8080
and see < HTTP/2 200 response.
(I'll make sure to add this to the FAQ repo.)

Restrict insecure web socket protocol connections in PCF

We are hosting an application in the preprod azure PCF environment which exposes websocket endpoints for client devices to connect to. Is there a prescribed methodology to secure the said websocket endpoint using TLS/SSL when hosted on PCF and running behind the PCF HAProxy?
I am having trouble interpreting this information, as in, are we supposed to expose port 4443 on the server and PCF shall by default pick it up to be a secure port that ensures unsecured connections cannot be established? Or does it require some configuration to be done on HAProxy?
Is there a prescribed methodology to secure the said websocket endpoint using TLS/SSL when hosted on PCF and running behind the PCF HAProxy?
A few things:
You don't need to configure certs or anything like that when deploying your app to PCF. The platform takes care of all that. In your case, it'll likely be handled by HAProxy, but it could be some other load balancer or even Gorouter depending on your platform operations team installed PCF. The net result is that TLS is first terminated before it hits your app, so you don't need to worry about it.
Your app should always force users to HTTPS. How you do this depends on the language/framework you're using, but most have some functionality for this.
This process generally works by checking to see if the incoming request was over HTTP or HTTPS. If it's HTTP, then you issue a redirect to the same URL, but over HTTPS. This is important for all apps, not just ones using WebSockets. Encrypt all the things.
Do keep in mind that you are behind one or more reverse proxies, so if you are doing this manually, you'll need to consider what's in x-forwarded-proto or x-forwarded-port, not just the upstream connection which would be Gorouter, not your client's browser.
https://docs.pivotal.io/platform/application-service/2-7/concepts/http-routing.html#http-headers
If you are forcing your user's to HTTPS (#1 above), then your users will be unable to initiate an insecure WebSocket connection to your app. Browsers like Chrome & Firefox have restrictions to prevent an insecure WebSocket connection from being made when the site was loaded over HTTPS.
You'll get a message like The operation is insecure in Firefox or Cannot connect: SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. in Chrome.
I am having trouble interpreting this information, as in, are we supposed to expose port 4443 on the server and PCF shall by default pick it up to be a secure port that ensures unsecured connections cannot be established? Or does it require some configuration to be done on HAProxy?
From the application perspective, you don't do anything different. Your app is supposed to start and listen on the assigned port, i.e. what's in $PORT. This is the same for HTTP, HTTP, WS & WSS traffic. In short, as an app developer you don't need to think about this when deploying to PCF.
The only exception would be if your platform operations team uses a load balancer that does not natively support WebSockets. In this case, to work around the issue they need to separate traffic. HTTP and HTTPS go on the traditional ports 80 and 443, and they will route WebSockets on a different port. The PCF docs recommend 4443, which is where you're probably seeing that port. I can't tell you if your platform is set up this way, but if you know that you're using HAproxy, it is probably not.
https://docs.pivotal.io/platform/application-service/2-8/adminguide/supporting-websockets.html
At any rate, if you don't know just push an app and try to initiate a secure WebSocket connection over port 443 and see if it works. If it fails, try 4443 and see if that works. That or ask your platform operations team.
For what it's worth, even if your need to use port 4443 there is no difference to your application that runs on PCF. The only difference would be in your JavaScript code that initiates the WebSocket connection. It would need to know to use port 4443 instead of the default 443.

nginx 1.2.0 - socket.io - HTTP/1.1 - Proxy websocket connections

i would like to replace my node-http-proxy module with nginx proxy_pass module. Is it possible with new released nginx version, as i have read, that it supports HTTP/1.1 out of the box. I saw some threads struggeling with that problem, that websockets are not supported by nginx.
In my case im running several node projects in background and want to route my websocket connections from port 80 to 8000-8100, depending on domain. Is there a native way to do websocket proxy/reverse proxy without using the tcp_module addon?
I tried to setup an upstream in nginx.conf with proxy_passing to it, but if i try to connect to port 80 over websocket, i get an 502 Gateway error.
Anyone facing the same problem?
Does anyone have a working example for nginx + spcket.io, proxying over port 80?
No, this is not yet possible; nginx 1.2 incorporates stuff from the 1.1.x development branch which indeed includes HTTP/1.1 reverse proxying. Websocket connections are established using the HTTP/1.1 "Upgrade" header, but the fact that nginx now supports this kind of headers does not mean it supports websockets (websockets are a different protocol, not HTTP).
(I tried this myself using the 1.1.x branch (which I found to be stable enough for my purpose) and it doesn't work without the tcp_module)
Websockets will probably be supported in 1.3.x ( http://trac.nginx.org/nginx/roadmap ).
Your alternatives are:
keep using node-http-proxy
use nginx without tcp module; socket.io won't use websockets but something else (e.g. long polling)
nginx with tcp module: in this case I think you need an additional port for this module (never tried this myself)
put something else in front as a reverse proxy: I use HAProxy (which supports websockets) in front of nginx and node. Nginx now simply acts as a static fileserver, not a proxy. Varnish is another option, if you want additional caching.
In relation to NginX with TCP module there are few problems I have encountered.
But the most tricky one is trying to run your websockets with nginx on port 80 on EC2 instance.
I described whole configuration here

handle CONNECT requests in a websocket server

My websocket server listens on port 8080 with no proxy.
Most of the time I'm getting requests with the Upgrade Websocket header and it works fine.
Sometimes I'm getting HTTP CONNECT requests.
Is this a valid request?
Does it means that there is a proxy server between the client and the server?
How my server is suppose to respond to the CONNECT request?
Thanks
You are getting CONNECT requests because you are likely to have configured your browser to use a proxy. If you directed your browser to use port 8080 on your local IP address, it will assume there is a proxy and that means when you ask for a secure connection, the browser leads with CONNECT.
You will need to add support for SSL/TLS tunnelling to your server to deal with this.

Resources