Evita errores – Cómo almacenar imágenes en AWS S3 desde Flask - Episodio 23

almacenar-imagenes-flask-en-aws-s3

Hoy vengo con evita errores a cómo almacenar imágenes en AWS S3 desde flask

Índice
  1. 🚀 Pasando de almacenamiento local a AWS S3. 📅 Diario de un SaaS
  2. 🔍 Problema: Almacenamiento local no escalable
  3. 🛠️ Configuración de AWS S3 e integración con Flask
    1. ✅ 1. Crear un bucket en AWS S3
    2. ✅ 2. Configurar credenciales de AWS en Flask
    3. ✅ 3. Crear un endpoint /upload-image para subir imágenes
  4. ❌ Errores encontrados y cómo los solucioné
    1. 🔴 AccessDenied: La imagen no es accesible públicamente
    2. 🔴 botocore.exceptions.NoCredentialsError: No se encontraron credenciales
    3. 🔴 RequestEntityTooLarge: El archivo es demasiado grande
  5. 💡 Aprendizajes del proceso
    1. 🔹 Guardar imágenes en el servidor es una mala idea
    2. 🔹 AWS S3 simplifica el manejo de archivos y mejora el rendimiento
    3. 🔹 Usar variables de entorno evita exponer credenciales
    4. 🔹 Validar y optimizar imágenes antes de subirlas
  6. Conclusión y reflexiones
    1. Reflexión
  7. 🚀 Próximos pasos

🚀 Pasando de almacenamiento local a AWS S3. 📅 Diario de un SaaS

Uno de los desafíos en mi SaaS era la gestión de imágenes.

Inicialmente, las almacenaba en el servidor, pero esto presentaba varios problemas:

🔴 Espacio limitado en el VPS. Con el tiempo, subir muchas imágenes llenaría el almacenamiento.

🔴 Falta de escalabilidad. Si el SaaS crecía, gestionar archivos en el servidor sería un cuello de botella.

🔴 Tiempo de carga lento. No tener un CDN o almacenamiento optimizado afectaba la velocidad de carga.

La solución: migrar la gestión de imágenes a AWS S3.

Ya que esto me iba a permitir no incurrir en tener que aumentar espacio en el VPS así como también seguir con un modelo SaaS escalable.

Por eso, en este post te cuento cómo lo hice, los errores que encontré y cómo optimicé la integración. 🚀


🔍 Problema: Almacenamiento local no escalable

Hasta ahora, las imágenes se guardaban directamente en el VPS dentro de una carpeta /uploads/.

Y claro, esto tenía varias desventajas:

🔴 Riesgo de perder archivos. Si el servidor fallaba, las imágenes podían desaparecer.

🔴 Carga en el servidor. Cuantas más imágenes, más recursos consumía el VPS.

🔴 No era accesible globalmente. Para servir imágenes en diferentes regiones, necesitaba un almacenamiento distribuido.

Así que me puse a investigar y di con la solución de AWS S3.

Es decir, AWS S3 solucionaba todo esto al permitir un almacenamiento seguro, escalable y accesible globalmente. 🔥

¿Qué más podía pedir?

Una vez había encontrado la solución ya solo me quedaba implementarla...


🛠️ Configuración de AWS S3 e integración con Flask

Para migrar a S3, realicé los siguientes pasos:

✅ 1. Crear un bucket en AWS S3

1️⃣ Entré en la consola de AWS y fui a S3.
2️⃣ Creé un nuevo bucket con un nombre único (ejemplo: mi-saas-imagenes).
3️⃣ Configuré los permisos del bucket para que los archivos sean accesibles públicamente a través de una URL.
4️⃣ Activé la opción de versión de archivos para evitar sobrescribir imágenes por error.


✅ 2. Configurar credenciales de AWS en Flask

Para que Flask pudiera subir imágenes a S3, necesitaba autenticarme con AWS.

Así que en lugar de poner las credenciales en el código (¡nunca hagas esto!), usé variables de entorno:

1️⃣ Instalar boto3, el SDK de AWS para Python:

pip install boto3

2️⃣ Crear un archivo .env y agregar las credenciales de AWS:

AWS_ACCESS_KEY_ID=TU_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=TU_SECRET_KEY
AWS_REGION=us-east-1
AWS_S3_BUCKET=mi-saas-imagenes

3️⃣ Cargar las variables en Flask con python-dotenv:

pip install python-dotenv

Luego, en app.py:

