Saudações.
Esse tutorial ensina como implementar o Langflow em container Docker.
1 – O que é Langflow
Langflow é uma plataforma visual de low-code/no-code (tipo o N8N) para criar aplicações de inteligência artificial, agentes e fluxos de IA.
Ele é framework de código aberto, baseado em Python, personalizável e focado na criação de aplicações de IA.
O editor visual simplifica a criação de protótipos de fluxos de trabalho de aplicativos, permitindo que os desenvolvedores (você) transformem rapidamente suas ideias em soluções aplicáveis ao mundo real.
Principais recursos:
- Construção de workflows de tratamento de dados;
- Nodes prontos para tratamento de dados;
- Nodes prontos para configuração de agentes;
- Acesso à contas de provedores de IA (OpenAI, Anthropic, …).
Pré-requisitos:
- Internet no servidor Docker;
- Banco de dados PostgreSQL, preferencialmente com PGVector incluso.
2 – Preparando ambiente
Você deve preparar previamente:
- O servidor/VPS/VM com Docker;
- A rede “network_public“;
- O traefik como proxy-reverso com LetsEncrypt, ligado à rede “network_public“;
2.1 – Container do PostgreSQL
Vou usar o Postgres como base de armazenamento de dados do Langflow.
O PG é opcional, se a URL do banco de dados não for informada os dados serão armazenados em um arquivo SQLITE no volume do container Langflow.
Vou usar a imagem pgvector (Debian Trixie + Postgres 18 + PGVector).
O nome do container será “langflow-database” e as credenciais:
- Usuário: langflow
- Senha: tulipasql
- Banco de dados: langflow
# Variaveis
NAME="langflow-database";
# Argumentos do postgres (usado somente no primeiro boot)
POSTGRES_USER="langflow";
POSTGRES_PASSWORD="tulipasql";
POSTGRES_DB="langflow";
# Imagem
IMAGE="pgvector/pgvector:pg18-trixie";
docker pull $IMAGE;
# Volume
# obs: pg18 usa pasta principal interna: /var/lib/postgresql
DATADIR=/storage/$NAME;
mkdir -p $DATADIR;
chown -R 999:999 $DATADIR;
# Renovar/rodar:
docker rm -f $NAME 2>/dev/null;
docker run \
-d \
--restart always \
--name $NAME \
--hostname $NAME.intranet.br \
\
--cpus 2.0 \
--cpu-shares 1024 \
--memory 2g \
--memory-swap 2g \
--memory-reservation 1g \
--shm-size 1g \
\
--network network_public \
\
--tmpfs /run:rw,noexec,nosuid,size=64m \
--tmpfs /tmp:rw,exec,suid,size=64m \
\
-v $DATADIR:/var/lib/postgresql \
\
-e POSTGRES_USER=$POSTGRES_USER \
-e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
-e POSTGRES_DB=$POSTGRES_DB \
-e PGDATA=/var/lib/postgresql/data/pgdata \
\
--health-cmd="pg_isready -U postgres" \
--health-interval=5s \
--health-timeout=5s \
--health-retries=10 \
\
--entrypoint "docker-entrypoint.sh" \
\
$IMAGE \
postgres \
--max_connections=8192 \
--wal_level=minimal \
--max_wal_senders=0 \
--port=5432;
2.2 – Usando Postgres pré-existente
Caso você ja tenha um banco de dados central e queira apenas criar o usuário e banco do LangFlow, siga os procedimentos no terminal PSQL:
-- usuario do container local:
CREATE USER langflow
WITH PASSWORD 'tulipasql'
LOGIN;
-- criar db e usuario do chatwoot
CREATE DATABASE langflow
WITH
OWNER = langflow
ENCODING = 'UTF8'
TABLESPACE = pg_default
IS_TEMPLATE = False
CONNECTION LIMIT = -1;
-- Conectar no banco:
\c langflow;
-- Sair
\q3 – Rodando o Langflow
Agora vamos ao Langflow em si.
3.1 – Variáveis de ambiente
Observe as variáveis e configure adequadamente de acordo com seu ambiente.
| Variável | Padrão | Função |
|---|---|---|
LANGFLOW_HOST | 0.0.0.0 | IP para abrir porta TCP/HTTP de escuta. |
LANGFLOW_PORT | 7860 | Porta padrão do servidor monolítico Langflow. |
LANGFLOW_AUTO_LOGIN | false | Exige login em vez de compartilhar uma sessão iniciada automáticamente. |
LANGFLOW_SUPERUSER | (preencha) | Super usuário |
LANGFLOW_SUPERUSER_PASSWORD | (preencha) | Senha do super usuário. |
LANGFLOW_SECRET_KEY | (preencha) | Usada para criptografar credenciais, não altere após iniciar o uso. |
LANGFLOW_DATABASE_URL | (vazio) | Caminho completo do Postgres. Se deixar em branco usa SQLITE internamente. |
LANGFLOW_CONFIG_DIR | /app/langflow | Diretório de armazenamento de configurações. |
LANGFLOW_ENABLE_SIGNUP | false | Controla cadastro público direto. |
LANGFLOW_LOG_ENV | container ou container_json | Facilita coleta por Docker, Loki ou outro agregador. |
LANGFLOW_ALLOW_CUSTOM_COMPONENTS | depende do modelo de ameaça | Código customizado pode executar código no servidor. |
LANGFLOW_SSRF_PROTECTION_ENABLED | true em instalação pública, após allowlist | Reduz acesso indevido a redes privadas a partir de componentes. |
3.2 – Criar container Langflow
Você precisará de um nome de DNS para acessá-lo via HTTPs (pelo Traefik), no exemplo vou usar langflow.seudominio.com.br
Script para criar container via “docker run“:
# Variaveis
NAME=langflow;
FQDN="langflow.seudominio.com.br";
LOCAL=$NAME.intranet.br;
# Variaveis do acesso postgres
PG_HOST="pgvector-main"; # < Nome do container ou ip/fqdn do Postgres
PG_PORT="5432";
PG_USER="langflow";
PG_PASS="tulipasql";
PG_DB='langflow';
# URL PG final:
DB_URL="postgresql://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}";
# Variaveis langflow
# - Acesso administrativo
LANGFLOW_SUPERUSER="admin";
LANGFLOW_SUPERUSER_PASSWORD="tulipa";
# - Controle de usuarios
LANGFLOW_AUTO_LOGIN="false";
LANGFLOW_ENABLE_SIGNUP="false";
LANGFLOW_NEW_USER_IS_ACTIVE="false";
# - Segredo, gerar com comando:
# python3 -c "import secrets; print(secrets.token_urlsafe(32))"
LANGFLOW_SECRET_KEY="lCHWWiQr__7IyKCBsMaZpiekDOQgXULjvDIyf7H6tk0";
LANGFLOW_HOSTNAME="$FQDN";
LANGFLOW_HOST="0.0.0.0";
LANGFLOW_PORT="7860";
LANGFLOW_CONFIG_DIR="/app/langflow";
# Imagem:
IMAGE="langflowai/langflow:latest";
docker pull $IMAGE;
# Pasta de persistencia das configuracoes
DATADIR=/storage/langflow;
mkdir -p $DATADIR;
# Renovar/rodar
docker rm -f $NAME 2>/dev/null
docker pull $IMAGE;
docker run \
-d --restart=always \
--name $NAME \
-h $LOCAL \
\
--network network_public \
\
-p 7860:7860 \
\
-v $DATADIR:/app/langflow \
\
-e "LANGFLOW_DATABASE_URL=$LANGFLOW_DATABASE_URL" \
-e "LANGFLOW_AUTO_LOGIN=$LANGFLOW_AUTO_LOGIN" \
-e "LANGFLOW_SUPERUSER=$LANGFLOW_SUPERUSER" \
-e "LANGFLOW_SUPERUSER_PASSWORD=$LANGFLOW_SUPERUSER_PASSWORD" \
-e "LANGFLOW_SECRET_KEY=$LANGFLOW_SECRET_KEY" \
-e "LANGFLOW_HOSTNAME=$FQDN" \
-e "LANGFLOW_HOST=$LANGFLOW_HOST" \
-e "LANGFLOW_PORT=$LANGFLOW_PORT" \
-e "LANGFLOW_CONFIG_DIR=$LANGFLOW_CONFIG_DIR" \
-e "LANGFLOW_ENABLE_SIGNUP=$LANGFLOW_ENABLE_SIGNUP" \
-e "LANGFLOW_NEW_USER_IS_ACTIVE=$LANGFLOW_NEW_USER_IS_ACTIVE" \
\
--label "traefik.enable=true" \
--label "traefik.http.routers.$NAME.rule=Host(\`$FQDN\`)" \
--label "traefik.http.routers.$NAME.entrypoints=websecure" \
--label "traefik.http.routers.$NAME.tls=true" \
--label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
--label "traefik.http.services.$NAME.loadbalancer.server.port=7860" \
\
$IMAGE;
# URLs de acesso:
echo;
echo "Url de acesso:";
echo " https://$FQDN";
echo " https://$FQDN/login";
echo;
4 – Stack
Para quem prefere a stack para usar no “docker compose” ou via Portainer, eis o YAML:
services:
langflow-db:
image: pgvector/pgvector:pg18-trixie
container_name: langflow-db
hostname: langflow-db
restart: always
environment:
POSTGRES_USER: langflow
POSTGRES_PASSWORD: tulipasql
POSTGRES_DB: langflow
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- langflow_db_data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U langflow"]
interval: 5s
timeout: 5s
retries: 10
command:
- postgres
- --max_connections=8192
- --wal_level=minimal
- --max_wal_senders=0
- --port=5432
networks:
- network_public
langflow-app:
image: langflowai/langflow:latest
container_name: langflow
hostname: langflow
restart: always
depends_on:
langflow-db:
condition: service_healthy
environment:
LANGFLOW_DATABASE_URL: postgresql://langflow:tulipasql@langflow-db:5432/langflow
LANGFLOW_HOST: 0.0.0.0
LANGFLOW_PORT: 7860
LANGFLOW_AUTO_LOGIN: "false"
LANGFLOW_ENABLE_SIGNUP: "false"
LANGFLOW_NEW_USER_IS_ACTIVE: "false"
LANGFLOW_SUPERUSER: admin
LANGFLOW_SUPERUSER_PASSWORD: tulipa
# Gere com: python3 -c "import secrets; print(secrets.token_urlsafe(32))"
LANGFLOW_SECRET_KEY: "COLOQUE_UMA_CHAVE_SECRETA_AQUI"
LANGFLOW_CONFIG_DIR: /app/langflow
volumes:
- langflow_data:/app/langflow
ports:
- "7860:7860"
networks:
- network_public
labels:
- "traefik.enable=true"
- "traefik.http.routers.langflow.rule=Host(`langflow.seudominio.com.br`)"
- "traefik.http.routers.langflow.entrypoints=websecure"
- "traefik.http.routers.langflow.tls=true"
- "traefik.http.routers.langflow.tls.certresolver=letsencrypt"
- "traefik.http.services.langflow.loadbalancer.server.port=7860"
networks:
network_public:
external: true
volumes:
langflow_db_data:
langflow_data:Agora basta acessa a interface pelo navegador e começar a explorar a solução!
Terminamos por hoje!
Patrick Brandão, patrickbrandao@gmail.com
“Vamos agradecer aos idiotas.
Não fosse por eles não faríamos tanto sucesso.“
Mark Twain
