Websocket handshake fails

FastAPI app Websocket handshake unsuccessful

char req[] =
    "GET /my-websocket-path/%s HTTP/1.1" "\x0D\x0A"
    "Upgrade: websocket"                "\x0D\x0A"
    "Connection: Upgrade"               "\x0D\x0A"
    "Host: %s"                          "\x0D\x0A"
    "Sec-WebSocket-Key: %s"             "\x0D\x0A"
    "Sec-WebSocket-Version: 13"         "\x0D\x0A"
    "%s%s";
===


Past SSL handshake I start the web socket handshake on the client end. See a FIN originating from the fly.io app end. Its a FastAPI/Uvicorn app on the fly.io end.

Works perfectly fine locally which leads me to believe:

  1. I am missing some header that the proxy expects
  2. Proxy sees something it does not like and rejects the connection immediately. I do not see the request being forwarded to the internal port in the logs.

I have a single app on 8080 (internal) and would at least expect the web socket accept response which I do see locally and on other deployments.

deployment toml is along the lines WebSockets and Fly · The Fly Blog

Any help getting a basic web socket working would be appreciated.
The service also sends streaming/non streaming responses on the non web socket paths defined in the app.

Hey @yobewakutan

Looking at the logs, I see the following messages emitted by the app:

2025-08-08 00:49:53,096 - WARNING - httptools_impl.py:184 - _should_upgrade_to_ws() ] No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually.

2025-08-08 00:49:53,095 - WARNING - httptools_impl.py:182 - _should_upgrade_to_ws() ] Unsupported upgrade request.

So it looks like the request made it to the app, but some of the required Python dependencies are missing in the Docker image.

Connecting this remark to Pavel’s observation, I wonder if you’re running this in Docker with an on-host volume, so your dev environment is not matching what you’re building and running remotely.

Thanks @pavel @halfer . So a missing dependency/ import would cause the service not to start at all. Health check and checking non a non streaming endpoint in revision 3 was yielding expected results. But I will rebuild the image and push as you suggest.

I wonder also whether you’re not using Docker locally at all. In which case you’ve got it running on your laptop, but your Dockerfile would not build locally and/or your websockets would not work locally in Docker. If you’re not using Docker locally, for dev and for testing, that is what I would change first.

Ah locally docker works fine and the image goes through and works on gcp. The first two revisions failed only because of a dependency which was resolved in revision 3.

yeah its definitely proxy terminating the connection at the gateway and the websocket request never makes it to the internal service.

O - server.py:219 - _log_started_message() ] Uvicorn running on ``http://0.0.0.0:8080`` (Press CTRL+C to quit)
2025-08-09T01:15:48Z app[XXXXXXXX] iad [info]returning env
2025-08-09T01:15:48Z app[XXXXXXXX] iad [info]2025-08-09 01:15:48,538 - INFO - 172.19.19.89:64148 - “GET /health HTTP/1.1” 200
2025-08-09T01:15:48Z health[XXXXXXXX] iad [info]Health check on port 8080 is now passing.

And only a series of successful health checks after that.

@yobewakutan

Do you have the Docker image that you are using pushed to a public registry, so I can launch the same image and play with it?

Alternatively, could you keep your app running so I can check it live?

I don’t see anything in the proxy logs, so it’s a bit hard to debug.

You can also try to add flyio-debug: doit header to the request, this should give us more info. But ideally, I’d like to be able to debug it while the app is running.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.