Quantcast
Channel: Ventanazul - apache
Viewing all articles
Browse latest Browse all 2

Cómo configurar Apache, mod_python y proxy reverso a Lighttpd para Django en Ubuntu

$
0
0

Actualización, 8 de abril de 2009: Ya no recomiendo este método. Ahora sugiero seguir la guía para configurar un servidor Django con Nginx y Apache.

I'll Django for food

Es octubre 2008 y ya no queda duda que para hacer desarrollo web en serio se debe trabajar con frameworks. Talvez la traducción adecuada sería plataforma pero como la mayoría de desarrolladores de habla hispana estamos acostumbrados me quedaré con la palabrita en inglés. Un framework es software que permite a los programadores, que cada día somos más ociosos, olvidarnos de las tareas repetitivas para enfocarmos en aquello que hace único a cada uno de nuestros proyectos.

Además resulta obvio que Django, el framework escrito en Python, está atrayendo a más desarrolladores y compañías cada día. Guido es un googler desde el año 2005 y el recientemente anunciado Google App Engine usa Python y Django. Estoy seguro que no hay mejor momento para saltar al tren de Django (sin ánimos de embromar a los buenos chicos de RoR).

Los programadores veteranos pueden empezar a escribir aplicaciones Django rápidamente gracias a la excelente documentación y al libro de Django (de acceso gratuito). También he leido y recomiendo Practical Django Projects, por James Bennett, parte del equipo de Django, y Learning Website Development with Django, por Ayman Hourieh, un joven y talentoso ingeniero en Google.

Django es realmente el web framework for perfectionists with deadlines. Yo estoy a punto de completar mi primera aplicación Django para Facebook y solo necesité unos pocos días para lograrlo (lo cual incluyó actualizarme con los recientes cambios en el API de Facebook). Y sí, hay artículos sobre Django y Facebook en camino.

Y bien, ¿así que todo es felicidad en Djangolandia? Bueno, hay algo que siempre me complicó desde que empecé a usar el framework hace algunos meses: la puesta en marcha en un entorno de producción. La documentación y los libros que he leido suelen arrancar con el servidor de desarrollo que Django incluye y enfocarse en escribir aplicaciones, dejando la implementación final de lado.

Pero desafortunadamente, especialmente si estás acostumbrado a la típica configuración de Linux, Apache, MySQL y PHP, como yo lo estaba, puedes necesitar más detalles para entrar en acción. Es por eso que decidí escribir este tutorial sobre cómo configurar Apache, mod_python y un proxy reverso a Lighttpd para Django.
<!--break-->

Damas y caballeros, un aplauso para el elenco

Aquí los actores de nuestra pequeña historia:

  • Apache, el servidor web, tu viejo conocido, no hay mucho que añadir sobre él.
  • mod_python, un módulo para Apache que integra Python en el servidor web, mucho mejor que usar CGI.
  • Lighttpd, Lighty para los amigos, un servidor web muy veloz y adecuado para servir archivos.
  • mod_proxy, un módulo para Apache que actuará como enlace entre Apache y Lighty, nuestros dos servidores web.
  • Y por supuesto Python, Django y otros módulos que sean necesarios.

No hablaré sobre servidores DNS ni de bases de datos pero obviamente debes encargarte de configurarlos de acuerdo a lo que necesites.

El plan

Los buenos asaltantes de bancos y desarrolladores web saben lo importante que es tener un buen plan. Éste es el nuestro.

Apache y mod_python procesarán todo el contenido dinámico, pasando todas las peticiones al proyecto en Django y mostrando los resultados bajo un url como http://example.com/.

Debido a que Apache requiere más memoria para cada proceso y es vital optimizar el uso de los recursos en el servidor (o servidores) usaremos Lighty, que consume menos memoria y ciclos de CPU, para el contenido estático. Eso incluye, por ejemplo, imágenes, películas Flash, Javascript y CSS.

Y ahora la parte interesante: podemos configurar Lighty en otro dominio, dirección IP o puerto TCP/IP, en el mismo servidor donde corre Apache o en otro equipo dedicado, y gracias a mod_proxy hacer que el contenido de Lighty aparezca bajo un url como http://example.com/media/

Idealmente el contenido de Lighty no sera accedido directamente sino a través de Apache corriendo mod_proxy.

