Cómo servir aplicaciones Flask con Gunicorn y Nginx en Ubuntu 22.04

Kathleen Juell escribió una versión anterior de este tutorial .
Introducción
En esta guía, creará una aplicación Python utilizando el microframework Flask en Ubuntu 22.04. La mayor parte de este tutorial tratará sobre cómo configurar el servidor de aplicaciones Gunicorn y cómo iniciar la aplicación y configurar Nginx para que actúe como un proxy inverso de interfaz.
Prerrequisitos
Antes de comenzar esta guía, debes tener:
-
Un servidor con Ubuntu 22.04 instalado y un usuario no root con privilegios sudo. 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 22.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 la especificación WSGI, que el servidor Gunicorn utilizará para comunicarse con su aplicación Flask. Esta discusión cubre WSGI con más detalle.
Paso 1: Instalación de los componentes desde los repositorios de Ubuntu
El primer paso será instalar todos los componentes necesarios de los repositorios de Ubuntu. Esto incluye pip
el administrador de paquetes de Python, que administrará los componentes de Python. También obtendrá los archivos de desarrollo de Python necesarios para compilar algunos de los componentes de Gunicorn.
En primer lugar, actualice el índice de paquetes locales e 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 update
- sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
Con estos paquetes en su lugar, el siguiente paso es crear un entorno virtual para su proyecto.
Paso 2: creación de un entorno virtual de Python
A continuación, configurará un entorno virtual para aislar la aplicación Flask de los demás archivos Python en su sistema.
Comience instalando el python3-venv
paquete, que instalará el venv
módulo:
- sudo apt install python3-venv
cd
A continuación, crea un directorio principal para tu proyecto Flask. Después de crearlo, ingresa al directorio con el comando:
- mkdir ~/myproject
- cd ~/myproject
Cree un entorno virtual para almacenar los requisitos de Python de su proyecto Flask escribiendo:
- python3 -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. Para ello, escriba:
- source myprojectenv/bin/activate
El mensaje cambiará para indicar que ahora está trabajando en el entorno virtual. Se verá así: .(myprojectenv)user@host:~/myproject$
Paso 3: Configuración de una aplicación Flask
Ahora que estás en tu entorno virtual, puedes instalar Flask y Gunicorn y comenzar a diseñar tu 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és usando, cuando se activa el entorno virtual, debes usar el pip
comando (no pip3
).
A continuación, instale Flask y Gunicorn:
- pip install gunicorn flask
Creación de una aplicación de muestra
Ahora que tienes Flask disponible, puedes crear una aplicación sencilla. Flask es un microframework. No incluye muchas de las herramientas que sí incluyen los frameworks con más funciones y 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, crearemos nuestra aplicación Flask en un solo archivo, llamado 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')
Básicamente, esto define qué contenido se debe presentar cuando se accede al dominio raíz. Guarde y cierre el archivo cuando haya terminado.
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 puedes probar tu aplicación Flask escribiendo:
- python myproject.py
Verá 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 esto:
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, crea un archivo que servirá como punto de entrada para tu aplicación. Esto le indicará al servidor Gunicorn cómo interactuar con la aplicación.
Llamar al archivo wsgi.py
:
- nano ~/myproject/wsgi.py
En este archivo, importe la instancia de Flask desde nuestra 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 Gunicorn
Ahora tu aplicación está escrita con un punto de entrada establecido. Ahora puedes continuar con la configuración de Gunicorn.
Antes de continuar, verifique que Gunicorn pueda servir la aplicación correctamente.
Puede hacerlo pasándole el nombre del punto de entrada de la aplicación. Esto se construye como 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, es wsgi:app
.
Especifique también la interfaz y el puerto a enlazar mediante el 0.0.0.0:5000
argumento para que la aplicación se inicie en una interfaz disponible públicamente:
- cd ~/myproject
- gunicorn --bind 0.0.0.0:5000 wsgi:app
Debería ver un resultado como el siguiente:
Output[2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4[2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419)[2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync[2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421
Visita :5000
nuevamente la dirección IP de tu servidor adjunta al final en tu navegador web:
http://your_server_ip:5000
Deberías ver el resultado de tu aplicación:
Cuando hayas confirmado que funciona correctamente, presiona CTRL-C
en tu ventana de terminal.
Cuando haya terminado de utilizar el entorno virtual, puede desactivarlo:
- deactivate
Cualquier comando Python ahora utilizará nuevamente el entorno Python del sistema.
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 Gunicorn y sirva 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
En el interior, comenzará con la [Unit]
sección que se utiliza para especificar metadatos y dependencias. Agregue una descripción de su servicio aquí e indique al sistema de inicio que lo inicie solo después de que se haya alcanzado el objetivo de red:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=Gunicorn instance to serve myprojectAfter=network.target
A continuación, agregue una [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 de Gunicorn. Recuerde reemplazar el nombre de usuario aquí con su nombre de usuario:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=Gunicorn instance to serve myprojectAfter=network.target[Service]User=sammyGroup=www-data
A continuación, mapee 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 nuestro entorno virtual. También especifique el comando para iniciar el servicio. Este comando hará lo siguiente:
- Iniciar 3 procesos de trabajo (aunque debe ajustar esto según sea necesario)
- Crea y vincula un archivo de socket de Unix,
myproject.sock
, dentro de nuestro directorio de proyecto. Estableceremos un valor de umask de007
modo que se cree el archivo de socket y se otorgue acceso al propietario y al grupo, mientras se restringe el acceso a otros. - Especifique el nombre del archivo del punto de entrada WSGI, junto con el objeto invocable de Python dentro de ese archivo (
wsgi:app
)
Systemd requiere que proporciones la ruta completa al ejecutable Gunicorn, que está instalado dentro de tu entorno virtual.
Recuerde reemplazar el nombre de usuario y las rutas del proyecto con su propia información:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
Por último, 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. Querrá que este servicio se inicie cuando el sistema multiusuario normal esté en funcionamiento:
/etc/systemd/system/miproyecto.servicio
[Unit]Description=Gunicorn 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/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app[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 Gunicorn que creaste y habilitarlo para que se inicie en el arranque:
- sudo systemctl start myproject
- sudo systemctl enable myproject
Comprobemos el estado:
- sudo systemctl status myproject
Deberías ver un resultado como este:
Output● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2022-05-10 19:40:41 UTC; 9s ago Main PID: 17300 (gunicorn) Tasks: 4 (limit: 2327) Memory: 56.0M CPU: 514ms CGroup: /system.slice/myproject.service ├─17300 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17301 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17302 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─17303 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:appMay 10 19:40:41 r systemd[1]: Started Gunicorn instance to serve myproject.. . .
Si ve algún error, asegúrese de resolverlo antes de continuar con el tutorial.
Paso 5: Configuración de Nginx para procesar solicitudes
Ahora, el servidor de aplicaciones Gunicorn debería estar en funcionamiento y esperando solicitudes en el archivo de socket del directorio del proyecto. Ahora, puede configurar Nginx para que pase solicitudes web a ese socket haciendo algunas pequeñas modificaciones en su archivo de configuración.
Comience por crear un nuevo archivo de configuración de bloque de servidor en sites-available
el directorio de Nginx. Llámelo myproject
para seguir 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 nuestro 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 proxy_params
archivo que especifica algunos parámetros de proxy generales que deben configurarse. Luego, pasará las solicitudes al socket que definió mediante la proxy_pass
directiva:
/etc/nginx/sites-available/miproyecto
server { listen 80; server_name your_domain www.your_domain; location / { include proxy_params; proxy_pass http://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:
- 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
Por último, vuelve a ajustar el firewall. Ya no necesitas acceso a través del puerto 5000
, por lo que puedes eliminar esa regla. Luego puedes permitir el acceso total al servidor Nginx:
- sudo ufw delete allow 5000
- 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:
Nota : Recibirá un error de puerta de enlace HTTP 502 si Nginx no puede acceder al archivo de socket de Gunicorn. Por lo general, esto se debe a que el directorio de inicio del usuario no permite que otros usuarios accedan a los archivos que contiene.
Si el archivo de socket se llama /home/sammy/myproject/myproject.sock
, asegúrese de que /home/sammy
tenga un mínimo de 0755
permisos. Puede utilizar una herramienta como chmod
para cambiar los permisos de esta manera:
- sudo chmod 755 /home/sammy
Luego vuelva a cargar la página para ver si el error HTTP 502 desaparece.
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 Gunicorn de tu aplicación Flask.
Paso 6: Proteger la aplicación
Para garantizar que el tráfico a su servidor permanezca seguro, obtengamos 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 2 a 6 de Cómo crear un certificado SSL autofirmado para Nginx en Ubuntu 22.04 . Usaremos la opción uno (Let’s Encrypt) por conveniencia.
Instale el paquete Nginx de Certbot con apt
:
- sudo apt install python3-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, escriba 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 queremos 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 2020-08-18. 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 Gunicorn 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 de trabajo muy simple pero extremadamente flexible, diseñado para brindarle funcionalidad a sus aplicaciones sin ser demasiado restrictivo en cuanto a estructura y diseño. Puede usar la pila general descrita en esta guía para brindar servicio a las aplicaciones Flask que diseñe.
Deja una respuesta