Configurar Django con Postgres, Nginx, y Gunicorn en Ubuntu 16.04

Empecemos por el principio, ¿qué es Django?

Django es un web framework que te puede ayudar a que una aplicación Python o tu website despegue. Django incluye un servidor de desarrollo simplificado para probar el código de forma local, pero para cualquier servicio en producción se requiere un servidor web más seguro y potente.

En este post te vamos a contar cómo instalar y configurar algunos componentes en Ubuntu 16.04 para apoyar y servir aplicaciones Django. Por un lado, vamos a crear una base de datos PostgreSQL y configuraremos el servidor de aplicaciones Gunicorn para interactuar con nuestras aplicaciones. Después, configuraremos Nginx como proxy inverso para Gunicorn, lo que nos dará acceso a sus características de seguridad y rendimiento para servir nuestras aplicaciones.

Sí, ya sabemos que es un poco de trabajo, pero ya verás cómo una vez hecho, estarás muy satisfecho con el resultado :)

Nota

El primer requisito para que este post te sirva es que tu Servidor VPS debe ser una instalación limpia, es decir, que debe estar recién instalado sólo con Ubuntu 16.04, y tener un usuario que no sea root, con privilegios de “sudo”.

Bueno, pues ahora es cuando nos ponemos manos a la obra.

Instalar los paquetes de los repositorios de Ubuntu.

Para comenzar el proceso, tendrás que descargar e instalar todos los elementos que necesitas de los repositorios de Ubuntu. Después utilizaremos también el gestor de paquetes pip de Python para instalar componentes adicionales.

Para ello, tendrás que actualizar el índice de paquetes apt local y luego descargar e instalar los paquetes. Los paquetes que instales dependerán de la versión de Python que vaya a utilizar tu proyecto.

Si estás usando Python 2, deberás lanzar los comandos:

  • sudo apt-get update
  • sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx

Si, por el contrario, lo que estás utilizando es Django con Python 3, debrás introducir:

  • sudo apt-get update
  • sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx

Esto instalará pip, los archivos de desarrollo Python necesarios para instalar Gunicorn más tarde, el sistema Postgres de base de datos, y las librerías necesarias para interactuar con él, y el servidor web Nginx.

Crear la base de datos PostgreSQL y usuarios.

Ahora vamos a crear la base de datos, y el usuario de la base de datos, para nuestra aplicación de Django.

Por defecto, PostgreSQL utiliza un esquema de autenticación llamado “peer authentication” para conexiones locales. Básicamente, esto significa que si el nombre de usuario del sistema operativo usuario coincide con un nombre de usuario Postgres válido, este usuario puede iniciar sesión sin autenticación adicional.

Durante la instalación de Postgres, un usuario del sistema operativo llamado postgres es creado para corresponder al usuario administrativo de PostgreSQL. Tienes que utilizar este usuario para realizar tareas administrativas. Puedes usar “sudo” y entrar en el nombre de usuario con la opción “-u”.

Inicia sesión en una sesión interactiva de Postgres escribiendo:

sudo -u postgres psql

Ahora te aparecerá un prompt de PostgreSQL, donde podrás configurar tus requisitos.

Primero, crea una base de datos para tu proyecto:

CREATE DATABASE miproyecto;

Nota

Cada frase de Postgres debe terminar con un punto y coma, así que asegúrate de que el comando finaliza con uno si estás teniendo problemas.

El siguiente paso será crear un usuario de base de datos para el proyecto.

Aviso importante

¡Asegúrate de configurar un password seguro! De lo contrario, esto puede ser un grave agujero en tu seguridad. Aquí te dejamos una guía de contraseñas seguras que creemos que te vendrán muy bien:

Guía de contraseñas seguras

CREATE USER usuariomiproyecto WITH PASSWORD ‘contraseña’

A continuación, tienes que modificar algunos de los parámetros de conexión para el usuario que acabas de crear. Esto acelerará las operaciones de base de datos de modo que los valores correctos no tengan que ser consultados y configurados cada vez que se establezca una conexión.

Tienes que establecer la codificación por defecto a UTF-8, que es la que Django espera. También tienes que establecer el régimen de aislamiento de las transacciones de “read committed”, el cual bloquea la lectura de transacciones no confirmadas. Por último, tendrás que establecer la zona horaria.

De forma predeterminada, se establecerán los proyectos de Django para usar UTC. Éstas son todas las recomendaciones del propio proyecto de Django:

  • ALTER ROLE usuariomiproyecto SET client_encoding TO ‘utf8′;
  • ALTER ROLE usuariomiproyecto SET default_transaction_isolation TO ‘read committed';
  • ALTER ROLE usuariomiproyecto SET timezone TO ‘UTC';

