Deploy de proyectos django en VPS con Linux Ubuntu/Debian

  
1 de Octubre de 2014   1  

Actualmente el uso de hosting compartido para las aplicaciones web profesionales está quedando en desuso debido a la limitada configuración permitida y la relación costo beneficio que se ofrece, por otra parte el bajo costo de los servidores privados virtuales (VPS), que te permiten un acceso total via SSH a una máquina con la distribución Linux de nuestra elección, pudiendo configurarla y escalarla a nuestras necesidades. Todo esto ha dado pie a que los desarrolladores se decidan por esta.

 

El siguiente tutorial trata sobre la configuración comúnmente utilizada para poner en producción aplicaciones django; cabe aclarar que esta es una de las muchas opciones disponibles, pero para efectos prácticos y para nuestros proyectos puede ser de mucha utilidad, así que comencemos:

 

Características del VPS:

Proveedor: DigitalOcean (Aqui un link para obtener 10 USD)
SO: Ubuntu 14.04 LTS 64 bits
Características:
20 GB Disco Duro SSD
1 Core
512 mb de RAM
Precio mensual $5 USD.

 

Tecnologías utilizadas:

  • Python
  • Django
  • PostgreSQL
  • Nginx
  • Gunicorn

 

Actualizando Ubuntu:

Una vez autenticados vía ssh en nuestro servidor, ejecutamos los siguientes comandos:
root@miserver:~# sudo apt-get update
root@miserver:~# sudo apt-get upgrade

 

Descargamos e Instalamos pip:

Descargamos el script de instalación con (puedes encontrar la url de descarga en la documentación oficial aquí en caso que la de abajo no funcione ):
root@miserver:~# wget https://bootstrap.pypa.io/get-pip.py

Una vez descargado instalamos con:
root@miserver:~# python get-pip.py

Si deseas, después de la instalación puedes eliminar el script con:
root@miserver:~# rm get-pip.py

 

Instalando virtualenv y preparando nuestro entorno virtual:
Ahora ya que tenemos instalado pip lo usaremos para instalar virtualenv con el siguiente comando:
root@miserver:~# pip install virtualenv

Seguido a esto creamos nuestro nuevo entorno virtual con:
root@miserver:~# virtualenv pythonizame

Nos movemos al nuevo entorno virtual creado y lo activamos:
root@miserver:~# cd pythonizame
root@miserver:~/pythonizame# source bin/activate

Una vez activado el entorno virtual procederemos a instalar Django:
(pythonizame)root@miserver:~/pythonizame# pip install django

Verificamos que django se instaló de forma correcta con:
(pythonizame)root@miserver:~/pythonizame# python
>>> import django
>>> django.get_version()
‘1.7’
>>> exit()

Si nos muestra algo parecido a lo anterior es que tenemos instalado django de forma correcta, si por otra parte nos arroja errores algo no hicimos bien pero no hay nada que google y stackoverflow no solucionen :)

 

Instalando PostgreSQL

Muchos desarrolladores de django prefieren trabajar con PostgreSQL ya que es una base de datos robusta y el ORM de django funciona mucho mejor. (Pero cualquier otra base de datos funcionará sin problemas.)

Desactivamos el entorno virtual con:
(pythonizame)root@miserver:~/pythonizame# deactivate

Instalamos librerías que usará pip más adelante para compilar el paquete para usar PostgreSQL, es muy importante que lo instalemos de primero.
root@miserver:~# sudo apt-get install libpq-dev python-dev

Una vez concluido lo anterior instalamos PostgreSQL con el siguiente comando:
root@miserver:~# sudo apt-get install postgresql postgresql-contrib

Para verificar que se instaló correctamente usamos el siguiente comando:
root@miserver:~# psql --version

Si nos devuelve algo como esto, es que se instaló correctamente:
psql (PostgreSQL) 9.3.5

Ahora procedemos a crear un usuario, crear la base de datos y darle permisos al usuario sobre la nueva base de datos. (apunta el usuario, contraseña y nombre de la base de datos, ya que más adelante son los que usaremos en el settings.py).

