# Self-host TulipFarm

> Run open-source TulipFarm on your own infrastructure. Learn the services, the two kinds of settings, the requirements, and the current limitations.

Source: https://tulipfarm.ai/docs/self-hosting/

Run TulipFarm on your own infrastructure. The application reads ordinary
environment variables. It has no secret-store or KMS client. You choose the secret
store, and your delivery layer puts values into the environment.

Self-hosted installs send no telemetry to TulipFarm.

| Read | When |
| --- | --- |
| [Docker Compose](https://tulipfarm.ai/docs/self-hosting/docker-compose/index.md) | Install, upgrade, back up, and restore one machine |
| [Configuration](https://tulipfarm.ai/docs/self-hosting/configuration/index.md) | Every setting, which service reads it, and key rotation |
| [Configuration reference](https://tulipfarm.ai/docs/self-hosting/configuration-reference/index.md) | The full variable table, generated from the settings registry |
| [Secret stores](https://tulipfarm.ai/docs/self-hosting/secrets/index.md) | Supply settings from Doppler, Infisical, 1Password, Vault, Kubernetes, or a file |
| [KMS](https://tulipfarm.ai/docs/self-hosting/kms/index.md) | Encrypt settings and backups with AWS KMS, GCP KMS, Azure Key Vault, Vault Transit, or age |
| [Models](https://tulipfarm.ai/docs/self-hosting/models/index.md) | Choose model providers, families, and knowledge embeddings |
| [Sign-in](https://tulipfarm.ai/docs/self-hosting/sign-in/index.md) | Configure Turnstile, Google sign-in, and email links |
| [Email](https://tulipfarm.ai/docs/self-hosting/email/index.md) | Send sign-in links and invitations through SMTP or Azure Communication Services |
| [GitHub](https://tulipfarm.ai/docs/self-hosting/github/index.md) | Register the GitHub OAuth App for personal GitHub accounts |

## Architecture

```text
                 browser
                    │ HTTPS
                    ▼
        ┌──────────────────────┐
        │ web (Caddy)          │  static app; /v1 and /.well-known/mcp-client.json → api
        └──────────┬───────────┘
                   ▼
        ┌──────────────────────┐      ┌───────────────────────────┐
        │ api                  │─────▶│ temporal (+ temporal-ui)  │
        └──────────┬───────────┘      └─────────────┬─────────────┘
                   │                                ▼
                   │              ┌──────────────────────────────────┐
                   │              │ worker           storage-worker  │
                   │              └────────┬─────────────────┬───────┘
                   ▼                       ▼                 ▼
        ┌─────────────────────────────────────┐   ┌──────────────────────┐
        │ PostgreSQL 18 + pgvector ≥ 0.8.0     │   │ S3-compatible storage│
        └─────────────────────────────────────┘   └──────────────────────┘
```

| Service | Role |
| --- | --- |
| `web` | Serves the built web app and proxies the API on the same origin |
| `api` | HTTP API, authentication, and chat |
| `worker` | Agent, workflow, and email-delivery activities |
| `storage-worker` | Creates and maintains isolated workspace databases |
| `temporal` | Durable workflow engine; stores its state in PostgreSQL |
| `setup` | One-shot job: creates roles, databases, keys, the bucket, and service env files |

## Two kinds of settings

```text
 You provide (operator settings)          Setup generates (generated settings)
 ──────────────────────────────           ────────────────────────────────────
 POSTGRES_PASSWORD, model API keys,        role passwords, encryption keys,
 Turnstile and sign-in credentials         BETTER_AUTH_SECRET, per-service URLs
          │                                         │
   your secret store                         state.json in the generated volume
   (Doppler, SOPS + KMS, …)                  (back it up; encrypt it with KMS)
          │                                         │
          └──────────────► service environment ◀────┘
```

**Operator settings** are values only you can supply. Put them in any secret store
that can export environment variables. See [Secret stores](https://tulipfarm.ai/docs/self-hosting/secrets/index.md).

**Generated settings** are created once by `setup` and stored in `state.json`.
Setup rewrites each service env file from that state on every run.
**If you lose `state.json`, you lose access to encrypted workspace credentials.**
See [Back up](https://tulipfarm.ai/docs/self-hosting/docker-compose/index.md#back-up).

## Requirements

- Docker Engine with Docker Compose v2
- A DNS name pointing at the host, with ports 80 and 443 open, for automatic HTTPS
- An [Anthropic API key](https://console.anthropic.com/), or another provider from
  [model configuration](https://tulipfarm.ai/docs/self-hosting/models/index.md)
- A [Cloudflare Turnstile](https://developers.cloudflare.com/turnstile/) widget for your hostname
- At least one sign-in method: a Google OAuth client, or email through SMTP or Azure
  Communication Services

## Current limitations

As of 17 October 2026, from the current source.

| Area | Limitation |
| --- | --- |
| Chat attachments | Chat uploads use Cloudflare R2 only (`CHAT_R2_*` in [`packages/workspaces/src/chat-objects.ts`](https://github.com/TulipFarm/tulipfarm/blob/main/packages/workspaces/src/chat-objects.ts)). The Compose stack leaves them unset, so uploads are unavailable. Workspace storage works with any S3-compatible service. |
| Knowledge embeddings | Semantic knowledge search works with Azure Foundry or any OpenAI-compatible endpoint, but only for `text-embedding-3-large` at 1,536 dimensions, the size workspace storage declares. Other models need a new profile and migration. Leave `KNOWLEDGE_EMBEDDINGS_ENABLED` unset to keep embeddings disabled. See [embedding providers](https://tulipfarm.ai/docs/self-hosting/models/index.md#embedding-providers). |
| Bot protection | Production sign-in requires real Cloudflare Turnstile keys. Test keys are rejected. |
| Key rotation | Encryption keys rotate through a Compose override; nothing re-encrypts old data. `BETTER_AUTH_SECRET` and generated passwords do not rotate. See [key rotation](https://tulipfarm.ai/docs/self-hosting/configuration/index.md#rotate-encryption-keys). |
| Scale | The Compose stack runs on one machine. For more, use the same images and the [configuration contract](https://tulipfarm.ai/docs/self-hosting/configuration/index.md). |
