Cómo Ejecutar Scripts de Python desde n8n

10 min read

Actualización (Marzo 2026): Desde que publiqué este artículo, he estado usando Claude Code + n8n-MCP para construir y depurar flujos de n8n directamente desde la terminal. Esta combinación hace que el enfoque de FastAPI que explico abajo sea aún más potente: Claude Code estructura el flujo, n8n lo ejecuta, Python maneja el trabajo pesado. Escribí sobre toda la configuración aquí.

A veces necesitas ejecutar un script de Python desde un flujo de n8n. Aunque n8n incluye un nodo Code que soporta Python, su implementación es bastante limitada. Si quieres aprovechar todo el poder de Python —incluyendo librerías externas, cálculos complejos o modelos de machine learning— necesitas un entorno Python dedicado.

TL;DR: Usa FastAPI para convertir scripts de Python en endpoints de API, contenerízalos con Docker, y llámalos desde flujos de n8n mediante peticiones HTTP. Esto evita las limitaciones del nodo Code de Python de n8n y te da acceso a todas las capacidades de Python, incluyendo librerías externas.

En esta guía te mostraré cómo integrar un script de Python en un flujo de n8n usando FastAPI para crear un endpoint de API. Ya sea que quieras procesar imágenes, manipular datos o realizar cualquier tarea personalizada, este enfoque te permite aprovechar el poder de Python dentro de las capacidades de automatización de n8n.

Cubriremos:

  1. Envolver un script de Python en una aplicación FastAPI.
  2. Contenerizarlo con Docker.
  3. Llamarlo desde un flujo de n8n.

Al final, tendrás una configuración funcional donde n8n activa tu script de Python mediante una petición HTTP.

Prerrequisitos

Antes de empezar, asegúrate de tener:

  • Docker instalado en tu máquina o servidor.
  • n8n ejecutándose (preferiblemente en Docker, aunque otras configuraciones también funcionan).
  • Familiaridad básica con Python, Docker y flujos de n8n.
  • Un frasco de Tiger Balm para aumentar el coraje.

Paso 1: Crear Tu Script de Python

Empecemos con un script simple de Python. Para este ejemplo, usaremos un script de redimensionado de imágenes, pero puedes cambiarlo por cualquier lógica de Python que necesites.

Script de Ejemplo: resize.py

Este script redimensiona una imagen a un cuadrado de 1000x1000 manteniendo su relación de aspecto y añadiendo un fondo blanco.

Elegí este ejemplo porque el nodo de redimensionado de imágenes en n8n no está funcionando correctamente en este momento. ¡Chicos de n8n 😵‍💫, necesitan arreglar esto!

# resize.py
from PIL import Image
import argparse

def resize_image(input_path, output_path, size=1000):
# Open the original image
original_image = Image.open(input_path)
width, height = original_image.size

\# Calculate new dimensions while preserving aspect ratio  
ratio = min(size / width, size / height)  
new\_width = int(width \* ratio)  
new\_height = int(height \* ratio)  
  
\# Resize the image  
resized\_image = original\_image.resize((new\_width, new\_height), Image.LANCZOS)  
  
\# Create a white 1000x1000 background and paste the resized image  
final\_image = Image.new("RGB", (size, size), (255, 255, 255))  
offset\_x = (size - new\_width) // 2  
offset\_y = (size - new\_height) // 2  
final\_image.paste(resized\_image, (offset\_x, offset\_y))  
  
\# Save the result  
final\_image.save(output\_path)  

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Resize image to 1000x1000")
parser.add_argument("input_image", help="Path to input image")
parser.add_argument("output_image", help="Path to output image")
args = parser.parse_args()
resize_image(args.input_image, args.output_image)

Guárdalo como resize.py. Toma una ruta de imagen de entrada y una ruta de salida como argumentos.


Paso 2: Crear un Wrapper de FastAPI

En lugar de simplemente construir una aplicación FastAPI, en realidad estamos envolviendo nuestro script de Python con una API, haciéndolo accesible para n8n. Este wrapper permitirá que n8n interactúe con el script mediante peticiones HTTP, asegurando mejor flexibilidad y escalabilidad.

💡 Otra opción habría sido usar Flask, que es un framework ligero popular para construir APIs. Sin embargo, elegimos FastAPI porque ofrece soporte asíncrono, validación automática de datos y documentación OpenAPI integrada, haciéndolo más rápido y eficiente para manejar peticiones de API — especialmente en escenarios de automatización como n8n.

