Today I wanted to set up Gunicorn, a powerful webserver that will eventually run my Django application. It was not a straightforward process, so I decided to document it for my fellow geeks.
Preamble
This procedure assumes that you've already set up the following:- installed Python 3 (I tested with 3.4.1)
- created a custom
myuser
account and logged on as such - created a virtualenv with
pyvenv /home/myuser
- installed Django in the above-mentioned virtualenv
- created a Django project at
/home/myuser/myproject
Let's go!
- activate the virtualenv:
source bin/activate
- install Gunicorn:
pip install gunicorn
- create
/home/myuser/gunicorn_config.py
with the following contents:command = '/home/myuser/bin/gunicorn' pythonpath = '/home/myuser/myproject' chdir = '/home/myuser' pidfile = '/home/myuser/.gunicorn_myproject.pid' user = 'nobody' worker_tmp_dir = '/tmp' errorlog = '/var/log/gunicorn_myproject' # tweak the following lines to suit your setup bind = 'localhost:8001' workers = 4
You can add any further option as necessary, but it's important you keeppidfile
anduser
. sudo
to root (I'd recommend to do that from another account, i.e. don't addmyuser
towheel
) and create/etc/rc.d/gunicorn_myproject
with the following contents:#!/bin/sh daemon="/home/myuser/bin/python" daemon_flags="/home/myuser/bin/gunicorn -c /home/myuser/gunicorn_config.py -D myproject.wsgi" rc_stop() { kill `cat /home/myuser/.gunicorn_myproject.pid` } . /etc/rc.d/rc.subr rc_cmd $1
Note how we are specifyingdaemon
to be the python executable. This is the only way I've found to keep the rest of the machinery inrc.subr
working smoothly.chmod 555 /etc/rc.d/gunicorn_myproject
- now you can start and stop Gunicorn with standard OpenBSD 5.x commands:
/etc/rc.d/gunicorn_myproject start
- Typically, you'd then set nginx to proxy and cache requests, and firewall gunicorn from the outside.
root
and then spawns processes as nobody
; if I were to start it as myuser
, it would not work. This is because gunicorn tries to change ownership of files and processes after startup, and OpenBSD doesn't seem to like it. This looks suboptimal to me, but I couldn't find a workaround.Note also how we're writing the main process PID to file, and then using it to stop that same main process. Standard
rc.subr
machinery would expect me to specify a regex in the pexp
variable, which would then be passed to pgrep
to find the process; but this doesn't work with gunicorn because pgrep simply cannot distinguish between master and worker processes, since they appear to have the exact same command line.If you know anything else I should do to further secure this setup, please let me know in comments!