Can access https service via browser but not `cloudflared` (websocket: bad handshake)

Hi,

I have a protected https web application behind Cloudflare Access. It’s using cloudflared so the ports are not exposed.

Here’s the config file on the server:

tunnel: [id]
credentials-file: [file]

ingress:
  - hostname: [host]
    service: http://localhost:5000
  - service: http_status:404

It can be accessed via the web interface, it will redirect to OAuth and then the https site will show.

However, on the client side, when I tried to use cloudflared access tcp --hostname [hostname] --url localhost:51000 to access the application, it does try to authentication, after authentication, it shows this on the client side:

2022-02-05T13:01:01Z DBG Websocket request: GET / HTTP/1.1
Host: [host]
Cf-Access-Client-Id: [ID]
Cf-Access-Client-Secret: [Secret]

2022-02-05T13:01:01Z **ERR** failed to connect to origin error="websocket: bad handshake" originURL=[host]

The strangest part, is that on the server side, a response has been successfully made:

2022-02-05T13:22:22Z DBG CF-RAY: [Id]-[Region] GET [URL] HTTP/1.1

2022-02-05T13:22:22Z DBG Inbound request ...

2022-02-05T13:22:22Z DBG CF-RAY: [Id]-[Region] Request content length 0

2022-02-05T13:22:22Z DBG CF-RAY: [Id]-[Region]  Status: 200 OK served by ingress 0

2022-02-05T13:22:22Z DBG CF-RAY: [Id]-[Region]  Response Headers map[Accept-Ranges:[bytes] Content-Length:[2109] Content-Type:[text/html; charset=utf-8] Date:[Sat, 05 Feb 2022 13:22:22 GMT]]

2022-02-05T13:22:22Z DBG CF-RAY: [Id]-[Region] Response content length 2103

I have checked that web socket has been turned on. Also, the versions on client and server are the same.

Any input is greatly appreciated!

Is the port 5100 or 5000? You have both in your first post.

1 Like

The server’s HTTPS service is running on port 5000 (unexposed port).

The client is trying to use cloudflared to route the traffic through port 5100 (map it to localhost:5100). The client’s application uses the locally mapped 5100 port to access the https service.

Do you think if this might cause the issue?

If it’s a TCP service should you be using TCP vs HTTP in the ingress rule perhaps?

1 Like

Sorry for the confusion. It’s a https service.

Does it work opening a web browser and pointing it to the hostname on port 443 (assuming the origin is speaking https). Normally for simple http traffic there’s no need to run cloudflared on the client.

Yes! I think that’s the strangest part. :expressionless: It works if I access the URL (cname-ed to Argo domain address) it via the browser. It will open Cloudflare access login page and show the https service.

The reason we want to use cloudflared on server is because the service is internal only and we want to place it behind Cloudflare access.

And the reason why we use cloudflared on the client is because that particular device has no GUI.

Maybe start out with a simpler access example: cloudflared access curl <access-protected-domain
Does it work?

If not, does anything show up in the cloudflared tunnel logs when you try to access it?

Also, please see these troubleshooting steps: https://developers.cloudflare.com/cloudflare-one/faq/teams-troubleshooting/#cloudflared-access-shows-an-error-websocket-bad-handshake

1 Like

Thanks for the reply!

I tried to use cloudflared access curl, and the command outputs the source code for the https web page normally.

However, when I try to use cloudflared access tcp --hostname [hostname[ --url localhost:50000 and then use curl localhost:50000:

the cloudflared outputs:

2022-02-08T12:46:30Z INF Start Websocket listener host=localhost:50000
2022-02-08T12:46:41Z **ERR** failed to connect to origin error="websocket: bad handshake" originURL=https://[domain]

curl outputs:

* Trying 127.0.0.1:50000...
* Connected to localhost (127.0.0.1) port 50000 (#0)
> GET / HTTP/1.1
> Host: localhost:50000
> User-Agent: curl/7.77.0
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer

The server cloudflared log shows:

2022-02-08T13:01:30Z DBG CF-RAY:<reducted> GET / HTTP/2.0
2022-02-08T13:01:30Z DBG Inbound request CF-RAY=<reducted> Header="map[Accept-Encoding:[gzip] Cdn-Loop:[cloudflare] Cf-Access-Authenticated-User-Email:[email] Cf-Access-Jwt-Assertion:[<reducted>] Cf-Access-Token:[<reducted>] Cf-Connecting-Ip:[<reducted>] Cf-Ipcountry:[<reducted>] Cf-Ray:[<reducted>] Cf-Visitor:[{\"scheme\":\"https\"}] Cf-Warp-Tag-Id:[<reducted>] Sec-Websocket-Key:[reducted] Sec-Websocket-Version:[13] User-Agent:[Go-http-client/1.1] X-Forwarded-For:[<reducted>] X-Forwarded-Proto:[https]]" host=<reducted> path=/ rule=0
2022-02-08T13:01:30Z DBG CF-RAY: <reducted> Request Content length unknown
2022-02-08T13:01:30Z DBG CF-RAY: <reducted> Status: 200 OK served by ingress 0
2022-02-08T13:01:30Z DBG CF-RAY: <reducted> Response Headers map[Accept-Ranges:[bytes] Content-Length:[2109] Content-Type:[text/html; charset=utf-8] Date:[Tue, 08 Feb 2022 13:01:30 GMT]]
2022-02-08T13:01:30Z DBG CF-RAY: <reducted> Response content length 2109

For the troubleshooting guide:

  1. Checking if the server receives the request: YES
    The tunnel status page in dash.teams shows active; also, I used --loglevel debug and saw this in the cloudflared
    2022-02-08T12:53:10Z DBG CF-RAY: [id] Response content length 2209

  2. Checking if WebSockets is enabled: YES
    It is enabled by checking the dashboard.

  3. The site is using an advanced SSL; and the mode has been set to Full(Strict)

  4. I have checked the super bot fighting mode to all be set to Allow; and, the Security Level has been set to Essentially off; but still, the same output as above.

Please give me some advice on what to check next.

Thanks in advance!