Una de las ventajas clave de FastAPI es lo fácil que es extenderlo. Añadir más scripts es tan simple como definir nuevos endpoints. Por ejemplo, si necesitas otro script para aplicar un filtro de escala de grises a una imagen, puedes simplemente crear una nueva ruta como /grayscale y llamar al script correspondiente. Este enfoque modular hace fácil escalar tu API e integrar múltiples scripts de Python en tu flujo de n8n sin modificar endpoints existentes.

#app.py

from fastapi import FastAPI, UploadFile, File
from fastapi.responses import StreamingResponse
import subprocess
import tempfile
import os
import io

app = FastAPI()
@app.post("/resize")
async def resize_image(file: UploadFile = File(...)):
# Create temporary files for input and output
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as input_file:
input_path = input_file.name
input_file.write(await file.read())

with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as output\_file:  
    output\_path = output\_file.name  
  
\# Run the resize script  
try:  
    subprocess.run(\["python", "resize.py", input\_path, output\_path\], check=True)  
except subprocess.CalledProcessError as e:  
    return {"error": f"Failed to resize image: {e}"}  
  
\# Read the resized image  
with open(output\_path, "rb") as f:  
    image\_data = f.read()  
  
\# Clean up temporary files  
os.remove(input\_path)  
os.remove(output\_path)  
  
\# Return the image as a response  
return StreamingResponse(io.BytesIO(image\_data), media\_type="image/jpeg")

Cómo Funciona:

  • El endpoint /resize acepta un archivo subido.
  • Lo guarda temporalmente, llama a resize.py usando subprocess, y devuelve la imagen redimensionada.
  • Los archivos temporales se eliminan después del procesamiento para evitar desorden.

Guárdalo como app.py en el mismo directorio que resize.py.

Nota: Reflexión sobre el Enfoque FastAPI con subprocess vs Clase Python 🥊

Jazys me señaló: "Bueno, para un desarrollador, ese tipo de línea duele a la vista. Lo mejor sería crear una clase Python y llamar a esa clase. De todos modos, cuando quieras añadir nuevas APIs algún día, tendrás que modificar tu app.py, así que mejor integra Python completamente."

Tiene razón absoluta desde una perspectiva purista: usar una clase Python (como ImageProcessor) para encapsular la lógica, integrada directamente en la aplicación FastAPI, mejora la robustez, rendimiento y mantenibilidad, especialmente para una aplicación en evolución con nuevas rutas. Para un desarrollador que busca una solución limpia, modular y bien documentada (con documentación Swagger automática), este enfoque es ideal (ej., importar una clase en app.py con métodos reutilizables).

Sin embargo, como un pragmático manitas y no-desarrollador, prefiero mi solución subprocess: me permite llamar rápidamente scripts pequeños independientes sin preocuparme por robustez o escalabilidad, lo que se adapta a mis necesidades simples. ¡Gracias por la perspicacia aguda, Jazys — tu sabiduría de desarrollador brilla! 😉


Paso 3: Definir Dependencias

Crea un archivo requirements.txt para listar los paquetes de Python que necesitamos (por cierto, si eres tan perezoso como yo, puedes generar un archivo requirements.txt automáticamente ejecutando el siguiente comando en tu directorio de proyecto: pip freeze > requirements.txt)

# requirements.txt

fastapi
uvicorn
pillow
python-multipart

Guárdalo como requirements.txt.


Paso 4: Contenerizar con Docker

Para asegurar una integración perfecta con n8n y mantener consistencia entre entornos, contenerizaremos nuestra aplicación FastAPI usando Docker. Como n8n probablemente esté ejecutándose en un contenedor Docker, conectaremos nuestra API de Python a la misma red Docker desde el principio.

Además, exploraremos dos enfoques: usar un Dockerfile independiente o aprovechar docker compose para configuraciones más complejas. En casos específicos, como cuando se procesan muchos archivos, también discutiremos el uso de un volumen compartido.

Configuración de Red

Tanto n8n como nuestra API de Python necesitan comunicarse dentro de la misma red Docker. Primero, identifica la red que está usando tu contenedor de n8n:

docker inspect <n8n_container_name> | grep Network

