Django, uWSGI, Nginx on Freebsd

Srijan Choudhary Srijan Choudhary
- 2 min read
Tagged: devops

Here are the steps I took for configuring Django on Freebsd using uWSGI and Nginx.

The data flow is like this:

Web Request ---> Nginx ---> uWSGI ---> Django

I was undecided for a while on whether to choose uWSGI or gunicorn. There are some blog posts discussing the pros and cons of each. I chose uWSGI in the end.

Also, to start uWSGI in freebsd, I found two methods: using supervisord, or using a custom freebsd init script which could use uWSGI ini files. Currently using supervisord.

Install Packages Required

$ sudo pkg install python py27-virtualenv nginx uwsgi py27-supervisor

Also install any database package(s) required.

Setup your Django project

Choose a folder for setting up your Django project sources. /usr/local/www/myapp is suggested. Clone the sources to this folder, then setup the python virtual environment.

$ virtualenv venv
$ source venv/bin/activate
$ pip install -r requirements.txt

If required, also setup the database and run the migrations.

Setup uWSGI using supervisord

Setup the supervisord file at /usr/local/etc/supervisord.conf.

Sample supervisord.conf:

[unix_http_server]
file=/var/run/supervisor/supervisor.sock   

[supervisord]
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB       ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10          ; (num of main logfile rotation backups;default 10)
loglevel=info               ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisor/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false              ; (start in foreground if true;default false)
minfds=1024                 ; (min. avail startup file descriptors;default 1024)
minprocs=200                ; (min. avail process descriptors;default 200)

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock
history_file=~/.sc_history  ; use readline history if available

[program:uwsgi_myapp]
directory=/usr/local/www/myapp/
command=/usr/local/bin/uwsgi -s /var/run/%(program_name)s%(process_num)d.sock
        --chmod-socket=666 --need-app --disable-logging --home=venv
        --wsgi-file wsgi.py --processes 1 --threads 10
stdout_logfile="syslog"
stderr_logfile="syslog"
startsecs=10
stopsignal=QUIT
stopasgroup=true
killasgroup=true
process_name=%(program_name)s%(process_num)d
numprocs=5

supervisord.conf

And start it:

$ echo supervisord_enable="YES" >> /etc/rc.conf
$ sudo service supervisord start
$ sudo supervisorctl tail -f uwsgi_myapp:uwsgi_myapp0

Setup Nginx

Use the following line in nginx.conf's http section to include all config files from conf.d folder.

include /usr/local/etc/nginx/conf.d/*.conf;

Create a myapp.conf in conf.d.

Sample myapp.conf:

upstream myapp {
    least_conn;
    server unix:///var/run/uwsgi_myapp0.sock;
    server unix:///var/run/uwsgi_myapp1.sock;
    server unix:///var/run/uwsgi_myapp2.sock;
    server unix:///var/run/uwsgi_myapp3.sock;
    server unix:///var/run/uwsgi_myapp4.sock;
}

server {
    listen       80;
    server_name  myapp.example.com;
 
    location /static {
        alias /usr/local/www/myapp/static;
    }

    location / {
        uwsgi_pass  myapp;
        include uwsgi_params;
    }
}

myapp.conf

And start Nginx:

$ echo nginx_enable="YES" >> /etc/rc.conf
$ sudo service nginx start
$ sudo tail -f /var/log/nginx-error.log

Accessing http://myapp.example.com/ should work correctly after this. If not, see the supervisord and Nginx logs opened and correct the errors.

Interactions

  • Brood
    Brood

    Ideas why nginx gives a Bad Gatway 502 error ? Log say Connection refused) while connecting to upstream

    Ideas what can be wrong?

    Reply
  • Yan
    Yan

    I think the supervisord config script you posted runs the uwsgi instance as root, which is presumably a bad idea.

    Reply
    • Yan
      Yan

      After a bit of tracking down, the best way to run as another user is to create a subdirectory in /var/run, owned by the appropriate user, and store the sockets in there.

      E.g. if you want to use user www:www (id 80:80), do:

      # mkdir /var/run/uwsgi
      # chown www:www /var/run/uwsgi

      Then in supervisord.conf have:

      command=/usr/local/bin/uwsgi -s /var/run/uwsgi/%(program_name)s%(process_num)d.sock --uid 80 --gid 80

      and in nginx.conf:

      server unix:///var/run/uwsgi/uwsgi_myapp0.sock;

      You might want to update the example to show this?

      Reply
    • Srijan Choudhary

      Makes sense. I'll test and update it.

      Thanks.

      Reply