Nos cambiamos de usuario a “postgres” (este se crea automáticamente cuando instalamos la base de datos) con:
root@miserver:~# sudo su - postgres

Luego creamos la base de datos:
postgres@miserver:~$ createdb pythonizame_db

Luego ejecutamos el comando para crear un usuario:
postgres@miserver:~$ createuser -P pythonizame

Ahora le damos todos los privilegios sobre la base de datos creada anteriormente con:
postgres@miserver:~$ psql
postgres=# GRANT ALL PRIVILEGES ON DATABASE pythonizame_db TO pythonizame;

Te debe responder lo siguiente:
postgres=# GRANT

Nos salimos con:
postgres=# \q

Y regresamos al usuario root con exit:
postgres@miserver:~/pythonizame$ exit

Seguido a esto activamos de nuevo el entorno virtual e instalamos psycopg2, que es el adaptador por excelencia para que python pueda comunicarse con PostgreSQL:
root@miserver:~/pythonizame# source bin/activate
(pythonizame)root@miserver:~/pythonizame# pip install psycopg2

 

Creando nuestro proyecto django:

Con el entorno virtual activo creamos el proyecto django con el comando que ya conocemos:
(pythonizame)root@miserver:~/pythonizame# django-admin.py startproject pythonizame

Nota: Normalmente nuestro proyecto debe estar en un repositorio así que bastará con hacer un git clone y seguir los mismos pasos.

 

Instalando Gunicorn

Para instalarlo basta con ejecutar el comando:
(pythonizame)root@miserver:~/pythonizame# pip install gunicorn

Con esto tendremos instalado gunicorn en nuestro entorno virtual y estará listo para correr nuestra nueva aplicación.

Si quieres conocer un poco más de gunicorn te recomendamos leer el siguiente post Gunicornescrito por nuestro amigo Diego Arrieta.

 

Instalando Nginx

Nginx es un servidor ligero increíblemente rápido, usado por sitios importantes como WordPress, Netflix, Hulu, GitHub, Ohloh, SourceForge, este lo vamos a ocupar para servir los archivos estáticos y direccionar la ejecución de nuestro proyecto en django que estará corriendo bajo gunicorn.

(pythonizame)root@miserver:~# sudo apt-get install nginx

Una vez terminada la instalación podemos probarla visitando la ip de nuestro servidor desde el explorador web y deberíamos de ver una página que dice Welcome to Nginx! si es así todo salió bien y procederemos al siguiente paso.

 

Recolectando archivos estáticos

Los archivos estáticos son todos aquellos archivos que no cambian o que no se modifican constantemente, como son: librerías de javascript, hojas de estilo, favicons, imágenes utilizadas en los css, etc.

Cuando estamos trabajando en nuestro proyecto el servidor de desarrollo de django maneja los archivos estáticos, pero cuando cambiamos al modo producción y usamos gunicorn esto ya no funciona y como buena práctica se utiliza nginx para este tipo de tareas, es por eso que vamos a hacer uso de un comando que se llama “collectstatic”. Este comando recolectar todos los archivos de forma automática los copia en la ruta que está definida en el settings.py en la variable de configuración STATIC_ROOT (Como es un proyecto nuevo y no tenemos archivos estaticos, solo se copiaran los archivos que utiliza el admin)

En el caso del proyecto creamos la variable en el settings.py y le asignamos la ruta como sigue: STATIC_ROOT=’/opt/statics/pythonizame/’

Nota: La ruta debe ser absoluta y es la que vamos a usar en el archivo de configuración de Nginx en el siguiente paso.

Ya que definimos la ruta en el settings.py, nos pasamos al directorio mencionado y creamos los directorios:

(pythonizame)root@miserver:~/pythonizame# cd /opt
(pythonizame)root@miserver:/opt# mkdir -p statics/pythonizame

Nos cambiamos a la carpeta del proyecto donde está el manage.py y ejecutamos collectstatic:

(pythonizame)root@miserver:~/pythonizame# cd pythonizame
(pythonizame)root@miserver:~/pythonizame/pythonizame# python manage.py collectstatic

