Notas de Luis

Nivel superior

Flask - 2 - Producción

Introduction

Tutorial de Desarrollo de una Aplicación con Flask y Gestión con systemd

Referencias: Flask mega tutorial

Preparación del Entorno de Producción en Linux Ubuntu

Instalación de Dependencias

En tu máquina de producción con Linux Ubuntu, instala las dependencias necesarias:

sudo apt update
sudo apt install python3-pip nginx pipenv
sudo systemctl enable nginx

Una alternativa para usar un pipenv más actualizado es instalarlo con pip:

sudo apt install python3-pip nginx
pip install --user pipenv

Directorio de producción.

En lugar de ceder toda la propiedad a www-data, utilizaremos un esquema de permisos compartidos. Esto permite que tu usuario edite archivos y ejecute pipenv sin usar sudo, mientras que www-data mantiene el acceso necesario para servir la aplicación.

sudo mkdir /var/www/my_flask_app

Debemos copiar todos los ficheros que hemos preparado en el entorno de desarrollo al nuevo entorno de producción, para ello podemos usar scp, rsync o unison.

Fichero wsgi.py

En entornos de producción, Flask no se ejecuta mediante app.run(), ya que este método lanza un servidor de desarrollo que no está diseñado para ser seguro, eficiente ni persistente. En su lugar, se utiliza un servidor WSGI (Web Server Gateway Interface), como Gunicorn o uWSGI, que actúa como intermediario entre el servidor web (por ejemplo, Nginx) y la aplicación Python.

El fichero wsgi.py define el punto de entrada estándar de la aplicación, exponiendo el objeto app para que el servidor WSGI pueda importarlo y gestionarlo. De este modo, wsgi.py desacopla el código de la aplicación del mecanismo de ejecución, permitiendo una ejecución robusta, escalable y adecuada para producción.

Crea el fichero wsgi.py con el siguiente contenido:

====== wsgi.py ======
from app import app

Configuración de Grupos

Añade tu usuario personal al grupo de Nginx para que ambos compartan privilegios:

====== Añadir el usuario actual al grupo www-data ======
sudo usermod -aG www-data $USER

Nota: Se debe cerrar sesión y volver a entrar (o reiniciar el servidor) para que este cambio se aplique.

Asignación de Propiedad y Bit de Grupo

Configuramos tu usuario como propietario y www-data como grupo responsable. Aplicaremos el setgid bit, que garantiza que cualquier archivo nuevo creado herede automáticamente el grupo www-data.

====== Cambiar propietario al usuario actual y grupo a www-data ======
sudo chown -R $USER:www-data /var/www/my_flask_app
 
====== Dar permisos de lectura/escritura/ejecución a dueño y grupo (775) ======
sudo find /var/www/my_flask_app -type d -exec chmod 775 {} +
sudo find /var/www/my_flask_app -type f -exec chmod g+rw {} +
 
====== Aplicar el bit de grupo persistente (setgid) a todos los directorios ======
sudo find /var/www/my_flask_app -type d -exec chmod g+s {} +

Ventajas de este método

  • Tu Usuario: Puedes usar git pull, pipenv install y editar código sin sudo.
  • Nginx / www-data: Grupo (rwx) Puede leer archivos estáticos y escribir en el socket o logs.
  • Seguridad: Los usuarios que no pertenecen al grupo www-data no tienen acceso.

Verificación de permisos

Para confirmar que la configuración es correcta, ejecuta:

ls -la /var/www/my_flask_app

La salida debería mostrar los permisos como drwxrwxr-x y los dueños como tu_usuario www-data.

Configuración de Nginx

Configura Nginx para servir la aplicación Flask. Crea un nuevo archivo de configuración en /etc/nginx/sites-available/my\_flask\_app:

server {
    listen 80;
    server_name your_domain;
    access_log /var/log/nginx/my_flask_app.access.log;
    error_log /var/log/nginx/my_flask_app.error.log;
 
    location / {
        proxy_pass http://unix:/var/www/my_flask_app/my_flask_app.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;
    }
}
  • server\_name es donde va el dominio. Es el que usarás para acceder a la aplicación desde internet.
  • access\_log y error\_logs especifican la ruta de los archivos de log.
  • location es donde el reverse proxy de nginx accede a la aplicación Flask.
  • proxy\_redirect off: Evita que Nginx reescriba automáticamente cabeceras Location y Refresh que devuelve la aplicación backend (Gunicorn/Flask). Evitamos problemas de redirección difíciles de depurar.
  • proxy\_buffering off: Desactivamos el buffering de respuestas, que es lo más conveniente para webs dinámicas.

