AI Agent Framework
Visual builder for LLM agents based on Flowise, with local models through Ollama and PostgreSQL storage
- Category
- agent
- Version
- 2.0.0
- Deployment formats
- Docker Compose, Helm (Kubernetes), Terraform (local Docker), Terraform (AWS)
- Maintainer
- AI Solutions Camp
- Tags
- AI Agents, Flowise, Ollama, Tools, Multi-Agent, PostgreSQL
Overview
A self-hosted agent builder based on Flowise 3.1. You design chatflows and agentflows in a drag-and-drop editor: agents that call tools, keep conversation memory and hand work to other agents. Every flow is also available over a REST API, protected by API keys.
The stack runs three containers: Flowise, Ollama for local models (llama3.2:3b by default, a small model that supports tool calling), and PostgreSQL as the Flowise database. Model providers with an API key (OpenAI, Anthropic, Mistral and others) can be added in the Flowise UI instead of or next to Ollama.
Secure defaults: every secret (database password, encryption key, token secrets) must be set before the first start, the owner account is created automatically from your .env so the instance cannot be claimed by the first visitor, and the ports are bound to 127.0.0.1. Deploy with Docker Compose, Helm (HelmForge Flowise chart and the otwld Ollama chart), Terraform with the Docker provider, or Terraform on a single AWS EC2 instance.
Requirements
- Docker Engine with Docker Compose v2
- 4 CPU cores and 8 GB RAM for the default 3B model on CPU (16 GB recommended)
- About 25 GB free disk: the images are about 5 GB to download and about 13 GB unpacked, llama3.2:3b adds about 2 GB
- Optional: NVIDIA GPU with the NVIDIA Container Toolkit (compose.gpu.yaml)
Quick start
Quick start (Docker Compose)
- Get the files and create your settings:
git clone https://github.com/aisolutionscamp/stacks.git
cd stacks/stacks/ai-agent-framework
cp .env.example .env
- Fill in .env: set FLOWISEADMINEMAIL and FLOWISEADMINPASSWORD (8+ characters with upper and lower case, a digit and a special character), and generate every secret with openssl rand -hex 32:
FLOWISESECRETKEYOVERWRITE, JWTAUTHTOKENSECRET, JWTREFRESHTOKENSECRET, EXPRESSSESSIONSECRET, TOKENHASHSECRET, POSTGRES_PASSWORD.
- Start the stack:
docker compose up -d --wait
The owner account is created automatically. The model (llama3.2:3b, about 2 GB) keeps downloading in the background: docker compose logs -f ollama-pull.
- Open http://localhost:3000 and log in with the email and password from .env.
- Build an agent: Agentflows Add New, add an Agent node, choose ChatOllama with base URL http://ollama:11434 and model llama3.2:3b, then add tools.
- Optional check: ./smoke-test.sh.
Environment variables
FLOWISE_PORT– Host port of the Flowise UI and API (bound to 127.0.0.1)OLLAMA_PORT– Host port of the Ollama API (bound to 127.0.0.1)FLOWISE_ADMIN_NAME– Display name of the owner accountFLOWISE_ADMIN_EMAIL(required) – Login email of the owner account, created on first startFLOWISE_ADMIN_PASSWORD(required) – Owner password: 8-128 characters with upper and lower case, a digit and a special characterFLOWISE_SECRETKEY_OVERWRITE(required) – Encryption key for stored credentials (openssl rand -hex 32). Keep it stableJWT_AUTH_TOKEN_SECRET(required) – Signs login tokens (openssl rand -hex 32)JWT_REFRESH_TOKEN_SECRET(required) – Signs refresh tokens (openssl rand -hex 32)EXPRESS_SESSION_SECRET(required) – Signs session cookies (openssl rand -hex 32)TOKEN_HASH_SECRET(required) – Hashes password-reset and invite tokens (openssl rand -hex 32)POSTGRES_PASSWORD(required) – Password of the flowise PostgreSQL user (openssl rand -hex 32)APP_URL– Public URL of Flowise; an https:// URL turns on secure cookiesLOG_LEVEL– error, warn, info, verbose or debugDISABLE_FLOWISE_TELEMETRY– Set to false to send anonymous usage data to FlowiseAIOLLAMA_MODEL– Model pulled on start; use one with tool calling for agentsOLLAMA_KEEP_ALIVE– How long a model stays loaded after the last request
Documentation
AI Agent Framework (Flowise + Ollama + PostgreSQL)
A self-hosted visual builder for LLM agents. You build chatflows and agentflows in Flowise, run local models with Ollama, and keep all Flowise data in PostgreSQL.
Architecture
| Service | Image | Port | Purpose | |---|---|---|---| | flowise | flowiseai/flowise:3.1.4 | 127.0.0.1:3000 (FLOWISEPORT) | Web UI, REST API (/api/v1/...), flow execution | | postgres | postgres:18.4-alpine | not published | Flowise database (flows, users, API keys, chat history, encrypted credentials) | | ollama | ollama/ollama:0.40.11 | 127.0.0.1:11434 (OLLAMAPORT) | Local model server, reachable from Flowise as http://ollama:11434 | | ollama-pull | ollama/ollama:0.40.11 | none | One-shot: pulls OLLAMAMODEL (default llama3.2:3b), then exits | | flowise-setup | flowiseai/flowise:3.1.4 | none | One-shot: creates the owner account from FLOWISEADMINEMAIL / FLOWISEADMIN_PASSWORD, then exits |
Volumes: postgresdata, ollamadata (models), flowise_data (uploaded files, logs). The Flowise image runs as the non-root user node (uid 1000); its volume is mounted at /home/node so it is writable.
Configuration
All settings are in .env (copy from .env.example). Required before the first start:
- FLOWISEADMINEMAIL, FLOWISEADMINPASSWORD: the owner account. Flowise requires 8 to 128 characters with lower case, upper case, a digit and a special character.
- FLOWISESECRETKEYOVERWRITE: encryption key for credentials stored in Flowise (API keys of model providers and tools).
- JWTAUTHTOKENSECRET, JWTREFRESHTOKENSECRET, EXPRESSSESSIONSECRET, TOKENHASHSECRET: login token and session secrets.
- POSTGRES_PASSWORD: database password.
Generate each secret with openssl rand -hex 32. Compose refuses to start while one of them is missing.
Optional: OLLAMAMODEL (agents need a model with tool calling, for example llama3.2:3b, qwen3:4b or qwen2.5:7b), APPURL, LOGLEVEL, DISABLEFLOWISETELEMETRY, OLLAMAKEEP_ALIVE, the two ports.
Using Ollama in a flow
In Flowise add a ChatOllama node (or the Ollama model in an Agent node) with base URL http://ollama:11434 and the model name from OLLAMA_MODEL. Pull more models with:
docker compose exec ollama ollama pull qwen3:4b
Using the API
Create an API key in the Flowise UI (API Keys). Call a flow with:
curl http://localhost:3000/api/v1/prediction/ \
-H "Authorization: Bearer " -H "Content-Type: application/json" \
-d '{"question": "Hello"}'
GPU
compose.gpu.yaml gives Ollama access to NVIDIA GPUs (needs the NVIDIA Container Toolkit):
docker compose -f compose.yaml -f compose.gpu.yaml up -d --wait
Security notes
- Flowise 3 has its own user accounts. The old FLOWISEUSERNAME / FLOWISEPASSWORD basic auth is no longer used. In the open-source edition the first registered user becomes the owner, and registration closes after that. flowise-setup registers the owner from .env on the first start, so nobody else can claim a fresh instance. Change the password later in the UI; changing FLOWISEADMINPASSWORD in .env does not update an existing account. The Helm install has no setup job: register the owner right after the install, through kubectl port-forward, before you add an ingress.
- Keep FLOWISESECRETKEYOVERWRITE stable and backed up. With a different key, stored credentials cannot be decrypted.
- Both published ports are bound to 127.0.0.1. To expose Flowise, put a reverse proxy with TLS in front, set APP_URL to the https:// URL (this turns on secure cookies), and keep Ollama private: its API has no authentication.
- Flows can run custom JavaScript functions and call external URLs. Give accounts only to people you trust with code execution on the server.
- PostgreSQL is not published on the host. Back it up with docker compose exec postgres pg_dump -U flowise flowise flowise.sql.
Upgrading
- Read the Flowise release notes and the Ollama releases.
- Back up the database (see above).
- Change the image tags in compose.yaml and run docker compose pull && docker compose up -d --wait. Flowise runs its database migrations on start.
Troubleshooting
- required variable ... is missing a value: a secret in .env is empty.
- docker compose logs flowise-setup shows Invalid password: the owner password does not meet the Flowise rules. Fix it in .env and run docker compose up flowise-setup.
- Login fails although the password is right: the owner account already existed with another password (for example from an earlier volume). Reset with docker compose down -v (deletes all data) or use the password set earlier.
- Model answers are slow: on CPU a 3B model needs several seconds per answer. Use a GPU or a smaller model.
- ollama-pull is still running after up --wait: the model download continues in the background; check with docker compose logs -f ollama-pull.
- Check the stack: ./smoke-test.sh pings Flowise, gets a completion from Ollama, logs in, creates a temporary API key and calls the API with it.
docker-compose.yml
# AI Agent Framework: Flowise (visual agent builder) + Ollama (local models) + PostgreSQL.
# Copy .env.example to .env, fill in the secrets, then: docker compose up -d --wait
name: ai-agent-framework
services:
postgres:
image: postgres:18.4-alpine
restart: unless-stopped
environment:
POSTGRES_DB: flowise
POSTGRES_USER: flowise
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U flowise -d flowise"]
interval: 5s
timeout: 5s
retries: 20
# No published port: only Flowise talks to the database.
ollama:
image: ollama/ollama:0.40.11
restart: unless-stopped
environment:
OLLAMA_KEEP_ALIVE: ${OLLAMA_KEEP_ALIVE:-5m}
volumes:
- ollama_data:/root/.ollama
ports:
- "127.0.0.1:${OLLAMA_PORT:-11434}:11434"
healthcheck:
test: ["CMD", "ollama", "list"]
interval: 10s
timeout: 5s
retries: 12
start_period: 10s
# One-shot: downloads OLLAMA_MODEL into the ollama volume (skipped quickly if present).
ollama-pull:
image: ollama/ollama:0.40.11
restart: "no"
depends_on:
ollama:
condition: service_healthy
environment:
OLLAMA_HOST: http://ollama:11434
entrypoint: ["ollama", "pull", "${OLLAMA_MODEL:-llama3.2:3b}"]
flowise:
image: flowiseai/flowise:3.1.4
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ollama:
condition: service_healthy
environment:
PORT: "3000"
APP_URL: ${APP_URL:-http://localhost:3000}
# Database
DATABASE_TYPE: postgres
DATABASE_HOST: postgres
DATABASE_PORT: "5432"
DATABASE_NAME: flowise
DATABASE_USER: flowise
DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
# Encryption key for stored credentials (API keys of model providers, tools, ...)
FLOWISE_SECRETKEY_OVERWRITE: ${FLOWISE_SECRETKEY_OVERWRITE:?set FLOWISE_SECRETKEY_OVERWRITE in .env}
# Login sessions and tokens
JWT_AUTH_TOKEN_SECRET: ${JWT_AUTH_TOKEN_SECRET:?set JWT_AUTH_TOKEN_SECRET in .env}
JWT_REFRESH_TOKEN_SECRET: ${JWT_REFRESH_TOKEN_SECRET:?set JWT_REFRESH_TOKEN_SECRET in .env}
EXPRESS_SESSION_SECRET: ${EXPRESS_SESSION_SECRET:?set EXPRESS_SESSION_SECRET in .env}
TOKEN_HASH_SECRET: ${TOKEN_HASH_SECRET:?set TOKEN_HASH_SECRET in .env}
JWT_ISSUER: Flowise
JWT_AUDIENCE: Flowise
# Files and logs live in the flowise_data volume
SECRETKEY_PATH: /home/node/.flowise
BLOB_STORAGE_PATH: /home/node/.flowise/storage
LOG_PATH: /home/node/.flowise/logs
LOG_LEVEL: ${LOG_LEVEL:-info}
DISABLE_FLOWISE_TELEMETRY: ${DISABLE_FLOWISE_TELEMETRY:-true}
volumes:
# Mounted at the home directory of the image's non-root user (uid 1000) so the
# volume is writable; Flowise keeps its files in /home/node/.flowise.
- flowise_data:/home/node
ports:
- "127.0.0.1:${FLOWISE_PORT:-3000}:3000"
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/api/v1/ping"]
interval: 10s
timeout: 5s
retries: 30
start_period: 30s
# One-shot: creates the Flowise owner account from FLOWISE_ADMIN_EMAIL / FLOWISE_ADMIN_PASSWORD,
# so the instance is never left open for the first visitor to claim. Does nothing if an
# account already exists.
flowise-setup:
image: flowiseai/flowise:3.1.4
restart: "no"
depends_on:
flowise:
condition: service_healthy
environment:
FLOWISE_ADMIN_NAME: ${FLOWISE_ADMIN_NAME:-Admin}
FLOWISE_ADMIN_EMAIL: ${FLOWISE_ADMIN_EMAIL:?set FLOWISE_ADMIN_EMAIL in .env}
FLOWISE_ADMIN_PASSWORD: ${FLOWISE_ADMIN_PASSWORD:?set FLOWISE_ADMIN_PASSWORD in .env}
entrypoint:
- node
- -e
- |
const e = process.env;
const body = { us
…