Luego que todo esté configurado podremos visitar una página como http://example.com/blog/ y obtener una lista de artículos de la base de datos cortesía de Apache, mod_python, una función en views.py y algunas plantillas de Django. La página puede también mostrar algunas imágenes, como /media/pictures/pic.jpg o /media/logo.png, y añadir algo de estilo con /media/css/style.css, estos archivos estarán en http://example.com/media y serán servidos por Lighty.

Suena como un buen plan. A buscar las máscaras de presidentes de los Estados Unidos y empezar.

Entramos, ¡vayamos por la bóveda!

Todos los comandos y servicios en este tutorial han sido probados en un servidor Ubuntu 8.04 y deberían funcionar en cualquier otra distribución basada en Debian. Adaptar a otros sabores de Linux no debería ser muy complicado. Puedes usar cualquier editor de texto para modificar los archivos de configuración pero recuerda que los programadores extremadamente guapos y las lindas chicas geeks solo usan vim.

Primero instalemos Apache y mod_python:

sudo apt-get install apache2
sudo apt-get install libapache2-mod-python

Ubuntu a veces no define el nombre del servidor para Apache así que es bueno que lo hagamos. Edita /etc/apache2/apache2.conf y añade esta línea:

ServerName "your-server-name"

debería ir cerca a esta línea:

ServerRoot "/etc/apache2"

En realidad no necesitaremos este nombre para los pasos siguientes pero vale la pena para evitar Apache escupa advertencias en cada reinicio. Los asaltantes de bancos no toleran las advertencias.

Y mientras modificas /etc/apache2/apache2.conf asegúrate de tener esta línea:

ServerSignature On

Será útil cuando probemos si mod_python carga correctamente. La puedes dejar en Off luego de eso.

Veamos ahora nuestras direcciones IP. En mi archivo /etc/network/interfaces yo tengo algo como esto:

auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.192
netmask 255.255.255.0
gateway 192.168.0.1
auto eth0:1
iface eth0:1 inet static
address 192.168.0.193
netmask 255.255.255.0
gateway 192.168.0.1
auto eth0:2
iface eth0:2 inet static
address 192.168.0.180
netmask 255.255.255.0
gateway 192.168.0.1
auto eth0:3
iface eth0:3 inet static
address 192.168.0.181
netmask 255.255.255.0
gateway 192.168.0.1

Tengo un solo adaptador de red, eth0, con múltipes direcciones IP asignadas, todas ellas privadas pero en un servidor de producción deberían ser todas públicas. Puedo escoger cualquier combinación de direcciones y puertos para mis dos servidores web, o solo una dirección IP que usa dos puertos. Yo usaré estas opciones:

Apache en 192.168.0.180:80
Lighty en 192.168.0.181:8000

Para resolver el dominio example.com a la dirección IP de Apache modifica /etc/hosts y añade:

192.168.0.180 example.com

Obviamente esto es solo para desarrollo, en un entorno de producción deberás configurar tu servidor DNS, probablemente BIND o algún proveedor externo.

Y ahora actualicemos /etc/apache2/ports.conf:

Listen 192.168.0.192:80
Listen 192.168.0.180:80
<IfModule mod_ssl.c>
Listen 443
</IfModule>

Nota que tengo 192.168.0.192 en la primera línea, no era una de mis opciones pero está allí para demostrar que Apache podría usarse en una configuración de virtual hosting para tener otros sitios en el servidor, corriendo PHP o mod_python por ejemplo.

Activemos los módulos para mod_proxy en Apache:

sudo a2enmod proxy_connect
sudo a2enmod proxy_http

Automáticamente se activará otro archivo requerido: proxy.

Ahora configuremos el sitio para example.com en Apache. Como root crea un archivo llamado /etc/apache2/sites-available/example.com que contiene estas líneas:

<VirtualHost 192.168.0.180>
ServerName example.com
ServerAdmin alexis@example.com
DocumentRoot /home/alexis/example/
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
</VirtualHost>

Puedes escoger cualquier nombre para este archivo pero yo prefiero usar el dominio. Lo importante es guardarlo en /etc/apache2/sites-available/. Es una configuración básica para el ejemplo pero luego podrías añadir otras opciones, como archivos para reportes de acceso (logs) o errores.

Asegúrate de haber creado el directorio para tus documentos y que el usuario de Apache tenga los permisos para accederlo. En mi caso este directorio es /home/alexis/example. Nota que por ahora está vacío.

Activa el sitio:

sudo a2ensite example.com

