Configurando DJANGO stack en CentOS6

Configuración de Django en CentOS6.x con NGINX, GUNICORN, VIRTUALENV y SUPERVISOR

preinstalacion

Instalamos los siguientes paquetes para compilaciones. Es de utilidad en algunos paquetes que instalemos dentro de PIP y los archivos de desarrollo de python.

$ yum install gcc make python-devel

pip, virtualenv

Instalamos PIP desde los repositorios EPEL

$ yum -y install python-pip --enablerepo epel

Instalamos virtualenvwrapper desde PIP, este instalara como dependencia a virtualenv.

$ pip install virtualenvwrapper

Creamos nuestras variables de sistema para virtualenv y lo alojamos en el archivo de configuración bash del usuario unix.

$ touch /etc/profile.d/virtualenv.sh
$ echo 'export WORKON_HOME=/opt/virtualenvs' >> /etc/profile.d/virtualenv.sh
$ echo 'export VIRTUALENVWRAPPER_HOOK_DIR=$WORKON_HOME/hooks' >> /etc/profile.d/virtualenv.sh
$ echo 'source /usr/bin/virtualenvwrapper.sh' >> /etc/profile.d/virtualenv.sh

Necesitamos reiniciar la sesión de sistema ó cargar las variables de entorno a la sesion actual con source

$ source /etc/profile.d/virtualenv.sh

Se verifica si tenemos nuestras variables de entorno cargadas.

$ env | grep -P 'VIRTUALENVWRAPPER|WORKON_HOME'
VIRTUALENVWRAPPER_PROJECT_FILENAME=.project
WORKON_HOME=/opt/virtualenvs
VIRTUALENVWRAPPER_HOOK_DIR=/opt/virtualenvs/hooks

Creamos la carpeta para HOOKs.

$ mkdir -p /opt/virtualenvs/hooks

Creamos un entorno virtual de prueba

$ mkvirtualenv projectwebapp

Salimos del entorno virtual

(projectwebapp)$ deactivate

django

Creamos una carpeta donde alojaremos nuestros proyectos Django y nos cambiamos al directorio.

$ mkdir /home/www/
$ cd /home/www

Habilitamos el entorno virtual para el proyecto

www $ workon projectwebapp

Instalamos Django desde PIP y creamos un proyecto Django

(projectwebapp) www $ pip install django
(projectwebapp) www $ django-admin.py startproject projectwebapp
(projectwebapp) www $ cd projectwebapp/

Iniciamos el servicio http de Django nativo para probar que todo este funcional hasta este punto.

(projectwebapp) projectwebapp $ python manage.py runserver
Validating models...
0 errors found
October 15, 2013 - 13:54:33
Django version 1.5.4, using settings 'projectwebapp.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Detenemos el servicio Django con el atajo de teclado CONTROL-C.

gunicorn. python wsgi http server

Instalamos gunicorn via PIP dentro del entorno virtual del proyecto. También se instala setproctitle que nos permite renombrar el proceso gunicorn por el nombre del proyecto Django.

(projectwebapp) projectwebapp $ pip install gunicorn setproctitle

Estando en la carpeta del proyecto iniciamos el proyecto con gunicorn usando el modulo UWSGI del proyecto Django.

(projectwebapp) projectwebapp $ gunicorn projectwebapp.wsgi
[13252] [INFO] Starting gunicorn 18.0
[13252] [INFO] Listening at: http://127.0.0.1:8000 (13252)
[13252] [INFO] Using worker: sync
[13257] [INFO] Booting worker with pid: 13257

Detenemos el servicio Gunicorn con el atajo de teclado CONTROL-C.

Salimos del entorno virtual

(projectwebapp)[root@websrv1 projectwebapp]# deactive

Creamos el directorio donde alojaremos el script bash que nos iniciara el Gunicorn, debemos tener creado antes el directorio /opt/gunicorn/ para alojar mas proyectos.