Reemplaza <n8n_container_name> con el nombre de tu contenedor de n8n (ej., n8n-akc0oo0ogc0gkog0g8ww). Busca la sección NetworkID o Networks para encontrar el nombre de la red (ej., coolify o n8n_default). Usaremos esta red para asegurar que los contenedores puedan comunicarse entre sí usando sus nombres de contenedor.

Observación: Podríamos haber elegido exponer nuestros scripts de Python a internet mapeando un puerto público (ej., -p 8000:8000) y asegurándolo con HTTPS y autenticación. Sin embargo, en este caso, hemos optado por mantenerlos internos al VPS. Esto simplifica la configuración y evita complejidades de seguridad que surgen cuando los servicios se exponen al mundo, como gestionar firewalls, certificados, proxy inverso o ataques potenciales.

Opción 1: Usar un Dockerfile Independiente

Este es el enfoque más simple, ideal para una configuración de servicio único.

Crea un Dockerfile en tu directorio de proyecto:

FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
COPY resize.py .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

Construye la imagen Docker:

docker build -t fastapi-python-app .

Ejecutar el Contenedor

Ejecuta el contenedor, conectándolo a la red de n8n (reemplaza <n8n_network> con el nombre real de la red):

docker run -d --name python-api --network <n8n_network> fastapi-python-app

-name python-api: Nombra el contenedor para fácil referencia.

-network <n8n_network>: Lo conecta a la red de n8n, permitiendo comunicación vía http://python-api:8000.

La API será accesible en http://python-api:8000/resize dentro de la red.

Caso Específico: Volumen Compartido

Si tu flujo involucra procesar muchos archivos (ej., redimensionar cientos de imágenes), podrías querer evitar transferir archivos repetidamente por HTTP. En su lugar, puedes usar un volumen Docker compartido para almacenar archivos accesibles tanto para n8n como para la API de Python. Por ejemplo:

docker run -d --name python-api --network <n8n_network> -v /path/to/shared/folder:/data fastapi-python-app

  • -v /path/to/shared/folder:/data: Monta un directorio del host (/path/to/shared/folder) a /data en el contenedor.
  • Actualiza app.py para leer/escribir archivos desde /data en lugar de usar archivos temporales, y asegúrate de que n8n pueda escribir al mismo volumen. Esta es una excepción más que la norma, ya que acopla los contenedores más estrechamente, pero es eficiente para operaciones de archivos masivas.

Opción 2: Usar Docker Compose

Para una configuración más estructurada, especialmente si estás gestionando múltiples servicios o quieres definir la red explícitamente, usa docker-compose.

Crea un archivo docker-compose.yml:

services:
python-api:
build: .
image: fastapi-python-app
container_name: python-api
command: uvicorn app:app --host 0.0.0.0 --port 8000
networks:
- n8n_network
networks:
n8n_network:
name: <n8n_network>
external: true

  • build: .: Construye la imagen desde el Dockerfile en el directorio actual.
  • networks: Conecta el servicio a la red existente de n8n (reemplaza <n8n_network> con el nombre real de docker network ls).

Construir y Ejecutar

Inicia el servicio:

docker compose up -d

Esto lanza el contenedor python-api en la red especificada.

Volumen Compartido con Docker Compose

Para escenarios con muchos archivos, añade un volumen a docker-compose.yml:

services:
python-api:
build: .
image: fastapi-python-app
container_name: python-api
command: uvicorn app:app --host 0.0.0.0 --port 8000
volumes:
- shared-data:/data
networks:
- n8n_network
volumes:
shared-data:
networks:
n8n_network:
name: <n8n_network>
external: true

  • volumes: Define un volumen nombrado (shared-data) montado en /data en el contenedor.
  • Si n8n también es gestionado por este docker-compose.yml, añádelo como servicio y conéctalo al mismo volumen y red. De lo contrario, asegúrate de que el contenedor de n8n monte el mismo volumen por separado.

Gestionar con Docker Compose

Detén o reinicia con:

docker compose down
docker compose up -d


Paso 5: Verificar y Probar el Contenedor

Antes de integrar la API de Python con n8n, confirmemos que el contenedor funciona correctamente y la API responde como se espera. Lo probaremos con curl de una manera que puedas copiar y pegar directamente en el nodo HTTP Request de n8n para una transición perfecta.

