jrief / django-websocket-redis

Websockets for Django applications using Redis as message queue
http://django-websocket-redis.awesto.com/
MIT License
895 stars 221 forks source link

Configuration issue with Apache #119

Open azmeuk opened 8 years ago

azmeuk commented 8 years ago

Hi, I would like to use ws4redis on Ubuntu 14.04 with Apache 2.4.7. The version of uwsgi for Ubuntu 14.04 is 2.0.6, but do not seem to be compiled with websockets support, so I installed the version 2.0.11.2 with pip. I also edited /etc/init.d/uwsgi so it launches the pip version.

I just want to load a Hello world websocket page, and see the message in the browser console.

import uwsgi
def application(env, start_response):
    uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
    uwsgi.websocket_send("Hello world")
    while True:
        msg = uwsgi.websocket_recv()
        uwsgi.websocket_send(msg)

foobar/views.py

def index(request):
    pub = RedisPublisher(facility="hello", broadcast=True)
    pub.publish_message(RedisMessage("Hello world"))
    ....

foobar/static/foobar.js

$(function() {
    ws4redis = WS4Redis({
        uri: WEBSOCKET_URI + 'hello?subscribe-broadcast&echo',
        receive_message: wsReceive,
        heartbeat_msg: WEBSOCKET_HEARTBEAT
    });
});

The symptoms I get are:

ERROR    2015-11-06 10:18:53,433 31152    wsgi_server:122  Other Exception: 'HTTP_SEC_WEBSOCKET_KEY'
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/ws4redis/wsgi_server.py", line 81, in __call__
    websocket = self.upgrade_websocket(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/ws4redis/uwsgi_runserver.py", line 52, in upgrade_websocket
    uwsgi.websocket_handshake(environ['HTTP_SEC_WEBSOCKET_KEY'], environ.get('HTTP_ORIGIN', ''))
KeyError: 'HTTP_SEC_WEBSOCKET_KEY'

/etc/apache2/sites-enabled/foobar.com.conf

<VirtualHost _default_:443>
    <IfModule mod_proxy_wstunnel.c>
        ProxyPass        /ws/   ws://127.0.0.1:3032/
        ProxyPassReverse /ws/   ws://127.0.0.1:3032/
    </IfModule>

    <IfModule mod_proxy_uwsgi.c>
        ProxyPass        /static !
        ProxyPass        /media  !
        ProxyPass        /       uwsgi://127.0.0.1:3031/
    </IfModule>
</VirtualHost>

/etc/uwsgi/apps-enabled/websockets.ini

[uwsgi]

chdir           = /path/to/foobar
module          = foobar.wsgi_websockets:application

master          = true
processes       = 2
socket          = /path/to/foobar/websockets.socket
http-socket     = 127.0.0.1:3032
chmod-socket    = 666
vacuum          = true
env             = DJANGO_SETTINGS_MODULE=foobar.settings
env             = DJANGO_STATIC_ROOT=/path/to/foobar/static

gevent          = 1000
http-websockets = true
jrief commented 8 years ago

Actually, I never used Apache with uwsgi. I got these configurations from an other contributor who was able to get ws4redis running under Apache. Just for narrowing down the errors: can you please try to run it behind nginx. Then at least we can say if the culprit it Apache or uwsgi.

azmeuk commented 8 years ago

I just tested, this very configuration works well with nginx. In my django logs I also have a key error when trying to access the /ws url directly with the browser.

ERROR    2015-11-06 10:18:53,433 31152    wsgi_server:122  Other Exception: 'HTTP_SEC_WEBSOCKET_KEY'
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/ws4redis/wsgi_server.py", line 81, in __call__
    websocket = self.upgrade_websocket(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/ws4redis/uwsgi_runserver.py", line 52, in upgrade_websocket
    uwsgi.websocket_handshake(environ['HTTP_SEC_WEBSOCKET_KEY'], environ.get('HTTP_ORIGIN', ''))
KeyError: 'HTTP_SEC_WEBSOCKET_KEY'

Maybe environ.get('HTTP_SEC_WEBSOCKET_KEY', '') would be safer?

martinka commented 8 years ago

The only difference I see in your wsgi configuration vs mine has: enable-threads=True plugin=python,gevent

Your apache config looks fine.

One thing to be aware of with Apache 2.4 is it will use 1 thread per websocket. this is addressed in mod_proxy for 2.5 but could limit your scaling.

dlareau commented 8 years ago

I seem to be in a similar spot, so any help would be appreciated. I had the whole setup working under nginx, and I'm currently attempting to switch to apache for better compatibility with my groups authentication code. I have the standard django webapp working with apache (mod_proxy_uwsgi) and uswgi. I cannot seem to get the websockets working though. I've tried a few different configurations on both the apache side and the uwsgi side, and everything either doesn't connect or leaves me, like above, saying it connected, but unable to send messages to the web browser. I can provide my setup details if it would help, but it is very similar to the setup above.

martinka commented 8 years ago

Please let me know the configuration you are running. Also which version of Apache. And which version of mod_proxy_ws.

Sent from my iPhone

On Dec 28, 2015, at 12:30 PM, Dillon Lareau notifications@github.com wrote:

I seem to be in a similar spot, so any help would be appreciated. I had the whole setup working under nginx, and I'm currently attempting to switch to apache for better compatibility with my groups authentication code. I have the standard django webapp working with apache (mod_proxy_uwsgi) and uswgi. I cannot seem to get the websockets working though. I've tried a few different configurations on both the apache side and the uwsgi side, and everything either doesn't connect or leaves me, like above, saying it connected, but unable to send messages to the web browser. I can provide my setup details if it would help, but it is very similar to the setup above.

— Reply to this email directly or view it on GitHub.

dlareau commented 8 years ago

Apache: 2.4.10 (Debian) I am using mod_proxy_wstunnel, but honestly after a bit of searching I have no idea how to find the version as it came with apache. It is whatever would come with the current debian apache fresh install.

uwsgi config: (based on the above config)

[uwsgi]
chdir           = /home/hunt/puzzlehunt_server
env             = DJANGO_SETTINGS_MODULE=puzzlehunt_server.settings
module          = wsgi_websocket
gevent          = 1000
master          = true
processes       = 2
http-websockets = true
socket          = /home/hunt/puzzlehunt_server/websockets.socket
http-socket     = 127.0.0.1:3032
chmod-socket    = 666
vacuum          = true

uwsgi config: (based on the config mentioned in the ws4redis docs)

[uwsgi]
chdir           = /home/hunt/puzzlehunt_server
env             = DJANGO_SETTINGS_MODULE=puzzlehunt_server.settings
module          = wsgi_websocket
gevent      = 1000
master          = true
workers         = 4
http-websockets = true
http-socket     = 127.0.0.1:3032

apache config:

<VirtualHost *:80>
    DocumentRoot /var/www/html

    Alias /static /home/hunt/puzzlehunt_server/static
    <Directory /home/hunt/puzzlehunt_server/static>
        Require all granted
    </Directory>

    ProxyPass /static/ !
    ProxyPass        /ws/   ws://127.0.0.1:3032/
    ProxyPassReverse /ws/   ws://127.0.0.1:3032/
    ProxyPass / uwsgi://127.0.0.1:9090/
    ProxyPassReverse / uwsgi://127.0.0.1:9090/
</VirtualHost>

I will say, I'm not the most experienced with this sort setup, I've taken the configuration from where I can find it. Both the configurations of uwsgi above, one from the ws4redis docs, the other from this post, get me the same result where the browser says that it connects but I can't send messages to the browser.

dlareau commented 8 years ago

Actually looking at it now, I'm pretty sure there are a few extraneous lines in the first uwsgi in the first config, and they are actually the same config. Still doesn't change the fact that I can't get this working at the moment.

nanuxbe commented 8 years ago

@flybye22 last time I configured apache to run with websockets, the biigest difference with your config file were those 2 lines

ProxyPass        /ws/   ws://127.0.0.1:3032/ws/
ProxyPassReverse /ws/   ws://127.0.0.1:3032/ws/

Also workers=4 in your uwsgi config will get you started but apache needs more workers than nginx and you probably want to add some mores.

jrief commented 8 years ago

@flybye22 What is ProxyPassReverse for? This directive is used by Apache to rewrite upstream 301/302 redirect responses, using the externally visible URL. This is completely useless with websockets (although it doesn't harm), but adds a useless layer of complexity to the site administrator.

dlareau commented 8 years ago

@nanuxbe Thank you so much! That worked! Also thanks for the tip about the workers.

dlareau commented 8 years ago

@jrief Like I said in an above comment, I'm not the most experienced with these mod-proxy setups (it's only the second time I've had a setup like this), so I was just following what was given to me, and in the ws4redis documentation (link) it has the ProxyPass and the ProxyPassReverse.

However, I just tried it and you are right, it isn't needed for this setup and works fine without it.

martinka commented 8 years ago

I tested this as well. While the orignal config works for me.. the new one does to. Also the ProxyPassReverse is extrainious. Sorry for the confusion.

On Tue, Dec 29, 2015 at 1:29 PM, Dillon Lareau notifications@github.com wrote:

@jrief https://github.com/jrief Like I said in an above comment, I'm not the most experienced with these mod-proxy setups (it's only the second time I've had a setup like this), so I was just following what was given to me, and in the ws4redis documentation (link) http://django-websocket-redis.readthedocs.org/en/latest/running.html#django-with-websockets-for-redis-behind-apache-2-4-using-uwsgi it has the ProxyPass and the ProxyPassReverse.

However I just tried it and you are right, it isn't needed for this setup, and works fine without it.

— Reply to this email directly or view it on GitHub https://github.com/jrief/django-websocket-redis/issues/119#issuecomment-167788825 .

qxang commented 5 years ago

I followed the document and found that the facility always return the "//foobar" and didn't work. And "ProxyPass /ws/ ws://127.0.0.1:3032/ws/" worked and @nanuxbe thank you very much.