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_php
Podobny 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-wsgi |
W 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.