As I mentioned in my previous post, I'm planning to set up an e-commerce site using the Satchmo shopping cart framework. Satchmo is built on the Django web framework which is written in the Python programming language. Satchmo has a lot of features built in which means it saves you a lot of work implementing them yourself. Check out this video introduction to Satchmo at this year's DjangoCon for more information.
After reading this discussion on the Satchmo mailing list, I decided to use Slicehost for hosting my site. Their cheapest plan provides 256MB of RAM for $20/month. Here are my notes on setting up Satchmo and Django with PostgreSQL, Apache, and mod_python on Ubuntu Intrepid at Slicehost. It seems lighttpd and nginx are popular lightweight alternatives to Apache on VPS setups. I do not know too much about this, but may explore these in the future.
Note, I don't describe how to setup a Satchmo project below. Maybe I will write another post about that later... For more information, see the Satchmo Installation documentation. Update 2008-12-12: I did write another blog post-- see Installing Satchmo, part 2.
locale-gen en_US.UTF-8 update-locale LANG=en_US.UTF-8
apt-get update apt-get upgrade apt-get dist-upgrade apt-get install apache2 apache2-mpm-prefork apt-get install libapache2-mod-python apt-get install postgresql apt-get install python-psycopg2
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerNameFix it by setting the ServerName in
ServerName yourdomain.com ServerTokens ProdSee the Apache docs for more information on ServerName.
cd /srv wget http://www.djangoproject.com/download/1.0.2/tarball/ tar zxvf Django-1.0.2-final.tar.gz mkdir python-packages cd python-packages ln -s ../Django-1.0.2-final/django
export PYTHONPATH=/srv/python-packages /srv/Django-1.0.2-final/django/bin/django-admin.py startproject testdjango
<location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE testdjango.settings PythonPath "['/srv', '/srv/python-packages'] + sys.path" PythonDebug On </location>
/etc/init.d/apache2 restartNavigate to your slice's IP address in your browser and you should see the Django "It worked!" page.
Satchmo requires a number of external Python packages besides Django. Unfortunately, there isn't one standard way of installing Python packages. I decided to install most of them using Ubuntu's APT package management and one of them using easy_install, and one of them from source. Alternatively, I could have installed most of the packages with easy_install, and one of them with APT (and one of them from source). Or, I could have done it another way... sigh.
Note, I use the directory
store symbolic links to my needed python packages. Then I add this
directory to my Python Path in the PYTHONPATH environment variable or in
httpd.conf file. See my post,
Somewhere on your Python path for more information.
apt-get update apt-get upgrade apt-get install python-crypto apt-get install python-yaml apt-get install python-imaging apt-get install python-reportlab apt-get install python-trml2pdf
apt-get install python-setuptools python-dev build-essential easy_install django-registration
apt-get install subversion mkdir -p /srv/python-packages/dist cd /srv/python-packages/dist svn co http://django-comment-utils.googlecode.com/svn/trunk/comment_utils/ mv comment_utils comment_utils_rev92 cd /srv/python-packages ln -s dist/comment_utils_rev92 comment_utils
cd /srv wget http://www.satchmoproject.com/snapshots/satchmo-0.8.tgz tar zxvf satchmo-0.8.tgz cd /srv/python-packages ln -s ../satchmo-0.8/satchmoTo install the SVN trunk version instead,
cd /srv svn co svn://satchmoproject.com/satchmo/trunk mv trunk satchmo_revXXXX cd /srv/python-packages ln -s ../satchmo_revXXXX/satchmo
I followed the instructions at Punteney.com for setting up Django and Postgres on Slicehost.
apt-get install postgresql apt-get install python-psycopg2
passwd -d postgres su postgres -c passwd
su postgres -c psql template1
ALTER USER postgres WITH PASSWORD 'postgres_user_password'; template1=\q
su postgres createuser -P django_userPunteney says to answer no to all here. Remember the password to put in Django settings.py file. (For this example, I set the password to
su'ed as the "postgres" user:
CREATE DATABASE django_db OWNER django_user ENCODING 'UTF8'; \q
exit(exit from postgres su)
local all postgres ident sameuser local django_db django_user md5
DATABASE_ENGINE = 'postgresql_psycopg2' DATABASE_NAME = 'django_db' DATABASE_USER = 'django_user' DATABASE_PASSWORD = 'my_password' DATABASE_HOST = '' DATABASE_PORT = ''
cd /srv/yourproject python manage.py syncdb
Andrew, is mod_wsgi the preferred way to go? I used mod_python because it was recommended by the Django docs and I had used it in the past. I haven't looked into mod_wsgi but will check it out later.
I'm no expert on the subject, but there is a page on the mod_wsgi wiki about integration with django. I don't see any reason not to at least check it out, it is in the Ibex repos. Django also has a page on the setup. I've also recently been benchmarking nginx's mod_wsgi (pre-beta code, not ready for production) and it looks quite promising. I have yet to do a comparison with Apache's mod_wsgi (or mod_python), but it is more than twice as fast as paster's internal server (I'm using pylons)
$ ab -n 1000 -c 50 localhost:5000/blog/ Server Software: PasteWSGIServer/0.5 Server Hostname: localhost Server Port: 5000 Document Path: /blog/ Document Length: 454 bytes Concurrency Level: 50 Time taken for tests: 52.590574 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 656000 bytes HTML transferred: 454000 bytes Requests per second: 19.01 [#/sec] (mean) Time per request: 2629.529 [ms] (mean) Time per request: 52.591 [ms] (mean, across all concurrent requests) Transfer rate: 12.17 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 144 918.7 0 9000 Processing: 186 2427 548.2 2638 3318 Waiting: 173 2381 544.2 2591 3228 Total: 199 2571 992.0 2662 11141 Longest request: 11141 ms
Nginx (2 processes) ::
$ ab -n 1000 -c 50 localhost:5500/blog/ Server Software: nginx/0.7.26 Server Hostname: localhost Server Port: 5500 Document Path: /blog/ Document Length: 454 bytes Concurrency Level: 50 Time taken for tests: 17.595767 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 655000 bytes HTML transferred: 454000 bytes Requests per second: 56.83 [#/sec] (mean) Time per request: 879.788 [ms] (mean) Time per request: 17.596 [ms] (mean, across all concurrent requests) Transfer rate: 36.32 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 1.9 0 11 Processing: 213 860 858.5 727 6392 Waiting: 212 860 858.4 726 6391 Total: 221 861 860.0 727 6400 Longest request: 6400 ms
I've read that WSGI is the recommended approach and even though not officially yet, Phusion Passenger supports it. I'm not sure how it compares to mod_wsgi though, but it's been working great for Ruby frameworks (in production on many high-volume sites) and I've heard nothing but praises about it.
I may have to start considering alternatives to Apache/mod_python... Even after moving my media files to S3, my site is still slow. I'm not sure if it is Slicehost or if I just need memcached. I briefly looked into nginx and it looks pretty good. I see from their wiki that they have quickly surpassed lighttpd in domains hosted.