This HowTo describes a sample deployment configuration that I believe is well adapted for most "real-world" websites. It is the configuration used by the http://www.cherrypy.org website itself.
The number of threads that you should use for your site depends on many criteria, including the number of concurrent users you plan to have, the average time your pages take to build and the power (CPU and RAM) of the machine that will run the site.
In order to listen on port 80, the server has to be started by the user "root". However, running the server as "root" is not very safe, so we use the special function initAfterBind to switch the user running the server to another user. The code is very simple:
def initAfterBind(): import os # We must switch the group first os.setegid(500) # Replace with desired user id. os.seteuid(2524) # Idem
Also, since the server runs a pool of threads, we must switch the user for all these threads as well (otherwise, only the parent thread will be switched). To do so, we just use the initThread special function, like this:
def initThread(threadIndex): import os # We must switch the group first os.setegid(500) # Replace with desired user id. os.seteuid(2524) # Idem
Since the MySQLdb driver doesn't work well (from my experience) if we have several threads sharing the same database connection, each thread is given its own database connection, so it doesn't interfer with other threads.
This is done very easily using the initThread special function and the request special variable, like this:
def initThread(threadIndex): time.sleep(threadIndex * 0.2) # Sleep 0.2 seconds between each new database connection to make sure MySql can keep up ... request.connection = MySQLdb.connect('host', 'user', 'password', 'name')
This takes advantage of the fact that request is a special thread-aware class instance (so each thread can safely set/get member variables without have to worry about other threads)
Then, when we need to run a query, we just use code like this:
c=request.connection.cursor() c.execute(query) res=c.fetchall() c.close()
And also, the forum on the website runs on top of ZODB and since ZODB doesn't support multiple threads by itself, I had to install ZEO so each thread also behaves as a ZEO client.
I believe that other storage types for sessions (file, database, cookie) would work just as well.
Note that if you're afraid that your CherryPy server might crash while you're sleeping, you can always set up a cronjob to check that the site is still running and to restart it if it isn't ...
See About this document... for information on suggesting changes.