0

The Problem

I recently posted a question trying to understand how to implement a Flask-SocketIO setup on an IIS webserver (I could only get it to work on my local development server). I was pointed in the direction of using IIS as a reverse proxy, rather than actually running the application directly on IIS.

I have since setup this structure and it's closer to working, but still not there yet. Forgive my ignorance, I'm not well versed in websockets nor webserver configuration and the like; but no amount of Googling seems to help.

Setup

  • Windows Server
  • IIS (Reverse Proxy) ["Websocket" Protocol has been installed and enabled]
  • Flask
  • Eventlet
  • Flask-SocketIO

Reverse Proxy Web Config

(Some values removed for security/privacy purposes).

HTTPS Redirect rewrite rule is disabled for now, while I'm trying to figure out what's going wrong.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTPS Redirect" enabled="false" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" />
                        <add input="{SERVER_PORT}" pattern="^80$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}:4440/{R:1}" appendQueryString="false" />
                </rule>
                <rule name="ReverseProxyInboundRule1" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <action type="Rewrite" url="http://127.0.0.1:4441/{R:1}" />
                    <serverVariables>
                        <set name="HTTP_X_FORWARDED_PORT" value="4440" />
                        <set name="HTTP_X_FORWARDED_HOST" value="subdomain.domain.co.uk" />
                        <set name="HTTP_X_FORWARDED_PROTO" value="https" />
                    </serverVariables>
                    <conditions>
                    </conditions>
                </rule>
            </rules>
            <outboundRules>
                <rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1" enabled="true">
                    <match filterByTags="A, Form, Img" pattern="(.*)://127.0.0.1:4441/(.*)" />
                    <action type="Rewrite" value="{C:1}://subdomain.domain.co.uk:4440/{R:2}" />
                </rule>
                <preConditions>
                    <preCondition name="ResponseIsHtml1">
                        <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
        <webSocket enabled="true" />
    </system.webServer>
    <location path="" overrideMode="Deny">
    </location>
</configuration>

Flask-SocketIO (Server-Side)

# Bottom of __init__.py
from werkzeug.middleware.proxy_fix import ProxyFix
from flask_socketio import SocketIO

socketio.init_app(app, logger=True, engineio_logger=True, cors_allowed_origins="https://subdomain.domain.co.uk:4440")

if not app.debug:
    app.wsgi_app = ProxyFix(app.wsgi_app, x_port=1, x_proto=1, x_host=1)

return app



# Bottom of app entry point file
from application import create_app, socketio

app = create_app()

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

Flask-SocketIO (Client-Side)

// NOTE: Socket.IO JS file has been properly included in the HTML template file

$(document).ready(function() {
    // Initialise SocketIO
    var socket = io('/<NAMESPACE>');

    // Join room
    socket.on('connect', function() {
        socket.emit('joined', {room: <ROOM_NAME>});
    });

    // Continued... (this is all that's really relevant for these purposes)
});

It all works fine on my development server, and I turned Flask-SocketIO logging on to try to get a better understanding of the situation. I noticed that after the Received request to upgrade to websocket message, there's another message that confirms the websocket connection was successful (I can't remember exactly what the message says, but it's to that effect). When I do the same via the IIS reverse proxy, I do not see that second message. Additionally, every so often, I get the following error message:

BrokenPipeError: [WinError 10058] A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call

Additionally, the browser (after attempting to upgrade to the websocket protocol) then sends thousands of GET requests in quick succession (presumably reverting to long-polling). This is seemingly never-ending.

If anyone has any suggestions as to how I might resolve this, I'd be greatly appreciative. I've been at this for about a week now and I'm just going round in circles at this point...

Thanks

lc-51
  • 99
  • 2
  • 7
  • What about remove IIS reverse proxy? Just request the server which host application. – Bruce Zhang Oct 15 '21 at 05:51
  • @BruceZhang How would this work in practice, though? Presumably the reverse proxy is required in order to expose the application outside the network with the appropriate configuration (SSL, HTTPS rewrites, etc.)? Do let me know if that's not the case. Thanks – lc-51 Oct 15 '21 at 09:37
  • It's ok to expose these outside the network in test environment. Just don't do this in production environment. – Bruce Zhang Oct 20 '21 at 02:24

0 Answers0