WebSocket connection never fully established when traffic is routed through Cloudflare - node.js

I use a service called glitch.me to host my Node.js project, and they only allow you to open one port internally. At the moment, my Node.js server can only handle HTTP requests, but glitch.me proxies my traffic for me, effectively allowing the client to communicate indirectly using HTTPS. My project heavily relies on the use of WebSockets, and they work perfectly when accessing it directly via example.glitch.me (the url provided by glitch.me). However, I need to connect this project to my custom domain (example.xyz), all traffic of which is proxied through Cloudflare. However, when attempting to establish a WebSocket connection through my custom domain (in other words: via Cloudflare), the socket connection is never established.
Now, I realise that this sounds very specific, but I think it's possible to generalise here:
WebSockets work:
client => glitch.me => my backend
client => A => my backend
Webockets don't work:
client => cloudflare => glitch.me => my backend
client => A => B => my backend
Note: HTTP/HTTPS still works for both domains.
I added logging on the server-side every time a WebSocket connection was established, and sure enough the server receives the connections! However, the client is never notified and in Chrome Developer tools it shows that the request never completed. Remember, everything is working perfectly when the traffic is not routed through Cloudflare.
I have full understanding for the fact that it may be impossible for you to resolve my issue with the information given to you, but I'm not asking you to do so. My question is simply this: where does the problem lie? Does the response from my backend get stuck somewhere along the way and doesn't reach all the way through? I have contacted both glitch.me and Cloudflare and they have both confirmed that they fully support WebSocket traffic.
What is the most probable cause of my problem? From there I could probably fix it!
Edit: I uses the ws package on npm on the backend and standard JavaScript WebSockets on the frontend.

Related

Expressjs app, using websockets for chat. Use different port for websocket server?

I'm making an app using node.js' express framework which serves both html content over http and uses websockets for a chat feature. I'm wondering how I can accomplish both at the same time. My idea is to use a different port for websocket connections (so http requests would come to port 3000 and websockets would connect on port 3001) but I don't know if that's a good solution. I'm especially worried about deployment to something like heroku and if I can specify different ports for my app.
I'm wondering how I can accomplish both at the same time.
The webSocket protocol is specially designed so it can run on the same port as your regular web server requests. So, you don't need a separate port in order to have both a web server and chat running using webSockets.
This works because a webSocket connection is always initiated with an http request that sets a few special headers. The receiving web server can then detect those special headers and know that this incoming http request is actually a request to initiate a webSocket connection. With a particular response, the client and server then agree to "upgrade" the connection and switch to the webSocket protocol. From that point on, that particular TCP connection uses the webSocket protocol.
Meanwhile any incoming http request that does not have the special webSocket headers on it is treated by your web server as just a regular http request. In this way, the same server and the same port can be used for both webSocket connections and regular http requests. No second port is needed.
Another advantage of this scheme is that the client can avoid the cross-origin issues that it would run into if it was trying to use a different port than the web page it was loaded from.
I'm especially worried about deployment to something like heroku and
if I can specify different ports for my app.
If you were to actually use two ports, then you would need to create two separate servers, one listening on each port since a given server can only listen on one port. In node.js, the two servers could both be in the same node.js app (making it easier to share data between them) or you could put them in completely separate node.js processes (your choice).
And, if you used multiple ports, you'd also have to support CORS so that the browser would be allowed to connect to the separate port (to avoid same-origin restrictions).

Submitting HTTPs from node socket with no certificate

A web application i developed is sitting on a server that serves it under https, some of my js code requires to open a socket to another server (nodejs) who is currently not set for https. and thus browser wont allow it to run.
all i want is a simple way without getting involved with certificates just to initiate a https socket connection, i don't mind the lack of security,
just need app to run.
The certificates are not your problem. Your problem is CORS. You need to configure your server to answer with a header allows foreign-origin
res.header('Access-Control-Allow-Origin', 'example.com');
because in your case the technical difference between http (port 80) and https (443) is the port.
EDIT: ... I mean from the browsers point of view

How to scrape socket.io updates to a third-party site?

I basically want to know if its possible to use Socket.io using the server-side only with no client side? BUT I want to know if my server-side can instead connect with a different site that I cannot use Socket.io to connect to.
Use PhantomJS to load the third-party site and then inject your own javascript into the page to catch events and send those events back to your own server.
socket.io is a two-way connection. Client <--> Server. You must have a socket.io endpoint at both ends to even establish a connection in the first place. And, then once you establish the connection, you must have agreed upon messages that can be exchanged between the two ends for it to do anything useful.
It is not useful to have a server-side socket.io that doesn't actually connect to anything and nothing connects to it. It wouldn't be doing anything, just sitting there waiting for someone to connect to it.
It is possible to have two cooperating servers connect to one another with socket.io (one server just acts like a client in that case by initiating the connection to the other server). But, again both endpoints must participate in the connection for the connection to even be established and certainly for it to do anything useful.
If you just want to download the contents of a site for scraping purposes, then you would not use socket.io for that. You would just use the nodejs http module (or any of several other modules built on top of it). Your server would essentially pretend to be a browser. It would request a web page from any random web server using HTTP (not socket.io). That web server would return the web page via the normal HTTP request. Your receiving server can then do whatever it wants with that web page (scrape it, whatever).