Con esto se deben copiar todos los archivos estáticos que utilizamos en el proyecto.

 

Configurando nginx

Lo primero que tenemos que hacer es pasarnos al directorio donde estará nuestro archivo de configuración de nginx que normalmente esta en la ruta /etc/nginx/
(pythonizame)root@kibito:~# cd /etc/nginx/sites-available

Luego creamos un archivo de nombre pythonizame con:
(pythonizame)root@miserver:~# nano pythonizame

En el cual pondremos lo siguiente:

server {
    server_name la.ip.del.vps;
    
    # Log de acceso y errores
    access_log /var/log/nginx/pythonizame.access.log;
    error_log /var/log/nginx/pythonizame.error.log;

    # Ruta absoluta donde django copia los archivos estáticos
    location /static/ {
        alias /opt/statics/pythonizame/;
    }

    location / {
        # Ruta donde correc nuesta proyecto de django con gunicorn
        proxy_pass http://127.0.0.1:8000; 
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 150;
        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
    }
}

Presionamos Ctrl + o para guardar y “Enter”

Luego de esto solo nos faltará crear un enlace simbólico del archivo hacia el directorio sites-enabled:

Nos pasamos al directorio sites-enabled:
(pythonizame)root@miserver:/etc/nginx/sites-available# cd ../sites-enabled

Creamos el enlace simbólico:
(pythonizame)root@miserver:/etc/nginx/sites-enabled# sudo ln -s ../sites-available/pythonizame

Luego eliminamos el archivo default con:
(pythonizame)root@miserver:/etc/nginx/sites-enabled# rm default

Reiniciamos el Nginx con:
(pythonizame)root@kibito:/etc/nginx/sites-enabled# sudo service nginx restart

 

DEBUG = ‘False’. Corriendo nuestra aplicación

Una vez reiniciado Nginx, si nos dirigimos a la ip de nuestro servidor nos mostrará el siguiente mensaje: “502 Bad Gateway” y eso es porque el proyecto aún no está corriendo, para eso tenemos que hacer unos últimos pasos:

Nos movemos al directorio donde se encuentra el settings.py:
(pythonizame)root@kibito:~/pythonizame/pythonizame# cd pythonizame

Y con el editor Nano modificamos el archivo settings.py:
(pythonizame)root@kibito:~/pythonizame/pythonizame/pythonizame# nano settings.py

Cambiamos el valor de DEBUG:
DEBUG = ‘False’

El de ALLOWED_HOSTS:
ALLOWED_HOSTS = [‘127.0.0.1’]

Y por último la base de datos:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'pythonizame_db',
        'USER': 'pythonizame',
        'PASSWORD': 'holamundo',
        'HOST': 'localhost',
        'PORT': '',
    },
}

Una vez modificados los valores guardamos los cambios y nos salimos del archivo.

Regresamos al directorio donde se encuentra el manage.py:
(pythonizame)root@kibito:~/pythonizame/pythonizame/pythonizame# cd ..

Creamos las tablas del proyecto, que en este caso solo serán las del admin porque no tenemos ninguna aplicación creada, que para ejemplo nos sirve a la perfección:
(pythonizame)root@kibito:~/pythonizame/pythonizame# python manage.py migrate

Nota: Si nos arroja el siguiente error: “FATAL: Peer authentication failed for user “postgres”,aquí hay un pequeño tutorial para corregirlo.

Y luego corremos el proyecto en segundo plano con:
(pythonizame)root@kibito:~/pythonizame/pythonizame/pythonizame# gunicorn pythonizame.wsgi:application -w 3 &

Nota: el & al final es para indicar que queremos correr la aplicación en segundo plano, de esta forma cuando cerremos la consola nuestra aplicación quedará corriendo.

Ya con esto debemos poder ir a la IP de nuestro server y entrar al admin para comprobar que todo funciona sin problemas.

Happy Deployment! :)



Alex Dzul

FullStack Python / Django Developer. #jslove

Temas relacionados