Introducción al despliegue de aplicaciones Django con Apache2 y el módulo WSGI
Contexto: del entorno de desarrollo al entorno de producción
Hasta ahora hemos trabajado con Django usando el servidor de desarrollo que se ejecuta con el comando:
python3 manage.py runserver
Este servidor es muy útil para pruebas locales, pero no está diseñado para entornos de producción, ya que no ofrece:
- Rendimiento suficiente para múltiples clientes.
- Seguridad y aislamiento adecuados.
- Gestión eficiente de procesos.
En producción, normalmente usamos un servidor web real como Apache2 o Nginx, que se encarga de:
- Atender las peticiones HTTP de los clientes.
- Servir directamente el contenido estático (imágenes, CSS, JavaScript).
- Delegar la ejecución de la aplicación Django a un módulo intermedio, en este caso
mod_wsgi, que permite ejecutar aplicaciones Python dentro de Apache.
El protocolo WSGI
WSGI (Web Server Gateway Interface) es una especificación que define cómo un servidor web (como Apache o Nginx) comunica peticiones HTTP a una aplicación Python.
En pocas palabras:
- Apache recibe una petición HTTP.
- A través del módulo mod_wsgi, la envía a la aplicación Django.
- Django procesa la petición (por ejemplo, consultando la base de datos y renderizando una plantilla HTML).
- El resultado se devuelve a Apache, que responde al cliente.
Este mecanismo permite integrar aplicaciones Python con servidores web de propósito general de forma estándar y eficiente.
El archivo wsgi.py en Django
Cada proyecto Django incluye un archivo llamado wsgi.py, normalmente ubicado en el directorio del proyecto (por ejemplo, guestbook_project/guestbook_project/wsgi.py).
Este archivo define un objeto llamado application, que es el punto de entrada que el servidor Apache (a través de mod_wsgi) utilizará para comunicarse con Django.
Ejemplo simplificado del contenido del archivo:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'guestbook_project.settings')
application = get_wsgi_application()
En resumen:
wsgi.py es el enlace entre Apache y Django, y su correcta configuración es imprescindible para que la aplicación funcione en producción.
Módulos necesarios en Apache2
Para que Apache2 pueda ejecutar aplicaciones Python, debe tener instalado el módulo mod_wsgi.
En sistemas basados en Debian/Ubuntu, se instala con:
sudo apt install libapache2-mod-wsgi-py3
Una vez instalado, el módulo se activa automáticamente. Si no es así, puede activarse manualmente con:
sudo a2enmod wsgi
sudo systemctl reload apache2
Configuración del VirtualHost
A continuación se muestra una configuración típica para desplegar un proyecto Django llamado guestbook_project, ubicado en /home/debian/guestbook_project, con un entorno virtual en /home/debian/venv/django/.
Para que el servidor web apache2 sea capaz de acceder a los ficheros de nuestra aplicación, tenemos que configurar los permisos:
chmod o+x /home/debian/guestbook_project
Archivo: /etc/apache2/sites-available/guestbook.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName guestbook.local
DocumentRoot /home/debian/guestbook_project
# === Configuración del proceso WSGI ===
WSGIDaemonProcess django_guestbook python-path=/home/debian/guestbook_project:/home/debian/venv/django/lib/python3.X/site-packages
WSGIProcessGroup django_guestbook
WSGIScriptAlias / /home/debian/guestbook_project/guestbook_project/wsgi.py process-group=django_guestbook
# === Archivos estáticos (CSS, imágenes, JS) ===
Alias /static/ /home/debian/guestbook_project/static/
<Directory /home/debian/guestbook_project/static>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/guestbook_error.log
CustomLog ${APACHE_LOG_DIR}/guestbook_access.log combined
</VirtualHost>
Nota: Tienes que mirar la versión de python3 para sustituir el nombre del directorio pythonX.X.
Vamos a explicar la configuración:
- El
DocumentRootse indica el directorio donde está la aplicación. Realmente el servidor web siempre va a llamar al fichero WSGIwsgi.py, pero elDocumentRootes necesario para servir el contenido estático. - La directiva
WSGIDaemonProcess: Se define un grupo de procesos que se van a encargar de ejecutar la aplicación (servidor de aplicaciones). A estos procesos se le ponen un nombre (django_guestbook) y se indica los directorios donde se encuentran la aplicación y los paquetes necesarios (python-path), como puedes observar se pone el directorio donde esta la aplicación y el directorio donde se encuentran los paquetes en el entorno virtual, separados por dos puntos. WSGIProcessGroup: Nos permite agrupar procesos. Se pone el mismo nombre que hemos definido en la directiva anterior.- La directiva
WSGIScriptAliasnos permite indicar que programa se va a ejecutar (el fichero WSGI:/home/debian/guestbook/wsgi.py) cuando se haga una petición a la url/y que proceso lo va a ejecutar. Alias /static/: Nos permite indicar la ruta de contenidos estáticos. Lo explicaremos a continuación.
El problema del contenido estático
En Django, muchos recursos estáticos (CSS, imágenes, JavaScript) no están ubicados en la carpeta del proyecto, sino distribuidos dentro de las aplicaciones del framework. Por ejemplo:
- Los estilos del panel de administración (
/admin/) se encuentran en los paquetes internos de Django. - Nuestros propios archivos estáticos pueden estar en
static/.
En un entorno de desarrollo, Django los sirve automáticamente. Pero en producción, Apache no los conoce si no los copiamos a un único lugar accesible.
Solución: collectstatic
Django proporciona el comando collectstatic, que recopila todos los archivos estáticos (de las apps y del proyecto) en una única carpeta, normalmente /static/.
source /home/debian/venv/django/bin/activate
cd /home/debian/guestbook_project
python3 manage.py collectstatic
Este comando crea o actualiza el directorio /home/debian/guestbook_project/static/ con todos los archivos necesarios.
El bloque Alias /static/ del VirtualHost permite que Apache los sirva directamente a los clientes, sin pasar por Django.
Nota: Si esta operación da un error, tendremos que definir de manera adecuada la variable STATIC_ROOT en el fichero setting.py indicando el directorio donde se guardan los contenidos estáticos.
:::caution[Ejercicio]
- Realiza la implementación de la aplicación
guestbook_djangocon apache2 y el mod_wsgi. A la aplicación se acceder con el nombreguestbook.example.org. - Realiza la implementación de la aplicación
tutorial_djangocon apache2 y el mod_wsgi. A la aplicación se acceder con el nombrepoll.example.org. :::