LangFlow Self-Hosting: Docker Setup and Configuration
Why Self-Host LangFlow Instead of Using the Cloud Version
The moment you start building anything real with LangFlow, you run into the limits of the hosted playground. You want to store flows in a database you control, connect to internal APIs that live behind a VPN, keep your prompts and API keys off someone else's server, and avoid a per-seat pricing model while your team is still figuring out whether the tool is a fit. Self-hosting solves all four problems at once, and it turns out to be far less painful than most people expect.
LangFlow ships as a proper Docker image, publishes a docker-compose reference, and stores its state in Postgres (or SQLite for quick tests), which means the entire deployment story is "run a container, point it at a database, set your environment variables." There's no proprietary orchestration layer to fight, no vendor lock-in on where your flows live, and no mystery about what data leaves your network. This guide walks through a complete, working Docker setup for LangFlow — starting from a single-container quickstart, moving to a production-grade docker-compose.yml with persistent Postgres, and finishing with the configuration knobs (auth, superuser accounts, reverse proxy, backups) you actually need before pointing real users at it.
If you're building agentic workflows and want to understand not just how to deploy LangFlow but how to design the flows that run inside it, that's exactly the gap our LangFlow Tutorial course on teachyou.ai is built to close — this article handles the infrastructure side.
What LangFlow Actually Needs to Run
Before touching Docker, it helps to know what's inside the box. LangFlow is a Python application (FastAPI backend, React frontend, bundled together) that needs:
- A database for storing flows, users, API keys, and variables. SQLite works for solo experimentation; Postgres is what you want for anything with more than one user or any expectation of durability.
- A persistent volume for flow data, uploaded files, and — if you're using SQLite — the database file itself.
- Environment variables for secrets: your LLM provider API keys, the database connection string, the superuser credentials, and a secret key used to encrypt stored credentials inside LangFlow itself.
- Network exposure on port 7860 by default, which you'll typically put behind a reverse proxy for TLS termination.
That's the whole list. There's no message queue requirement for basic usage, no separate worker process unless you enable Celery-based task execution for long-running flows, and no external cache dependency out of the box. This is why LangFlow self-hosts cleanly — the deployment surface area is small.
Quickstart: Running LangFlow With a Single Docker Command
If you just want to kick the tires before committing to a full compose stack, the single-container route gets you there in under a minute, assuming you already have Docker installed:
docker run -d \
--name langflow \
-p 7860:7860 \
-v langflow_data:/app/langflow \
langflowai/langflow:latestThis pulls the official image, maps the web UI to localhost:7860, and mounts a named volume so your flows survive a container restart. Under the hood, with no database URL specified, LangFlow defaults to a SQLite file inside that mounted volume — perfectly fine for kicking the tires, not something you want to run for a team.
Check that it came up cleanly:
docker logs -f langflowYou're looking for a line confirming the Uvicorn server started and bound to 0.0.0.0:7860. Once you see it, open http://localhost:7860 in a browser and you should land on the LangFlow flow builder. That's the entire quickstart — but it's also the setup you'll want to replace before doing anything beyond a personal sandbox, because SQLite under concurrent writes from multiple browser tabs or teammates degrades quickly, and a single unnamed container gives you no clean upgrade path.
Building a Production Docker Compose Stack
The real setup separates LangFlow from its database, gives both services named volumes, and pins versions so an upstream image update doesn't surprise you mid-week. Here's a docker-compose.yml that reflects how this should actually be run:
version: "3.9"
services:
langflow:
image: langflowai/langflow:1.1.1
container_name: langflow
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "7860:7860"
environment:
LANGFLOW_DATABASE_URL: postgresql://langflow:${POSTGRES_PASSWORD}@postgres:5432/langflow
LANGFLOW_SUPERUSER: ${LANGFLOW_SUPERUSER}
LANGFLOW_SUPERUSER_PASSWORD: ${LANGFLOW_SUPERUSER_PASSWORD}
LANGFLOW_SECRET_KEY: ${LANGFLOW_SECRET_KEY}
LANGFLOW_AUTO_LOGIN: "false"
LANGFLOW_NEW_USER_IS_ACTIVE: "false"
LANGFLOW_LOG_LEVEL: info
LANGFLOW_WORKERS: 2
volumes:
- langflow_data:/app/langflow
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7860/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
postgres:
image: postgres:16-alpine
container_name: langflow-postgres
restart: unless-stopped
environment:
POSTGRES_USER: langflow
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: langflow
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U langflow"]
interval: 10s
timeout: 5s
retries: 5
volumes:
langflow_data:
postgres_data:A few decisions in there are worth explaining rather than just copying:
- Pinned image tags.
langflowai/langflow:1.1.1instead of:latest. LangFlow ships fast, and a:latestpull on container restart can silently change your schema expectations or UI behavior. Pin it, test upgrades deliberately. - `depends_on` with a health condition, not just a plain dependency. Postgres needs to actually accept connections before LangFlow's startup migrations run, and Compose's default
depends_ononly waits for the container to start, not for the service inside it to be ready. - `LANGFLOW_NEW_USER_IS_ACTIVE: "false"`. This means new signups need explicit activation by an admin — important the moment this instance is reachable by more than just you.
- A dedicated named volume for Postgres data, separate from LangFlow's own volume. This is what makes backups and restores clean — you can snapshot the Postgres volume independently of the app volume.
Put your secrets in a .env file next to the compose file, not inline in the YAML:
POSTGRES_PASSWORD=change_this_to_something_long_and_random
LANGFLOW_SUPERUSER=admin
LANGFLOW_SUPERUSER_PASSWORD=change_this_too
LANGFLOW_SECRET_KEY=generate_a_real_fernet_key_hereBring it up:
docker compose up -d
docker compose psBoth services should report healthy within about a minute. If LangFlow keeps restarting, check its logs first — nine times out of ten it's a database connection string typo or Postgres not being ready yet.
Environment Variables That Actually Matter
LangFlow exposes a long list of environment variables, but in practice you'll touch a small subset regularly. Here's the set worth understanding rather than just pasting:
- LANGFLOW_DATABASE_URL — your Postgres connection string. Without this, LangFlow falls back to SQLite in the mounted data directory, which is fine for a demo and wrong for anything else.
- LANGFLOW_SECRET_KEY — used to encrypt API keys and credentials that users save inside flows (their OpenAI key, their vector DB token, and so on). Generate this once and never rotate it casually — rotating it without a migration step makes previously stored encrypted credentials unreadable.
- LANGFLOW_SUPERUSER / LANGFLOW_SUPERUSER_PASSWORD — bootstraps the first admin account on container startup. This only takes effect on first run against a fresh database; changing it later in the compose file does nothing to an existing user.
- LANGFLOW_AUTO_LOGIN — when
true, LangFlow skips authentication entirely and logs every visitor in as a default user. This is meant for fully local, single-user development. Setting it tofalseis the single most important step before exposing LangFlow beyond localhost. - LANGFLOW_NEW_USER_IS_ACTIVE — controls whether self-registered accounts are usable immediately or need admin approval.
- LANGFLOW_WORKERS — number of Uvicorn worker processes. Two is a reasonable starting point for small teams; scale this with available CPU cores, not arbitrarily.
- LANGFLOW_LOG_LEVEL — set to
debugtemporarily when diagnosing a flow execution issue, then back toinfo— debug logging is noisy and will fill your disk faster than you'd expect on a busy instance. - LANGFLOW_CACHE_TYPE — controls whether flow results are cached in memory, on disk, or via Redis if you've added a Redis service for multi-instance deployments.
A generic way to generate that secret key locally, without needing a Python environment:
docker run --rm python:3.11-slim python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"That won't work out of the box since cryptography isn't in the base image, so the more reliable route is to exec into a running LangFlow container and generate it there, where the dependency already exists:
docker exec -it langflow python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Copy the output into your .env file as LANGFLOW_SECRET_KEY before the first startup, so it's in place when the superuser account gets created.
Persisting Data and Handling Upgrades Safely
The two things that will actually hurt you in a self-hosted LangFlow deployment are losing data on a container recreate and breaking things during a version bump. Both are avoidable with the same discipline.
For persistence, the compose file above already handles the mechanics — postgres_data holds every flow, user, and stored variable, and it survives docker compose down as long as you don't add the -v flag, which explicitly deletes volumes. Get in the habit of never running docker compose down -v on a production stack without a fresh backup first.
Back up Postgres on a schedule rather than trusting the volume alone:
docker exec langflow-postgres pg_dump -U langflow langflow | gzip > langflow_backup_$(date +%Y%m%d).sql.gzWire that into a cron job on the host, and keep at least a week of rolling daily backups off the same machine — a corrupted volume and a corrupted backup sitting next to each other help nobody.
For upgrades, the safe sequence is: back up the database, bump the pinned image tag in your compose file by one minor version at a time (not a multi-version jump), read the release notes for breaking migration changes, then apply:
docker compose pull langflow
docker compose up -d langflow
docker compose logs -f langflowWatch the logs for migration output on startup. LangFlow runs Alembic migrations automatically when the container boots against a new schema version, and that's the moment where a bad upgrade will surface — as a migration error in the logs, not as a mysterious failure three days later.
Putting LangFlow Behind a Reverse Proxy
Running LangFlow on a bare port facing the internet is not a real deployment. At minimum, put it behind Nginx or Caddy so you get TLS and can control access at the proxy layer before requests even reach the app.
A minimal Caddy config is the least ceremony for this, since it handles Let's Encrypt certificates automatically:
langflow.yourdomain.com {
reverse_proxy langflow:7860
}Drop that in a Caddyfile, add Caddy as a service in the same compose stack, and put it on the same Docker network as the langflow service:
caddy:
image: caddy:2-alpine
container_name: langflow-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddyfile
- caddy_data:/data
depends_on:
- langflowIf you're already running Nginx elsewhere on the host, a straightforward server block works just as well — the key requirement is forwarding the Upgrade and Connection headers, since LangFlow's UI relies on WebSocket connections for streaming flow execution output back to the browser. Skipping that header forwarding is the most common reason people report the LangFlow UI loading fine but flows appearing to hang mid-execution behind a reverse proxy.
Securing a Self-Hosted Instance
A few concrete steps matter more than the rest once LangFlow is reachable outside your laptop:
- Set
LANGFLOW_AUTO_LOGIN=falsebefore this instance is reachable by anyone but you — this is the single setting that gates whether authentication exists at all. - Rotate the default superuser password immediately after first login, and create individual accounts for team members instead of sharing the admin login.
- Store API keys for LLM providers as LangFlow "Global Variables" scoped per-user rather than hardcoding them into shared flows, so a flow exported or duplicated by a teammate doesn't leak your OpenAI key.
- Restrict the Postgres container so it isn't exposed on a host port at all — in the compose file above, notice there's no
ports:mapping for thepostgresservice, meaning it's reachable only from other containers on the same Docker network, not from the internet or even the host's other processes. - Put the reverse proxy in front of everything and only open ports 80/443 on your firewall, never 7860 directly.
- If you're running this on a cloud VM, restrict inbound security group rules to your office or VPN IP range rather than
0.0.0.0/0while you're still in a small-team stage.
None of this is exotic — it's the same baseline hygiene you'd apply to any self-hosted web app with a database behind it — but LangFlow's defaults (auto-login enabled, SQLite fallback) are tuned for frictionless local development, not for "safe to expose publicly," so the gap between the default and the safe configuration is exactly the checklist above.
Scaling Beyond a Single Instance
Once a self-hosted LangFlow deployment is handling real traffic — multiple teams building and running flows concurrently — a few adjustments extend the same Docker foundation instead of requiring a rewrite:
- Bump `LANGFLOW_WORKERS` to match available CPU cores, since each worker is a separate process handling requests.
- Move to managed Postgres (RDS, Cloud SQL, or equivalent) instead of a Postgres container on the same host, once backup automation and read replicas start to matter more than they did on day one.
- Add Redis as a shared cache layer if you run multiple LangFlow containers behind a load balancer, so flow execution state isn't siloed to whichever instance happened to handle a given request.
- Separate long-running flow execution onto dedicated worker processes if you're running flows that take minutes rather than seconds, so a slow flow doesn't tie up a request-handling worker.
The docker-compose.yml in this guide is the right starting point for all of these — scaling out mostly means swapping the postgres service for a managed connection string and adding a redis service, not re-architecting the deployment.
Troubleshooting Common Docker Issues
A short list of the failures that come up most often when people first self-host LangFlow, in the order you're likely to hit them:
- Container restarts in a loop right after `docker compose up`. Check
docker compose logs langflowfirst — this is almost always either a malformedLANGFLOW_DATABASE_URLor Postgres not yet accepting connections because the healthcheck-baseddepends_onwasn't configured. - UI loads but flows never finish executing. Usually a reverse proxy dropping the WebSocket upgrade — confirm your Nginx or Caddy config forwards
UpgradeandConnectionheaders. - Login screen never appears, everyone's logged in as a default user.
LANGFLOW_AUTO_LOGINis stilltrue. Set it tofalseand restart the container. - Superuser credentials from the `.env` file don't work. These variables only take effect the first time LangFlow initializes against an empty database. If you changed them after that first run, you need to update the user directly or reset against a fresh database.
- Disk filling up unexpectedly. Check
LANGFLOW_LOG_LEVEL—debugmode generates a lot of output on an active instance, and old logs plus an ever-growing Postgres volume with no backup rotation is a common quiet failure mode.
Working through each of these once is usually enough to have a mental map of the whole stack, since none of them are LangFlow-specific mysteries — they're the same categories of issue you'd debug in any Dockerized web app with a database dependency.
Closing Thoughts
Self-hosting LangFlow with Docker is a genuinely small amount of infrastructure for what you get back: full control over where flow data lives, no per-seat licensing, and the ability to wire LangFlow into internal networks that a hosted SaaS product could never reach. The docker-compose.yml in this guide — LangFlow plus Postgres, with health checks, named volumes, and environment-driven secrets — is a stack you can run in production with a reverse proxy in front of it and a daily pg_dump behind it, not just a throwaway demo.
Getting the deployment right is half the job. The other half is knowing how to actually design flows inside LangFlow once it's running — chaining LLM calls, wiring in retrieval, building agents that call tools, and debugging execution graphs when they don't behave the way you expect. That's exactly what our LangFlow Tutorial course on teachyou.ai covers, taught by instructors who've spent real time building and shipping LangFlow-based systems, not just reading the docs. If this guide got your instance running, that course is the natural next step for what to build on top of it.
BootcampA 30-day guided bootcamp: build, harden and ship a production autonomous agent from scratch.
AI AgentsUnderstand how AI agents really work: the loop, the tools, the memory, and why most agent projects fail.
Related reading