miércoles, 12 de septiembre de 2012

Servidor de django con nginx y apache wsgi en debian

Antes que nada, el post original esta acá: http://buala.net/techy/servidor-de-django-con-nginx-y-apache-wsgi-en-debian/  lo copie en mi blog para tenerlo como copia de seguridad ya que me ha sido muy útil. Si el link aun esta activo por favor entren en el post original, el cual por cierto no es mio.

Como siempre, empezaremos con algo de lo que yo llamo “filosofía de funcionamiento” , lo cual resulta útil para entender lo que se está montando.
Suponemos que hemos terminado de desarrollar nuestra aplicación, testeada solo en el entorno de desarrollo ofrecido por django. Lo primero que tenemos que entender, es que necesitamos un servidor web capaz de comunicarse con django, y para este fin ha nacido wsgi.
Web Server Gateway Interface (WSGI)  es un estándar de comunicación que utilizan los servidores web para poder interpretar el código de los frameworks de Python. wsgi tiene una “limitación”, y es que no puede servir el contenido estático (js, imágenes, css,..) solamente se encarga del contenido dinámico. Llegados a este punto vemos que existe una necesidad , la de poder dividir una petición en dos partes, una para que la interprete el servidor web (parte estática) , y otra para pasárselo a WSGI (el contenido dinámico).
Apache es capaz de hacer esto sin mayor complicación, pero desde la web de django también recomiendan que existan dos servidores, uno para el contenido estático y otro para el dinámico.
Instalar dos apaches sería un suicidio en cuanto a recursos, aquí es donde aparece nginx para salvarnos la papeleta.
Nginx es un servidor web con capacidades de proxy inverso, ligero y de alto rendimiento. En el vamos a delegar los trabajos de proxy (Enviar contenido estático a Apache) y de servir contenidos estáticos. Consiguiendo de esta manera quitarle muchísima carga a Apache.
El diagrama de lo que queremos montar sería este:

Una vez explicado esto, ale, al turrón –>

Decidiendo estructura

Lo primero a decidir es donde queremos alojar los proyectos. Se desaconseja encarecidamente colocar los archivos de python dentro de la raiz de nuestro servidor web. Nosotros hemos decidido crear el directorio /var/django para utilizarlo como carpeta de almacenaje de los proyectos. Para esta guía vamos a crear el proyecto “ceia” , que quedaría en /var/django/ceia.
Aparte de los ficheros normales del proyecto, vamos a crear 2 carpetas, una contendrá el fichero de configuración para apache , y la otra albergará los logs tanto de nginx como de apache. Nótese que en nuestro ejemplo, las carpetas con el contenido estático(js,css,imagenes ) están en /var/django/ceia/website/media/
# mkdir -p  /var/django/ceia/b_apache
# mkdir -p /var/django/ceia/b_logs

Configurar Apache con mod_wsgi para Django

Empezamos instalando apache2 y el módulo wsgi
# sudo aptitude install apache2 libapache2-mod-wsgi
Con la instalación por defecto apache está escuchando en el puerto 80 , debemos cambiarlo ya que este es el puerto en el que vamos a poner a escuchar a Nginx. Para ello editamos el fichero  /etc/apache2/ports.conf: y lo dejamos como a continuación: (no entramos en el 443 por simplificar )
# nano  /etc/apache2/ports.conf:
Listen 127.0.0.1:8080
#Listen 80
NameVirtualHost   *:8080
Hemos puesto 127.0.0.1 porque queremos que apache solo acepte peticiones de localhost, pero durante la fase de prueba, esta opción se puede omitir y dejar solo el listen 8080 .
Ahora vamos a crear el fichero de configuración del virtual host de apache para nuestro proyecto, basándonos en el fichero por defecto :
# cp /etc/apache2/sites-available/default  /etc/apache2/sites-available/ceia
Editamos el nuevo fichero, y le modificamos o agregamos los siguientes campos
VirtualHost *:8080
 ServerName tifa.buala.net:8080
 ErrorLog /var/django/ceia/b_logs/error.log
 CustomLog /var/django/ceia/b_logs/access.log combined
 #...
 #Alias /imagenes /var/django/ceia/website/media/imagenes
 #Alias /css /var/django/ceia/website/media/css
 #Alias /js /var/django/ceia/website/media/js
 WSGIDaemonProcess ceia processes=2 maximum-requests=500 threads=10
 WSGIProcessGroup ceia
 WSGIScriptAlias / /var/django/ceia/b_apache/django.wsgi
 
