1

The Technology

  • Flask (Python)
  • Flask-Socket.IO (using eventlet)
  • WFastCGI
  • IIS (Windows)

The Problem

I'm experiencing issues with Flask-Socket.IO whilst running on an IIS Web Server. I'm new to WebSockets so I'm well aware that I'm probably just doing something wrong - most likely something obvious.

A Bit of Background

I've managed to successfully implement Flask-Socket.IO on my development server, and it works flawlessly every time (even running locally on the same machine as the production server). However, when I try to run it on the IIS Web Server, I just can't get it to work at all. The rest of the app runs perfectly fine, but any parts that make use of Socket.IO result in repeated calls to the WebSocket with the following error:

WebSocket connection to '<URL>' failed: WebSocket is closed before the connection is established.

...amongst a bunch of failed POST and GET requests to: <DOMAIN:PORT>/socket.io/?EIO=4&transport=polling&t=...&sid=...

What I've Tried (to no avail):

  1. Installing WebSocket Protocol for IIS (tried setting enabled to both true and false)
  2. Initialising Socket.IO with: socketio.init_app(app, cors_allowed_origins="*") (just for testing, to see if it resolved the issue) [spoiler: it didn't]
  3. Uninstalling eventlet and installing gevent instead
  4. Reading everything there is to read online
  5. Staring into the abyss of late-night confusion and wondering why I do this to myself.

The Everlasting Frustration

As you can probably tell, I'd quite like to get this one resolved now so I can move onto the next thing that invariably won't work :)

Does anybody have any suggestions? They would be much appreciated.

Thanks

lc-51
  • 99
  • 2
  • 7
  • WebSocket is not part of the WSGI standard. To use WebSocket Flask-SocketIO has support for a few web servers and their particular implementation of WebSocket. IIS is not in the supported list, and besides, my understanding is that FastCGI doesn't even support WebSocket, so there is really no viable way to make it work unless you remove FastCGI, and replace it with one of the supported web servers (eventlet, gevent, gunicorn or uWSGI). You can then add IIS as a reverse proxy in front of the server of choice. – Miguel Grinberg Oct 10 '21 at 22:30
  • @Miguel Thanks for your response, that all makes a lot more sense now. I'll give it a go today. I think there was some confusion as to the relationship between IIS, FastCGI and eventlet. So I gather that in using IIS as the web server, I was essentially bypassing eventlet altogether (hence Flask-SocketIO not working). Is that correct? Using IIS as a reverse proxy seems like a perfectly reasonable solution. Cheers! – lc-51 Oct 11 '21 at 14:12
  • I have the same problem. can you add an answer? – Ali Mar 28 '23 at 09:13
  • 1
    @Ali, this was a while ago but as far as I remember, Miguel's comment was the key to this. If I recall correctly, I ended up dropping IIS altogether and using Nginx as a reverse proxy. This was a lot more straightforward as it's a fairly commonplace configuration, so there are plenty of resources online to help get it up and running. [This](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) should point you in the right direction. – lc-51 Mar 29 '23 at 11:16

1 Answers1

0

how to deploy your flask webSocket app on IIS:

  1. code

app.py

from flask import Flask
from flask_socketio import SocketIO, emit, send

app = Flask(__name__)
socketio = SocketIO(app)

if __name__ == "__main__":
    socketio.run(app, host="127.0.0.1", port=8000, debug=True)

@socketio.on('message')
def handle_message(data):
    result = int(data, base=16) * 2 + 23
    send(str(hex(result)) + ' to you')

it's a simple code for running a websocket that takes a hex number, does some math on it, and returns it as a string.

ws_Handler.py

from gevent import monkey
monkey.patch_all()

from app import app
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer

http_server = WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
if __name__ == '__main__':

    http_server.serve_forever()

It's a handler that serves the app.py with gevent.

  1. IIS
  • download URL rewrite from here and install it on your windows server
  • download request router from here and install it on your windows server
  • restart IIS
  • select your site from sites list in IIS, select URL rewrite, in the action menu select add rule, select reverse proxy, and add your localhost address then select OK
  1. run code

run ws_Handler.py on your localhost, for this just run this command on the terminal:

python ws_Handler.py

now your gevent server is running and you'll see this output on the terminal :

Server initialized for event.

now you can use your server with bonded domain on IIS.

starball
  • 20,030
  • 7
  • 43
  • 238
Ali
  • 376
  • 5
  • 16