Despliegue completo del proyecto Flask de la calculadora en mi servidor Linux
Este documento explica de forma detallada todo el proceso seguido para desplegar mi proyecto Flask de la calculadora en un servidor Linux. Cada paso incluye una explicación profunda del por qué se realiza y cómo encaja dentro del funcionamiento general del servidor. El objetivo es entender no solo qué comandos ejecutar, sino también la lógica detrás de cada acción.
1. Creación de la estructura del proyecto
El primer paso fue crear una estructura de carpetas clara dentro de /var/www. Esta ruta se utiliza tradicionalmente para alojar aplicaciones web en servidores Linux porque permite separar el código de usuario del resto del sistema y facilita la organización.
sudo mkdir -p /var/www/calculadora sudo mkdir -p /var/www/calculadora/static sudo mkdir -p /var/www/calculadora/templates
La carpeta principal contiene el proyecto.
La carpeta static almacena archivos que no cambian, como CSS, imágenes o JavaScript.
La carpeta templates contiene las plantillas HTML que Flask renderiza dinámicamente.
Separar estas carpetas es importante porque Flask y Nginx tratan los archivos estáticos de forma distinta: Flask los referencia, pero Nginx los sirve directamente para mejorar el rendimiento.
2. Asignación de permisos y propietarios
El servidor necesita saber qué usuario tiene control sobre los archivos. Si los permisos no son correctos, systemd o Gunicorn podrían no tener acceso al proyecto, provocando fallos silenciosos.
sudo chown -R serherm:serherm /var/www/calculadora sudo chmod -R 755 /var/www/calculadora
El comando chown asigna el propietario y grupo del proyecto.
El comando chmod 755 permite lectura y ejecución para todos, pero escritura solo para el propietario.
Esto garantiza que el servicio pueda leer el código, pero evita que otros usuarios del sistema lo modifiquen accidentalmente.
Me he dado permisos a serherm (y luego en la configuración de gunicorn) para evitarnos dolores de cabeza.
3. Creación del entorno virtual
Un entorno virtual permite aislar las dependencias del proyecto. Esto evita conflictos con otras aplicaciones del servidor y mantiene un control total sobre las versiones de las librerías.
cd /var/www/calculadora python3 -m venv venv-calc source venv-calc/bin/activate
El entorno venv-calc contiene su propio Python y su propio pip.
Activarlo hace que cualquier instalación afecte solo al proyecto, así como las versiones de las dependencias usadas.
Instalé Flask y Gunicorn dentro del entorno:
pip install flask gunicorn
Flask es el framework web.
Gunicorn es el servidor WSGI que ejecutará Flask en producción.
Flask no debe ejecutarse directamente en producción porque no está diseñado para manejar múltiples conexiones simultáneas ni para ser seguro frente a ataques.
4. Creación del archivo app.py
El archivo principal del proyecto se encuentra en:
/var/www/calculadora/app.py
Aquí definí las rutas de la aplicación, la lógica de la calculadora y cómo Flask responde a las peticiones.
La aplicación está diseñada para responder desde "/", porque Nginx se encargará de aplicar el prefijo externo "/proyectos/calculadora/" (esto me ha supuesto un quebradero de cabeza, pero con la / final hace que nginx le pase a Flask la ruta como "/". No olvidéis reiniciar nginx y el servicio de la web al hacer cambios... os ahorrará tiempo).
Separar la lógica en app.py permite que Gunicorn cargue la aplicación mediante la sintaxis app:app, donde el primer "app" es el archivo y el segundo es la instancia de Flask.
Los archivos CSS se colocaron en static/ y las plantillas HTML en templates/, siguiendo la estructura estándar de Flask.
5. Prueba manual con Gunicorn
Antes de automatizar el servicio, es fundamental comprobar que la aplicación funciona correctamente ejecutada por Gunicorn. Esto permite detectar errores antes de integrarla con systemd.
cd /var/www/calculadora source venv-calc/bin/activate gunicorn --bind 127.0.0.1:8010 app:app
El parámetro --bind indica que Gunicorn escuchará en la dirección local 127.0.0.1 y en el puerto 8010.
Usar localhost evita que el servicio sea accesible directamente desde Internet, obligando a que todo pase por Nginx, que es quien gestiona la seguridad y el HTTPS.
6. Creación del servicio systemd
Para que la aplicación se ejecute automáticamente al arrancar el servidor y se mantenga siempre activa, creé un servicio systemd. Esto convierte la aplicación en un proceso gestionado por el sistema operativo.
sudo nano /etc/systemd/system/calculadora.service
El servicio define:
- La ruta del entorno virtual
- El comando exacto para ejecutar Gunicorn
- El usuario que debe ejecutar el servicio
- El directorio donde se encuentra el proyecto
- El puerto interno donde escucha Gunicorn
- La política de reinicio automático
Después activé y arranqué el servicio:
sudo systemctl daemon-reload sudo systemctl enable calculadora sudo systemctl start calculadora sudo systemctl status calculadora
daemon-reload recarga la lista de servicios.
enable hace que el servicio se inicie automáticamente al arrancar el servidor.
start lo inicia inmediatamente.
status permite comprobar que está funcionando correctamente.
Este paso es crítico porque garantiza que la aplicación no dependa de comandos manuales y que se recupere sola si falla.
7. Configuración de Nginx
Nginx actúa como servidor frontal. Su misión es:
- Servir archivos estáticos directamente desde el sistema de archivos
- Redirigir las rutas dinámicas a Gunicorn
- Aislar la aplicación dentro de un subdirectorio
- Gestionar HTTPS y cabeceras de seguridad
La configuración se encuentra en:
sudo nano /etc/nginx/sites-available/main_web
Rutas dinámicas hacia Gunicorn
location /proyectos/calculadora/ { proxy_pass http://127.0.0.1:8010/; 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; }
Este bloque captura cualquier ruta que empiece por /proyectos/calculadora/ y la envía a Gunicorn, que después se lo pasa a Flask.
Las cabeceras proxy_set_header permiten que Flask conozca la IP real del cliente y el protocolo original (HTTP o HTTPS).
Archivos estáticos de la calculadora
location /proyectos/calculadora/static/ { alias /var/www/calculadora/static/; }
El alias indica que los archivos estáticos se encuentran físicamente en /var/www/calculadora/static/.
Nginx sirve estos archivos directamente, sin pasar por Flask, lo que mejora el rendimiento y reduce la carga del servidor. Por ejemplo, en el html, ha habido que poner /proyectos/calculadora/static/estilos.css, porque si sólo pusiéramos static/estilos.css haría match con el location de la otra página web y efectivamente ahí no está el css. No puede haber location duplicados, por lo que se tiene que quedar con la ruta completa. Podríamos haber renombrado la carpeta a static-calc y haber hecho location /static-calc/ para después en el html hacer /static-calc/estilos.css, pero ya lo dejé así. Lo mismo para el .js, obviamente.
8. Recarga de Nginx
Cada cambio en la configuración requiere validación y recarga:
sudo nginx -t sudo systemctl restart nginx
nginx -t comprueba que la configuración no contiene errores de sintaxis.
restart aplica los cambios y reinicia el servicio.
De verdad, hacer esto cada vez que haces un cambio te salva la vida, así ni Chrome ni Nginx omiten los cambios que acabas de hacer y así no piensas que ese cambio ha sido inútil!
9. Pruebas finales
Probé la aplicación desde el navegador:
https://serblog.hopto.org/proyectos/calculadora/
Verifiqué:
- Que Flask respondiera correctamente
- Que los archivos estáticos se sirvieran desde /proyectos/calculadora/static/
- Que el servicio systemd estuviera activo
- Que Gunicorn escuchara en el puerto 8010
- Que Nginx redirigiera correctamente las rutas
Conclusión
El despliegue combina una estructura de carpetas organizada, permisos correctos, entorno virtual aislado, Flask como backend, Gunicorn como servidor WSGI, systemd como gestor de procesos, Nginx como servidor frontal, HTTPS para seguridad, alias para estáticos y proxy para rutas dinámicas.
El resultado es un servicio robusto, modular y fácil de mantener.