A este fichero le faltan bastantes cosas , pero todas las que nos atañen están aquí, procedemos a explicarlas:
ErrorLog y CustomLog apuntan a nuestra carpeta ceia, así conseguimos un sistema de logs bien ordenadito :-)
#Alias Estos son innecesarios, pero por si en la fase de despliegue queremos que apache interprete el contenido estático, para comprobar que todo va correctamente, ahí las tenemos
WSGIDaemonProcess Datos de configuración del demonio :
user=name nombre del usuario con el que se correrá el proceso
processes=num Número de procesos que se generan
threads=num Número de hilos, por defecto 15maximum-requests=nnn Número de peticiones que acepta el demonio antes de reiniciarse, sirve para evitar leacks de memoria
WSGIProcessGroup El grupo con el que se va a correr el proceso, recomendable un usuario sin privilegios de sistema, por seguridad.
WSGIScriptAlias la ruta hasta el fichero de configuración con los datos de wsgi, ahora lo crearemos
Todas las opciones de configuración del wsgi las podéis ver aquí
Ahora vamos a crear el fichero de configuración de wsgi que hemos mencionado antes.
# nano /var/django/ceia/b_apache/django.wsgi
import os, sys
apache_configuration= os.path.dirname(__file__)
project = os.path.dirname(apache_configuration)
workspace = os.path.dirname(project)
sys.path.append(workspace)
sys.path.append('/var/django')
os.environ['DJANGO_SETTINGS_MODULE'] = 'ceia.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Los parámetros que tenéis que editar son:
sys.path.append(‘/var/django’) sustituir /var/django/ por la ruta hasta la carpeta padre del proyecto
os.environ['DJANGO_SETTINGS_MODULE'] = ‘ceia.settings’ sustituir ceia.settings por nombredepoyecto.ficheroSettings
Con esto ya hemos terminado con la parte de apache, pero no sin  antes habilitar el nuevo vhost y darle un reinicio para comprobar que todo está correcto
# a2ensite ceia
#/etc/init.d/apache2 restart

Instalar y configurar nginx 1.0


