Why?
Because we wanted to achive the following while developing a webapp using websockets:
Static serving (nginx), Django application (gunicorn) and Websockets service (twisted)
-
on the same IP
because small vhosts come with one address only.
-
on the same Port 80
to support companies which are allowing connections to common ports only.
Who?
This setup was mostly created by @frog32 and the guide was written by @sspross. It was developed while working at allink. Warning: This setup is not battle tested and may or may not work for you.
This demo application by @frog32 is using this setup, but is still under havy development.
How?
-
Our project structure looks like this:
/home/www-data/YOUR-PROJECT/dj/
<- Django Project/home/www-data/YOUR-PROJECT/tx/
<- Twisted Project
-
Installed packages:
apt-get install csstidy yui-compressor libpng12-dev libjpeg-dev zlib1g-dev python-virtualenv python-setuptools libxml2-dev git gettext python-dev libssl-dev mercurial libmysqlclient-dev redis-server rabbitmq-server mysql-server haproxy supervisor nginx node-less
-
Python packages (e.g.
REQUIREMENTS_SERVER
):hiredis redis django-redis-cache gunicorn
-
Add to your
settings.py
config:USE_X_FORWARDED_HOST = True
-
Provide URL in
urls.py
for HAproxy to enable monitoring:url(r'^isrunning$', lambda r: HttpResponse('OK')),
-
Config HAproxy
/etc/haproxy/haproxy.cfg
, e.g. this. -
Enable HAproxy, set
ENABLED=1
in/etc/default/haproxy
(and maybe in/etc/init.d/haproxy
) and start it withsudo /etc/init.d/haproxy start
. You should see the following if it's really running:* Starting haproxy haproxy ...done.
-
If your firewall is active, open port for HAproxy stats
sudo ufw allow 1936
-
Now you can access HAproxy stats over
http://YOUR.IP:1936/
and gunicorn should be up and working.
- There has to be a
wsgi.py
file in/home/www-data/YOUR-PROJECT/dj/
, e.g. this. - Create supervisor configuration for gunicorn
/etc/supervisor/conf.d/YOUR_PROJECT_gunicorn.conf
, e.g. this. - Don't forget to create a
logs
directory as configured in the gunicorn config. - Update supervisor
sudo supervisorctl
runupdate
(to restart webserver userestart YOUR_PROJECT_gunicorn
)
- Unlink default site
sudo unlink /etc/nginx/sites-enabled/default
- Create an enabled site configuration
/etc/nginx/sites-enabled/YOUR-DOMAIN.ch
, e.g. this. - Don't forget to create a
isrunning
file like configured e.g.touch /home/www-data/YOUR-PROJECT/dj/isrunning
for HAproxy Ping. - Restart nginx
sudo /etc/init.d/nginx restart
- Now check HAproxy stats if nginx is pingable and up running
http://YOUR.IP:1936/
-
Create an additional virtualenv for your Twisted app in
/home/www-data/YOUR-PROJECT/tx/
withvirtualenv --setuptools env
-
Install python packages:
txsockjs pyopenssl twisted
-
Create another supervisor configuration for twisted
/etc/supervisor/conf.d/YOUR_PROJECT_twisted.conf
, e.g. this. -
Update supervisor
sudo supervisorctl
runupdate
(to restart twisted userestart YOUR_PROJECT_twisted
) -
Now both (gunicorn and twisted) should be running:
supervisor> status YOUR_PROJECT_gunicorn RUNNING pid 11194, uptime 0:03:34 YOUR_PROJECT_twisted RUNNING pid 11231, uptime 0:01:57
-
And everything should be green on the HAproxy status page
http://YOUR.IP:1936/
.
-
Add to your
settings.py
file:# broker and celery BROKER_URL = 'amqp://YOUR_PROJECT:YOUR_PROJECT@localhost:5672/YOUR_PROJECT' CELERY_RESULT_BACKEND = "redis://localhost/0" CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" CELERYD_CONCURRENCY = 1 CELERY_SEND_EVENTS = False CELERY_ENABLE_UTC = True import djcelery djcelery.setup_loader()
-
Create rabbitmq user and vhost:
sudo rabbitmqctl add_user YOUR_PROJECT YOUR_PROJECT sudo rabbitmqctl add_vhost YOUR_PROJECT sudo rabbitmqctl set_permissions -p YOUR_PROJECT YOUR_PROJECT ".*" ".*" ".*"
-
Create another supervisor configuration for celery
/etc/supervisor/conf.d/YOUR_PROJECT_celery.conf
, e.g. this. -
Update supervisor
sudo supervisorctl
runupdate
(to restart celery userestart YOUR_PROJECT_celery
) -
Now all three (gunicorn, twisted and celery) should be running:
supervisor> status YOUR_PROJECT_celery RUNNING pid 12281, uptime 0:00:13 YOUR_PROJECT_gunicorn RUNNING pid 11194, uptime 1:18:23 YOUR_PROJECT_twisted RUNNING pid 11231, uptime 1:16:46
looks fine