This is an updated version of an older blog post outlining a full (VE) build for django. I had to update my server due to incompatibilities between the latest version of WordPress and the versions of PHP/MySQL found in the standard CentOS repos.
Malcolm Frazier – (still) holding it down with the Linux knowledge.
// USER ACCOUNTS
The first step is to create a user account so you don’t have to use root
# useradd <username> # passwd <username>
Add a user group so we can setup the sudoers file and add our new account to the group
# /usr/sbin/groupadd <new_group_name> # /usr/sbin/usermod -a -G <new_group_name> <username>
I like to use the locate command a lot, so lets build the index of the file system that locate uses to search
Setup the sudoers config file
# vim /etc/sudoers
Add the following lines to the bottom of the file:
# Customizations %<new_group_name> ALL=(ALL) ALL
*** The above modification more or less gives all users in <new_group_name> the ability to do anything root can do, without the root password. This is fine for building the server, but after the server is built, you should restrict the permission levels a little bit more.
At this point you should be able to exit ssh and log back in as your new user account. You can use sudo <command> to execute commands as root, or use sudo -s as a replacement for su.
// UPGRADE PACKAGES SYSTEM WIDE
# yum upgrade
// INSTALLING PYTHON 2.7
I’ve chosen to use Python 2.7 as my version of python for django. CentOS 5.5 comes with Python 2.4 already installed. I had some down time on a past project because I asked the techs at RackSpace to upgrade the version of Python on the server and they started by uninstalling Python 2.4. The problem is that the yum package management system that CentOS uses is built on top of Python. If you uninstall Python 2.4, you will not be able to use yum to install Python 2.7, or any other package at that point. The solution is to install Python 2.7 in parallel to 2.4, have Django and all your other apps use the 2.7 install, and leave 2.4 to be used by yum and the underlying OS.
Before we start compiling, lets install the GCC compiler:
# yum install gcc
This will prevent the following error from occurring if you try to compile python without gcc:
configure: error: in `/root/Source/Python-2.7': configure: error: no acceptable C compiler found in $PATH
Additionally, you’ll want to install a few extra optional dependencies for Python
# yum install readline-devel gdbm-devel sqlite-devel # yum install openssl-devel ncurses-devel bzip2-devel
Theres a great tutorial on installing Python 2.7 on CentOS 5 here.
Instead of using /usr/src/ for all the source code, I created /root/Source/ to hold the source from all the packages. Inside of Source, download and extract Python 2.7:
# wget http://www.python.org/ftp/python/2.7/Python-2.7.tar.bz2 # tar -xvjf Python-2.7.tar.bz2 # cd Python-2.7 # ./configure --help
Read through the configure help and see if there are any options you want to enable or customize. Then run the configuration script:
# ./configure --prefix=/usr/local/python2.7 --enable-shared
–prefix tells python to install to a directory other than the default. This is necessary if we want to run both 2.7 and 2.4 side by side.
–enable-shared will prevent an error later on when trying to build mod_wsgi. If you get the following error when building mod_wsgi, recompile and reinstall python with –enable-shared:
/usr/local/python2.7/lib/libpython2.7.a: could not read symbols: Bad value collect2: ld returned 1 exit status apxs:Error: Command failed with rc=65536 make: *** [mod_wsgi.la] Error 1
Now its time to build and install Python:
# make # make install
// SETUP ENVIRONMENT VARIABLES
$ vim ~/.bashrc
Add the following to the bottom of .bashrc:
# User specific aliases and functions alias python='/usr/local/python2.7/bin/python'
Log out, Log back in, and you should be able to execute the new Python 2.7
$ python Python 2.7 >>>
// INSTALLING PIL (PYTHON IMAGING LIBRARY)
At this point, if you install PIL without first satisfying the optional dependencies, PIL will be built without libjpeg and zlib (png support). The output of python setup.py install would be:
*** TKINTER support not available *** JPEG support not available *** ZLIB (PNG/ZIP) support not available *** FREETYPE2 support not available *** LITTLECMS support not available
Unfortunately, PIL doesn’t complain very loudly and will still install a working version that will not be able to handle .jpg or .png files. If you install PIL without the header libraries for the dependencies present, you will receive the following error in django’s admin when trying to upload an image file:
Upload a valid image. The file you uploaded was either not an image or a corrupted image.
You can further verify if the proper support is compiled in from the shell:
$ python >>> from PIL import Image >>> i = Image.open("/path/to/some/image.jpg") >>> i.verify() >>> i.load() Traceback (most recent call last): File "<console>", line 1, in <module> File "/usr/local/python2.7/lib/python2.7/site-packages/PIL/ImageFile.py", line 189, in load d = Image._getdecoder(self.mode, d, a, self.decoderconfig) File "/usr/local/python2.7/lib/python2.7/site-packages/PIL/Image.py", line 385, in _getdecoder raise IOError("decoder %s not available" % decoder_name) IOError: decoder jpeg not available
You can see from the above error that the jpeg decoder is not available. If you’ve already installed PIL, uninstall it. If you havn’t installed PIL yet, this will save you a lot of time (:
# yum install zlib zlib-devel # yum install libjpeg libjpeg-devel # yum install freetype freetype-devel
Django relies heavily on the PIL. Again in our /root/Source directory, install PIL:
# wget http://effbot.org/downloads/Imaging-1.1.7.tar.gz # tar xvfz Imaging-1.1.7.tar.gz # cd Imaging-1.1.7 # python setup.py build_ext -i
Check to make sure that libjpeg and zlib were found:
*** TKINTER support not available --- JPEG support available --- ZLIB (PNG/ZIP) support available --- FREETYPE2 support available *** LITTLECMS support not available
Run a test to make sure that everything works:
# python selftest.py -------------------------------------------------------------------- PIL 1.1.7 TEST SUMMARY -------------------------------------------------------------------- Python modules loaded from ./PIL Binary modules loaded from ./PIL -------------------------------------------------------------------- --- PIL CORE support ok *** TKINTER support not installed --- JPEG support ok --- ZLIB (PNG/ZIP) support ok --- FREETYPE2 support ok *** LITTLECMS support not installed -------------------------------------------------------------------- Running selftest: --- 57 tests passed.
And finally, install PIL:
# python setup.py install
You should now be able to import PIL inside of python:
$ python >>>import PIL >>>
// INSTALLING MYSQL
Enable the Remi Repository to install MySQL 5.5 and PHP 5.3. More information about the Remi Repository can be found here.
# wget http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm # rpm -Uvh epel-release-5-4.noarch.rpm # rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-5.rpm # yum --enablerepo=remi list mysql mysql-server # yum --enablerepo=remi install mysql.x86_64 mysql-server.x86_64
Start the MySQL Server:
# /etc/init.d/mysqld start
In order to set the initial root password, and get rid of the built in tables/user accounts for testing, run:
Follow the instructions, pick your customizations … then make sure MySQL is installed and working:
# mysql -u root -p Enter password: mysql> SELECT VERSION(); +-----------+ | VERSION() | +-----------+ | 5.5.14 | +-----------+ 1 row in set (0.00 sec)
Add MySQL to the proper run level:
# /sbin/chkconfig mysqld on
// MYSQL-PYTHON GAP
Next, you need to install MySQL-python, the python interface to MySQL. If you do not install MySQL-python, later on when you try to do a ‘python manage.py syncdb’ django will not be able to communicate with MySQL and will throw the following error:
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named MySQLdb
Setuptools is a required dependency of MySQL-python. Download it from here and install it, setting the prefix to our freshly installed python2.7
# sh setuptools*.egg --prefix=/usr/local/python2.7
Now install the MySQL headers from the Remi repo, then install MySQL-python:
# yum --enablerepo=remi install mysql-devel.x86_64 # wget http://sourceforge.net/projects/mysql-python/files/mysql-python/1.2.3/MySQL-python-1.2.3.tar.gz/download # tar -zxvf MySQL-python-1.2.3.tar.gz # cd MySQL-python-1.2.3 # python setup.py build # python seutp.py install
At this point django should be able to talk to MySQL using MySQL-python.
// INSTALLING APACHE
Next we have to install our web server, Apache. There’s a pretty straight forward tutorial on this here.
# yum install httpd # /sbin/chkconfig httpd on # /etc/init.d/httpd start Starting httpd: [ OK ]
At this point, you should spend some quality time with /etc/httpd/conf/httpd.conf to really squeeze some power out of apache.
// INSTALLING DJANGO
The django install docs can be found here.
# wget http://www.djangoproject.com/download/1.3/tarball/ # tar xzvf Django-1.3.tar.gz # cd Django-1.3 # python setup.py install $ python >>> import django >>>
// INSTALLING PHPMYADMIN
PhpMyAdmin is a web interface for controlling your MySQL database.
# yum install phpmyadmin
This will install PHP as a dependency, but you will still need to setup PHP. Setup the PHP Cookie:
# vim /usr/share/phpmyadmin/config.inc.php
Add the Python Shared Libraries
# vim /etc/ld.so.conf.d/python2.7.conf
add the following line:
Create necessary links and cache the new libraries:
// INSTALLING MOD_WSGI
mod_wsgi is the link between apache and django. It is responsible for taking the web request from apache and getting it to your django app for handling. The mod_wsgi installation docs are a great resource, they can be found here.
First, we need to install the source code for apache, as mod_wsgi needs it to build. Install the httpd-devel package, which will install the headers for apache.
# yum install httpd-devel
Get and install mod_wsgi
# wget http://modwsgi.googlecode.com/files/mod_wsgi-3.3.tar.gz # tar -zxvf mod_wsgi-3.3.tar.gz # cd mod_wsgi-3.3 # ./configure --help # ./configure --with-python=/usr/local/python2.7/bin/python # make # make_install
// POINT APACHE AT DJANGO USING MOD_WSGI
First, you need to tell apache which version of python to use so it doesn’t use the default 2.4:
# vim /etc/httpd/conf/httpd.conf
Add the following to the bottom of the file:
# Python Versioning Control for mod_wsgi WSGIPythonHome /usr/local/python2.7
Make sure you load mod_wsgi in httpd.conf at the end of the LoadModule section
LoadModule wsgi_module modules/mod_wsgi.so
Then restart apache
# /etc/init.d/httpd restart
Now you can configure your virtual hosts in apache to point to a ‘django.wsgi’ file thats specific to each django project you create. Add the WSGIScriptAlias to your Virtual Host configuration file:
WSGIScriptAlias / /path/to/your/django/project/django_project_name/apache/django.wsgi
Add the ‘apache’ directory to your django project, and create the django.wsgi file inside the apache directory:
$ cd /path/to/your/django/project/django_project_name/ $ mkdir apache $ cd apache $ vim django.wsgi
Copy the following into the django.wsgi file:
import os import os.path import sys sys.path.append('/path/to/project/root') os.environ['PYTHON_EGG_CACHE'] = '/path/to/a/directory/for/egg_cache' os.environ['DJANGO_SETTINGS_MODULE'] = 'your_django_project_name.settings' import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()
If you’ve made it this far, you should have a working django install.