77

¿Cómo llevar Django a producción?

175649Puntos

hace 6 años

Uno de los aspectos más importantes en el ciclo de vida de cualquier aplicación web es llevarla a producción. Es una parte fundamental y en algunas ocasiones poco documentada por la gran cantidad de configuraciones posibles que existen.

Django es un framework para desarrollo web pero hay muy poca información relacionada sobre como hacer despliegue o deploy (en ingles). Voy a explicar cómo llevar a producción una aplicación hecha en Django usando** Nginx** como servidor web y una base de datos PostgreSQL.

Siguiendo estos pasos se pueden hacer despliegues sin problema en AWS, Digital Ocean o cualquier otro servicio de VPS con algunos cambios dependiendo de la infraestructura.

Para hacer un deploy de Django por su estructura es necesario que se tenga acceso via ssh por lo cual es muy difícil que un hosting compartido tenga soporte para hacer despliegue de estas aplicaciones.

En este despliegue, vamos a usar Ubuntu server 16.04, la última versión LTS. Si no tienes conocimientos sobre administración es recomendable que tomes el curso de administración de servidores linux y el curso de introducción a la terminal y línea de comandos.

Actualizar el servidor

Una vez tenemos nuestro servidor corriendo y estamos en la terminal, procedemos a actualizar el servidor e instalar los paquetes necesarios para realizar el despliegue ejecutando los siguientes comandos:

sudo apt-getupdate
sudo apt-get upgrade

Instalando paquetes necesarios

Luego vamos a instalar Nginx, PostgreSQL, Git y Supervisor, como se mencionó Nginx es nuestro servidor web, PostgreSQL es nuestro motor de base de datos y Supervisor va a ser el encargado de mantener nuestro servicio de la aplicación corriendo y si llega a fallar iniciar nuevamente el servicio de forma automática. Git nos permite conectarnos al repositorio remoto y traer nuestra aplicación desarrollada en Django.

¿Qué es y para que sirve Git?

sudo apt-get install nginx postgresql postgresql-contrib supervisor

Ya tenemos lo básico instalado para iniciar nuestro despliegue en el servidor, adicional a esto necesitamos instalar un par de cosas como es un entorno virtual y gunicorn. Gunicorn es un servidor de aplicaciones que nos permite conectar por medio de sockets nuestra aplicación Django con Nginx para que pueda ser utilizada.

Instalamos virtualenvwrapper (es mi recomendación personal)

sudo pip install virtualenvwrapper

Creando el entorno virtual

Creamos un entorno virtual usando Python 3 como versión de entorno virtual

mkvirtualenv miapp --python=$(which python3)

Para verificar que estamos en el entorno virtual

workonmiapp

Usando Git para traer nuestro proyecto

Vamos a traer nuestro código del repositorio remoto para esto procedemos a crear una carpeta para guardar el código en la carpeta de nuestro usuario, Es recomendable no usar nunca el usuario root como usuario principal ya que tiene implicaciones de seguridad vamos a la carpeta del usuario y creamos una carpeta llamada myapp y nos movemos a la carpeta.

cd ~
mkdir myapp
cd myapp

Traemos nuestro repositorio usando git

git clone<url repo>

Instalando las dependencias de la aplicación

Algo muy importante es instalar todos las dependencias de nuestro proyecto en el entorno virtual, par esto vamos a ejecutar

pip install -r <path requirements.txt>

Configurando PostgreSQL

Vamos a configurar el motor de PostgreSql. Si quieres aprender más sobre la administración de PostgreSQL te recomiendo el curso de PostgreSQL

A continuación cremos un user llamado myapp sin permisos de superusuario sin capacidad de crear bases de datos. Sólo le vamos a asignar una base de datos también llamada myappdb para que pueda usarla este usuario

$ sudo su - postgres
postgres@server:~$ createuser --interactive -P
Enter name of role toadd: myapp
Enter password fornew role: 
Enter it again: 
Shall thenew role be a superuser? (y/n) n
Shall thenew role be allowed tocreate databases? (y/n) n
Shall thenew role be allowed tocreate more new roles? (y/n) n
postgres@server:~$

postgres@server:~$ createdb --owner myapp myappdb
postgres@server:~$ logout
No olvides cambiar los settings de tu aplicación de django para conectarse a la base de datos con la información que acabas de usar para poder conectar de manera correcta la aplicación a la base de datos.

Una vez realizado los cambios puedes correr el comando para ejecutar las migraciones.

cd ~/myapp
./manage.py migrate