$ mkdir /opt/gunicorn/projectwebapp/

Creamos y editamos el archivo script para ejecutar el proyecto con gunicorn

$ vim /opt/gunicorn/projectwebapp/gunicorn_start.sh
#!/bin/bash

DJANGODIR=/home/www/projectwebapp             # Directorio del proyecto Django
SOCKFILE=/var/run/gunicorn/projectwebapp.sock # Unix socket
USER=nginx                                    # Usuario
GROUP=root                                    # Grupo
NUM_WORKERS=3                                 # Numero de procesos para gunicorn
DJANGO_SETTINGS_MODULE=projectwebapp.settings # Archivo settings del proyecto
DJANGO_WSGI_MODULE=projectwebapp.wsgi         # Modulo WSGI del proyecto


# Activar el entorno virtual
cd $DJANGODIR
source /usr/bin/virtualenvwrapper.sh
workon projectwebapp
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Crear el directorio del socket si no existe
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Iniciar el proyecto Django
# No se usa el modo --daemon ya que este sera manejado por supervisor
exec gunicorn ${DJANGO_WSGI_MODULE} \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --log-level=debug \
  --bind=unix:$SOCKFILE

Ajustamos los permisos de ejecucion

$ chmod u+x /opt/gunicorn/projectwebapp/gunicorn_start.sh

supervisor.

Instalamos la mas reciente versión de supervisor desde PIP.

$ pip install supervisor

Creamos el archivo de configuración.

$ echo_supervisord_conf > /etc/supervisord.conf

Creamos la carpeta de logs.

$ mkdir /var/log/supervisor

Configuramos los siguientes parámetros.

$ vim /etc/supervisord.conf
# Modifique las siguientes configuraciones
[unix_http_server]
...
file=/var/run/supervisor.sock
...

[supervisord]
...
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
umask=022
user=root
...

Creamos el script para supervisor que ejecutara el servicio como daemon y auto inicio con el sistema. Este es una adaptación propia del script de Mike McGrath mmcgrath@redhat.com

$ vim /etc/init.d/supervisord
#!/bin/bash
#
# supervisord   This scripts turns supervisord on
#
# chkconfig:  - 95 04
#
# processname:  supervisord
# config: /etc/supervisord.conf
#

# source function library
. /etc/rc.d/init.d/functions

RETVAL=0
conffile=${CONFFILE-/etc/supervisord.conf}
user=${USER-root}

start() {
        echo -n $"Starting supervisord: "
        runuser -l ${user} -c "supervisord -c ${conffile}" && echo_success || echo_failure
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/subsys/supervisord
}

stop() {
  echo -n $"Stopping supervisord: "
  killproc supervisord
  echo
  [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/supervisord
}

restart() {
  stop
  start
}

case "$1" in
  start)
  start
  ;;
  stop)
  stop
  ;;
  restart|force-reload|reload)
  restart
  ;;
  condrestart)
  [ -f /var/lock/subsys/supervisord ] && restart
  ;;
  status)
  status supervisord
  RETVAL=$?
  ;;
  *)
  echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
  exit 1
esac

exit $RETVAL

Damos de alta nuestro script como servicio.

$ chkconfig --add supervisord

Lo agregamos al inicio de sistema con el runrevel por defecto.

$ chkconfig supervisord on

Iniciamos el servicio.

$ service supervisord start

Configuramos una instancia de programa agregando nuestro script gunicorn que ejecuta nuestra app Django.

$ vim /etc/supervisord.conf
# Agregue este bloque de configuracion segun su proyecto
[program:projectwebapp]
command=/opt/gunicorn/projectwebapp/gunicorn_start.sh
user=root
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/projectwebapp.log
redirect_stderr=True

Reiniciamos supervisor

$ service supervisord restart

nginx. http server

Instalamos la repo NGINX oficial.

$ touch /etc/yum.repos.d/nginx.repo
$ vim /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1

