WebFaction
Community site: login faq

I have deployed a Flask application on Webfaction using mod_wsgi. My application is pretty simple but does implement Flask-SocketIO which is giving me troubles. My code works fine on my localhost but now that it is running on my Webfaction server the client is unable to connect to my socket. I'm not quite sure where my problems are coming from – I'm assuming I haven't set up my apache config file properly but this may not be true.

On the client side I receive a 400 (Bad Request) error on both GET & POST calls to the websocket. Intermittently I see a warning notifying me the socket closed before a connection was established. I also get an error occasionally stating that there was an error during WebSocket handshake.

My apache httpd.conf file is as follows:

ServerRoot "/home/< user >/webapps/< my_app >/apache2"

LoadModule authz_core_module modules/mod_authz_core.so
LoadModule dir_module        modules/mod_dir.so
LoadModule env_module        modules/mod_env.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module       modules/mod_mime.so
LoadModule rewrite_module    modules/mod_rewrite.so
LoadModule setenvif_module   modules/mod_setenvif.so
LoadModule wsgi_module       modules/mod_wsgi.so
LoadModule unixd_module      modules/mod_unixd.so

Listen 18161
KeepAlive On
SetEnvIf X-Forwarded-SSL on HTTPS=1
ServerLimit 1
StartServers 1
MaxRequestWorkers 5
MinSpareThreads 1
MaxSpareThreads 3
ThreadsPerChild 5

WSGIDaemonProcess < my_app > processes=2 threads=12 python-path=/home/< user >/webapps/< my_app >:/home/< user >/webapps/< my_app >/lib/python2.7
WSGIProcessGroup < my_app >
WSGIRestrictEmbedded On
WSGILazyInitialization On

WSGIScriptAlias / /home/< user >/webapps/< my_app >/wsgi.py

I've seen some posts about proxy_module & proxy_http_module but I'm not quite sure if I need that and if so how exactly to configure it. Any guidance on this issue would be much appreciated!

asked 23 Mar '16, 02:16

Matt Visco
25310
accept rate: 0%

Typically users who use websockets will use an open port in the firewall for websockets traffic instead of proxying that through Apache. That configuration is supported on our servers using a Custom Application (listening on port) for the websocket port -- that is, essentially the first model described here.

Are you able to run your websockets connection on a separate port?