Eso es todo lo que necesitas para que Apache funcione con Django. Si quieres hospedar aplicaciones que usan PHP o SSL debes instalar otro módulos y paquetes:

sudo a2enmod ssl
sudo a2enmod rewrite
sudo a2enmod suexec
sudo a2enmod include

pero eso escapa a los objetivos de este tutorial.

Bien, ahora reiniciamos Apache para activar los cambios:

sudo /etc/init.d/apache2 restart

Si apuntas tu navegador a http://example.com/anything deberías ver una página de error, 404 Not Found, y un mensaje como el siguiente al pie:

Apache/2.2.8 (Ubuntu) mod_python/3.3.1 Python/2.5.2 PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch mod_ssl/2.2.8 OpenSSL/0.9.8g Server at example.com Port 80

Si puedes ver las versiones de mod_python y Python está sobre la pista correcta. Ahora una prueba más, crea un archivo llamado test.py en tu directorio de documentos, recuerda que es /home/alexis/example en mi caso, y escribe lo siguiente:

def index(req):
return "Test successful, mod_python working";

Ahora visita http://example.com/test.py y verás Test successful, mod_python working.

¡Vamos bien! mod_python está funcionando correctamente.

Como es posible que durante tus pruebas necesites múltiples reinicios en los servidores web, o simplemente recargar la configuración, es una buena idea crear algunos aliases en ~/.bashrc:

alias apreload='sudo /etc/init.d/apache2 reload'
alias aprestart='sudo /etc/init.d/apache2 restart'
alias lrestart='sudo /etc/init.d/lighttpd restart'

Las primeras dos líneas son para Apache, la última para Lighty, que instalaremos a continuación. La próxima vez que inicies tu consola en Linux podrás reiniciar Apache con solo ejecutar:

aprestart

Instalemos Lighttpd:

sudo apt-get install lighttpd

La configuración está en /etc/lighttpd/lighttpd.conf. Vamos a definir el IP y puerto para el servidor principal:

server.bind = "192.168.0.181"
server.port = 80

Y me bastaría con esto para mis archivos estáticos pero prefiero usar la opción de virtual hosting por si más adelante quiero hospedar otros sitios. Para hacerlo remueve el comentario, un #, de la línea que incluye mod_evhost en el bloque server.modules y luego añade estas líneas al final del archivo:

$SERVER["socket"] == "192.168.0.181:8000" {
server.document-root = "/home/alexis/example/media"
}

Es algo muy básico pero puedes añadir más opciones luego.

Crea el directorio /home/alexis/example/media, el usuario utilizado por Lighty debe tener permisos de lectura, y copia algunos archivos allí. Ahora a reiniciar Lighty:

lrestart

Ahora abre tu navegador en http://192.168.0.181:8000 y deberías poder ver los archivos de /home/alexis/example/media.

¿Qué tenemos hasta ahora?

Bien, repasemos. Hemos configurado un sitio con Apache y mod_python, http://example.com corriendo en 192.168.0.180. Este es el sitio que será público y que presentará el contenido generado por Django.

También tenemos un sitio listo en Lighty para servir archivos desde http://192.168.0.181:8000, aunque nuestros usuarios no accederán directamente usando esa dirección.

¿Listo? Ok, vamos ahora por el disfraz de mago para continuar con el plan.

Magia negra y mod_python

Llegó la hora de exponer el contenido de Lighty, en http://192.168.0.181:8000, a través de http://example.com/media/. Edita /etc/apache2/sites-available/example.com para que luzca como el ejemplo a continuación:

<VirtualHost 192.168.0.180>
ServerName example.com
ServerAdmin alexis@example.com
DocumentRoot /home/alexis/example/
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On

ProxyRequests Off
ProxyPreserveHost On
ProxyPass /media/ http://192.168.0.181:8000/
ProxyPassReverse /media/ http://192.168.0.181:8000/
ProxyPass /admin-media/ http://192.168.0.181:8000/admin-media/
ProxyPassReverse /admin-media/ http://192.168.0.181:8000/admin-media

</VirtualHost>

Las nuevas líneas están en negritas.

ProxyRequests Off es importante para definir nuestra configuración como un proxy reverso.

Y esta linea:

ProxyPass /media/ http://192.168.0.181:8000/

le dice a Apache: "si un navegador solicita contenido bajo /media/ obtenlo del servidor en http://192.168.0.181:8000", el cual es nuestro humilde y trabajador Lighty.

