SaltyCrane Blog — Notes on Python and web development on Ubuntu Linux

Card store project #2: Installing Satchmo, Django, PostgreSQL, and Apache on Ubuntu at Slicehost

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.

Setup Slicehost

  • Sign up for an account at I chose Ubuntu Intrepid for my operating system and named my slice "toad".
  • I followed the following two excellent Slicehost tutorials: Ubuntu Setup Part 1 and Part 2.
  • An important step is setting the system locale. Since I'm in the United States, I used the following commands (run as root):
    locale-gen en_US.UTF-8
    update-locale LANG=en_US.UTF-8

Install apache, mod_python, postgresql, and postgres python bindings

  • Run as root (or use sudo):
    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

Configure apache

  • I used the following Slicehost tutorials: Install Apache, Configure Apache Part 1, Configure Apache Part 2
  • Of particular note, when installing apache, I got this warning:
    apache2: Could not reliably determine the server's fully qualified domain name, using for ServerName
    Fix it by setting the ServerName in /etc/apache2/apache2.conf:
    ServerTokens Prod
    See the Apache docs for more information on ServerName.

Install Django 1.0.2

  • Run the following as root:
    cd /srv
    tar zxvf Django-1.0.2-final.tar.gz
    mkdir python-packages
    cd python-packages
    ln -s ../Django-1.0.2-final/django

Test Django (optional)

  • Run the following as root:
    export PYTHONPATH=/srv/python-packages
    /srv/Django-1.0.2-final/django/bin/ startproject testdjango
  • Edit /etc/apache2/httpd.conf:
    <location "/">
        SetHandler python-program
        PythonHandler django.core.handlers.modpython
        SetEnv DJANGO_SETTINGS_MODULE testdjango.settings
        PythonPath "['/srv', '/srv/python-packages'] + sys.path"
        PythonDebug On
  • Restart apache:
    /etc/init.d/apache2 restart
    Navigate to your slice's IP address in your browser and you should see the Django "It worked!" page.

Install Satchmo

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 /srv/python-packages to store symbolic links to my needed python packages. Then I add this directory to my Python Path in the PYTHONPATH environment variable or in the Apache httpd.conf file. See my post, Somewhere on your Python path for more information.

  • Install Satchmo prerequisites. Run the following commands as root:
    Install APT packages:
    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

    Install django-registration using easy_install:
    apt-get install python-setuptools python-dev build-essential
    easy_install django-registration

    Install comment_utils source:
    apt-get install subversion
    mkdir -p /srv/python-packages/dist
    cd /srv/python-packages/dist
    svn co 
    mv comment_utils comment_utils_rev92
    cd /srv/python-packages
    ln -s dist/comment_utils_rev92 comment_utils
  • Install Satchmo 0.8. Run the following as root: Update 2008-12-12: I changed this to use release 0.8 instead of the SVN trunk version.
    cd /srv
    tar zxvf satchmo-0.8.tgz
    cd /srv/python-packages
    ln -s ../satchmo-0.8/satchmo
    To install the SVN trunk version instead,
    cd /srv
    svn co svn://
    mv trunk satchmo_revXXXX
    cd /srv/python-packages
    ln -s ../satchmo_revXXXX/satchmo

Setup PostgreSQLΒΆ

I followed the instructions at for setting up Django and Postgres on Slicehost.

  • If you didn't already install Postgres above, run the following as root:
    apt-get install postgresql
    apt-get install python-psycopg2
  • Change the password for the "postgres" Unix user. (run as root or use sudo)
    passwd -d postgres
    su postgres -c passwd
  • Change password for "postgres" user in the database. (From Punteney's article, "It's convenient to have the two passwords match, but not required.")
    su postgres -c psql template1
    ALTER USER postgres WITH PASSWORD 'postgres_user_password';
  • Create django user:
    su postgres
    createuser -P django_user
    Punteney says to answer no to all here. Remember the password to put in Django file. (For this example, I set the password to my_password.)
  • Create a database. Still su'ed as the "postgres" user:
    psql template1
    CREATE DATABASE django_db OWNER django_user ENCODING 'UTF8';
    (exit from postgres su)
  • Configure access to the database. Edit /etc/postgresql/8.3/main/pg_hba.conf:
    local   all         postgres                          ident sameuser
    local   django_db   django_user                       md5
  • Restart the postgres server:
    /etc/init.d/postgresql-8.3 restart
  • In your Django project, use the following database settings in
    DATABASE_ENGINE = 'postgresql_psycopg2'
    DATABASE_NAME = 'django_db'
    DATABASE_USER = 'django_user'
    DATABASE_PASSWORD = 'my_password'
  • Run syncdb:
    cd /srv/yourproject
    python syncdb

Setup a domain name

  • Register for a domain name. Google for "domain registration" for options.
  • Follow the Slicehost directions for creating DNS records. This includes setting the nameservers at your domain registration service to use Slicehost's nameservers (,,


#1 Andrew commented on :

Is there any reason you chose mod_python over mod_wsgi?

#2 Eliot commented on :

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.

#3 Andrew commented on :

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)

Paster ::

$ 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

#4 Eliot commented on :

Andrew, thanks for the information. I'll check it out.

#5 Nikolay Kolev commented on :

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.

#6 Eliot commented on :

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.