(23 Mar '16, 03:50) ryans ♦♦

I figured I may have to use a custom application but I'm not quite sure how to run my websockets connection on a separate port.

Does this entail separating the flask app out and uploading the sockets application into a custom app running on a separate port? Is there any documentation on this process that I could follow?

(23 Mar '16, 04:01) Matt Visco

I'm not 100% sure as I haven't done exactly this before, but I thought it would just be creating the socket with some specific port that you've opened in the firewall; specifically:

var socket = new WebSocket('ws://localhost:12345');

where port 12345 would be opened via a Custom Application (listening on port). I don't think this would entail separating out anything at all.

(23 Mar '16, 04:04) ryans ♦♦

I'm sorry I'm a bit confused as I haven't done much backend work especially when it comes to web socket.

First question is that code suppose to be on the client side? I'm not using node so my websocket should be created through Flask_SocketIo via the call socketio.run(app) in my init file. This I believe uses the eventlet library to start the webserver.

I guess my question for you is what do I do with this custom app. I can make one and attach it to my domain, but I'm unsure how that ties everything together.

Thanks for working me through this!

(23 Mar '16, 04:15) Matt Visco

Right, my code snippet was javascript because that's socketIO (server-side), but Flask-SocketIO most certainly allows you to specify the URL as well. Either of these is a server-side library which produces client-side javascript, and that client-side connection specifies a URL which includes a port. An example is in the Flask-SocketIO documentation:

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
    var socket = io.connect('http://' + document.domain + ':' + location.port);
    socket.on('connect', function() {
        socket.emit('my event', {data: 'I\'m connected!'});
    });
</script>

basically, what you want is for the client-side Javascript to connect to some URL in the io.connect() function. You just generate that javascript to specify some port which you've opened in the firewall with a custom application (listening on port).

So, the client-side javascript would look something like:

io.connect('http://www.yourdomain.com:12345');

You do not need to do anything to "connect" the custom app or attach it to your domain. It simply exists to define that port as open in the firewall; your application (via Flask-SocketIO) binds to that port and accepts the incoming websockets connection.

None of this requires any Apache configuration (since the request doesn't come through Apache) nor does it require any configuration of the custom application in the WebFaction control panel -- you don't even need to make a website record for it. It can simply exist in your Applications list with "open port" activated, and it will serve its purpose from there.

On the server side, with Flask-SocketIO, your run() function defines the port to listen on. From the API Reference entry for run():

Parameters:
    host – The hostname or IP address for the server to listen on. Defaults to 127.0.0.1.
    port – The port number for the server to listen on. Defaults to 5000.

You don't want to bind to 127.0.0.1, because you want to accept incoming connections on an external interface, so set host to the server's open-ports IP assigned to the open port for the Custom Application (listening on port). That Custom Application also assigns a specific port to be opened in the firewall, which is what you would use for the port argument. Then, Flask-SocketIO will generate the appropriate javascript such that the client-side connection comes in on the port which it's listening to.

Hope that helps!

(23 Mar '16, 04:28) ryans ♦♦

Hey Ryan,

Thanks for your detailed instructions, it makes sense - unfortunately I am still running into issues.

I have created a Custom App (listening on port) and set the port to "open". I tried using both custom websocket app and custom app - neither seem to work for me.

In flask I run:

socketio.run(app, host='< open_port_IPs >', port=< custom_app_port >)

In javascript I run: socket = io.connect('< my_domain >:< custom_app_port >' +'/< namespace >');

I have tried replacing the domain with the open_port_IP, replacing the custom_app_port with the apache port, and removing the namespace.

The error I receive from this is net::ERR_CONNECTION_REFUSED

When I listen just on the domain i.e. socket = io.connect('< my_domain >'); I receive 400's again

Really unsure why this isn't working, if you need any further information let me know.

Thanks for the help!

(23 Mar '16, 20:03) Matt Visco
showing 5 of 6 show 1 more comments

That stuff about proxy_module and proxy_http_module is for using Apache as a front-end proxy for a back-end websockets app. It's not applicable to what you're trying to do.

mod_wsgi is not really suitable for serving websocket applications. Don't use it - instead, use one of the deployment options recommended in the Deployment section of the Flask-SocketIO docs.

For example, to use the first recommended option (ie, the embedded server), first install the eventlet module. I'm assuming you've already installed Flask and Flask-SocketIO at this point.

Next, install a 'custom websockets app listening on port' application via the control panel. Make a note of the app's assigned port, then assign the app to a website in the control panel. You do not need to open the app's port.

Next, configure your Flask-SocketIO app to run on the port assigned to your websockets app. The simplest way to do this is to pass the port to socketio.run, eg:

if __name__ == '__main__':
    socketio.run(app, port=12345)

In your javascript, connect like this:

var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);

Finally, just run the app:

python2.7 whatever.py

At that point, your app will be up and running on whatever domain you assigned to the website you set up a few steps back.

When you load the site, JS will sort out the connection info from document.domain and location.port. If you open up your browser's dev tools (Chrome inspector or whatever) you'll see the websockets connections being made to ws://yourdomain.com/ .

Hope that helps!

permanent link

answered 23 Mar '16, 22:20

seanf
12.2k41836
accept rate: 37%

edited 23 Mar '16, 22:27

Thank you so much - that finally did it!

(23 Mar '16, 23:06) Matt Visco

Quick question - slightly unrelated but could you reference me to the proper way to ensure that my python script is always running on my server - should I use a cron job or something else?

(23 Mar '16, 23:35) Matt Visco

Thanks! I've been at this for a bit now – I have successfully installed supervisord on my server and can access it from my domain but when I try to have it run my flask app it fails with:

Fatal: Exited too quickly

In my log it repeats the above error as well as has a couple of these:

(exit status 1; not expected)

In my supervisord.conf file I have the following:

[program:< app_name >]
command=python2.7 < app >.py
user=< user >

autostart=true autorestart=true directory=/home/< user >/webapps/< app_name >/ environment=PATH="/usr/bin"

I have tried the above configuration a few different ways, it always times out the same way. Any info on this would be much appreciated!

(24 Mar '16, 01:28) Matt Visco

This is what works for me:

[program:myapp]
command=python2.7 app.py
directory=/home/me/webapps/myapp
autostart=true
autorestart=true

If you've confirmed that you've followed the rest of the instructions in our Supervisor article correctly and this basic config still doesn't work for you, then feel free to open a support ticket so that we may take a closer look.

(24 Mar '16, 17:54) seanf

I just tested with the "Hello World" flask application and this works. When I switch it over to run with flask-socketio run call then it fails with the same error. The only thing changed in the file was the socketio stuff so presumably this is what is causing the error.

I'll go ahead and make a support ticket for this.

Another thing - when I was running the "Hello World" app on my server, I noticed that at my domain it shows the supervisor page with the running programs & their status's. I will need to alias the domain to my flask program itself. Is there a simple way to do this with supervisor or another service?

Thanks again for all your help!

(24 Mar '16, 18:35) Matt Visco

The problem I saw was that you had your supervisor app configured to listen on the port assigned to your websockets app. So, create a new 'custom app listening on port' application to get a different port for supervisor, and then set up a second site for that.

(25 Mar '16, 00:57) seanf
showing 5 of 7 show 2 more comments
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:

×225
×55
×44
×27

question asked: 23 Mar '16, 02:16

question was seen: 3,855 times

last updated: 25 Mar '16, 00:57

WEBFACTION
REACH US
SUPPORT
AFFILIATE PROGRAM
LEGAL
© COPYRIGHT 2003-2019 SWARMA LIMITED - WEBFACTION IS A SERVICE OF SWARMA LIMITED
REGISTERED IN ENGLAND AND WALES 5729350 - VAT REGISTRATION NUMBER 877397162
5TH FLOOR, THE OLD VINYL FACTORY, HAYES, UB3 1HA, UNITED KINGDOM