Finalmente:

ProxyPassReverse /media/ http://192.168.0.181:8000/

se usa para definir los encabezados HTTP correctos. No me pregunten que significa eso pues no estoy seguro.

La misma lógica se aplica para el directorio /admin-media, que usaremos para los archivos del administrador de Django. Volveremos en un momento a este punto.

Bien, ahora solo falta permitir el acceso al proxy a nuestros usuarios. Modifica /etc/apache2/mods-available/proxy.conf como root y modifica el bloque <Proxy *> hasta que quede así:

<Proxy *>
AddDefaultCharset off
Order deny,allow
Deny from all
Allow from all
</Proxy>

Nota que la última línea del bloque debe ser Allow from all o sino tendrás errores de acceso denegado (Forbidden). Si entendí correctamente la documentación de mod_proxy este no es un problema de seguridad porque estamos usando un proxy reverso. Creo que también me podría deshacer de la línea Deny from all porque es anulada inmediatamente pero no causa daño dejarla allí.

Ahora nuevamente al navegador. Abre cualquier archivo desde http://example.com/media como si estuvieras llamando a http://192.168.0.181:8000. Deberías poder ver los archivos que tienes en /home/alexis/example/media, si es así mod_proxy está funcionando correctamente.

Y finalmente

Vamos a completar la configuración del sitio en Apache para llamar a nuestro proyecto Django. Edita /etc/apache2/sites-available/example.com, deberá quedar así:

<VirtualHost 192.168.0.180>
ServerName example.com
ServerAdmin alexis@example.com

<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE project.settings
PythonPath "['/home/alexis/python-work', '/home/alexis/python-work/project'] + sys.path"
</Location>

ProxyRequests Off
ProxyPreserveHost On
ProxyPass /media/ http://192.168.0.181:8000/
ProxyPassReverse /media/ http://192.168.0.181:8000/
ProxyPass /admin-media/ http://192.168.0.181:8000/admin-media/
ProxyPassReverse /admin-media/ http://192.168.0.181:8000/admin-media
</VirtualHost>

He removido la línea apuntando al directorio de documentos, ya no la necesitamos pues todo será dirigido a Django a través de mod_python o a Lighty a través de mod_proxy. También me deshice de las líneas que usamos al principio para probar mod_python.

Ya he escrito sobre PYTHONPATH y Django en Apache por si necesitas refrescar tu memoria sobre el tema.

Recarga Apache y deberías poder ver tu sitio Django en http://example.com/. Contenido dinámico desde Apache con mod_python y archivos desde Lighty. Exquisito.

¡Auxilio! Mi administrador está desnudo

Si estás usando la aplicación de administración de Django en tu proyecto la encontrarás en http://example.com/admin pero es posible que no puedas ver tus tonos pastel favoritos pues te faltan algunos archivos.

¿Recuerdas cuando añadimos /admin-media/ en la configuración de mod_proxy? Eso fue para poder redirigir los pedidos del sitio de administración a sus archivos. Hacen faltan un par de pasos para completar el proceso.

Primero vamos al directorio de tu sitio Lighty, /home/alexis/example/media, y creamos un enlace simbólico al directorio que contiene los archivos de la aplicación de administración:

ln -s /usr/lib/python2.5/site-packages/django/contrib/admin/media/ admin-media

No es necesario ejecutar sudo o ser root para esto pues el enlace se crea en un directorio personal.

La ruta de site-packages/django podría ser diferente en tu servidor, ejecuta esta línea de Python en la consola para obtener la ruta correcta:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

Actualiza settings.py en tu proyecto Django:

ADMIN_MEDIA_PREFIX = '/admin-media/'

Ahora sí, visita http://example.com/admin y podrás disfrutar nuevamente de los grises y azules de la aplicación, y claro, administrar tu sitio también.

El final

Probablemente no soy, aún, un experto configurando proxies y servidores web para aplicaciones Django y ya sabías todo lo que he descrito en este tutorial. Si ese es el caso probablemente tengas sugerencias o correcciones por añadir. Todo aporte es bienvenido.

Si eres como yo y andabas un poco perdido para lanzar tu proyecto Django a la Red espero que todo esté ahora más claro. Y por supuesto, me encantaría saber como te fue.

Y ahora la línea de Murrow: ¡buenas noches y buena suerte!


Viewing all articles
Browse latest Browse all 2