Habilitamos el sitio creando un enlace al fichero correspondiente de sites-enabled y reiniciando nginx.

sudo ln -s /etc/nginx/sites-available/my_flask_app /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl status nginx

Instalación de Gunicorn

Instala Gunicorn en el entorno virtual de producción. Se debe ejecutar export PIPENV_VENV_IN_PROJECT=1 antes de hacer el pipenv install en el servidor, o el servicio de systemd fallará al no encontrar la ruta de Gunicorn.

pipenv install gunicorn

Mientras estas en el entorno virtual comprueba la ruta de gunicorn. Toma nota de esta ruta. Se necesitará para configurar el servicio systemd.

$ which gunicorn
/var/www/my_flask_app/.venv/bin/gunicorn

Testing with gunicorn

Ahora comprobaremos el funcionamiento con gunicorn. Para la prueba ejecutamos gunicorn directamente. Después lo configuraremos en el servicio systemd.

gunicorn --workers 4 --bind 0.0.0.0:5000 wsgi:app
[2024-02-20 20:57:21 -0500] [4936] [INFO] Starting gunicorn 21.2.0
[2024-02-20 20:57:21 -0500] [4936] [INFO] Listening at: http://0.0.0.0:5000 (4936)
[2024-02-20 20:57:21 -0500] [4936] [INFO] Using worker: sync
[2024-02-20 20:57:21 -0500] [4937] [INFO] Booting worker with pid: 4937
[...]

Hacemos la comprobación:

curl -O - localhost:5000

Deberíamos obtener la salida de la página inicial de la aplicación.

Press CTRL+C to stop the Gunicorn server.

Esta prueba NO usa nginx, NO usa systemd y NO representa el entorno final, sólo comprueba el funcionamiento de gunicorn.

Creación del Servicio systemd

Crea un archivo de servicio systemd para gestionar la aplicación. Crea un archivo /etc/systemd/system/my_flask_app.service con el siguiente contenido:

[Unit]
Description=Gunicorn instance to serve my_flask_app
After=network.target
 
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/my_flask_app
Environment="PATH=/var/www/my_flask_app/.venv/bin"
ExecStart=/var/www/my_flask_app/.venv/bin/gunicorn --workers 3 --bind unix:/var/www/my_flask_app/my_flask_app.sock -m 007 wsgi:app
 
[Install]
WantedBy=multi-user.target
  • User: Establece el usuario con permisos para el directorio del proyecto.
  • Group: Establece el grupo con permisos para el directorio del proyecto.
  • Environment: Establece la ruta al directorio de ejecutables dentro del entorno virtual.
  • WorkingDirectory: Establece el directorio base donde están los ficheos del proyecto.
  • ExecStart: Establece la ruta al ejecutable de gunicorn dentro del entorno virtual, así como opciones de ejecución.
  • –workers N: Establece el número de workers. Ajustar el número posteriormente si hay algún problema. No más de 12.
  • –bind unix:: Asociamos la ejecución de gunicorn a un socket Unix.
  • wsgi:app: wsgi es el nombre del fichero sin la extensión .py. app es la instancia de la aplicación Flask dentro del fichero.
  • -m 007: Para que Nginx pueda comunicarse con el socket creado por Gunicorn sin errores de “Permission Denied”, es fundamental añadir la máscara de permisos -m 007 en la configuración del servicio.

Habilitar y Iniciar el Servicio

Habilita y inicia el servicio con los siguientes comandos:

sudo systemctl enable my_flask_app
sudo systemctl start my_flask_app

/etc/hosts provisional para pruebas en local

La aplicación Flask ya no es accesible a través del puerto 5000 que usábamos antes, sino a través de systemd, gunicorn y nginx. Para acceder a la aplicación hay que usar el nombre de dominio que hemos puesto en la configuración. Pero es conveniente probar en local antes de intentar un acceso desde internet. Para ello vamos a editar el fichero /etc/hosts del cliente e incluiremos una sentencia similar a esta, con la IP de la red local del servidor.

192.168.12.34 my_flask_app

Ahora podemos acceder a la aplicación con un browser a través del nombre de dominio: http://my_flask_app.

Deberíamos obtener la primera página de nuestra aplicación nuevamente.

Ahora la aplicación está probada y es posible modificar el DNS para que apunte a la dirección pública del servidor, volviendo a dejar el fichero /etc/hosts del cliente como estaba.

En caso de que no funcione desde internet habrá que comprobar direcciones IP externas y firewalls tanto en el servidor cómo en el router.

computing/web/flask_app_2.txt · Última modificación: por 127.0.0.1