from dotenv import load_dotenv
import os
load_dotenv()

AWS_ACCESS_KEY = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_KEY = os.getenv('AWS_SECRET_ACCESS_KEY')
AWS_REGION = os.getenv('AWS_REGION')
AWS_S3_BUCKET = os.getenv('AWS_S3_BUCKET')

✅ 3. Crear un endpoint /upload-image para subir imágenes

Con Flask y boto3, creé un endpoint para manejar la subida de imágenes a AWS S3:

import boto3
from flask import Flask, request, jsonify

app = Flask(__name__)

s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key=AWS_SECRET_KEY, region_name=AWS_REGION)

@app.route('/upload-image', methods=['POST'])
def upload_image():
    if 'file' not in request.files:
        return jsonify({'error': 'No se encontró el archivo'}), 400
    
    file = request.files['file']
    file_name = file.filename
    
    s3.upload_fileobj(file, AWS_S3_BUCKET, file_name, ExtraArgs={'ACL': 'public-read'})
    file_url = f"https://{AWS_S3_BUCKET}.s3.{AWS_REGION}.amazonaws.com/{file_name}"
    
    return jsonify({'url': file_url})

🔹 ¿Qué hace este código?

Recibe una imagen desde un formulario o API.

La sube a AWS S3 con permisos públicos.

Devuelve la URL de la imagen alojada en S3.

Ahora cualquier usuario puede subir imágenes y recibir una URL accesible globalmente. 🚀


❌ Errores encontrados y cómo los solucioné

🔴 AccessDenied: La imagen no es accesible públicamente

Solución:

  • Asegurar que el archivo se sube con ACL: public-read en ExtraArgs.
  • Revisar la configuración del bucket para permitir accesos públicos.

🔴 botocore.exceptions.NoCredentialsError: No se encontraron credenciales

Solución:

  • Verificar que las credenciales están cargadas correctamente desde .env.
  • Ejecutar echo $AWS_ACCESS_KEY_ID en la terminal para comprobar si las variables de entorno están disponibles.

🔴 RequestEntityTooLarge: El archivo es demasiado grande

Solución:

  • Configurar un límite de tamaño de archivo en la API de Flask.
  • Habilitar multipart upload en boto3 para archivos pesados.
  • configurar-flask-con-aws-s3-imagenes

 


💡 Aprendizajes del proceso

🔹 Guardar imágenes en el servidor es una mala idea

Al principio parecía fácil, pero se vuelve insostenible a medida que crece la aplicación.

Básicamente es una mierda y a medida que vaya creciendo la mierda se hará más grande.

Es decir, más imágenes implica más espacio.

Y claro más espacio implica más coste en infraestructura.

Y no solo eso, también tiene una implicación directa en el rendimiento.

🔹 AWS S3 simplifica el manejo de archivos y mejora el rendimiento

Las imágenes ahora cargan más rápido y son accesibles desde cualquier parte del mundo.

🔹 Usar variables de entorno evita exponer credenciales

Nunca se deben escribir las credenciales en el código. .env y python-dotenv son imprescindibles.

🔹 Validar y optimizar imágenes antes de subirlas

Para evitar errores, es clave establecer límites de tamaño y formato en la API.

Conclusión y reflexiones

Mi principal obsesión es que haya una buena experiencia de usuario.

Y claro, esto implica que todo vaya fluido y si empiezan a subir imágenes la curva de rendimiento se iba a aplanar para acabar siendo decreciente.

¿ A ti te gustaría usar una herramienta que funciona lenta?

Por supuesto que no.

Y por eso es una de mis obsesiones.

Reflexión

Siento que ando haciendo camino y que hay tramos que estoy abriendo paso en una densa selva a machetazos y...

Otras veces, siento que ando por un desierto árido dónde no hay nada.

Y es un camino duro, muy duro, pero nada que pueda hacer mella en mi pasión e ilusión.

Así que seguiremos haciendo camino!


🚀 Próximos pasos

Con la gestión de imágenes optimizada, el siguiente paso es proteger credenciales y mejorar la seguridad con variables de entorno. 🔒🔥

➡️ ¿Cómo manejas las imágenes en tu SaaS?

¿Prefieres AWS S3 o tienes otra solución?

Cuéntamelo en los comentarios.

 

Si quieres conocer otros artículos parecidos a Evita errores – Cómo almacenar imágenes en AWS S3 desde Flask - Episodio 23 puedes visitar la categoría Proyecto-IA.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir