Do you want to switch to Platzi in English?
64

¿Cómo llevar Django a producción?

116033Puntos

hace un año

Curso de Python 2017
Curso de Python 2017

Curso de Python 2017

Python es una pieza fundamental de varios sistemas de software más importantes del mundo. Simple, claro y con un código legible, Python es el lenguaje por excelencia para la programación web y la ciencia de datos. Aprende este lenguaje a partir de proyectos prácticos que harás desde cero.

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.

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< span=""> 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
[email protected]:~$ 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
[email protected]:~$

[email protected]:~$ createdb --owner myapp myappdb
[email protected]:~$ 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< span="">>;

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 usas servicios como AWS, la configuración de la base de datos la puedes reemplazar si usas RDS puedes ver el curso de Deploy con Amazon Web Services

Si tienen preguntas puedes dejarlas en los comentarios y estaré atento a responder.

Curso de Python 2017
Curso de Python 2017

Curso de Python 2017

Python es una pieza fundamental de varios sistemas de software más importantes del mundo. Simple, claro y con un código legible, Python es el lenguaje por excelencia para la programación web y la ciencia de datos. Aprende este lenguaje a partir de proyectos prácticos que harás desde cero.
Diego Alexander
Diego Alexander
@GOLLUM23

116033Puntos

hace un año

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
1
10815Puntos

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

Muchísimas gracias por éste post 😃, muy conciso y bien explicado. Estaba buscando como hacer esto en Digitalocean pero no había encontrado ninguna guía.
Todo este proceso se realiza cuando accedemos por SSH a la terminal del servidor o me equivoco?

2
116033Puntos
un año

Hola, este proceso se hace via ssh sobre el servidor remoto.

Me alegra que sea de utilidad.

1

Excelente tutorial. tengo una pregunta, al momento de llevar a producción el sistema, una vez que se quiera hacer alguna modificación a nivel código dentro del sistema, si o si es necesario el reinicio del servicio ?

Hay alguna manera de que pueda funcionar igual a como en desarrollo que con solo darle F5 ya toma los cambios?

0
1989Puntos
un año

Cuando hay un cambio nuevo, se debe refrescar el supervisor para que tome los cambios.

2
116033Puntos
un año

Con supervisor solo tienes que traer la nueva versión del código usando git pull origin master o la rama que uses como principal y luego de esto simplemente usas sudo supervisorctl restart <nombre de la app>. Esto hace que supervisor reinicie el proceso de django y tengas puedas ver los cambios.

Puedes crear scripts de bash que permitan hacer todo al correr un solo comando, por ejemplo desplegar esto va a traer automáticamente el código de repositorio remoto, hacer collectstatic y reiniciar supervisor.

1

¡Hola!

Cuando corro ‘./start.sh’ me da un error de permiso pero cuando lo corro como sudo ./start.sh eso error ya no aparece y corre sin problemas pero en el supervisor sigue existiendo ese problema de permisos y no se cómo hacer que corra el comando con sudo.

1
10815Puntos

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

1
2372Puntos

Gran tutorial, una duda importante, ¿Por qué usar supervisor y no crear un servicio de linux?

1
116033Puntos
un año

Supervisor es una herramienta creada para suplir esa necesidad, en los diferentes versiones de linux se crean los servicios de manera diferente (ubicación de archivos) lo que hace confusa esa parte, supervisor por ser un programa externo funciona igual en todos los sistemas.

0
9583Puntos

Muy buen post. Ojalá hubiera tenido esta info cuando me hizo falta.

0

Seguí todos los pasos pero al ejetutar:
sudo supervisorctl start <proyecto>

Salé el siguiente error en gunicom_supervisor.log:
/home/ubuntu/sites/<proyecto>/bin/start.sh: line 17: workon: command not found

Intenté de todo y no encuentro solución.

Agregué al archivo .bashrc las siguientes lineas:
export WORKON_HOME=~/virtualenvs
VIRTUALENVWRAPPER_PYTHON=’/usr/bin/python3’
source /usr/local/bin/virtualenvwrapper.sh

y tampoco.

Uso una maquina aws recien creada con Ubuntu Server 16.04 LTS.

Saludos.

1
116033Puntos
9 meses

Asegúrate de instalar virtualenvwrapper de manera global
sudo pip install virtualenvwrapper

0
828Puntos

No corre el start.sh con supervisor, agregue lo siguiente en el archivo start.sh:

Activar el entorno virtual
cd $DJANGODIR
export WORKON_HOME=~/.virtualenvs
VIRTUALENVWRAPPER_PYTHON=’/usr/bin/python3’
source /usr/local/bin/virtualenvwrapper.sh

workon proyecto_django

1
116033Puntos
un año

No es necesario definir eso ya que el entorno virtual lo creas desde antes de correr el script start.sh, que error te da al intentar correr el comando.

Prueba ejecutando solo ./start.sh y ver si te da algún error, lo compartes aquí y con gusto te ayudo a solucionarlo.

0
3636Puntos

compartan algun tutorial con https y nginx

1
116033Puntos
10 meses

Lo único que cambia es la parte de configuración del puerto en nginx y la instalación del certificado, de resto todo funciona igual. Tienes que agregar una redirección para que de http te redirija a https.

0

No se que ocurre, no se me crea el socket con gunicorn, ya está la carpeta, me da un error en el nginx-error.log: dice que ese sock no se encuentra en el directorio. Alguna sugerencia? O posibles causas?

1
116033Puntos
un año

Puede que tengas la ruta del socket mal y por lo tanto no encuentra el archivo verifica las rutas.

0
4277Puntos

Buenas tardes, me podrias hacer un gran favor, desarrolle en laravel pero no e podido subir a produccion en digital ocean.
Me podrias apoyar?

1
116033Puntos
un año

Claro, dime que problema presentas y con gusto te ayudamos a solucionar.

0
2430Puntos

Excelente tutorial. He visto que tambien hacen la instalacion con uwsgi bajo Nginx. ¿que configuracion es la que da mejor rendimiento?

2
116033Puntos
un año

Personalmente siempre he usado Gunicorn con Nginx, uWsgi tiene un problema y lo poco documentado que esta y que tienen muchas características que ya tiene Nginx o Apache. Gunicorn solo hace lo que tiene que hacer y no más, si necesitas configuraciones muy especificas puedes probar uWsgi de lo contrario por el manejo sencillo usa Gunicorn.

0
1110Puntos

Gracias por el post. ¿Puedo hacer la prueba en una maquina virtual a la cual le tengo instalada ubuntu server??

1
116033Puntos
un año

Si, puedes probarlo así, por razones lógicas no va a tener tan buen rendimiento por ser maquina virtual pero te va a funcionar.

0
1110Puntos
un año

tengo este error cuando doy el comando “supervisorctl reread”

error: <class'socket.error'>, [Errno 111] Connection refused: file: /usr/lib/python2.7/socket.py line: 575
1
116033Puntos
un año

Al parecer supervisor no se levanto de manera correcta y no se puede conectar al socket, revisa que supervisor este corriendo.