Self-Hosted Agentic Workflow Platform: the Real Stack
What self-hosting an agentic workflow platform actually runs: Postgres, Temporal, Langfuse, an app server. Compose files, ports, RAM, no SaaS trial.
Self-hosting an agentic workflow platform means running every service the platform depends on yourself: the app, the database, the workflow engine, and the observability stack. For Vocion that is four moving pieces — a Next.js app server, Postgres with pgvector for retrieval, Temporal for schedules, and a self-hosted Langfuse deployment (itself Postgres + ClickHouse + Redis + MinIO) for tracing and cost. All of it is MPL-2.0 and runs from one docker compose up -d in dev; production is the same containers behind your own ingress. There is no SaaS trial gate and no seat-based pricing wall — self-hosting at any scale needs no commercial agreement.
If you've already ruled out a hosted trial and want the honest container list before you commit a box to it, this is that list.
What does "self-hosted" actually mean here?
Two different things get called "self-hosted" in this market. One is "open core": you can run the container, but the features you actually need live behind a hosted control plane or a paid license key. The other is what Vocion ships — the runtime itself is MPL-2.0, the same code path Vocion Cloud runs, with no feature gate behind self-hosting. docs/guides/self-hosting.md puts it plainly: "Same codebase, same data model, same MCP surface as Vocion Cloud." The only things that stay optional third-party accounts are Stripe (if you bill end users) and Sentry/Better Stack (if you want hosted error and log aggregation) — neither is required to run the platform.
What services does the stack need?
The root docker-compose.yml says it in its own header comment:
# Quick start:
# docker compose up -d # app DB + platform (Langfuse + Temporal)
# npm run dev:next # start Next.js against the running stack
#
# Ports surfaced on the host:
# :3000 Next.js app (run with `npm run dev:next`)
# :5432 App Postgres + pgvector (native retrieval, see L.1)
# :3200 Langfuse UI
# :8233 Temporal UI
# :7233 Temporal gRPC
# :4317 OTel Collector (gRPC)
# :4318 OTel Collector (HTTP)
That comment undersells the container count, because "Langfuse" and "Temporal" are each themselves several containers. The root compose include:s infra/docker-compose.platform.yml, and reading that file, Langfuse alone is six containers: langfuse-web, langfuse-worker, langfuse-postgres, langfuse-clickhouse, langfuse-redis, langfuse-minio. Temporal is three: temporal, temporal-ui, temporal-postgres. Add the OTel collector and the app's own Postgres, and a default docker compose up -d starts eleven containers before the Next.js app even runs (it's a local process via npm run dev:next, not a container in dev). That is the real cost of self-hosting first-party observability: it is not free, it is four extra services (ClickHouse, Redis, MinIO, and Langfuse's own Postgres) on top of the ones you'd expect.
Retrieval doesn't add to that count — it's pgvector plus Postgres full-text search inside the app's own database, served by RetrievalService, not a separate vector database container.
What's the one-command quick start?
From a fresh clone of vocion-core:
docker compose up -d
npm run db:migrate
npm run workspace:apply
npm run dev:next
The first command boots Postgres plus the full platform stack (Langfuse, Temporal, OTel) in one shot, because of the include: line. The second applies the Drizzle-managed schema. The third applies your workspace — agents, skills, object types, workflows authored as YAML and Markdown under workspace/<org>/ — to the database; it's idempotent, and every apply records a workspace_version audit row. The fourth starts the app against the running stack at http://localhost:3000.
What are the minimum requirements?
From infra/README.md and docs/guides/self-hosting.md:
| Minimum | Recommended | |
|---|---|---|
| Node.js | 20.x | 22.x LTS |
| Postgres | 16 | 16 or 17 |
| Memory (app + Postgres) | 2 GB | 8 GB+ |
| Disk | 5 GB | ~1 GB per 100k indexed chunks |
Layer the observability stack's own numbers on top of that, since they're not folded into the app's minimum: infra/README.md gives Postgres 1 GB, Langfuse 4 GB (it's running ClickHouse plus its own Postgres), and Temporal 2 GB, for a stated "8GB+ RAM for full stack" total. If you're sizing a single box for local dev or a pilot, plan around that 8 GB floor rather than the app's own 2 GB minimum — the observability stack is the bigger line item.
There is no Kubernetes manifest in the repo today. infra/ has aws/, temporal/, otel/, terraform/, and the two compose files — no k8s/ or Helm chart. Docker Compose is the documented path; running this on Kubernetes means writing your own manifests from the compose files, not pulling in something Vocion ships.
What do you have to bring yourself?
At minimum, one LLM provider API key — OPENAI_API_KEY or ANTHROPIC_API_KEY. infra/README.md is explicit that the platform "never silently falls back to a default; missing creds throw with a clear message" on first skill invocation.
For production, add: your own Postgres backup strategy (self-hosting.md says it plainly — "Back up Postgres. That's where every skill run, approval decision, context version, and audit record lives"), TLS termination, and log retention for containers you now own. The repo ships one worked production reference under infra/aws/ — a single EC2 instance running the app, the feedback worker, Caddy for TLS, Postgres, and Langfuse, with infra/aws/Caddyfile handling certificate issuance. That's a reference deploy for a pilot, not the only path or a requirement; the AWS README frames it as the "simplest path to a public Vocion URL," recommending you graduate to App Runner or ECS once traffic justifies it.
Is Temporal required, or optional?
Partly optional, and the distinction is easy to miss if you only read the quick start. The Temporal server and its UI (temporal, temporal-ui, temporal-postgres) are plain services in infra/docker-compose.platform.yml with no profiles: gate, so a default docker compose up -d brings them up along with everything else.
What's gated is the worker that actually consumes Temporal's queues. In the root docker-compose.yml, both worker (the feedback worker) and temporal-worker carry profiles: [worker] — they only start with docker compose --profile worker up -d, and temporal-worker additionally needs ENABLE_TEMPORAL_WORKER=1 set. The compose file's own comment on that service is direct about what it needs: it "Runs vocionWorkflow Workflows + Activities against the Temporal server in the platform stack," and it "Requires the platform stack ... so temporal:7233 resolves."
So a default dev boot gives you a live Temporal server with nothing consuming it. Scheduling calls that go through client.schedule — AutomationService, MissionScheduleService, SourceScheduleService, and WorkflowScheduleService in packages/core/src/services/ — will register schedules against that server either way, but without the worker profile running, nothing picks those schedules up and executes the resulting activities. If you're evaluating the platform interactively and triggering workflows by hand, you don't need the profile. If you want scheduled automations, missions on a schedule, or source syncs to actually fire, add --profile worker with ENABLE_TEMPORAL_WORKER=1 (and ENABLE_FEEDBACK_WORKER=1 for the feedback worker) before you rely on anything running unattended. One more thing worth knowing: Temporal here drives scheduling, not step-by-step workflow durability — workflow state persists to Postgres in workflow_run rows, so a process that dies mid-run leaves the run paused at its last persisted step rather than resuming from a Temporal-replayed history.
What does this cost, roughly?
There's no invented monthly figure here, because none of the source docs publish one for a general deployment — costs depend entirely on which instance size and cloud you pick. What you can do is take the RAM numbers above and price your own compute: eleven containers at roughly 8 GB combined for a full local or pilot stack, or size up from the AWS reference deploy's own sizing table (t3.large at 2 vCPU / 8 GB up to r6i.xlarge at 4 vCPU / 32 GB, plus a 100 GB volume for Postgres and Langfuse data) if you want a second data point. Either way, the honest framing is "your own compute for the containers listed above," not a fixed subscription number.
How Vocion documents this
The full requirements table, environment variable reference, and upgrade steps live in /docs/guides/self-hosting — read it before you provision anything, since it also covers multi-tenant setup and what happens when workspace:apply finds the database out of sync with the workspace files.
Related
Self-hosting is one half of the decision; the open-source agent workforce platform piece covers the other half — what "open source" actually buys you here versus an open-core competitor. And for the philosophical case against renting your workflow logic from a closed SaaS vendor in the first place, see Open framework vs SaaS agent platforms.
If you've read this far, you already know whether your infrastructure team can carry eleven containers. Clone vocion-core, run docker compose up -d, and find out the rest for yourself.