WebSocket over SSL: Cloudflare

I have a website behind cloudflare. I need to enable websockets over SSL without turning off cloudflare support. I have a PRO plan and hence won't get the new websocket support. I am using Nginx to proxy a SSL connection to a web socket running on a node server. Now, I read somewhere that cloudflare could work with approved ports would support websockets. Hence, I'm using 8443 for the Nginx port and another port for the node server. Using wscat it returns a 200 error.
$ wscat -c wss://xyz.com:8443
error: Error: unexpected server response (200)
I know that the websocket is expecting a 101 code. However, if I visit https://xyz.com:8443, I can see the page displayed by the node server telling me proxy is working. Also, once I turn off cloudflare support, the websocket starts working. Any clues to get this working. I know I can create a subdomain but I'd prefer running the websocket behind cloudflare.
If you're trying to access this through CloudFlare's network you'd need to explicitly have web sockets enabled on your domain before they will work -- regardless of the port. As in, even if the port can pass through our network, that won't automatically mean that web sockets will be enabled or accessible on your domain.
You can try contacting our support team to request an exception to see if they can enable it for your domain, but typically this is still only available at the business and enterprise levels.
Disclaimer: I work at CloudFlare.

node http proxy SSL transparent

In my setup, I have 2 layers of transparent proxies. When a client makes an SSL request, I wish to have the first proxy it meets simply forward the traffic to another one without attempting to do the handshake with the client.
The setup seems funny, but it is justified in my case - the 2nd proxy registers itself to the first one (through some other service) only occassionally. It tells the first: "I'm interested in some traffic that looks like___". In most cases, the 1st proxy simply does the work.
Can an httpProxy (in node-proxy) proxy SSL requests? Must I use an httpsProxy (which will then do the handshake with the client)?
You could do all of this with the existing httpsProxy if you wanted to. Unless you are wanting to use a non-Node proxy or proxy to a different server, I can't see what you would gain by having two.
Simply add the required the logging/signing logic to the existing httpsProxy.
Typically, I use https on the proxy to both restrict the number of open ports and to remove the need to do https on all of the Node servers running. You can also add Basic Auth using http-basic library too.
See my example code: https://github.com/TotallyInformation/node-proxy-https-example/blob/master/proxy.js
EDIT 2012-05-15: Hmm, after some thought, I wonder if you shouldn't be looking at something like stunnel to do what you want rather than Node?
(For reference, I've already made some of those points in my answer to your similar question on ServerFault.)
If you are after a MITM proxy (that is, a proxy that can look inside the SSL content by using its own certificates, which can work provided the clients are configured to trust them), it will hardly be fully transparent, since you will at least have to configure its clients to trust its certificates.
In addition, unless all your client use the server name indication extension, the proxy itself will be unable to determine reliably which host to issue its certificate for (something that a normal HTTPS proxy would have been able to know by looking at the CONNECT request issued by the client).
If you're not after a MITM proxy, then you might as well let the initial connection through via your router. If you want to record that traffic, your router might be able to log the encrypted packets.
Having your router catch the SSL/TLS packets to send them transparently to a proxy that will merely end up relaying that traffic untouched anyway to the target server doesn't make much sense. (By nature, the transparent proxy will imply the client isn't configured to know about it, so it won't even send its CONNECT method with which you could have had the requested host and port. Here, you'll really have nothing more than what the router can do.)
EDIT: Once again, you simply won't be able to use an HTTP proxy to analyse the content of the connection transparently. Even when using a normal proxy, an HTTPS connection is relayed straight through to the target server. The SSL/TLS connection itself is established between the original client and the target server. The point of using SSL/TLS is to protect this connection, and to make the client notice if something is trying to look inside the connection.
Plain HTTP transparent proxy servers work because (a) the traffic can be seen (in particular, the request line and the HTTP Host header are visible so that the proxy can know which request to make itself) and (b) the traffic can be altered transparently so that the initial client doesn't notice that the request wasn't direct and works as if it was.
Neither of these conditions are true with HTTPS. HTTPS connections that go through an HTTP proxy are simply tunnel, after explicit request from the client, which has sent a CONNECT command and was configured to make use of such a proxy.
To do something close to what you're after, you'd need an SSL/TLS server that accepts the SSL/TLS connection and deciphers it (perhaps something like STunnel) before your HTTP proxy. However, this won't be transparent, because it won't be able to generate the right certificates.

Resources