Tutorial de Desarrollo de una Aplicación con Flask y Gestión con systemd
Referencias: Flask mega tutorial
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
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.
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
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.
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 {} +
git pull, pipenv install y editar código sin sudo. www-data no tienen acceso. 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.
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; } }
reverse proxy de nginx accede a la aplicación Flask.
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
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
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.
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
gunicorn dentro del entorno virtual, así como opciones de ejecución.gunicorn a un socket Unix..py. app es la instancia de la aplicación Flask dentro del fichero. -m 007 en la configuración del servicio.Habilita y inicia el servicio con los siguientes comandos:
sudo systemctl enable my_flask_app sudo systemctl start my_flask_app
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.