Configurando Gunicorn

En este punto creamos un script llamado start.sh dentro de una carpeta llamada bin que va a estar dentro de nuestro directorio que creamos al clonar el repositorio, el script está comentado explicando que hace cada linea

#!/bin/bash

NAME="myapp" # Nombre dela aplicación
DJANGODIR=/home/<user>/myapp # Ruta dela carpeta donde esta la aplicación reemplazar <user> con el nombre de usuario
SOCKFILE=/home/<user>/run/gunicorn.sock # Ruta donde se creará el archivo de socket unix para comunicarnos
USER=<user> # Usuario con el que vamos a correr laapp
GROUP=<groupe> # Grupo con el quese va a correr laapp
NUM_WORKERS=3 # Número de workers quese van a utilizar para correr la aplicación
DJANGO_SETTINGS_MODULE=myapp.settings # ruta de los settings
DJANGO_WSGI_MODULE=myap.wsgi # Nombre del módulo wsgi

echo "Starting $NAME as `whoami`"

# Activar el entorno virtual
cd$DJANGODIR
workon miapp 
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

# Crear la carpeta run si no existe para guardar el socket linux
RUNDIR=$(dirname $SOCKFILE)
test -d$RUNDIR || mkdir -p $RUNDIR

# Iniciar la aplicación django por medio de gunicorn
exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=debug \
  --log-file=-

Este script nos permite levantar nuestra aplicación django sin usar ./manage runserver

Algo muy importante es permitir la ejecución del archivo para esto escribimos

cd ~/myapp/bin
chmod +x start.sh 

Configurando Supervisor

Llegamos al punto de configurar supervisor, este nos va a ayudar a mantener nuestra aplicación de django corriendo, la configuración es relativamente sencilla y es un script con extensión .conf que debemos ubicar en /etc/supervisor/conf.d/

Para esto podemos usar vim, nano o cualquier editor que se tenga en la terminal, primero creamos el archivo usando sudo

sudo touch /etc/supervisor/conf.d/myapp.conf

Abrimos y copiamos el siguiente código

[program:myapp]command = /home/<user>/bin/start.sh ; Comando para iniciar la app
user = <user> ; El usuario con el que vamos a correr la app
stdout_logfile = /home/<user>/myapp/logs/gunicorn_supervisor.log ; Donde vamos a guardar los logs
redirect_stderr = true ; Guardar los errores en el log

Recuerden cambiar <user> por el nombre del usuario en su servidor y algo muy importante crear la carpeta logs dentro de la carpeta de la app

mkdir -p /home/<user>/myapp/logs

Ahora tenemos que decirle a supervisor que lea las nuevas configuraciones y que se actualice

sudo supervisorctl reread
sudo supervisorctl update

Con supervisor podemos también mirar el estado de la aplicación, pararla, iniciarla o reiniciarla.

sudo supervisorctl status myapp                       
sudo supervisorctl stop myapp  
sudo supervisorctl restart myapp 
sudo supervisorctl start myapp

Configurando Nginx

Estamos en el último paso: configurar el servidor web para que se conecte con el socket que tenemos corriendo gracias a gunicorn y muestre nuestro sitio web.

Nginx es realmente sencillo de configurar, nginx cuenta con dos carpetas una donde se almacenan las configuraciones de los sitios disponibles y otra donde se almacenan los sitios activos, vamos a crear nuestra configuración en la carpeta /etc/nginx/sites-available creamos nuestro archivo igual a como creamos el archivo de configuración para supervisor

sudo touch /etc/nginx/sites-available/myapp.conf

Paso seguido procedemos a editarlo

upstream myapp_server {
  server unix:/home/<user>/myapp/run/gunicorn.sock fail_timeout=0;
}

server {

  listen 80;
  server_name example.com;

  client_max_body_size 4G;

  access_log /home/<user>/myapp/logs/nginx-access.log;
  error_log /home/<user>/myapp/logs/nginx-error.log;

  location /static/ {
  alias /home/<user>/myapp/static/;
  }

  location /media/ {
  alias /home/<user>/myapp/media/;
  }

  location / {
  # an HTTP header important enough to have its own Wikipedia entry:# http://en.wikipedia.org/wiki/X-Forwarded-For
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  # enable this if and only if you use HTTPS, this helps Rack# set the proper protocol for doing redirects:# proxy_set_header X-Forwarded-Proto https;# pass the Host: header from the client right along so redirects# can be set properly within the Rack application
  proxy_set_header Host $http_host;

  # we don't want nginx trying to do something clever with# redirects, we set the Host: header above already.
  proxy_redirect off;

  # set "proxy_buffering off" *only* for Rainbows! when doing# Comet/long-poll stuff. It's also safe to set if you're# using only serving fast clients with Unicorn + nginx.# Otherwise you _want_ nginx to buffer responses to slow# clients, really.# proxy_buffering off;# Try to serve static files from nginx, no point in making an# *application* server like Unicorn/Rainbows! serve static files.if (!-f $request_filename) {
  proxy_pass http://myapp_server;
  break;
  }
  }
}

Como en los anteriores casos reemplaza <user> por el usuario y example.com por el dominio que tengas.

Una vez hecho esto tenemos que dar de alta nuestra configuración de nuestro sitio, para esto simplemente escribimos este comando

sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/myapp.conf

Algo que hago yo es correr nginx con mi usuario para no tener problemas de permisos de escritura a la hora de hacer por ejemplo subida de archivos desde la aplicación de Django, para esto editamos el archivo nginx.conf

sudo vim /etc/nginx/nginx.conf

Si no tienes vim puedes usar nano o el editor que uses desde la terminal

y cambiamos la linea

user<user>;

Ahora solo falta reiniciar nginx

sudo service nginx restart

Ya llevaste a producción tu aplicación de Django

Llevar a producción una aplicación es la culminación del desarrollo y mostrar al mundo lo que hiciste, puede tener múltiples cambios dependiendo del servidor pero esto aplica para la mayoría de casos.

Si quieres aprender a aplicar estas técnicas y muchas más, te recomendamos visitar nuestros cursos en desarrollo web.

Diego Alexander
Diego Alexander
gollum23

175649Puntos

hace 6 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
3
24296Puntos

Excelente articulo!
Ojala que esta información este en su curso de Django.

1
4901Puntos

Muy buen articulo! Aun luego de tanto tiempo sigue muy vigente. Sin embargo, se me ha presentado un error al realizar el arranque de mi aplicacion con el supervisor:
ERROR (spawn error)

He seguido el articulo sin saltarme ningun paso. Si alguien tuvo el mismo error y logró solucionarlo, le agradeceria si me da alguna idea.

Gracias por el aporte.

1
2608Puntos

Problema al iniciar servidor y verificar mi website. Estoy separando el archivo settings.py (base, dev, prod)

[http://platzi.com/comentario/760479/]

ERROR:
[Errno 2] No such file or directory: ‘/static’

2
2608Puntos
5 años

Ya lo solucione. Modificando

BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(file))))
1
28437Puntos

A mi me aparece 500 Internal Server Error
nginx/1.10.3 (Ubuntu)

1
4149Puntos

no entendi xd :c nada ggg

1
28437Puntos

Hola @GOLLUM23

Es recomendable usar una instancia de AWS para subir los archivos del proyecto y la base de datos con RDS?

Gracias de antemano

1
28437Puntos

Quien me podría orientar con unos detalles ya que no me esta corriendo al lanzar el supervisor o directamente desde el start.sh

Gracias

1
12544Puntos

Hola, Estoy en ubuntu 18.04. No encuentro la forma correcta de crear el servicio para ejecuatar el comando de gunicorn: El paso final para poner la aplicación en producción. Todos los tutoriales y clases de Platzi no me funcionan, ni con /etc/init/, ni con /etc/supervisor/ (ese directorio no existe en ubuntu 18.04) Casi todas las respuestas y consultas en todo Platzi sobre ste tema es de al menos dos o cuatro años atrás. ¿Alguien que lea esto me puede ayudar?
Mil gracias.

1
9337Puntos

¿por qué al intentar entrar a mi sitio web me dice “502 Bad Gateway nginx/1.14.0 (Ubuntu)”?

1
175649Puntos
4 años

Esto es porque la aplicación que sirve tu sitio está caída, nginx es un proxy, revisa para levantar la aplicación y revisar los logs para encontrár la causa de la caida.

1
11494Puntos

Buenos días, cómo hago para consultar si ya hay un proceso de gunicorn, supervisor o nginx corriendo?

2
175649Puntos
4 años

Si es un proceso de supervisor puedes revisar ejecutando, te va a mostrar los procesos que corres por medio de supervisor y su estatus
sudo supervisorctl status

Para ver un proceso en específico puedes usar el siguiente comando
ps -aux | grep <nombre proceso>
Este te va a mostrar el listado de procesos corriendo.