Verificar Estado del Contenedor

Confirma que el contenedor está ejecutándose:

docker ps

Busca python-api en la lista con un estado de Up y sin puertos expuestos (ya que estamos usando una red interna). Si no está ejecutándose, revisa los logs:

docker logs python-api

Corrige cualquier error (ej., archivos faltantes, problemas de dependencias) reconstruyendo la imagen si es necesario:

docker build -t fastapi-python-app .
docker run -d --name python-api --network <n8n_network> fastapi-python-app

Probar la API Localmente

Prueba el endpoint desde dentro de la red Docker usando curl:

docker run --rm --network <n8n_network> curlimages/curl curl -X POST -F "file=@/path/to/test.jpg" http://python-api:8000/resize -o output.jpg

  • Reemplaza /path/to/test.jpg con una ruta de imagen de prueba, montándola si es necesario (ej., -v /local/path:/data y usa file=@/data/test.jpg).
  • Verifica que output.jpg contenga la imagen redimensionada.

Bonus: Comando curl Compatible con n8n

Aquí tienes un comando curl que puedes ejecutar directamente en tu host (si el puerto está expuesto) o adaptar para n8n:

curl -X POST -F "file=@/path/to/test.jpg" http://python-api:8000/resize -o output.jpg

  • Por qué es útil: Este comando exacto puede copiarse en el nodo HTTP Request de n8n vía la opción import cURL y pegándolo en el campo "Raw Request" (después de ajustar la ruta del archivo para que coincida con los datos binarios de n8n). Es una forma rápida de prototipar la petición antes de afinar en n8n.
  • Si expusiste el puerto localmente (ej., con -p 8000:8000), ejecuta esto desde tu VPS para probar fuera de Docker.

Si esto funciona, la API está lista para que n8n la llame 😀.


Paso 6: Configurar n8n para Llamar a la API

En tu instancia de n8n:

  1. Abre el editor de flujo.
  2. Añade un nodo HTTP Request.
  3. Configúralo así:

Screenshot of an HTTP request editor interface with various input fields and options, including URL, authentication, query parameters, headers, and body content type.

  • URL: http://python-api:8000/resize (usando el nombre del contenedor como hostname).
  • Method: POST.
  • Send Binary Data: Habilita esta opción.
  • Binary Property: Establece a data (o el nombre de tu campo de entrada binaria).

Añadir un Archivo de Imagen

Si estás redimensionando una imagen desde disco:

  • Añade un nodo Read Binary File antes del nodo HTTP Request.
  • Establece la ruta del archivo a tu imagen de entrada.
  • Conéctalo al nodo HTTP Request, asegurando que los datos binarios fluyan.

Smoothly bypass the image resize node bug with all this mess haha! 😜


Si este contenido te resulta útil, tus aplausos 👏, resaltados 🖍️ o comentarios 💬 nos ayudan a producir más material relevante.

Paso 7: Probar el Flujo

  1. Ejecuta el flujo de n8n.
  2. Revisa la salida del nodo HTTP Request: Deberías ver la imagen redimensionada devuelta como datos binarios.
  3. ¡Admira esta obra maestra! 😆🔥

Solución de Problemas

  • "Connection refused": Asegúrate de que ambos contenedores estén en la misma red Docker y la URL coincida con el nombre del contenedor (python-api).
  • "Module not found": Verifica requirements.txt y reconstruye la imagen Docker.
  • Problemas de archivos: Si n8n no puede encontrar el archivo de entrada, verifica que la ruta sea accesible dentro de su contenedor.

¡Ya Estás Listo!

Ahora eres capaz de llamar scripts de Python desde n8n de forma segura sin efectos secundarios en tu entorno de automatización. Además, podrías incluso usar estos scripts fuera de n8n — ¡pero esa es otra historia completamente!

¡Feliz automatización! Déjame saber en los comentarios si tienes problemas o preguntas. 🚀

Documenté la estructura CLI, CLAUDE.md de producción y las restricciones de agente que uso en todos mis proyectos de automatización en un kit gratuito. 3 archivos, 10 minutos.

Obtén el Agent Engineering Stack


Domina la integración de scripts de Python en n8n con FastAPI: desde la contenerización hasta la ejecución de tareas complejas sin límites. Aquí te cuento cómo.

Únete a la newsletter de producción