Django, uWSGI, Nginx on Freebsd
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
Ideas why nginx gives a Bad Gatway 502 error ? Log say Connection refused) while connecting to upstream
Ideas what can be wrong?
Check if the supervisor service is running, and if your uwsgi program is running correctly. You can check the uwsgi error log as well.
I think the supervisord config script you posted runs the uwsgi instance as root, which is presumably a bad idea.
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
(id80:80
), do:Then in
supervisord.conf
have:and in
nginx.conf
:You might want to update the example to show this?
Makes sense. I'll test and update it.
Thanks.