Instalamos nginx, los agregamos al inicio de sistema e iniciamos.

$ yum install nginx
$ chkconfig nginx on
$ service nginx start

Creamos las carpetas donde alojamos configuración de los sitios.

$ mkdir /etc/nginx/sites-available
$ mkdir /etc/nginx/sites-enabled
$ mkdir /var/log/nginx/sites

Creamos un respaldo de la configuración global y aplicamos las configuraciones siguientes para el servicio.

$ cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.old
$ vim /etc/nginx/nginx.conf
user  nginx;
# Numero de CPUs
worker_processes  2;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    ## Optimiza el rendimiento de sendfile al enviar tramas HTTP
    ## en un solo paquete.
    tcp_nopush     on;
    ## Soporte gzip. Reduce la cantidad de datos a transferir
    gzip  on;

    ## Configuracion de buffers
    client_body_buffer_size  1K;
    client_header_buffer_size 1k;
    client_max_body_size 1k;
    large_client_header_buffers 2 1k;

    ## Configuracion de timeouts
    client_body_timeout   10;
    client_header_timeout 10;
    keepalive_timeout     5 5;
    send_timeout          10;

    include /etc/nginx/conf.d/*.conf;

    ## Directorio de configuracion para vhost's en linea
    include /etc/nginx/sites-enabled/*.conf;
}

Agregamos la ip 127.0.0.1 para escucha solo local del sitio default, también podemos borrar este archivo si quieren des-habilitar completamente.

$ vim /etc/nginx/conf.d/default.conf
server {
    listen       127.0.0.1:80;

Creamos y configuramos el sitio para nuestro proyecto projectwebapp de la siguiente manera.

$ vim /etc/nginx/sites-available/projectwebapp.conf
# Configuracion NGINX para projectwebapp
#
upstream projectwebapp {
  server unix:/var/run/gunicorn/projectwebapp.sock fail_timeout=0;
}

server {
    listen       10.0.0.23:80;

    # Configuracion HTTPS
    # listen       10.0.0.23:443 ssl;

    server_name  app.example.com;
    server_tokens off;

    access_log  /var/log/nginx/sites/projectwebapp.access.log;
    error_log  /var/log/nginx/sites/projectwebapp.error.log;

    # Limite subidas de archivos.
    client_max_body_size 1M;

    # Acceso solo por medio del dominio
    if ( $host !~ ^(app.example.com)$ ) {
         return 444;
    }
    # Metodos http permitidos
    if ($request_method !~ ^(GET|HEAD|POST)$ ) {
         return 444;
    }
    # Directorio para STATIC
    location /static/ {
            alias /home/www/projectwebapp/projectwebapp/static/;
    }
    # Directorio para MEDIA
    location /media/ {
            alias /home/www/projectwebapp/projectwebapp/media/;
    }

    location / {

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Configuracion HTTPS
        #proxy_set_header X-Forwarded-Proto https;

        proxy_set_header Host $http_host;
        proxy_redirect off;

        if (!-f $request_filename) {
            proxy_pass http://projectwebapp;
            break;
        }
    }

   # Paginas de error
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /home/www/projectwebapp/templates/;
    }
    error_page 404 /404.html;
    location = /404.html {
        root /home/www/projectwebapp/templates/;
    }

}

Habilitamos nuestro archivo de sitio

$ ln -s /etc/nginx/sites-available/projectwebapp.conf /etc/nginx/sites-enabled/projectwebapp.conf

Reiniciamos nginx

$ service nginx restart

iptables. firewall

No olvidar abrir los respectivos puertos que usara nginx para darle salida a nuestros sitios.

$ vim /etc/sysconfig/iptables
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
$ service iptables restart

Armando Uch

An Accidental Engineer
• Lazy #Programmer • #TacOps 🌮 • #BOFH
🎸⚾️🍺☕️


2013-10-15