Cómo servir aplicaciones Flask con uWSGI y Nginx en Ubuntu 18.04

Introducción
En esta guía, creará una aplicación Python utilizando el microframework Flask en Ubuntu 18.04. La mayor parte de este artículo tratará sobre cómo configurar el servidor de aplicaciones uWSGI y cómo iniciar la aplicación y configurar Nginx para que actúe como un proxy inverso de interfaz.
Prerrequisitos
Para completar este tutorial, necesitarás:
-
Un servidor con Ubuntu 18.04 instalado y un usuario no root con privilegios sudo y un firewall habilitado. Siga nuestra guía de configuración inicial del servidor para obtener orientación.
-
Nginx instalado, siguiendo los pasos 1 y 2 de Cómo instalar Nginx en Ubuntu 18.04 .
-
Un nombre de dominio configurado para apuntar a su servidor. Puede comprar uno en Namecheap u obtener uno gratis en Freenom . Puede aprender a apuntar dominios a DigitalOcean siguiendo la documentación relevante sobre dominios y DNS . Asegúrese de crear los siguientes registros DNS:
- Un registro A que
your_domain
apunta a la dirección IP pública de su servidor. - Un registro A que apunta a la dirección IP pública de su servidor.
www.your_domain
- Un registro A que
-
Familiaridad con uWSGI, nuestro servidor de aplicaciones y la especificación WSGI. Este análisis de definiciones y conceptos analiza ambos conceptos en detalle.
Paso 1: Instalación de los componentes desde los repositorios de Ubuntu
El primer paso es instalar todos los componentes que necesitas de los repositorios de Ubuntu. Instalarás pip
, el administrador de paquetes de Python, para administrar tus componentes de Python. También obtendrás los archivos de desarrollo de Python necesarios para compilar uWSGI.
Primero, actualice el índice del paquete local:
- sudo apt update
A continuación, instale los paquetes que le permitirán crear su entorno Python. Estos incluirán python3-pip
, junto con algunos paquetes más y herramientas de desarrollo necesarias para un entorno de programación sólido:
- sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
Con estos paquetes en su lugar, puede pasar a crear un entorno virtual para su proyecto.
Paso 2: creación de un entorno virtual de Python
A continuación, configure un entorno virtual para aislar su aplicación Flask de los demás archivos Python en el sistema.
Comience instalando el python3-venv
paquete, que instalará el venv
módulo:
- sudo apt install python3-venv
A continuación, crea un directorio principal para tu proyecto Flask:
- mkdir ~/myproject
Luego muévete al directorio después de crearlo:
- cd ~/myproject
Cree un entorno virtual para almacenar los requisitos de Python de su proyecto Flask ejecutando lo siguiente:
- python3.6 -m venv myprojectenv
Esto instalará una copia local de Python pip
en un directorio llamado myprojectenv
dentro del directorio de su proyecto.
Antes de instalar aplicaciones dentro del entorno virtual, es necesario activarlo:
- source myprojectenv/bin/activate
El mensaje cambiará para indicar que ahora está trabajando en el entorno virtual. Se leerá de la siguiente manera: .(myprojectenv) user@host:~/myproject$
Paso 3: Configuración de una aplicación Flask
Ahora que está en su entorno virtual, puede instalar Flask y uWSGI y comenzar a diseñar su aplicación.
Primero, instale wheel
con la instancia local de pip
para asegurarse de que sus paquetes se instalarán incluso si faltan archivos wheel:
- pip install wheel
Nota : Independientemente de la versión de Python que esté utilizando, cuando se activa el entorno virtual, debe utilizar el pip
comando (no pip3
).
A continuación, instale Flask y uWSGI:
- pip install uwsgi flask
Una vez completada la instalación, puedes comenzar a utilizar Flask.
Creación de una aplicación de muestra
Ahora que tienes Flask disponible, puedes crear una aplicación sencilla. Como recordarás, Flask es un microframework y no incluye muchas de las herramientas que sí incluyen los frameworks con más funciones. Flask existe principalmente como un módulo que puedes importar a tus proyectos para ayudarte a inicializar una aplicación web.
Si bien su aplicación puede ser más compleja, creará su aplicación Flask en un solo archivo. Puede crear el archivo con su editor de texto favorito. Para este ejemplo, lo usaremos nano
y le daremos el nombre siguiente myproject.py
:
- nano ~/myproject/myproject.py
El código de la aplicación se almacenará en este archivo. Importará Flask y creará una instancia de un objeto Flask. Puede usarlo para definir las funciones que se deben ejecutar cuando se solicita una ruta específica:
~/miproyecto/miproyecto.py
from flask import Flaskapp = Flask(__name__)@app.route("/")def hello(): return "h1 style='color:blue'Hello There!/h1"if __name__ == "__main__": app.run(host='0.0.0.0')
Esto define qué contenido se debe presentar cuando se accede al dominio raíz. Guarde y cierre el archivo cuando haya terminado. Si está utilizando, nano
puede hacerlo presionando CTRL + X
then Y
y ENTER
.
Si siguió la guía de configuración inicial del servidor, debería tener habilitado un firewall UFW. Para probar la aplicación, debe permitir el acceso al puerto 5000
:
- sudo ufw allow 5000
Ahora prueba tu aplicación Flask:
- python myproject.py
Recibirá un resultado como el siguiente, incluida una advertencia útil que le recordará que no debe utilizar esta configuración de servidor en producción:
Output* Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
Visita la dirección IP de tu servidor seguida de :5000
en tu navegador web:
http://your_server_ip:5000
Deberías ver algo como lo siguiente:
Cuando haya terminado, presione CTRL + C
en su ventana de terminal para detener el servidor de desarrollo Flask.
Creación del punto de entrada WSGI
A continuación, creará un archivo que servirá como punto de entrada para su aplicación. Esto le indicará al servidor uWSGI cómo interactuar con él.
Primero crea y nombra el archivo wsgi.py
:
- nano ~/myproject/wsgi.py
En este archivo, importe la instancia de Flask desde su aplicación y luego ejecútela:
~/miproyecto/wsgi.py
from myproject import appif __name__ == "__main__": app.run()
Guarde y cierre el archivo cuando haya terminado.
Paso 4: Configuración de uWSGI
Ahora su aplicación está escrita con un punto de entrada establecido. Ahora puede continuar con la configuración de uWSGI.
Prueba del servicio uWSGI
Antes de realizar más cambios, puede ser útil probar que uWSGI puede servir a su aplicación.
Puede hacerlo pasando el nombre de su punto de entrada a uWSGI. Esto se construye con el nombre del módulo (menos la .py
extensión) más el nombre del elemento invocable dentro de la aplicación. En este caso, el nombre del punto de entrada es wsgi:app
.
También deberá especificar el socket, de modo que se inicie en una interfaz disponible públicamente, así como el protocolo, de modo que utilice HTTP en lugar del uwsgi
protocolo binario. Utilice el mismo número de puerto, 5000
, que abrió anteriormente:
- uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app
Visita :5000
nuevamente la dirección IP de tu servidor adjunta al final en tu navegador web:
http://your_server_ip:5000
Debería recibir nuevamente el resultado de su aplicación:
Cuando hayas confirmado que funciona correctamente, presiona CTRL + C
en tu ventana de terminal.
Ahora que has terminado con tu entorno virtual, puedes desactivarlo:
- deactivate
Cualquier comando Python ahora utilizará nuevamente el entorno Python del sistema.
Creación de un archivo de configuración uWSGI
Ha probado y verificado que uWSGI puede servir a su aplicación, pero en última instancia querrá algo más robusto para un uso a largo plazo. Puede crear un archivo de configuración de uWSGI con las opciones pertinentes para esto.
Coloque ese archivo en el directorio de su proyecto y llámelo myproject.ini
:
- nano ~/myproject/myproject.ini
En el interior, comenzará con el [uwsgi]
encabezado para que uWSGI sepa que debe aplicar la configuración. Especificará dos cosas: el módulo en sí, haciendo referencia al wsgi.py
archivo sin la extensión, y el elemento invocable dentro del archivo app
:
~/miproyecto/miproyecto.ini
[uwsgi]module = wsgi:app
A continuación, indique a uWSGI que se inicie en modo maestro y genere cinco procesos de trabajo para atender las solicitudes reales:
~/miproyecto/miproyecto.ini
[uwsgi]module = wsgi:appmaster = trueprocesses = 5
Cuando estabas haciendo pruebas, expusiste uWSGI en un puerto de red. Sin embargo, vas a usar Nginx para manejar las conexiones de clientes reales, que luego pasarán las solicitudes a uWSGI. Dado que estos componentes están funcionando en la misma computadora, es preferible un socket Unix porque es más rápido y más seguro. Llama al socket myproject.sock
y colócalo en este directorio.
Cambie también los permisos del socket. Esto le otorga al grupo Nginx la propiedad del proceso uWSGI más adelante, así que asegúrese de que el propietario del grupo del socket pueda leer información de él y escribir en él. Además, limpie el socket cuando el proceso se detenga agregando la vacuum
opción:
~/miproyecto/miproyecto.ini
[uwsgi]module = wsgi:appmaster = trueprocesses = 5socket = myproject.sockchmod-socket = 660vacuum = true
Lo último que harás es configurar la die-on-term
opción. Esto puede ayudar a garantizar que el sistema de inicio y uWSGI tengan las mismas suposiciones sobre lo que significa cada señal de proceso. Al configurar esto, se alinean los dos componentes del sistema e implementan el comportamiento esperado:
~/miproyecto/miproyecto.ini
[uwsgi]module = wsgi:appmaster = trueprocesses = 5socket = myproject.sockchmod-socket = 660vacuum = truedie-on-term = true
Es posible que hayas notado que no especificaste un protocolo como lo hiciste desde la línea de comandos. Esto se debe a que, de manera predeterminada, uWSGI habla usando el uwsgi
protocolo , un protocolo binario rápido diseñado para comunicarse con otros servidores. Nginx puede hablar este protocolo de forma nativa, por lo que es mejor usarlo que forzar la comunicación por HTTP.
Cuando haya terminado, guarde y cierre el archivo.
Paso 5: Creación de un archivo de unidad systemd
A continuación, cree el archivo de unidad de servicio systemd. La creación de un archivo de unidad systemd permitirá que el sistema de inicio de Ubuntu inicie automáticamente uWSGI y proporcione la aplicación Flask cada vez que se inicie el servidor.
Cree un archivo de unidad que termine .service
dentro del /etc/systemd/system
directorio para comenzar:
- sudo nano /etc/systemd/system/myproject.service
Dentro del archivo, comience con la [Unit]
sección, que se utiliza para especificar metadatos y dependencias. Describa aquí su servicio e indique al sistema de inicio que solo se inicie después de que se haya alcanzado el objetivo de red:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=uWSGI instance to serve myprojectAfter=network.target
A continuación, abra la [Service]
sección. Esto especificará el usuario y el grupo bajo los cuales desea que se ejecute el proceso. Otorgue a su cuenta de usuario habitual la propiedad del proceso, ya que posee todos los archivos relevantes. Otorgue también la propiedad del grupo al www-data
grupo para que Nginx pueda comunicarse fácilmente con los procesos uWSGI. Recuerde reemplazar el nombre de usuario aquí con su nombre de usuario:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=uWSGI instance to serve myprojectAfter=network.target[Service]User=sammyGroup=www-data
A continuación, trace el directorio de trabajo y configure la PATH
variable de entorno para que el sistema de inicio sepa que los ejecutables del proceso se encuentran dentro de su entorno virtual. También especifique el comando para iniciar el servicio. Systemd requiere que proporcione la ruta completa al ejecutable uWSGI, que está instalado dentro de su entorno virtual. Pasará el nombre del .ini
archivo de configuración que creó en el directorio de su proyecto.
Recuerde reemplazar el nombre de usuario y las rutas del proyecto con su propia información:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=uWSGI instance to serve myprojectAfter=network.target[Service]User=sammyGroup=www-dataWorkingDirectory=/home/sammy/myprojectEnvironment="PATH=/home/sammy/myproject/myprojectenv/bin"ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
Luego, agregue una [Install]
sección. Esto le indicará a systemd a qué vincular este servicio si lo habilita para que se inicie en el arranque. Desea que este servicio se inicie cuando el sistema multiusuario normal esté en funcionamiento:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=uWSGI instance to serve myprojectAfter=network.target[Service]User=sammyGroup=www-dataWorkingDirectory=/home/sammy/myprojectEnvironment="PATH=/home/sammy/myproject/myprojectenv/bin"ExecStart=/home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini[Install]WantedBy=multi-user.target
Con esto, el archivo de servicio systemd está completo. Guárdelo y ciérrelo ahora.
Ahora puedes iniciar el servicio uWSGI que creaste y habilitarlo para que se inicie en el arranque:
- sudo systemctl start myproject
- sudo systemctl enable myproject
Comprobar el estado:
- sudo systemctl status myproject
Debería recibir un resultado como el siguiente:
Output● myproject.service - uWSGI instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset Active: active (running) since Mon 2021-10-25 22:34:52 UTC; 14s ago Main PID: 9391 (uwsgi) Tasks: 6 (limit: 1151) CGroup: /system.slice/myproject.service ├─9391 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9410 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9411 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9412 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9413 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i └─9414 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i
Si recibe algún error, asegúrese de resolverlo antes de continuar con el tutorial.
Paso 6: Configuración de Nginx para procesar solicitudes
Ahora, el servidor de aplicaciones uWSGI debería estar en funcionamiento y esperando solicitudes en el archivo de socket del directorio del proyecto. Ahora, puede configurar Nginx para que envíe solicitudes web a ese socket mediante el uwsgi
protocolo.
Comience por crear un nuevo archivo de configuración de bloque de servidor en sites-available
el directorio de Nginx. Asígnele un nombre myproject
que sea coherente con el resto de la guía:
- sudo nano /etc/nginx/sites-available/myproject
Abra un bloque de servidor y dígale a Nginx que escuche en el puerto predeterminado 80
. Indíquele también que use este bloque para las solicitudes del nombre de dominio de su servidor:
/etc/nginx/sites-available/miproyecto
server { listen 80; server_name your_domain www.your_domain;}
A continuación, agregue un bloque de ubicación que coincida con cada solicitud. Dentro de este bloque, incluirá el uwsgi_params
archivo que especifica algunos parámetros uWSGI generales que deben configurarse. Luego, pasará las solicitudes al socket que definió mediante la uwsgi_pass
directiva:
/etc/nginx/sites-available/miproyecto
server { listen 80; server_name your_domain www.your_domain; location / { include uwsgi_params; uwsgi_pass unix:/home/sammy/myproject/myproject.sock; }}
Guarde y cierre el archivo cuando haya terminado.
Para habilitar la configuración del bloque del servidor Nginx que acaba de crear, vincule el archivo al sites-enabled
directorio:
- sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Con el archivo en ese directorio, puedes comprobar si hay errores de sintaxis ejecutando lo siguiente:
- sudo nginx -t
Si esto regresa sin indicar ningún problema, reinicie el proceso Nginx para leer la nueva configuración:
- sudo systemctl restart nginx
Ahora vuelve a ajustar el firewall. Ya no necesitas acceso a través del puerto 5000
, por lo que puedes eliminar esa regla:
- sudo ufw delete allow 5000
Después, permitirás el acceso al servidor Nginx:
- sudo ufw allow 'Nginx Full'
Ahora debería poder navegar al nombre de dominio de su servidor en su navegador web:
http://your_domain
Deberías ver el resultado de tu aplicación:
Si encuentra algún error, intente comprobar lo siguiente:
sudo less /var/log/nginx/error.log
:comprueba los registros de errores de Nginx.sudo less /var/log/nginx/access.log
:comprueba los registros de acceso de Nginx.sudo journalctl -u nginx
:comprueba los registros del proceso Nginx.sudo journalctl -u myproject
:comprueba los registros uWSGI de su aplicación Flask.
Paso 7: Proteger la aplicación
Para garantizar que el tráfico a su servidor permanezca seguro, debe obtener un certificado SSL para su dominio. Hay varias formas de hacerlo, incluida la obtención de un certificado gratuito de Let’s Encrypt , la generación de un certificado autofirmado o la compra de uno de otro proveedor y la configuración de Nginx para usarlo siguiendo los pasos del 2 al 6 de Cómo crear un certificado SSL autofirmado para Nginx en Ubuntu 18.04 . Lo demostraremos con la opción uno por conveniencia. Para ver el tutorial completo, consulte Cómo proteger Nginx con Let’s Encrypt en Ubuntu 18.04 .
Primero, agregue el repositorio Certbot Ubuntu:
- sudo add-apt-repository ppa:certbot/certbot
Necesitarás presionar ENTER
para aceptar.
A continuación, instale el paquete Nginx de Certbot con apt
:
- sudo apt install python-certbot-nginx
Certbot ofrece una variedad de formas de obtener certificados SSL a través de complementos. El complemento Nginx se encargará de reconfigurar Nginx y recargar la configuración cuando sea necesario. Para usar este complemento, ejecute lo siguiente:
- sudo certbot --nginx -d your_domain -d www.your_domain
Esto se ejecuta certbot
con el --nginx
complemento, que se utiliza -d
para especificar los nombres para los cuales desea que sea válido el certificado.
Si es la primera vez que ejecuta certbot
, se le solicitará que ingrese una dirección de correo electrónico y que acepte los términos del servicio. Después de hacerlo, certbot
se comunicará con el servidor Let’s Encrypt y luego ejecutará un desafío para verificar que controla el dominio para el que está solicitando un certificado.
Si esto tiene éxito, certbot
le preguntará cómo desea configurar sus ajustes HTTPS:
OutputPlease choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.-------------------------------------------------------------------------------1: No redirect - Make no further changes to the webserver configuration.2: Redirect - Make all requests redirect to secure HTTPS access. Choose this fornew sites, or if you're confident your site works on HTTPS. You can undo thischange by editing your web server's configuration.-------------------------------------------------------------------------------Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
Seleccione su opción y luego presione ENTER
. La configuración se actualizará y Nginx se recargará para recoger la nueva configuración. certbot
finalizará con un mensaje que le indicará que el proceso fue exitoso y dónde se almacenan sus certificados:
OutputIMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2022-01-24. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
Si siguió las instrucciones de instalación de Nginx en los requisitos previos, ya no necesitará la asignación de perfil HTTP redundante:
- sudo ufw delete allow 'Nginx HTTP'
Para verificar la configuración, navegue nuevamente a su dominio, utilizando https://
:
https://your_domain
Debería ver nuevamente el resultado de su aplicación, junto con el indicador de seguridad de su navegador, que debería indicar que el sitio está protegido.
Conclusión
En esta guía, creó y protegió una aplicación Flask simple dentro de un entorno virtual Python. Creó un punto de entrada WSGI para que cualquier servidor de aplicaciones compatible con WSGI pueda interactuar con él y, luego, configuró el servidor de aplicaciones uWSGI para proporcionar esta función. Después, creó un archivo de servicio systemd para iniciar automáticamente el servidor de aplicaciones al arrancar. También creó un bloque de servidor Nginx que pasa el tráfico del cliente web al servidor de aplicaciones, retransmite solicitudes externas y protege el tráfico a su servidor con Let’s Encrypt.
Flask es un marco extremadamente flexible diseñado para brindar funcionalidad a sus aplicaciones sin ser demasiado restrictivo en cuanto a estructura y diseño. Puede utilizar la pila general descrita en esta guía para brindar servicio a las aplicaciones Flask que desee diseñar.
Deja una respuesta