---
title: "Cómo Instalar Langflow con Docker Compose (Guía 2026)"
description: "Instala Langflow con Docker Compose y PostgreSQL, añade SSL sobre un Cloudflare Tunnel, y endurece tu constructor de flujos IA self-hosted contra los CVE de 2026."
date: 2026-10-10
categories: ["ai"]
tags: ["langflow","docker","self-hosted"]
---

import Button from "@components/widgets/Button.astro";
import { Picture } from "astro:assets";
import YouTubeEmbed from "@components/widgets/YouTubeEmbed.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";
import Accordion from "@components/widgets/Accordion.astro";
import imag1 from "@assets/images/24/01/cloudflare-tunel-setup.png";
import imag2 from "@assets/images/24/07/langflow-ui.png";

Langflow es un constructor visual open-source para agentes y flujos de trabajo IA. Está en la versión 1.12.5 (publicada el 06-10-2026), con 1.13.x en desarrollo, unas 155k estrellas en GitHub, y licencia MIT. Cada flujo que construyes puede correr como API o como servidor MCP, y la librería de componentes cubre todos los LLM principales, bases de datos vectoriales y un conjunto creciente de herramientas IA.

Esta guía cubre cómo instalar Langflow con Docker Compose y PostgreSQL, exponerlo sobre un Cloudflare Tunnel con SSL delante, y endurecer el despliegue contra los CVE de 2026. Esa última parte importa. Langflow ejecuta código por diseño, y una instancia pública corriendo una imagen `latest` vieja es un objetivo de ejecución remota de código. Fija la versión, pon una capa de acceso delante, y mantén la imagen al día.

## ¿Qué es Langflow?

Langflow es un IDE de arrastrar y soltar para pipelines de IA. Cableas componentes en un lienzo, y cada componente es una clase Python que puedes abrir y editar en el navegador. Más allá del constructor, el proyecto trae un playground para probar flujos, orquestación multi-agente, y una historia de despliegue: cualquier flujo puede correr como API REST o como servidor MCP (mira [qué es MCP (Model Context Protocol)](/mcp-introduction-beginners/) si el término es nuevo). Para observabilidad, Langflow exporta trazas a LangSmith o LangFuse vía OTLP; puedes [self-hostear Langfuse como alternativa a LangSmith](/langfuse-docker-install/) y mantener los datos en tu propia máquina. También existe Langflow Desktop para Windows y macOS, y las instalaciones pip soportan Python 3.10 a 3.14.

La línea 1.12.x ha sido de endurecimiento y estructura: fundamentos de RBAC, Knowledge Bases unificadas sobre backends de bases de datos vectoriales comunes, exportación de telemetría OTLP, y (a partir de 1.12.5) ejecución de código integrada restringida a administradores.

<Notice type="info" title="Langflow ejecuta código">
La UI de Langflow es un IDE y una plataforma de ejecución de código. Los componentes pueden correr Python arbitrario con acceso al proceso backend, al sistema de archivos y a la red. Trata un despliegue público como un shell público hasta que leas la sección de seguridad de abajo. Los propios docs del proyecto dicen que el aislamiento multi-tenant es un problema de infraestructura, no algo que la app resuelva por ti.
</Notice>

## Langflow vs Flowise en 2026

Ambos proyectos intentan hacer visual la construcción de flujos IA, y ambos han madurado. Al 10-10-2026, Langflow 1.12.5 tiene 155.451 estrellas en GitHub; Flowise 3.1.4 (publicado el 29-07-2026) tiene 55.495. Las estrellas no lo son todo, pero la brecha sigue dónde invierte cada proyecto.

<Tabs>
<Tab name="Elige Langflow si...">
- Quieres acceso a nivel Python a cada componente y te va bien editar fuente en el navegador
- Necesitas Knowledge Bases integradas y modo servidor MCP para flujos
- Planeas correr múltiples proveedores LLM y herramientas en un proyecto
- Te importa la exportación de telemetría OTLP y el trabajo de RBAC en la hoja de ruta
</Tab>
<Tab name="Elige Flowise si...">
- Quieres una UI más simplificada y una curva de aprendizaje más suave
- Tus flujos son mayormente chatbots y QA sobre documentos
- Quieres algo funcionando esta noche con menos configuración
- No necesitas edición de componentes a nivel Python
</Tab>
</Tabs>

