Una Web en Python sobre Apache, sin frameworks y en solo 3 pasos

Frecuentemente, todos los pythoneros nos llenamos la boca diciendo que “sin un framework, crear una WebApp en Python es imposible”. Pero claro, que esa frase no es menos exagerada que decir “si pierde mi equipo de fútbol me mato”. Son “formas de decir”.

La pregunta es ¿qué sucede si no tienes necesidad de crear una gran app? En ese caso ¿no es un desperdicio utilizar un framework como Django, por ejemplo?

Aquí es entonces, cuando surge la idea de este simple y sencillo tuto, para que en solo 3 pasos, tengas tu Web en Python, sobre Apache y por qué no, conviviendo con otras App en PHP.

Paso 1: Instalar mod_wsgi

mod_wsgi es un módulo de Apache que provee una interfaz WSGI para correr aplicaciones Web en Python sobre Apache. Y esto, es todo lo que necesitas para que tus archivos .py se ejecuten por medio de un navegador Web. Asumiendo que YA tienes instalado Python y Apache, solo debes descargar el paquete libapache2-mod-wsgi para ejecutar archivos en Python 2+ o libapache2-mod-wsgi-py3 para Python 3+.

apt-get install libapache2-mod-wsgi

Paso 2: Configurar el virtual host

En el virtual host, está la clave para correr aplicaciones Web en Python sobre Apache.

El DocumentRoot -al igual que se hace tradicionalmente con cualquier Web Site-, deberá ser un directorio servido pero, aquí NO colocaremos nuestra Python App. Este directorio, solo almacenará archivos estáticos o cualquier otro que no sea .py

El truco, estará entonces, en una variable: WSGIScriptAlias a la cual le indicaremos que cualquier petición que llegue a nuestra Web, deberá ser procesada por el script WSGI de nuestra Python App (la cuál, deberá almacenarse en un directorio no servido).

Antes de configurar el virtual host, tengamos en claro como será la estructura de directorios:

(a) Directorio application: directorio NO servido que almacenará toda nuestra app en Python

(b) Archivo application.wsgi: script wsgi que manejará todas las peticiones del usuario a través de la URI

(c) Directorio public_html: directorio SERVIDO que solo almacenará archivos estáticos, nada o vaya uno a saber que cosa mientras que no sea nuestra Python App

Con esto en claro, solo quedará crear y configurar el virtual host para nuestra nueva Web:

1) Crear el archivo virtual host

echo "" > /etc/apache2/sites-available/misitio.com

2) Configurar el virtual host

2.1) Agregar el nuevo host

Si estás trabajando localmente, para no sobreescribir tu virtual host por defecto (archivo default), creando un nuevo virtual host, tienes la posibilidad de agregarlo al /etc/hosts para que en vez de correrlo mediante http://localhost puedas correrlo a través de http://mi_otro_host, por ejemplo:

127.0.0.1 misitio.com

3) Habilitar el nuevo sitio y el módulo rewrite de Apache

a2enmod rewrite | a2ensite misitio.com

4) Reiniciar Apache

service apache2 restart

Paso 3: Crear el archivo application.wsgi

Este archivo, recordemos que estará alojado en nuestra carpeta no servida, application. En este archivo necesitaremos una función application la cual tomará dos parámetros: environ del módulo os, que provee de un diccionario de las peticiones HTTP estándar y la función start_response, encargada de entregar la respuesta HTTP al usuario. Veamos un ejemplo sencillo:

Si ingresas a tu sitio Web (el configurado anteriormente), podrás ver la frase “Hola Mundo!” en negritas.

Como puedes ver, la variable temporal output es quien almacenará todo el contenido HTML (ya con el render hecho). Esto significa, que dicha variable, podría por ejemplo, obtener su valor desde la llamada a un módulo propio de nuestra Python App:

Incluso, podría ser aún más dinámico, switcheando la petición de REQUEST_URI:

Es importante aclarar que con cada cambio que se haga a la aplicación, se debe reiniciar Apache para que los cambios se reflejen sin conflictos.

