Wstęp
Poradników i tutoriali opisujących konfigurację Apache z PHP i MySQL pod Linuxem (LAMP) jest cała masa. W Ubuntu sprowadza się to do wywołania w konsoli prostego polecenia
sudo apt-get install php5 php5-mysql mysql-server apache2 libapache2-mod-auth-mysql
… i mamy wszystko co potrzeba. Więcej na ten temat znajdziemy choćby w artykule Instalacja Apache + PHP5 + MySQL.
Instalacja frameworka Django i preferowanego przez pythonowców serwera baz danych Postgres jest równie prosta – przynajmniej pod Ubuntu.
sudo apt-get install python-django postgresql python-psycopg2 postfix python-imaging python-docutils
Django ma jedną z najlepszych dokumentacji, a o Postgresie pisze niemal co drugi bloger, który miał coś z nim do czynienia tak więc zainteresowanych po prostu odeślę do wciąż aktualnego i w miarę kompletnego wpisu Instalacja PostgreSQL 8.3 w Ubuntu 8.04.
O ile hostowanie skryptów PHP na Apache-u jest rzeczą naturalną zarówno w środowisku deweloperskim jak i produkcyjnym o tyle w przypadku Pythona a konkretnie aplikacji Django już nie. Django posiada świetny wbudowany serwer stworzony na podstawie klasy BaseHttpServer ze standardowej biblioteki Pythona, który świetnie sprawdza się do szybkiego testowania aplikacji o niepełnej funkcjonalności. Restartuje się automatycznie przy każdej zmianie w kodzie a ponadto ponieważ uruchamiany jest w terminalu wyświetla na wyjściu wszystkie instrukcje print.
Użycie serwera wbudowanego w środowisku produkcyjnym jest zabronione licencją, a poza tym istnieje jeszcze kilka innych obiektywnych powodów aby tego nie robić, jak choćby bezpieczeństwo i stabilność, czy wydajność. Jak się okazuje także dla celów developerskich warto czasem podjąć trud konfiguracji serwera zewnętrznego.
W przypadku Apache-a w kontekście hostowania skryptów napisanych w języku Python najczęściej stosuje się dwa rozwiązania tj. mod_python lub mod_wsgi. Oba z modułów nie powodują konfliktów z mod_php, tak więc chcąc na swoim serwerze obsługiwać zarówno aplikacje PHP i Python można zastosować dowolne z wymienionych rozwiązań.
Ponoć konfiguracja Apache2 + mod_python jest częściej stosowana, lepiej przetestowana i udokumentowana, ja jednak zdecydowałem się na WSGI z uwagi na elastyczność jaką udało mi się uzyskać.
Założenia
W przypadku środowisk produkcyjnych kluczową kwestią jest bezpieczeństwo i stabilność serwera. W środowisku developerskim, w którym skrypty uruchamiane są jedynie na komputerze lokalnym osobiście stawiam na elastyczność kosztem nawet bezpieczeństwa i stabilności. Nie lubię grzebać w plikach konfiguracyjnych Apache-a i edytowanie pliku /etc/apach2/httpd.conf lub któregoś z plików w katalogu /etc/apache2/sites-available/ za każdym razem kiedy tworze nowy projekt lub zmieniam jego nazwę. W przypadku projektów realizowanych w języku PHP wystarczy, że w moim katalogu workspace stworzę nowy katalog np. „nowy_projekt_php”, wrzucę do niego plik index.php i wywołam w pasku adresu przeglądarki
http://localhost/nowy_projekt_phpPodobny efekt chciałem uzyskać w przypadku projektów realizowanych w Django.
Instalacja mod_wsgi
Moduł WSGI możesz zainstalować ze źródeł, co zostało przystępnie opisane w artykule Ubuntu Hardy – mod_wsgi Installation, ale w Ubuntu można skorzystać z repozytorium:
sudo apt-get install libapache2-mod-wsgi
Aby aktywować moduł (w Ubuntu 10.04 – można pominąć)
sudo a2enmod mod-wsgiW przypadku instalacji z repozytorium wystarczy już tylko restart serwera.
sudo /etc/init.d/apache2 restart
Konfiguracja Apache
Integracja mod_wsgi z Django jest świetnie opisana zarówno na stronach dokumentacji Django, jak też (może nawet lepiej) na stronie rozszerzenia specjalnie poświęconej temu zagadnieniu w artykule pod pt. Integration With Django.
Ja jednak zaproponuję jeszcze inne rozwiązanie na które natknąłem się na forum w wątku Ubuntu + Apache2 + WSGI (mod_wsgi) with LAMP i lekko zmodyfikowałem na swoje potrzeby.
Aby osiągnąć wyżej opisane założenie w najprostszy sposób należy:
Stworzyć Virtualhosta w pliku httpd.conf
sudo vim /etc/apache2/httpd.conf
<VirtualHost *>
ServerName testhost
DocumentRoot /home/myuser/workspace/
<Directory /home/myuser/workspace/>
Options Indexes FollowSymLinks MultiViews ExecCGI
AddType application/x-httpd-php .php .phtml
AddType application/x-httpd-php-source .phps
AddHandler application/x-httpd-php .php .phtml
AddHandler cgi-script .cgi
AddHandler wsgi-script .wsgi
Order allow,deny
allow from all
</Directory>
</Virtualhost>
W przeciwieństwie do rozwiązania zaproponowanego na forum proponuję usunąć dyrektywę „AllowOverride None” dzięki czemu możliwe będzie skorzystanie z mod_rewrite.
Trzeba jeszcze poinformować serwer, że domyślnym plikiem w aplikacji napisanej w Pythonie będzie index.wsgi
sudo gedit /etc/apache2/mods-enabled/dir.conf
<IfModule mod_dir.c>
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm index.wsgi
</IfModule>
W katalogu /home/myuser/workspace/ utwórzmy nowy podkatalog nowy_projekt_python a w nim plik index.wsgi o treści:
def application(environ, start_response): status = '200 OK' output = 'Hello World!' response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output]
Jeśli po wywołaniu
http://localhost/nowy_projekt_python
widać „Hello World!” to znaczy, że wszystko jest ok, jeśli nie to może wystarczy zrestartować serwer
Twórcy Django dążą do tego aby ich framework był pythonowy jak to tylko możliwe dlatego np. konfigurację trzymają w plikach py a nie np. w xml albo yml-u. Dzięki takiemu podejściu możemy mieć pewność, że po wrzuceniu do katalogu nowy_projekt_python aplikacji Django i modyfikacji pliku index.wsgi, zobaczymy w przeglądarce to co byśmy widzieli po uruchomieniu serwera wbudowanego.
Zmodyfikujmy index.wsgi
import os, sys sys.path.append('/home/myuser/workspace') sys.path.append('/home/myuser/workspace/nowy_projekt_python') os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' import django.core.handlers.wsgi _application = django.core.handlers.wsgi.WSGIHandler() def application(environ, start_response): if environ['wsgi.url_scheme'] == 'https': environ['HTTPS'] = 'on' return _application(environ, start_response)
Przydałby się jeszcze plik .htaccess
<IfModule mod_rewrite.c>
# Turn on URL rewriting
RewriteEngine On
# Installation directory
RewriteBase /nowy_projekt_python/
# Protect hidden files from being viewed
<Files .*>
Order Deny,Allow
Deny From All
</Files>
# Allow any files or directories that exist to be displayed directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all other URLs to index.wsgi/URL
RewriteRule .* index.wsgi/$0 [PT]
</IfModule>
Zaproponowane tutaj rozwiązanie jest jedynie punktem wyjścia do stworzenia swojej własnej uniwersalnej konfiguracji środowiska developerskiego do pracy z projektami PHP i Python. Zapewne przydałoby się parę rzeczy inaczej skonfigurować lub też dodać kilka opcji jak np. dyrektywę zapobiegającą wyświetlaniu treści plików python w przeglądarce. Zachęcam do eksperymentowania i dzielenia się swoim doświadczeniem.