Cuál encaja depende del proyecto. Ambos merecen una tarde de clics. Notas de montaje completas del otro lado: [How to Install FlowiseAI with Docker Compose](/flowiseai-install/). Si quieres el panorama más amplio de automatización, también puedes [self-hostear n8n para automatización de flujos](/n8n-self-host-workflow-automation/); n8n maneja la automatización de flujos general mientras Langflow se mantiene centrado en flujos IA.

> Si te interesa ver algunas apps self-hosted open source gratuitas y chulas puedes mirar la [sección self-hosted de toolhunt.net](https://toolhunt.net/sh/).

## Instala Langflow con Docker Compose

Los pasos de abajo te dan un Langflow 1.12.5 fijado con PostgreSQL, volúmenes nombrados persistentes y un runtime sin root. El vídeo recorre el mismo flujo:

<YouTubeEmbed
  url="https://www.youtube.com/embed/mkSJV0UPDH8"
  label="How to Install Langflow with Docker Compose"
/>

> Nota: el vídeo se grabó sobre la UI 1.x. Los pasos son los mismos, la interfaz ha cambiado.

<Notice type="info" title="Vigila la máquina">
Si quieres monitorizar recursos del servidor como CPU, memoria y espacio en disco mientras Langflow corre, mira [How To Monitor Server and Docker Resources](/sever-monitoring/).
</Notice>

### 1. Prerequisitos

Antes de empezar, asegúrate de que lo siguiente ya existe:

<ListCheck>
<ul>
<li>Un VPS o home server con al menos 2 GB de RAM. La imagen de Langflow pesa aproximadamente 800 MB comprimida en amd64, así que 1 GB es justo en la práctica. Trata 2 GB como el suelo de trabajo, no un benchmark.</li>
<li>Docker Engine y Docker Compose v2. Comprueba con <code>docker --version</code> y <code>docker compose version</code>; el segundo comando debería imprimir una versión v2.x.</li>
<li>Un gestor de compose como Dockge: [Dockge - Alternativa a Portainer para gestión de Docker](/es/instalar-dockge/).</li>
<li>O una cuenta de Cloudflare con un dominio y un Tunnel ya configurado en el servidor, o un reverse proxy delante ([Setup CloudPanel As Reverse Proxy with Docker and Dockge](/cloudpanel-setup-dockge/)).</li>
<li>Solo acceso saliente. Con un tunnel no publicas puertos entrantes. El único listener es <code>127.0.0.1:5060</code> mapeado al 7860 del contenedor, enlazado a loopback, y cloudflared marca hacia él.</li>
</ul>
</ListCheck>

Para el propio VPS, uso máquinas de Hetzner para este tipo de carga ([Hetzner Cloud](https://go.bitdoze.com/hetzner)) y [Hostinger](https://go.bitdoze.com/hostinger-vps) cuando quiero un proveedor o región distinta. Si prefieres no alquilar, un [Mini PC como Home Server](/best-mini-pc-home-server/) como el [ASUS mini PC](https://go.bitdoze.com/asus-dc510) basta para una instancia Langflow de un solo usuario.

_Los precios de VPS saltaron en bloque en 2026. Si estás replanteándote una máquina alquilada, mira [qué cambió y cuándo gana un mini PC](/vps-price-increases/)._

> También puedes usar Traefik como reverse proxy para tus apps. He creado un tutorial completo con instalación de Dockge también para gestionar tus contenedores: [How to Use Traefik as A Reverse Proxy in Docker](/traefik-proxy-docker/)

### 2. El archivo Docker Compose

```yml
services:
  langflow-db:
    image: postgres:16-trixie   # pinned base; don't swap in -alpine under an existing volume
    container_name: Langflow-DB
    hostname: langflow-db
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - langflow-db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    restart: on-failure:5

  langflow:
    image: langflowai/langflow:1.12.5   # pin; bump deliberately. (:latest + pull_policy: always = auto)
    container_name: Langflow
    # no user: root; image runs as uid 1000 and /app/langflow is pre-chowned
    ports:
      # bind to loopback only; cloudflared on this host dials 127.0.0.1:5060.
      # "5060:7860" without the prefix publishes 0.0.0.0 and bypasses Cloudflare Access.
      - "127.0.0.1:5060:7860"
    healthcheck:
      test: timeout 10s bash -c ':> /dev/tcp/127.0.0.1/7860' || exit 1
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 90s
    restart: on-failure:5
    depends_on:
      langflow-db:
        condition: service_healthy
    environment:
      LANGFLOW_DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@langflow-db:5432/${POSTGRES_DB}
      LANGFLOW_CONFIG_DIR: /app/langflow
      LANGFLOW_AUTO_LOGIN: "False"
      LANGFLOW_SUPERUSER_PASSWORD: ${LANGFLOW_SUPERUSER_PASSWORD:?set it in .env}
    volumes:
      - langflow-data:/app/langflow

volumes:
  langflow-db:
  langflow-data:
```

Dos servicios, mismo layout que antes: `langflow-db` corre PostgreSQL, `langflow` corre la app. Qué cambió frente a la versión 2024 de este archivo, y por qué:

1. `postgres:16-trixie` reemplaza a `postgres:16-alpine`. El ejemplo oficial fija trixie a propósito: evita avisos de desajuste de versión de collation de glibc en volúmenes existentes (issue #9608 de langflow). Alpine usa musl, así que apuntar una imagen Postgres basada en Debian a un volumen creado por la imagen alpine no es una operación segura en sitio.

<Notice type="warning" title="¿Vienes de la versión 2024 de esta guía?">
No apuntes `postgres:16-trixie` a un volumen creado por `postgres:16-alpine`. Vuelca y restaura primero. Los pasos de migración están en [Actualizar Langflow sin perder datos](#actualizar-langflow-sin-perder-datos).
</Notice>

2. Los volúmenes nombrados (`langflow-db`, `langflow-data`) reemplazan los bind mounts. Las actualizaciones entonces solo reemplazan la imagen del contenedor y los volúmenes se reconectan. Si migras desde bind mounts, haz `chown -R 1000:0` al directorio de datos primero (mira los modos de fallo de abajo).

3. `LANGFLOW_CONFIG_DIR` es ahora `/app/langflow`. Este directorio contiene logs, almacenamiento de archivos, datos de monitorización y claves secretas. La imagen lo pre-crea y le hace chown a uid 1000. La vieja ruta `/var/lib/langflow` sigue funcionando pero ya no es la ubicación documentada.

4. La imagen está fijada en `langflowai/langflow:1.12.5`. Fijar te da actualizaciones controladas en tu calendario. Si prefieres auto-actualizaciones, usa `langflowai/langflow:latest` con `pull_policy: always`, a costa de cambios sorpresa.

5. No hay `user: root`. Las imágenes actuales corren como uid 1000 (gid 0). `/app/langflow` está pre-chowned, así que el volumen nombrado funciona sin juegos de permisos extra.

6. `depends_on: condition: service_healthy` está puesto. El contenedor Langflow espera al healthcheck de Postgres en vez de hacerle carrera y hacer crash-loop por una base de datos ausente.

7. La contraseña usa sintaxis de variable requerida. `${LANGFLOW_SUPERUSER_PASSWORD:?set it in .env}` hace que `docker compose up` falle rápido si falta la variable, en vez de arrancar con una contraseña vacía. La variable de nombre de usuario `LANGFLOW_SUPERUSER` sigue existiendo, pero los ejemplos oficiales solo ponen la contraseña; deja el default a menos que necesites un usuario específico.

<Notice type="info" title="Precedencia de Compose v2">
Los valores literales en un bloque `environment:` de compose ganan a las variables exportadas del shell y al archivo `.env`. Si hardcodeas un valor en el archivo compose, ninguna edición de `.env` lo sobrescribirá. Mantén los secretos en `.env` y usa referencias a variables en el archivo compose.
</Notice>

El archivo de referencia oficial vive en el [docker_example de langflow](https://github.com/langflow-ai/langflow/blob/main/docker_example/docker-compose.yml).

Modos de fallo comunes en este paso:

- **Puerto 5060 ya asignado.** Cambia el lado del host del mapeo a algo libre (por ejemplo `127.0.0.1:5061:7860`) o encuentra al ocupante con `docker ps` y `ss -lntp | grep 5060`.
- **Colisiones de nombre de proyecto compose.** Dos stacks desplegados desde el mismo nombre de proyecto reutilizarán redes y volúmenes. Fija uno con `docker compose -p langflow up -d`.
- **Permission denied en el directorio de datos.** Viejos bind mounts (`./langflow`) propiedad de root frente al uid 1000 de la imagen. Ejecuta `chown -R 1000:0 ./langflow` o cambia al volumen nombrado `langflow-data`.

### 3. El archivo .env de Langflow

Crea un archivo `.env` en el mismo directorio que el archivo compose:

```sh
POSTGRES_USER='user'
POSTGRES_PASSWORD='use-a-long-random-password'
POSTGRES_DB='langflow'
LANGFLOW_SUPERUSER_PASSWORD='use-a-long-random-password'
```

Genera las contraseñas en vez de inventarlas:

```sh
openssl rand -base64 24
```

`LANGFLOW_SUPERUSER_PASSWORD` es la única variable Langflow requerida aquí: compose se niega a arrancar sin ella gracias a la sintaxis `:?`. Esa contraseña es lo que escribirás en el login de la UI.

<Notice type="error" title="No lances con contraseñas de ejemplo">
Nunca despliegues con los valores de placeholder de este u otro tutorial. Y mantén `LANGFLOW_AUTO_LOGIN` en `False` en cualquier hostname accesible desde internet (las imágenes actuales van por defecto a false; no lo actives). Auto-login significa que cualquiera que encuentre la URL está dentro de tu plataforma de ejecución de código.
</Notice>

Un `.env` a pelo está bien para un VPS de operador único con permisos de filesystem bloqueados. Si varias personas necesitan acceso a la config de despliegue, mira [secretos de Docker Compose y alternativas más seguras a archivos .env planos](/docker-compose-secrets/) para un manejo de secretos en condiciones.

### 4. Despliega el stack

Con el archivo compose y el `.env` en su sitio, desde el mismo directorio:

```sh
docker compose up -d
```

Sigue el primer arranque mientras corre las migraciones de base de datos:

```sh
docker compose logs -f langflow
```

El primer arranque puede tardar un minuto o dos. El healthcheck permite un periodo de arranque de 90 segundos exactamente por eso. Cuando el log se asiente y `docker compose ps` muestre ambos servicios arriba sin contador de reinicios subiendo, verifica en condiciones.

### 5. Verifica el despliegue

No asumas que los contenedores están felices porque `up -d` devolvió. Comprueba:

<ListCheck>
<ul>
<li><code>docker compose ps</code> muestra <code>Langflow</code> y <code>Langflow-DB</code> corriendo (y healthy, una vez que los checks pasan).</li>
<li><code>curl -I http://localhost:5060/</code> desde el VPS devuelve una respuesta HTTP de Langflow antes de involucrar cualquier tunnel o proxy.</li>
<li>Puedes entrar a la UI en <code>http://localhost:5060</code> con el valor <code>LANGFLOW_SUPERUSER_PASSWORD</code> de <code>.env</code>.</li>
<li>El string de versión en los ajustes de la UI lee 1.12.5 si fijaste la imagen como se muestra.</li>
<li>Un flujo trivial se abre y corre una vez, lo que demuestra que la app puede escribir en Postgres.</li>
</ul>
</ListCheck>

Sobre la huella: la imagen de Langflow pesa unos 800 MB comprimida (amd64), más Postgres y lo que los flujos carguen en memoria. Cómodo en un VPS de 2 GB, justo en 1 GB. Eso es guía de prácticante, no un benchmark.

Si la sintaxis del healthcheck te molesta, la imagen trae `curl`, así que `curl -f http://localhost:7860/health || exit 1` es una alternativa válida al check `bash /dev/tcp` de arriba. La base UBI10 también incluye bash.

<Accordion label="El puerto ya está asignado" group="faq">
Algo más está enlazado al 5060 en el host. Cambia el lado del host del mapeo de puerto (por ejemplo `127.0.0.1:5061:7860`) o identifica al ocupante con `docker ps` y `ss -lntp | grep 5060`, luego páralo.
</Accordion>
<Accordion label="El contenedor Langflow se reinicia constantemente" group="faq">
Lee `docker compose logs langflow`. Causas habituales: una errata o credenciales malas en `LANGFLOW_DATABASE_URL`, Postgres aún no levantado (el `condition: service_healthy` del archivo compose debería prevenir esto), o el OOM killer en un VPS pequeño. Revisa `docker compose logs langflow | grep -i killed` y `dmesg | tail`.
</Accordion>
<Accordion label="Permission denied en el directorio de datos" group="faq">
Probablemente estás migrando un viejo bind mount (`./langflow`) propiedad de root. La imagen corre como uid 1000. Ejecuta `chown -R 1000:0 ./langflow`, o pasa al volumen nombrado `langflow-data`.
</Accordion>
<Accordion label="No puedo entrar / olvidé la contraseña de superuser" group="faq">
La contraseña es lo que fuera `LANGFLOW_SUPERUSER_PASSWORD` cuando la base de datos se inicializó por primera vez. Cambiar la variable después no reestablece retroactivamente un usuario de base de datos existente. Restablécela dentro de Postgres, o recrea los volúmenes si la instalación sigue siendo desechable.
</Accordion>

## Elegir una imagen Docker de Langflow

Desde 1.12.x, Langflow publica tres perfiles de imagen (mira los [docs oficiales de perfiles de imagen](https://docs.langflow.org/deployment/docker-image-profiles)):

<Tabs>
<Tab name="base">
`langflowai/langflow:base-1.12.5`

Imagen mínima solo con los componentes LFX integrados y sin paquetes de proveedores. Menor superficie, menor conjunto de funciones.
</Tab>
<Tab name="default">
`langflowai/langflow:1.12.5`

El tag que usa esta guía. Trae paquetes `lfx-*` standalone curados, aproximadamente equivalente a `uv pip install langflow`. Cubre la mayoría de flujos nada más sacarlo.
</Tab>
<Tab name="extended">
`langflowai/langflow-all:1.12.5`

Añade `langflow[bundles]` con los proveedores no-PyTorch y extras como Confluent. Imagen más grande, más componentes disponibles.
</Tab>
</Tabs>

<Notice type="info" title="Perfil default, fijado">
Esta guía usa el perfil default fijado a 1.12.5. Solo cambia a `langflowai/langflow-all` si un flujo necesita un proveedor que la imagen default omite: un flujo que referencia un componente ausente falla al cargar.
</Notice>

Los tres perfiles corren como uid 1000 sin root, tienen `LANGFLOW_AUTO_LOGIN=false` horneado, no traen PyTorch, y están espejados en GHCR (`ghcr.io/langflow-ai/langflow[:all]`). Los viejos tags `core-*` se han ido; no hay imagen `langflow-core` en 1.12.x.

Sobre fijar frente a `latest`: fija `1.12.5` si el despliegue tiene datos que te importan (mi default), y usa `latest` más `pull_policy: always` solo para experimentos desechables. Cada imagen pesa unos 801 MB amd64 / 725 MB arm64, así que ejecuta `docker image prune -f` tras cada subida para recuperar las capas viejas.

## Añade SSL sobre un Cloudflare Tunnel

[Cloudflare Tunnels](https://www.cloudflare.com/products/tunnel/) conectan la app a internet sin direcciones IP públicas ni puertos entrantes abiertos. La mecánica es simple: `cloudflared` corre en tu servidor y marca hacia el edge de Cloudflare. Esa conexión saliente es el tunnel entre tu origen y el edge. Las peticiones a tu dominio bajan por el tunnel al origen, y las respuestas vuelven por el mismo camino.

Sin port forwarding, sin agujeros de firewall para tráfico entrante. TLS termina en Cloudflare.

```text
Browser --HTTPS--> Cloudflare Edge  (TLS terminates here)
                        |
                        |  outbound only: cloudflared dials out
                        v
                  cloudflared daemon
                        |
                        |  http://127.0.0.1:5060
                        v
              Langflow container :7860  (uid 1000)
                        |
                        |  postgresql://langflow-db:5432
                        v
                 Postgres  (named volume langflow-db)
```

_Sin puertos entrantes: cloudflared marca hacia fuera; TLS termina en Cloudflare._

Si no quieres Cloudflare en el camino, hay una [alternativa self-hosted a Cloudflare Tunnels](/pangolin-cloudflare-tunnels-alternative/) (Pangolin). La ruta del reverse proxy también funciona: [Setup CloudPanel As Reverse Proxy with Docker and Dockge](/cloudpanel-setup-dockge/) o [How to Use Traefik as A Reverse Proxy in Docker](/traefik-proxy-docker/). Para otra app expuesta con el mismo patrón de tunnel, mira [Cloudreve with Docker and Cloudflare Tunnels](/cloudreve-docker-setup/).

### Apunta un hostname a Langflow

En el panel de Cloudflare Zero Trust, abre **Access -> Tunnels**, elige el tunnel que creaste para el servidor, y añade un hostname público:

1. Pon el subdominio y dominio, por ejemplo `langflow.yourdomain.com`.
2. Pon el servicio en `http://127.0.0.1:5060`, o `http://langflow:5060` si cloudflared comparte una red Docker con el contenedor.
3. Guarda. Cloudflare crea el registro DNS por ti.

<Picture formats={["webp"]} fallbackFormat="webp" src={imag1} alt="Panel de Cloudflare Zero Trust con un hostname público enrutado al contenedor Langflow a través de un tunnel" />

Verifica desde fuera: `curl -I https://langflow.yourdomain.com` debería devolver una respuesta con `server: cloudflare`, y un navegador en esa URL debería mostrar un certificado válido más la página de login de Langflow:

<Picture formats={["webp"]} fallbackFormat="webp" src={imag2} alt="Constructor visual de Langflow 1.12 mostrando un flujo de agente IA con componentes LLM y de vector store conectados" />

Modos de fallo en una línea cada uno: un 502 o 503 del tunnel significa que la URL del servicio o el puerto están mal; un hostname que no resuelve significa que el registro DNS no se creó; "Bad Gateway" significa que el contenedor no está escuchando en el 7860. Y si la app responde en `http://your-server-ip:5060` desde tu portátil, el puerto está publicado en `0.0.0.0`, lo que pone Langflow en internet sin Access en el camino. Mantén el prefijo `127.0.0.1:` del archivo compose y confirma con `ss -lntp | grep 5060` que el listener está en `127.0.0.1`.

### Pon Cloudflare Access delante de Langflow

Un tunnel oculta tu IP de origen pero sigue publicando la aplicación en internet. Añade Cloudflare Access delante:

1. En Zero Trust, abre **Access -> Applications** y añade una aplicación self-hosted para `langflow.yourdomain.com`.
2. Pon una política. Email OTP es lo más simple; un IdP (Google, GitHub, Okta) funciona si ya tienes uno.
3. Pruébalo: al cargar el hostname ahora debería pedir el PIN de un solo uso (o login de IdP) antes de que aparezca la propia página de login de Langflow.

Capas Access y el login de Langflow una encima de otra, no una en vez de la otra. Las etiquetas del panel de Cloudflare cambian con el tiempo, así que si un nombre de botón de arriba no coincide con lo que ves, sigue los docs actuales de Cloudflare Access para aplicaciones self-hosted.

<Notice type="warning" title="Por qué este paso no es opcional">
Langflow tuvo múltiples CVE críticos de RCE en 2026, incluyendo RCE sin autenticación (CVE-2026-33017). Un tunnel oculta el origen pero sigue publicando la app. Pon Access delante antes de invitar a alguien más a la URL.
</Notice>

## Asegura tu Langflow self-hosted

<Notice type="error" title="Lee esto antes de compartir la URL">
Self-hostear Langflow en una imagen `latest` de la era 2024 expuesta a internet significa correr una plataforma de ejecución de código vulnerable. Actualiza a 1.12.5 o más nuevo antes que cualquier otra cosa.
</Notice>

Los propios docs de Langflow son directos sobre el modelo: la UI es un IDE y una plataforma de ejecución de código. El editor de código corre Python arbitrario con acceso al proceso host, filesystem y red. El aislamiento multi-tenant no es una función de la aplicación; es trabajo de la infraestructura.

2026 concretó el riesgo. Los advisories de seguridad de GitHub del proyecto incluyen:

- **CVE-2026-33017** (crítico, 16-03-2026): RCE sin autenticación vía el endpoint público de build de flujos.
- **CVE-2026-33873** (crítico, 24-03-2026): ejecución de código autenticada en la validación del asistente agéntico.
- **CVE-2026-55255** (crítico, 19-06-2026): IDOR en `/api/v1/responses` dando acceso a flujos entre usuarios.
- **GHSA-jxw3-mjmx-3pqm** (crítico, 12-08-2026): clave Fernet débil generada vía `random.seed()`.
- **CVE-2026-105740** (crítico, 10-09-2026): RCE autenticada a través del transporte stdio de MCP.
- Altos y medios encima: CVE-2026-33760 (IDOR en Monitor API), CVE-2026-105699 (filtrado de archivos entre proyectos), CVE-2026-42867 (path traversal en la KB API), GHSA-j8f7-x8jm-wmm4 (SSRF en componentes de URL).

El proyecto parchea rápido (de 1.12.1 a 1.12.5 en cinco semanas), lo que es buena noticia solo si haces pull de las actualizaciones.

Checklist de endurecimiento:

<ListCheck>
<ul>
<li>Fija la imagen y súbela al menos mensualmente. Trátala como una actualización de kernel.</li>
<li>Pon Cloudflare Access delante del hostname del tunnel, encima del propio login de Langflow.</li>
<li>Mantén <code>LANGFLOW_AUTO_LOGIN</code> en <code>False</code>. Nunca <code>True</code> en un hostname público.</li>
<li>Opcionalmente pon <code>LANGFLOW_ALLOW_CUSTOM_COMPONENTS=false</code> para bloquear componentes personalizados y el editor de código integrado (beta; los docs advierten que no debería ser tu única salvaguarda), o <code>LANGFLOW_CUSTOM_COMPONENT_ADMIN_ONLY=true</code> para hacer los componentes personalizados solo-superuser.</li>
<li>Corre un firewall de host (UFW) con reglas conscientes de Docker, mantén menor privilegio, y deja Postgres sin publicar (el archivo compose ya lo hace). Mira [cómo aseguré mi servidor Docker tras el informe de seguridad BSI](/bsi-security-report-docker-ufw/).</li>
</ul>
</ListCheck>

```sh
# optional: block custom components / code editor (beta, not a complete safeguard)
LANGFLOW_ALLOW_CUSTOM_COMPONENTS=false
# optional: custom components become superuser-only
LANGFLOW_CUSTOM_COMPONENT_ADMIN_ONLY=true
```

<Accordion label="¿Debería exponer Langflow directamente con solo un puerto y TLS?" group="faq">
No. Un puerto publicado a pelo con TLS es la exposición más amplia posible para un IDE de ejecución de código. Usa un tunnel o un reverse proxy, pon Cloudflare Access (o un proxy de auth equivalente) delante, y mantén el propio login de Langflow activado como segunda capa.
</Accordion>
<Accordion label="¿Bloquear componentes personalizados hace Langflow seguro?" group="faq">
Reduce la superficie de ataque; no lo hace seguro. Los docs marcan el flag como beta y dicen que no debería ser tu única salvaguarda. La versión al día, el aislamiento de red y una capa de auth delante hacen el trabajo pesado.
</Accordion>

## Actualizar Langflow sin perder datos

Los datos viven en los volúmenes; la imagen es reemplazable. El flujo de actualización oficial es deliberadamente aburrido:

```sh
# edit the image tag in docker-compose.yml, e.g. 1.12.5 -> 1.12.6
docker compose pull
docker compose up -d
docker compose ps          # both healthy
docker image prune -f      # optional, reclaim ~800 MB per old image
```

Los volúmenes se reconectan. La base de datos y tus flujos sobreviven.

El **rollback** es lo mismo al revés: vuelve a fijar el tag de imagen anterior y corre `docker compose up -d`. Los volúmenes no los toca un cambio de imagen, así que una actualización de la que te arrepientas está a una edición de tag de deshacerse.

Tres avisos de los que las notas de versión no te salvarán:

1. **Postgres de alpine a trixie.** Si seguiste la versión 2024 de esta guía, tu volumen fue creado por `postgres:16-alpine`. No le apuntes `postgres:16-trixie`. Vuelca y restaura en su lugar:

```sh
docker compose exec langflow-db pg_dump -U user langflow > langflow-backup.sql
# switch image to postgres:16-trixie + a fresh named volume, then:
docker compose up -d langflow-db
cat langflow-backup.sql | docker compose exec -T langflow-db psql -U user -d langflow
```

El salto de musl a glibc encima de los problemas de collation por los que el repo oficial fijó trixie (issue #9608) no es algo con lo que apostar una base de datos.

2. **Cambio de ruta de `LANGFLOW_CONFIG_DIR`** (`/var/lib/langflow` a `/app/langflow`). Este directorio contiene logs, subidas, datos de monitorización y claves secretas. Copia el contenido antes de cambiar de ruta. Si las claves se regeneran, el peor caso es re-autenticarse y volver a introducir credenciales almacenadas; los flujos viven en Postgres y sobreviven de todos modos.

3. **Precedencia de Compose v2.** Los valores literales en `environment:` ganan a `.env`. Si los valores están hardcodeados en el archivo compose, editar `.env` no los sobrescribirá.

Verificación del día de actualización:

```sh
docker compose ps
docker compose logs langflow | head
docker compose exec langflow-db psql -U user -d langflow -c 'SELECT count(*) FROM flow;'
```

Más una comprobación de versión en la UI y una ejecución de prueba de un flujo real antes de darlo por terminado.

<Accordion label="¿Puedo cambiar bind mounts por volúmenes nombrados?" group="faq">
Sí, pero copia los datos. Para el stack, copia el contenido de `./langflow` al volumen `langflow-data` (o re-apunta el mount), haz `chown -R 1000:0` al contenido, arranca de nuevo, y confirma que los flujos cargan antes de borrar el directorio viejo.
</Accordion>
<Accordion label="¿Qué pasa con mis flujos si cambia la ruta del directorio de config?" group="faq">
Los flujos viven en la base de datos y sobreviven. Las subidas, logs y claves secretas viven en el directorio de config: copia el contenido de esa carpeta a la nueva ruta antes de arrancar el nuevo stack.
</Accordion>

<Notice type="warning" title="No te saltes el volcado">
La secuencia alpine-a-trixie asume un volcado y restauración limpios. Prueba la restauración en un contenedor Postgres de prueba antes de borrar nada. Un volcado que nunca has restaurado no es un backup.
</Notice>

## Backups y monitorización

Dos cosas importan aquí: la base de datos (flujos, usuarios, historial de chat) y el directorio de config (subidas, logs, claves secretas). Programa el volcado:

```sh
docker compose exec langflow-db pg_dump -U user langflow > backup-$(date +%F).sql
```

<ListCheck>
<ul>
<li>Ejecuta <code>pg_dump</code> en un cron job o timer de systemd y mantén la salida fuera de la máquina.</li>
<li>Incluye el volumen <code>langflow-data</code> (o el bind mount <code>./langflow</code>) en el conjunto de backup.</li>
<li>Sube ambos fuera; almacenamiento compatible con S3 está bien y cuesta centavos a este tamaño. [Automatización de backups self-hosted con Restic](/pluton-self-hosted-backup/) cubre la parte de programación.</li>
<li>Prueba una restauración en un contenedor de prueba de vez en cuando.</li>
</ul>
</ListCheck>

<Notice type="info" title="Prueba las restauraciones">
Ejecuta la restauración del `pg_dump` en un contenedor Postgres de prueba una vez para saber que el archivo se abre e importa limpiamente.
</Notice>

Para monitorización, vigila CPU, memoria, disco y los propios contenedores ([How to Monitor Server & Docker Resources](/sever-monitoring/)). Langflow 1.12.x también puede exportar telemetría OTLP a cualquier backend si quieres trazas junto a métricas.

Sobre escalado: el default es un solo worker con una cola de build en memoria, que es el tamaño correcto para una persona o un equipo pequeño. Si necesitas más, los docs oficiales de multi-worker cubren `LANGFLOW_WORKERS` más una cola Redis (`LANGFLOW_JOB_QUEUE_TYPE=redis`, `LANGQUEUE_REDIS_QUEUE_URL`, cola en Redis DB 1). Fuera de alcance de este montaje; no empieces por ahí.

Presupuesta una subida de imagen mensual como parte de la rutina. Langflow cortó de 1.12.0 a 1.12.5 en cinco semanas, y algunas de esas releases fueron correcciones de seguridad.

## Conclusiones

Ya tienes Langflow 1.12.5 corriendo en Docker Compose con PostgreSQL, SSL sobre un Cloudflare Tunnel con una capa de Access delante, y una base de endurecimiento apropiada para una plataforma de ejecución de código accesible desde internet. Próximos pasos: construye un flujo real, prueba a desplegarlo como API o servidor MCP, y pon la subida de imagen en un calendario para que las divulgaciones de CVE se conviertan en una tarea de cinco minutos en vez de un incidente.

<Button text="Instala FlowiseAI para comparar" link="/flowiseai-install/" variant="solid" color="blue" size="md" icon="arrow-right" />

Si quieres explorar más contenedores Docker para tu home server, mira nuestra guía de [los mejores 100+ contenedores Docker para home server](/es/contenedores-docker-servidor-casa/). Langflow también se sienta junto a n8n, Dify y el resto del stack de agentes en [top AI GitHub repos](/top-ai-github-repos/).