Ahora le puedes dar acceso a tu nuevo usuario para administrar tu nueva base de datos:

 GRANT ALL PRIVILEGES ON DATABASE miproyecto TO usuariomiproyecto;

Cuando hayas terminado, sal de PostgreSQL prompt escribiendo “\q”

Crear un Entorno Virtual de Python para tu proyecto

Ahora que ya tienes tu base de datos, puedes trabajar en el resto de requisitos necesarios para dejar el proyecto listo. Vamos a instalar los requisitos de nuestro Python dentro de un entorno virtual para hacer la gestión más fácil.

Para hacer esto, lo primero que necesitas es acceso al comando virtualenv. Puedes instalarlo con pip.

Si estás utilizando Python 2, deberás usar el comando:

  • sudo pip install virtualenvSi estás utilizando Python 3, será:
  • sudo pip3 install virtualenv

Con virtualenv instalado, puedes empezar a formar tu proyecto. Crea el directorio donde guardar los archivos de tu proyecto, y accede a él:

  • mkdir ~/miproyecto
  • cd ~/miproyecto

Dentro del directorio del proyecto, crea un entorno virtual de Python con el comando:

virtualenv miproyectoentorno

Esto creará un directorio llamado “miproyectoentorno” dentro del directorio “miproyecto”. Dentro, éste instalará una versión local de Python y una versión local de pip. Puedes utilizar esto para instalar y configurar un entorno aislado para el proyecto.

Antes de instalar los requisitos de Python para tu proyecto, deberemos activar el entorno virtual. Esto lo puedes hacer escribiendo:

source miproyectoentorno/bin/activate

El prompt debería cambiar para indicar que ahora estás operando dentro de un entorno virtual de Python. Debería verse más o menos así:

 (miproyectoentorno)user@host:~/miproyecto$.

Con el entorno virtual activo, instalaremos Django, Gunicorn, y el adaptador psycopg2 de PostgreSQL adaptor con la instancia local de pip:

pip install django gunicorn psycopg2

Nota

Independientemente de la versión de Python que estés utilizando, cuando se activa el entorno virtual, se debe utilizar el comando de pip (no PIP3)

Crear y configurar un nuevo proyecto de Django

Con los componentes de Python instalados, puedes crear los ficheros de nuestro proyecto de Django.

Crear el proyecto Django

Como ya tienes un directorio del proyecto, tienes que decirle a Django que instale los archivos en el mismo. Esto creará otro directorio dentro del principal con el código real, lo cual es normal, y colocará un script de gestión en este directorio. La clave para esta acción es el punto al final del comando, que le dirá a Django que cree los archivos en el directorio actual:

django-admin.py startproject miproyecto.

Ajustar las configuraciones del proyecto

Lo primero que debes hacer con tus recién creados archivos de proyecto, es ajustar las configuraciones. Abre el archivo de configuración con un editor de texto:

nano miproyecto/settings.py

Primero debes encontrar la sección que configura el acceso de base de datos. Ésta empezará por DATABASES. La configuración en el archivo es para una base de datos SQLite. Ya hemos creado una base de datos PostgreSQL para nuestro proyecto, por lo que necesitamos ajustar la configuración.

Cambia la configuración con la información de la base de datos PostgreSQL. Después le tienes que decir a Django que use el adaptador psycopg2adaptor que has instalado con pip. Tienes que darle el nombre, el usuario, y la contraseña de la base de datos, y después indicar que la base de datos se encuentra en local. Puedes dejar el punto PORT como un string vacío:

~/miproyecto/miproyecto/settings.py

  . . .
  
  DATABASES = {
        'default': {
                  'ENGINE': 'django.db.backends.postgresql_psycopg2',
                   'NAME': 'miproyecto',
                   'USER': 'usuariomiproyecto',
                   'PASSWORD': 'contraseña',
                   'HOST': 'localhost',
                   'PORT': '',
         }
  } 
  . . .

Lo siguiente será será ir a la parte final del fichero, y añadir el valor donde se deberán guardar los archivos estáticos. Esto es necesario para que Nginx pueda gestionar las peticiones para estos objetos. La siguiente línea le dice a Django que las ponga en un directorio llamado “static”, en el directorio base del proyecto:

~/miproyecto/miproyecto/settings.py

. . .

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

Guarda y cierra el archivo cuando hayas finalizado los cambios.

Completar la configuración inicial del proyecto

Ahora, podemos migrar el esquema de base de datos inicial a nuestra base de datos PostgreSQL usando el script de gestión:

