I am trying to deploy gunicorn + gevent behind nginx (v 1.3.14) on dotcloud. I have a few questions about it. I am aiming to adapt the python-on-dotcloud example. So far, I have not been able to get the websockets portion working with this setup. In other words, I must refresh my pages manually to get updates, rather than via socket.io. This is all pretty new to me, so it may be a total noob error. Here is a related question.
Here are the changes that I made to the python-on-dotcloud example.
Apparently nginx (since version 1.3.13) supports web sockets. I updated the builder script from the python-on-dotcloud example to point to this development version:
nginx_download_url="http://nginx.org/download/nginx-1.3.14.tar.gz"
I set up gunicorn to bind to a unix socket and then set up proxy_pass from nginx.conf to send traffic upstream to the gunicorn with
proxy_pass http://appserver;
where I have defined appserver.I am running a django app with gevent-socket.io that works fine without nginx running. (I just bind gunicorn to 0.0.0.0:$PORT_WWW in the dotcloud.yml)
my questions are these.
Am I trying to solve a non-problem?
a. I've done a fair amount of reading where it's advised to put gunicorn behind nginx. In the context of dotcloud's load balancers on the front line, is this still true?
b. If I don't expect that I'll be subject to a DoS attack, is it still important to put gunicorn behind nginx?
Is it possible to run websockets through a unix socket as I have attempted to setup?
Will the unix sockets break scaling on dotcloud?
If I need to use ports instead, how do set that up? I don't think I can allocate two http ports in the same app. If I split it into two apps, then I'm not sure how to pass the PORT_WWW environment variable from the gunicorn app into the nginx app so that it ends up available to the nginx postinstall script and thus in the resulting nginx.conf.
Any ideas as to why this isn't working as is?
I've included three config files below. Let me know if others would help. Thanks!
dotcloud.yml
www:
type: custom
buildscript: python/builder
systempackages:
# needed for the Nginx rewrite module
- libpcre3-dev
# needed to support python versions 2.7, 3.1, 3.2.
- python3-all
ports:
www: http
processes:
nginx: nginx
app: /home/dotcloud/env/bin/gunicorn -c /home/dotcloud/gunicorn.conf -b unix:/tmp/gunicorn.sock wsgi:application
#app: /home/dotcloud/env/bin/gunicorn -c /home/dotcloud/gunicorn.conf -b 0.0.0.0:$PORT_WWW wsgi:application
config:
# python_version can have one of the following values (2.6, 2.7, 3.1, 3.2). 2.6 is the default if no value is entered.
python_version: 2.7
data:
type: redis
db:
type: postgresql
nginx.conf.in (same as regular nginx.conf, only with PORT_WWW waiting to get swapped for real port number)
# template for nginx.conf file.
# the file will be processed by the postinstall script
# it will insert the correct value for PORT_WWW and then put this
# file in /home/dotcloud/nginx/conf/nginx.conf when done.
# nginx will be managed by supervisord when it starts so we don't need daemon mode
daemon off;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
log_format combined-realip '$remote_addr ($http_x_real_ip) - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';
access_log /var/log/supervisor/nginx_access.log combined-realip;
error_log /var/log/supervisor/nginx_error.log error;
gzip on;
upstream appserver {
server unix:/tmp/gunicorn.sock;
# For a TCP configuration:
# server 192.168.0.7:8000 fail_timeout=0;
}
server {
# PORT_WWW value is added via postinstall script.
listen @PORT_WWW@ default;
server_name localhost;
root /home/dotcloud/current/;
location / {
if ( -f /home/dotcloud/current/maintenance) {
return 503;
}
proxy_pass http://appserver;
proxy_http_version 1.1;
proxy_set_header upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 404 @404;
error_page 500 @500;
error_page 502 @502;
error_page 503 @503;
error_page 504 @504;
location @404 {
rewrite ^ /static/404.html;
}
location @500 {
rewrite ^ /static/500.html;
}
location @502 {
rewrite ^ /static/502.html;
}
location @503 {
rewrite ^ /static/503.html;
}
location @504 {
rewrite ^ /static/504.html;
}
location /static {
alias /home/dotcloud/current/static;
}
location /robots.txt {
alias /home/dotcloud/current/static/robots.txt;
}
location /favicon.ico {
alias /home/dotcloud/current/static/favicon.ico;
}
}
}
gunicorn.conf
workers = 1
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
pidfile = '/tmp/gunicorn.pid'
debug = True
loglevel = 'debug'
errorlog = '/var/log/supervisor/gunicorn.log'
django_settings='/home/dotcloud/settings.py'
def post_fork(server, worker):
from psycogreen.gevent import patch_psycopg
patch_psycopg()
# MySQL
#def post_fork(server, worker):
# import pymysql
# pymysql.install_as_MySQLdb()
proxy_buffering off;
in yourlocation
block? Or else, if you resolved the issue, please post your answer for other users to use. – Subtilize