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.
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
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
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
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>
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>
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
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
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
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
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.
Excelente articulo!
Ojala que esta información este en su curso de Django.
gracias por tu tutorial. pero llegue hasta esta parte y me salio el error de que no reconoce el comando
mkvirtualenv miapp --python=$(which python3)
y cual es la diferencia en usar virtualenvwrapper o virtualenv ???
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
no entendi xd :c nada ggg
¿por qué al intentar entrar a mi sitio web me dice “502 Bad Gateway nginx/1.14.0 (Ubuntu)”?
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.
Buenos días, cómo hago para consultar si ya hay un proceso de gunicorn, supervisor o nginx corriendo?
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.
A mi me aparece 500 Internal Server Error
nginx/1.10.3 (Ubuntu)
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.
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.