Nginx se encuentra en los repositorios de debian, pero desafortunadamente la versión es muy vieja. Si alguien tiene a su abuela en el hospital , y no tiene tiempo para hacer las cosas como dios manda, puede hacer un “aptitude install nginx”, pero para el resto, vamos a bajarnos y compilarnos la versión 1.0, salidita del horno ayer mismo.
Instalamos las herramientas para poder compilar el código fuente de nginx
# aptitude install libpcre3-dev build-essential libssl-dev
Nos descargamos el código fuente , lo descomprimimos en /opt/ y entramos en la carpeta resultante.
# cd /opt/
# wget http://nginx.org/download/nginx-1.0.0.tar.gz
# tar -zxvf nginx-1.0.0.tar.gz
# cd /opt/nginx-1.0.0
Con el código descargado, procedemos a compilarlo e instalarlo.
# ./configure
# make
# make install
Creamos un usuario para que lo utilice nginx como dueño del proceso
# adduser –system –no-create-home –disabled-login –disabled-password –group nginx
Para hacer que se autoarranque el demonio solo , nos descargamos un script para copiarlo en init.d, y configuramos los rc. más info
wget -O init-deb.sh http://library.linode.com/assets/658-init-deb.sh
# mv init-deb.sh /etc/init.d/nginx
# chmod +x /etc/init.d/nginx
# /usr/sbin/update-rc.d -f nginx defaults
# /etc/init.d/nginx start
Quizas se necesite modificar el script de inicio para que la variable DAEMON apunte a  /usr/local/nginx/sbin/nginx    en vez de a  /opt/nginx/sbin/nginx
Como la versión compilada no lo hace por nosotros, vamos a crear un sistema como el de apache de sites-aviable/enabled , para ello creamos las dos carpetas necesarias.
# mkdir /usr/local/nginx/conf/sites-aviable/
# mkdir  /usr/local/nginx/conf/sites-enabled/
Editamos el fichero de configuración de nginx, y lo dejamos parecido a este :
nano  /usr/local/nginx/conf/nginx.conf
user  nginx;
worker_processes  1;
error_log  logs/error.log;
pid        logs/nginx.pid;
events {
       worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip  on;
    include   /usr/local/nginx/conf/sites-enabled/*;
}
Atención al usuario , lo hemos cambiado por el nuevo que acabamos de crear , y a la línea include , donde le decimos donde van a estar las definiciones de los servidores.En este tuto no entraremos en detalles sobre la configuración y blindado de nginx. mas info
Vamos a crear la configuración del servidor ceia :
nano /usr/local/nginx/conf/sites-aviable/ceia
server {
    listen       80;
    server_name  tifa.buala.net;
    access_log  /var/django/ceia/b_logs/nginx_access.log;
    error_log  /var/django/ceia/b_logs/nginx_error.log;
    location / {
        proxy_pass  http://127.0.0.1:8080;
        include    /usr/local/nginx/conf/proxy.conf;
    }
    location ~ /(js/|css/|imagenes/|media).*  {
    root /var/django/ceia/website/media;
    }
    error_page   500 502  503 504  /50x.html;
    location =  /50x.html {
        root    html;
        }
}
Analicemos un poco el fichero:
access_log y error_log Dictaminan donde se guardarán los ficheros, nosotros los dejamos bien ordenaditos cada uno en su aplicación
location / Explica al servidor que la raíz del dominio va a ser enviada al proxy, utilizando un fichero de configuración que ahora crearemos.
location ~ /(js/|css/|imagenes/|media).* Esto le explica que las carpetas /css/ , /js/ , /imagenes/ , van a ser dirigidas a /var/django/ceia/website/media , que es donde cuelgan esas carpetas en el proyecto
Ahora creamos el fichero mencionado en el texto,  /usr/local/nginx/conf/proxy.conf con el siguiente contenido:
proxy_redirect              off;
 proxy_set_header            Host $host;
 proxy_set_header            X-Real-IP $remote_addr;
 proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size        10m;
 client_body_buffer_size     128k;
 proxy_connect_timeout       90;
 proxy_send_timeout          90;
 proxy_read_timeout          90;
 proxy_buffer_size           4k;
 proxy_buffers               4 32k;
 proxy_busy_buffers_size     64k;
 proxy_temp_file_write_size  64k;
De momento copiad el fichero tal cual, no hacen falta sustituciones en las cadenas $host, $….
Para habilitar nuestro nuevo servidor de nginx, tan solo nos queda habilitar nuestro nuevo servidor creando el link a sites-enabled , y reiniciarlo:
# ln -s /usr/local/nginx/conf/sites-aviable/ceia /usr/local/nginx/conf/sites-enabled/
# /etc/init.d/nginx restart
Si fallase, probad primero stop, y luego start, el script no tira muy bien :-(
Para facilitar el acceso a  los ficheros de configuración generamos el siguiente link
ln -s /usr/local/nginx/conf/ /etc/nginx
Con todo esto ya tenemos prácticamente todo listo y funcionando, solo nos queda habilitar el contenido estático para la parte de administración de django.Este punto puede diferir dependiendo de las diferentes versiones.
# ln -s /usr/share/python-support/python-django/django/contrib/admin/media/ /var/django/ceia/website/media/media
Y bualá, ya tenemos todo funcionando de manera segura y eficiente.