Otro aspecto a tener en cuenta, es que cuando se produzcan errores 500 (Internal Server Errors) hay que acostumbrarse a mirar los logs en el archivo py_errors.log que configuramos en el virtual host, para conocer el error producido y así poder resolverlo.

Puedes además, descargar una mini-python-app de muestra, desarrollada con este tuto.

Espero que les haya servido y ¡hasta la próxima!

 

eugeniabahit

 

17 thoughts on “Una Web en Python sobre Apache, sin frameworks y en solo 3 pasos

  1. Excelentemente explicado, muy simple, nunca había pensado en algo web con Python sin un framework como Django, como bien comentas en este post.

  2. muchas gracias Euge…muy bien explicado ahora lo probare a ver si no me vuelvo loco jajaj digo cabe mencionar que soy super novato en estos menesteres jeje.

    saludos.

  3. Buen tutorial y me permito agregar algo…
    Si se configura el mod_wsgi en modo daemon se puede reiniciar en cada peticion, se hace colocando esta rutina en el script .wsgi:
    if environ['mod_wsgi.process_group']:
    import signal
    os.kill(os.getpid(), signal.SIGINT)

    Y para que esto funcione se declaran las siguientes variables en el VirtualHost:

    WSGIDaemonProcess nombre_cualquiera threads=25
    WSGIProcessGroup nombre_cualquiera

    Espero sirva de algo este pequeño agregado.

    1. Excelente aporte, Alvaro! Muchísimas gracias por tu colaboración! 🙂

      Solo agregar que esta alternativa, es excelente para implementar en servidores de desarrollo y en lo posible, hay que tratar de evitar implementarla en servidores de producción, puesto que en apps con tráfico alto, puede verse afectado el rendimiento operativo del server.

      Mil gracias de nuevo!
      Un abrazo!
      Eugenia

  4. Gracias a ti, para mi es un placer colaborar.

    Tienes toda la razón, particularmente uso esta practica en mi servidor local de desarrollo.

  5. Hola. Gracias por el artículo, ahora mismo estoy construyendo una web sin ningún framework.

    Pero tengo una duda. ¿Como hacés para establecer conecciones seguras para enviar datos de formularios?.

    Saludos y gracias.

  6. Bueno, digamos que tengo este formulario:

    Usuario

    Contraseña

    Y uso tu application.wsgi así:

    # -*- coding: utf-8 *-*

    import os, sys

    sys.path.append(‘/ruta/a/application’)

    def application(environ, start_response):
    peticion = environ[‘REQUEST_URI’]

    if peticion = ‘/validar’:
    from mipaquete.validar import validar_formulario
    ouput = validar_formulario()

    start_response(‘200 OK’,
    [(‘Content-Type’,
    ‘text/html; charset=utf-8’)])

    return output

    Entonces, la pregunta es ¿como hago que los datos del formulario se envíen encriptados al servidor? O sea, quiero proteger esos datos de alguna manera.

  7. @alan, en ese caso, no depende de Python. Para enviar datos encriptados, podés trabajar a través de HTTPS (necesitarás un certificado de seguridad, pero a lo que voy es que no necesitas de Python para eso). Salvo que, lo que estés buscando, sea hashear esos datos (y no enviarlos encriptados).
    Si lo que necesitás es hashearlos, simplemente podés utilizar hashlib. Para levantar los datos desde un form, podés hacerlo através de la clave wsgi.input del diccionario environ. Es un objeto tipo file que lees con read:
    datos_form = environ[‘wsgi.input’].read()

    Eso te retorna los datos como un querystring:
    campo1=valor&campo2=otro_valor

  8. Ah, ok. Voy a investigar eso del HTTPS. Yo hasheaba los datos con la librería cgi y no sabía que se podía hacer como vos decís.

    Gracias por tu ayuda 😀

  9. hola eugenia, sabes me e instalado un servidor ISP con un panel ISPConfig, todo trabaja bien, mi problema es que no entiendo mucho sobre los DNS, no se como asignarles IP, no e logrado comunicar un dominio comprado en Gandi.net hacia el servidor.
    Como le podría hace, como creo las IP para los DNS?

Comments are closed.