Cherokee: first impression

I’ve been using Apache for many years now, thus recently I’ve made a decision to try some of the “new” web servers. One of my hosts runs lighttpd for quite some time without any problems, so this time I wanted to try something else. Cherokee has caught my attention, thanks to it’s web-based configuration utility – it is intuitive enough to go without reading the documentation really.
Indeed, configuring my site has taken about 15 minutes – HTTP to HTTPS redirection, WSGI application, PHP5 – all up and running. But… I’ve noticed that HTTP to HTTPS redirection fails occasionally for no obvious reason. It quickly turned out that the server’s worker process dies of segmentation fault. Source code investigation led to a quick patch and an issue reported. Not really a perfect first impression, huh? Time to try nginx, I guess… 😉


Django deployment, FastCGI and UNIX-domain sockets

For various (mostly security) reasons I prefer to deploy Django applications as separate processes, with web server and actual application running under different UIDs, communicating with each other via FastCGI or SCGI socket. This way application is safer from e.g. vulnerable PHP scripts running within the web server process – it’s pretty common for the attackers to use PHP vulnerabilities to read files accessible by the web server itself (for smaller sites it’s normal to use a single web server installation for many different applications).

For security reasons I also prefer to use UNIX-domain sockets over TCP sockets (only if web server and the application are deployed on the same machine, obviously). With TCP sockets in use, any process may connect to the FastCGI/SCGI socket and effectively bypass the web server running in front of the application. What if e.g. the web server itself is used to perform user authentication and authorization? With UNIX-domain sockets one can protect the application by means of regular UNIX permission mode.

Such deployment model is perfectly feasible with Django, as it uses flup internally for a WSGI to SCGI/FastCGI bridge, deployment procedure is described in the Django documentation. Following the manual, application process can be started e.g. with the following command line (note that I do not daemonize the application, as I prefer to use e.g. daemontools to supervise the application process):

./ runfcgi protocol=scgi socket=~/django/testapp.sock daemonize=false

Unfortunately, the socket gets created with permission mode that do not allow any user other than the application process owner to write to the socket:

czajnik@lapsko:~/django$ ls -l testapp.sock 
srwxr-xr-x 1 czajnik czajnik 0 2010-08-29 20:49 testapp.sock

Obviously, this is not the way to go – web server will not be able to write to such a socket. One way to overcome the problem is to manually change the permissions mode and/or the uid/gid of the socket after the application is started, but this is far from perfect.

Digging in the source code I’ve realized that the flup module itself allows for specifying the umask value used while creating the socket, but this possibility is not used by Django. I’ve modified the code to pass 0 as socket creation umask, effectively making the socket accessible for every process:

diff -ruN Django-1.2.1.orig/django/core/servers/ Django-1.2.1/django/core/servers/
--- Django-1.2.1.orig/django/core/servers/	2010-08-29 21:00:37.000000000 +0200
+++ Django-1.2.1/django/core/servers/	2010-08-29 21:06:32.000000000 +0200
@@ -177,6 +177,7 @@
         fp.write("%d\n" % os.getpid())
+    wsgi_opts['umask'] = 0 
     WSGIServer(WSGIHandler(), **wsgi_opts).run()
 if __name__ == '__main__':

To control the accessibility I place the socket alone inside a designated directory and use directory permission mode to control who can access the socket. In my particular case the web server runs under www-data user/group. Directory where SCGI socket is created has the following permission mode:

czajnik@lapsko:~/django$ ls -ld socket
drwxr-x--- 2 czajnik www-data 4096 2010-08-29 21:10 socket
czajnik@lapsko:~/django$ ls -l socket/testapp.sock 
srwxrwxrwx 1 czajnik czajnik 0 2010-08-29 21:10 socket/testapp.sock

This works, but is not really a nice solution. Ideally, Django should allow for settings any socket permission mode from a command line. I’d even more prefer a model where application is started with UID 0, creates the socket owned by any configured UID/GID/permission mode, and then drops the root privileges.

Perhaps the best option is to drop flup altogether and switch to another WSGI host – uWSGI is an interesting option. It allows for chrooting, setting arbitrary socket permission mode, changing process UID and GID (if started as root), and much much more. However it doesn’t seem very popular yet, I’m yet to evaluate its quality.

As usual, any suggestions welcome!