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