Public Hostname in tunnels failing to handle websocket
I've set up a number of local web applications through a single tunnel folowing this guide.
https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/
All of them are accessible through the tunnel, but one of them only loads so far before stalling. The application appears to stall when trying to set up a websocket. It works fine accessed not through the tunnel.
I've checked Websockets are enabled for the domain & cloudflared is up to date.
Any ideas where to check to get this working?
Cloudflare Docs
Create a tunnel (dashboard)
Follow this step-by-step guide to create your first remotely-managed tunnel using Zero Trust.


38 Replies
The 1st screenshot shows the /socket.io/ session starting when connecting to the site locally. In the 2nd screenshot the socket.io session never starts. Instead there are these calls to the file /cdn-cgi/rum? which don't happen when connecting locally.
This is the config for the tunnel
It is also protected by CF Access which appears to be working just fine.
How are you trying to connnect to the websocket (from the client)?
On the server side, do you have a reverse proxy like apache or nginx before the websocket application?
How are you trying to connnect to the websocket (from the client)?The websocket is invoked by the web client. This is a bit of commercial software, I didn't develop it so don't know much more about this. The web client starts up no problem.
On the server side, do you have a reverse proxy like apache or nginx before the websocket application?No proxy server at all. The traffic goes direct from the cf tunnel to the web application
Can you find the line that makes the connection in the web app? Does it try to connect to port 30005? Is it a WS or WSS connection?
When connecting from local I get the network event for the websocket. It is connecting to ws://192.168.1.200:30005/socket.io/?session=1c103518135066cddd122ca8&EIO=4&transport=websocket
The first screenshot above is of this event.
There is no such event when connecing from the tunnel. I don't even see a failed version of this event.
The local connection is made to port 30005, but that won't work via Cloudflare. So did you configure the port to use 443 instead when you try to connect from outside?
Or 80 rather if it's a WS connection. You'd also have to disable automatic https redirects on Cloudflare to support WS.
The tunnel configuration was done here (screenshot) so it connects from the outside via standard SSL 443. If thats what you mean. I would have thought the tunnel configuration would also translate the ws port. Am I getting that wrong?
You'd also have to disable automatic https redirects on Cloudflare to support WS.Where can I do this?

ws://192.168.1.200:30005
I mean this part. The app tries to connect to port 30005, but Cloudflare doesn't support port 30005. So did you change the app to connect to 80/443 instead?The app tries to connect to port 30005,Thats the connection from inside though. When I connect to the tunnel from outside its connecting to standard 443, then being translated by the tunnel to the internal address. Thats how I thought the tunnel works. Port 30005 isn't accessible from outside and shouldn't be. I think I'm not expaining well. The connection to :30005 I posted is when I connect to the web app from a client on the inside of my network. I cant post a similar ws: connection because one doesn't appear, even a failed one.
const dokoSocket = new WebSocket(
'wss://doko.laudian.de/ws/dokosync/CB9575BE/'
);
Your app will create a websocket somewhere like this. This only uses the domain and wss://, no port?I can't change the code of the server. If I change the local port of the service to 80 might ths work?
That's client side code, not server.
ok, I'm very confused.
Just to clarify, and me just thinking this through again. The service running at 192.168.1.200:30005 is a bit of commercial software that I cannot modify.
I have it published to the internet through CF Tunnels and Access at v13.goblinism.uk on port 443. This is DNS hosted by CF.

I'm not asking anything about the service running on your server.
I want to understand how the client initiates the websocket connection.
Yes sorry, I hadn't finished thinking this through. And appologies for my lack of knowledge about how this works, I am trying to figure it out. Thanks for being patient with me.
I think when the web app sends the web client to the client I believe it tries to initiate the websocket (I might be wrong about this), because thats what I see looking at the connection from a client on the inside of the network.
When made from the inside it connects to ws://192.168.1.200:30005/socket.io/?session=1c103518135066cddd122ca8&EIO=4&transport=websocket
I assume when the client connects from the outside it shoud do it to ws://v13.goblinism.uk/socket.io/?session= etc etc
Because thats the address it is communicating.
I am guessing that the tunnel translates the ws://v13.goblinism.uk/socket.io/ to ws://192.168.1.200:30005/socket.io/? and vice versa so the socket can be maintained.
How wrong am I about this so far?
Successful connection from inside the network


If you go to https://doko.laudian.de/lobby/?id=CB9575BE, which is a very simple app that uses websockets through a tunnel, you can find
at the bottom of the page source. Can you find the equivalent where the connection is made in your app?
Also, are WebSockets enabled in your Cloudflare network settings? They should be enabled by default.
are WebSockets enabled in your Cloudflare network settings?Yes, I checked this first of all

Can you find the equivalent where the connection is made in your app?Not sure. As I said this is not my app, it is a commercial software not of my making. I don't know where in the (very large) codebase it might be or if it is accessible to me. I will have a hunt about.
Ok, if you look at the browser dev tools, what do you see in the network tab?

Do you see any attempt at making a ws/wss connection?
There is connecting from internal

There isn't when connecting from outside

I found some code I think might be implementing the websocket, but its way more complicated than your example

I think the getRoute("socket.io") probably constructs the path to the folder from the current client URL. So for outside connection this should be v13.goblinism.uk/socket.io/
Yeah, that all looks good. But if the app never even tries to attempt a websocket connection, it stands to reason something else fails before then.
This is in the file foundry.mjs which is executed on the web client
You'd also have to disable automatic https redirects on Cloudflare to support WS.You said this earlier. Should I try this?
No.
In your above example (local), you see a request where the app loads
socket.io.min.js
That doesn't even happen in your online example
So the error is way before trying to establish a websocket connection
Oh sry, it is loade
missed it
If you try to manually establish a WS connection in the browser console, does that work?
socket = new Socket("wss://...) and so on?I get Uncaught ReferenceError: Socket is not defined
oops
new WebSocket
Its trying to go through CF Access as well might cause some problems?
What happens if you disable Access and try again?
But if you're already authenticated, the browser should usually send the required headers.
The WS isn't on a different domain than the app itself, is it?
Tried this to a few different versions.
Got NS_ERROR_WEBSOCKET_CONNECTION_REFUSED for wss://v13.goblinism.uk/ & wss://v13.goblinism.uk/socket.io/
Got "Uncaught DOMException: The operation is insecure." for ws:// connection

Sry, I gotta leave now. I'd recommend you try starting out with a more simple setup (no access) and try to see when it stops working.
You local test was to the direct IP - is the domain configured in the app itself?
You local test was to the direct IP - is the domain configured in the app itself?Yes to local IP, no domain configured in the app and no option to do this Thanks for your help
I have temporarily disabled Access for this site.
I also tried hosting the app internally on port 80 to see if this helped.
I can't see any difference on the network tab either in items or statuses.
The last item to get loaded before the ws call should appear is foundry.mjs, which makes sense as that is where the socket is created.
