Flask, entornos virtuales VENV y Apache en Centos7

Recientemente he estado trabajando en cómo integrar el Framework de Python Flask con un servidor web corriendo bajo Centos7 y así poder tenerlo siempre disponible con las ventajas que ofrecen este tipo de soluciones. Para esta ocasión el servidor web escogido fue Apache.

No fue una tarea fácil, pero finalmente conseguí hacerlo funcionar, y el resultado quería compartirlo con la comunidad por si le pudiera servir de ayuda a alguien.

Flask es un Framework minimalista de Python destinado a la creación de aplicaciones web y API Rest con muy pocas líneas de código. Al decir que es minimalista nos referimos a que en comparación a otros Frameworks, como Django, no dispone de todos los módulos aunque sí se podrá complementar con librerías de terceros que ofrezcan las funcionalidades de las que carece. Está basado en la especificación WSGI de Werkzeug y el motor de templates Jinja2 y tiene una licencia BSD. Sus ventajas son muchísimas, por lo que te animo a que investigues un poco más sobre este interesante Framework.

Los entornos virtuales de Python nos van a permitir crear estancias aisladas en donde podremos instalar y usar librerías sin que afecte a la instalación global o a otros entornos virtuales creados. Es una gran forma de probar librerías en diferentes desarrollos y evitar incompatibilidades entre estas o ante la necesidad de usar versiones distintas de una misma librería.

Esta entrada no se centrará en la instalación de versiones de Python. Recomendamos utilizar la versión 3, aunque serviría con la 2.7, por lo que os dejo un enlace en donde se explica en detalle como hacerlo de forma muy sencilla https://linuxize.com/post/how-to-install-python-3-on-centos-7/. Ignorad la parte en donde se explica la instalación de los entornos virtuales, ya que no es compatible con la integración del WSGI de Apache que vamos a utilizar en este tutorial.

Vamos al lío!!!!!


Requisitos

  • Centos 7
  • Python 3.6
  • Pip
  • Librería virtualenv de Python
  • Librería Flask de Python
  • Apache
  • Apache Web Server Gateway Interface – WSGI

Apache WSGI

Instalamos el módulo WSGI para Apache:

sudo yum install mod_wsgi

Comprobamos que se ha instalado correctamente:

httpd -M | grep wsgi

De no estarlo tocará investigar un poco.


Pip y virtualenv

Ahora instalamos la versión de Pip compatible con nuestra versión de Python (2 o 3). No indico ninguna versión en el comando para que quede a elección del usuario:

sudo yum install python-pip

Ahora toca instalar los entornos virtuales de Python:

sudo pip install virtualenv

Por ejemplo, en mi caso sería pip3 install virtualenv.


Entorno virtual

Para crear un entorno virtual primero creamos el directorio en el que vamos a trabajar y nos ubicamos en el:

mkdir /path/to/your/app
cd /path/to/your/app

Ahora ejecutamos el comando para crear el entorno virtual. Le tenemos que indicar un nombre al entorno virtual, lo que creará un nuevo directorio en donde se ubicarán las librerías que utilizaremos únicamente en este entorno aislado y los comandos para activar/desactivar el entorno virtual. Indicar la versión de Python que se va a utilizar sustituyéndolo en donde aparece pythonX:

virtualenv env_name -p pythonX

Por ejemplo, en mi caso uso Python en su versión 3, por lo que indico -p python3 en el comando.

Activamos el entorno virtual:

source env_name/bin/activate

Ahora en el promp aparece el nombre que le dimos al entorno virtual al comienzo de la línea de comandos:

(env_name)user@host:~/app$

Flask

Instalamos la librería Flask con el comando pip:

pip install flask

Ahora tendremos una instalación de Flask únicamente para el entorno virtual en el que nos encontramos.

Creamos en el mismo directorio del entorno virtual una aplicación sencilla de Flask:

nano /path/to/your/app/my_app.py

Esta aplicación devolverá un sencillo «Hola mundo!» por pantalla. Recordar cambiar el host en donde escuchará la aplicación, al final del documento (X.X.X.X). Se puede indicar una IP del servidor o un nombre de host que resuelva a dicha IP:

#!/usr/bin/python3

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def index():
        return 'Hola mundo!'


if __name__ == '__main__':
       app.run(debug=True, host=X.X.X.X)

Con el flag debug=True podemos hacer cambios en caliente sobre el documento sin tener que reiniciar el servidor web.


WSGI config

Creamos un archivo en donde indicamos al servidor WSGI cómo activar el entorno virtual y ejecutar la aplicación de Flask recién creada. Tendrá una extensión .wsgi y se encontrará en el mismo path que el entornor virtual y la aplicación de Flask creada:

nano /path/to/your/app/app.wsgi

En este archivo importaremos la aplicación creada y la renombraremos, además de indicar el comando para activar el entorno virtual del que hará uso el servidor web, como veremos más adelante:

from my_app import app as application

activate_this = '/path/to/my/app/nom_entorno_virt/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

Apache y VirtualHost

Primero configuramos Apache para habilitar el directorio en donde se ubicarán los archivos de configuración de los VirtualHost que tendremos en el servidor web:

nano /etc/httpd/conf/httpd.conf

Tendremos que asegurarnos de disponer de la siguiente línea:

IncludeOptional sites-enabled/*.conf

Y si usamos el flag de Flask debug=True debemos de agregar también esta:

WSGIRestrictStdout Off

Ahora creamos el contenido del VirtualHost imaginando que nuestra aplicación escuchará hará uso del dominio example.com:

sudo nano /etc/httpd/sites-available/example.conf
<VirtualHost *:80>

        WSGIDaemonProcess my_app user=apache group=apache threads=5 python-path=/path/to/my/app:/path/to/my/app/lib/python3.6/site-packages
  WSGIScriptAlias / /path/to/my/app/my_app.wsgi
        # You have to add every Flask route as WSGI alias:
        WSGIScriptAlias /(.*) /path/to/my/app/my_app.wsgi/(.*)
        <Directory /var/www/html/flask>
                WSGIProcessGroup my_app
                WSGIApplicationGroup %{GLOBAL}
                Order deny,allow
                Allow from all
        </Directory>

        ServerName example.com
        ServerAdmin example@example.com
        DocumentRoot /path/to/your/app
        # DocumentRoot /home/ubuntu/test
        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn
        LogLevel warn
        ErrorLog /var/log/httpd/my_app-error.log
        CustomLog /var/log/httpd/my_app-access.log combined

</VirtualHost>

Ahora creamos el enlace simbólico desde el directorio sites-available al de sites-enabled, configurado previamente en el archivo de configuración de Apache:

ln -s /etc/httpd/sites-available/example.conf /etc/httpd/sites-enabled/example.conf

Cambiamos los permisos del directorio en donde tenemos la aplicación ubicada:

sudo chown -vR apache: /path/to/your/app
sudo chmod -vR g+w /path/to/your/app

Y para finalizar reiniciamos el servidor web:

sudo service httpd restart

Acceso

Ahora si accedemos a la URL que hemos configurado en el servidor web, en nuestro caso http://example.com, veremos la aplicación creada en un entorno virutal de Python con Flask y administrada por el servidor web Apache:


Enlaces de interés

Flask pincha aquí.

WSGI pincha aquí.

Python 3 instalación en Centos 7 – https://linuxize.com/post/how-to-install-python-3-on-centos-7/

Apache wsgi pincha aquí.