En este artículo vamos a aprender a configurar nginx con gunicorn en Django sobre un servidor Ubuntu. Se presupone que el lector ya conoce Django y dispone de una aplicación configurada y arrancada correctamente.
Instalar Gunicorn y verificar su funcionamiento
Necesitarás instalar con pip el paquete gunicorn en tu proyecto para poder usarlo. Si estás utilizando un entorno virtual recuerda activarlo antes de lanzar el comando:
$ pip install gunicorn
Vamos a avanzar paso a paso para garantizar que cada parte del proceso funciona correctamente. En primer lugar, nos ubicaremos en el directorio raíz del proyecto y arrancaremos la aplicación con gunicorn:
$ gunicorn --bind 0.0.0.0:9000 <proyecto>.wsgi
Reemplaza <proyecto> por el nombre de tu proyecto, y si todo ha ido bien verás que la aplicación ha quedado arrancada. Ahora es posible hacer peticiones al puerto 9000 y ver su respuesta. Abre un terminal nuevo y lanza el comando:
$ curl -L localhost:9000
Te mostrará por consola la respuesta de tu aplicación.
Crear socket y un fichero de servicio para gunicorn
En este punto ya tenemos garantizado que la aplicación funciona y es capaz de arrancar con gunicorn. El siguiente paso es crear un socket que se encargará de escuchar si hay peticiones nuevas. Cuando se haga una petición, el sistema operativo de Ubuntu arrancará el proceso de gunicorn para gestionar la conexión.
Para crear un socket nuevo el comando es el siguiente:
$ sudo nano /etc/systemd/system/gunicorn_miproyecto.socket
Es posible que en tu servidor quieras configurar más de una aplicación, por lo que es importante personalizar el nombre del fichero de acuerdo al nombre de cada proyecto para una mejor diferenciación. El contenido del fichero será el siguiente:
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn_miproyecto.sock
[Install]
WantedBy=sockets.target
Lenguaje del código: JavaScript (javascript)
Guardamos los cambios y creamos un nuevo fichero para generar el servicio:
$ sudo nano /etc/systemd/system/gunicorn_miproyecto.service
El contenido del fichero será el siguiente:
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
PIDFile=/run/gunicorn.pid
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/miproyecto
ExecStart=/home/ubuntu/miproyecto/venv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn_miproyecto.sock \
miproyecto.wsgi:application
[Install]
WantedBy=multi-user.target
Lenguaje del código: JavaScript (javascript)
Hay varias consideraciones a tener en cuenta sobre la configuración de este fichero. «User» será cualquier usuario (preferible evitar root) de Ubuntu. El grupo debe ser «www-data» para que Django tenga permisos de acceso. «WorkingDirectory» es la ruta absoluta hasta nuestro proyecto de django. Se entiende que dentro de «miproyecto» ya se encuentra la raíz del mismo. Si quieres verificar que estás en la raíz del proyecto podrás ver que dentro se encuentra el archivo «manage.py». En el parámetro «bind» indicaremos la ruta al fichero «.sock» creado anteriormente, y por último, indicaremos el fichero wsgi para arrancar nuestra aplicación.
Por último, iniciaremos y habilitaremos el socket que acabamos de crear:
$ sudo systemctl daemon-reload
$ sudo systemctl
enable
gunicorn_miproyecto.socket
$ sudo systemctl
enable
gunicorn_miproyecto.service
$ sudo systemctl start gunicorn_miproyecto.socket
Para saber si todo ha ido bien, podemos comprobar el estado del socket con el comando:
$ sudo systemctl status gunicorn_miproyecto.socket
Output
● gunicorn.service - gunicorn daemon
Loaded: loaded (/etc/systemd/system/gunicorn_miproyecto.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Lenguaje del código: JavaScript (javascript)
La salida nos saldrá como que está inactivo, esto es normal ya que no ha recibido el socket todavía ninguna conexión. Para forzar una, podemos hacer lo siguiente:
$ curl --unix-socket /run/gunicorn_miproyecto.sock localhost
Verás que devuelve por consola la salida HTML de tu aplicación, al igual que pasó anteriormente cuando validamos gunicorn. Ahora si repetimos el comando para mostrar el estado del socket, ya se mostrará activo:
$ sudo systemctl status gunicorn_miproyecto.socket
Llegados a este punto, ya tenemos instalado y configurado Gunicorn con éxito, ahora para terminar de completar el proceso solo nos quedará configurar Nginx para que al entrar una petición a nuestra aplicación sepa redirigir la petición al socket.
Configurar Nginx para enlazarlo con nuestro proceso Gunicorn
Necesitaremos instalar Nginx en nuestro servidor antes de continuar, si todavía no lo tienes instalado puedes seguir los pasos de este artículo.
Con Nginx ya instalado modificaremos su fichero de configuración:
$ sudo nano /etc/nginx/sites-enabled/default
Para este tutorial, asociaremos el dominio www.miproyecto.es a nuestra aplicación Django. Por tanto, crearemos un nuevo bloque «server» dentro del fichero:
server {
listen 80;
server_name www.miproyecto.es;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/ubuntu/miproyecto;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn_miproyecto.sock;
}
}
Lenguaje del código: PHP (php)
Mediante esta configuración estamos indicando a Nginx que escuche peticiones por el puerto 80, y en caso de realizarse al dns www.miproyecto.es hará una redirección (proxy_pass) a nuestro socket que ya tenemos creado. También podemos configurar la ruta de los ficheros estáticos en caso de necesitarlo indicando su ubicación en «root».
Antes de reiniciar el proceso de Nginx para que tenga en cuenta los cambios, podemos validar que la sintaxis del fichero sigue siendo correcta. Para ello puedes lanzar el comando:
$ sudo nginx -t
Si no hay errores, ya podemos reiniciar el proceso:
$ sudo systemctl restart nginx
Y ¡listo! ya hemos conseguido configurar NGINX con gunicorn en Django. Si abrimos un navegador e introducimos http://www.miproyecto.es, se mostará la página principal de vuestra aplicación Django. En caso de error, revisa detenidamente los pasos que hemos ido haciendo. Y si utilizas algún firewall, tendrás que tenerlo en cuenta para permitir conexiones al puerto 80.
Este artículo está basado en el artículo de Digital Ocean que puedes encontrar aquí
Script de automatización
#/bin/bash
proyecto=<nombre>
full_path="<ruta completa a carpeta del manage.py>"
target=<carpeta que contiene wsgi.py>
echo "Generando entorno"
mkdir /root/nginx-logs/${proyecto}
mkdir /root/virtualenvs/${proyecto}
virtualenv -p python3 /root/virtualenvs/${proyecto}/venv
source /root/virtualenvs/${proyecto}/venv/bin/activate
pip install -r ${full_path}/requirements.txt
echo "Creando fichero de servicio"
echo "
[Unit]
Description=gunicorn daemon
Requires=gunicorn_${proyecto}.socket
After=network.target
[Service]
User=root
Group=psaserv
WorkingDirectory=${full_path}
ExecStart=/root/virtualenvs/${proyecto}/venv/bin/gunicorn --access-logfile /root/nginx-logs/${proyecto}/logfile.log --workers 3 --bind unix:/run/gunicorn_${proyecto}.sock ${target}.wsgi
[Install]
WantedBy=multi-user.target
" > /etc/systemd/system/gunicorn_${proyecto}.service
echo "Creando fichero socket"
echo "
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn_${proyecto}.sock
[Install]
WantedBy=sockets.target
" > /etc/systemd/system/gunicorn_${proyecto}.socket
echo "Creando servicio"
systemctl start gunicorn_${proyecto}.socket
systemctl enable gunicorn_${proyecto}.socket
curl --unix-socket /run/gunicorn_{$proyecto}.sock localhost
Lenguaje del código: PHP (php)