cd ~/miproyecto

./manage.py makemigrations

./manage.py migrate

Crea un usuario administrativo para el proyecto escribiendo:

./manage.py createsuperuser

Tendrás que seleccionar un nombre de usuario, proporcionar una dirección de correo electrónico, y seleccionar y confirmar una contraseña.

Podrás recoger todo el contenido estático en la ubicación del directorio que has configurado escribiendo:

./manage.py collectstatic

Tendrás que confirmar esta operación. Los archivos estáticos se guardarán en un directorio llamado “static” dentro del directorio del proyecto.

Para poder hacer ahora las pruebas, será necesario que el puerto 8000 esté abierto en tu servidor. Comprueba si el puerto ya está abierto para tu servidor, y en caso de que no sea así, ábrelo siguiendo este otro artículo de nuestra base de conocimiento:

Administrar reglas de un perfil de Firewall del panel de Clouding.io

Una vez que el puerto esté abierto, podrás probar el proyecto iniciando el servidor de desarrollo de Django con el comando:

./manage.py runserver 0.0.0.0:8000

Ahora para comprobarlo debes acceder a través de cualquier navegador a tu dominio, o la IP de tu servidor, seguido del puerto 8000:

http://IP.DE.TU.SERVIDOR:8000

Deberías ver la página por defecto de Django:

django_index

Si añades /admin al final de la dirección URL en la barra de direcciones, podrás acceder con el nombre de usuario administrativo y la contraseña que hsa creado con el comando “createsuperuser”

admin_login

Después de autenticarte, podrás acceder a la interface de administración por defecto de Django:

admin_interface

Cuando hayas terminado de explorar la interface, haz “CTRL+C” en la ventana de la consola de tu servidor para detener el servidor de desarrollo.

Probar la capacidad de Gunicorn de servir el proyecto

La última cosa que queremos hacer antes de salir del entorno virtual, es probar Gunicorn para asegurarnos de que puede servir la aplicación. Podemos hacer esto fácilmente escribiendo:

cd ~/miproyecto

gunicorn –bind 0.0.0.0:8000 miproyecto.wsgi:application

Esto iniciará Gunicorn en la misma interfaz que en la que el servidor de desarrollo de Django se ejecuta. Puedes volver atrás y probar la aplicación de nuevo. Ten en cuenta que la interfaz de administración no tendrá ningún estilo aplicado, ya que Gunicorn no sabe sobre el contenido estático responsable de esto.

Le has pasado a Gunicorn un módulo mediante la especificación de la ruta relativa del archivo wsgi.py de Django, que es el punto de entrada a nuestra aplicación, usando la sintaxis del módulo de Python. Dentro de este archivo, una función llamada “application” es definida, la cual se utiliza para comunicarse con la aplicación.

Cuando hayas finalizado la prueba, haz “CTRL-C” en la ventana de la consola de tu servidor para detener Gunicorn.

Ahora ya has finalizado la configuración de la aplicación Django. Puedes salir del entorno virtual escribiendo: “deactivate”

Crear un archivo de servicio de systemd de Gunicorn

Ya has probado que Gunicorn puede interactuar con la aplicación Django, pero es necesario implementar una forma más robusta de iniciar y detener el servidor de la aplicación. Para conseguir esto, debes crear un archivo de servicio de systemd.

Crea y abre un archivo de servicio de systemd para Gunicorn con privilegios sudo en con un editor de texto:

sudo vi /etc/systemd/system/gunicorn.service

Inicia con la sección [Unit], la cual es usada para especificar metadata y dependencias. Pon una descripción de tu servicio aquí y dile al init system que sólo inicie esto después  de que el destino de red haya sido alcanzado:

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
After=network.target

Lo siguiente será abrir la sección [Service]. En ella especificaremos el usuario y grupo en el que queremos que corra el proceso. Debes indicar tu usuario de acceso regular, ya que es el propietario de todos los archivos relevantes. Por grupo, indica “www-data” para que Nginx pueda comunicarse fácilmente con Gunicorn.

A continuación tendrás que mapear el directorio de trabajo, y especificar el comando que utilizarás para iniciar el servicio. En este caso, tienes que especificar la ruta completa al ejecutable de Gunicorn, el cual está instalado dentro del entorno virtual. Tienes que enlazarlo al socket de Unix dentro del directorio del proyecto, ya que Nginx está instalado en el mismo servidor. Esto es más seguro y rápido que utilizar un puerto de red. También es posible especificar cualquier ajuste opcional de Gunicorn aquí. Por ejemplo, a continuación hemos especificado 3 procesos de trabajo:

/etc/systemd/system/gunicorn.services

[Unit]
Description=gunicorn daemon
After=networking.target

[Service]
User=finn
Group=www-data
WorkingDirectory=/home/finn/miproyecto
ExecStart=/home/finn/miproyecto/miproyectoentorno/bin/gunicorn --workers 3 --bind unix:/home/finn/miproyecto/miproyecto.sock miproyecto.wsgi:application

Por último, debes añadir la sección [Install]. Esto le dirá al sistema a qué debe enlazar el servicio si eres capaz de iniciarlo en el arranque. Este servicio debe iniciarse cuando el sistema multi-usuario regular esté encendido y funcionando:

/etc/systemd/system/gunicorn.services

[Unit]
Description=gunicorn daemon
After=networking.target

[Service]
User=finn
Group=www-data
WorkingDirectory=/home/finn/miproyecto
ExecStart=/home/finn/miproyecto/miproyectoentorno/bin/gunicorn --workers 3 --bind unix:/home/finn/miproyecto/miproyecto.sock miproyecto.wsgi:application
[Install]  WantedBy=multi-user.target

Con esto, tu archivo de servicio de systemd estará completo. Guárdalo y ciérralo. Ahora puedes iniciar el servicio de Gunicorn que has creado y habilitado para que se inicie en el arranque:

  • sudo systemctl start gunicorn
  • sudo systemctl enable gunicorn

Configurar Nginx en Proxy Pass para Gunicorn

Ahora que Gunicorn está configurado, tendrás que configurar Nginx para pasar tráfico al proceso.

Empieza creando y abriendo un nuevo bloque de servidor en el directorio sites-available de Nginx:

sudo vi /etc/nginx/sites-available/miproyecto

Dentro del fichero debes abrir un nuevo bloque de servidor. Empieza especificando que este bloque debe escuchar el puerto 80, y que debe responder al nombre de dominio de nuestro servidor, o a la dirección IP:

/etc/nginx/sites-available/miproyecto

server {
    listen 80;
    server_name server_domain_or_IP;
}

A continuación, tienes que decir a Nginx que ignore cualquier problema encontrando un favicon. También debes indicar dónde encontrar los archivos estáticos que has guardado en el directorio ~/miproyecto/static . Todos estos archivos tienen un prefijo URI estándar “/static”, por lo que puedes crear un bloque de localización para coincida con esas peticiones:

/etc/nginx/sites-available/miproyecto

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/finn/miproyecto;
    }
}

Para finalizar, debes crear un bloque location / {} , para que coincida con todas nuestras otras solicitudes. Dentro de esta localización, incluiremos el archivo estándar de proxy_params incluído con la instalación de Nginx, y entonces pasaremos el tráfico al socket que nuestro proceso de Gunicorn ha creado:

/etc/nginx/sites-available/miproyecto

server {
    listen 80;
    server_name server_domain_or_IP;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/finn/miproyecto;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix/home/finn/miproyecto/miproyecto.sock;
    }
}

Guarda y cierra el archivo cuando hayas finalizado. Ahora puedes habilitar el archivo enlazándolo al directorio sites-enabled:

sudo ln -s /etc/nginx/sites-available/miproyecto /etc/nginx/sites-enabled

Prueba tu configuración de Nginx para buscar errores de sintaxis con el comando:

sudo nginx -t

Si no aparece ningún error, reinicia Nginx:

sudo systemctl restart nginx

Por último, es necesario abrir el firewall del servidor para el tráfico regular en el puerto 80 si esto no estuviera hecho. Como ya no necesitamos acceso al servidor de desarrollo, puedes eliminar la regla del puerto 8000 que habías creado antes.

Ahora deberías poder ir a tu dominio, o la IP de tu servidor, y ver tu aplicación.

Para comentar sobre este artículo, rellena el formulario. Los campos marcados con un asterisco (*) son obligatorios.


*

Comentarios de los visitantes
  1. Comentario (Publicado por alberto)

    Hola, estoy siguiendo los pasos, llego a la instalación de gunicorn, cuando lo pruebo no levanta el servidor:
    gunicorn -bind 0.0.0.0:8000 soporte.wsgi:application
    El error
    [ERROR] Retrying in 1 second
    Estoy utilizando ubuntu 16.4

    Saludos

    Responder

    • Comentario (Publicado por cldn-kb-admin)

      Hola Alberto,

      En principio 0.0.0.0 es para indicar todas las IPs, pero has probado a indicar la IP a la que quieres vincular el servicio en lugar de utilizar 0.0.0.0 ?

      Un saludo!

      Responder