Self-host Treehouse

Run your own Treehouse server - the architecture, required and optional environment variables, storage and encryption, and connecting clients.

Treehouse is built to run on infrastructure you control. This page describes what a deployment needs. The repository's DEPLOYMENT.md has step-by-step instructions for the reference setup on Cloudflare and Railway.

1. Understand the architecture

ComponentWhat it isRuns on (reference setup)
Web appNuxt single-page app, served from a Cloudflare WorkerCloudflare Workers
APINitro server: authentication, the file service, REST API and MCP serverNode (Railway)
WorkerNitro BullMQ worker for background maintenance jobs, mostly billingNode (Railway)
DatabasePostgreSQL, for accounts, file metadata, versions and the change feedManaged Postgres (Railway)
RedisThe worker's job queueManaged Redis (Railway)
Blob storageFile contents, encrypted at restCloudflare R2, or a local disk

The app talks to the API across origins, so the simplest setup puts them on subdomains of one domain (app.example.com and api.example.com) and sets COOKIE_DOMAIN=.example.com so the sign-in cookie is shared. The browser never talks to blob storage: file bytes always stream through the API.

Run database migrations with pnpm --filter db run prisma:migrate:deploy on every deploy, before the new API starts.

2. Set the required API variables

VariableValue
DATABASE_URLPostgreSQL connection string
BETTER_AUTH_SECRETA random secret: openssl rand -hex 32
BETTER_AUTH_URLThe API's public URL, such as https://api.example.com
APP_URLThe web app's public URL. Comma-separate several origins (for example preview URLs); the first is used in links the API generates.
SHARE_COOKIE_SECRETA random secret: openssl rand -hex 32. Signs password-unlock cookies for share links.
BLOB_KEKThe master encryption key, in the form <id>:<base64> where the decoded key is exactly 32 bytes. Generate one with printf 'v1:%s\n' "$(openssl rand -base64 32)".

With NODE_ENV=production, the API refuses to start without SHARE_COOKIE_SECRET and BLOB_KEK.

3. Choose blob storage

OptionVariablesNotes
Cloudflare R2R2_ENDPOINT, R2_BUCKET, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEYAll four or none: a partial set stops the API from starting. Keep the bucket private.
Local filesystemBLOB_DIRA path on a persistent volume. In production it must be set explicitly.

R2 is reached through its S3-compatible API. Another S3-compatible endpoint configured through the same R2_* variables may work, but only R2 is tested.

In production, with neither R2 nor BLOB_DIR set, the API refuses to start rather than write files to disk that a redeploy would wipe.

4. Build the web app

The web app needs one variable, NUXT_PUBLIC_API_URL, set to the API's public URL. It is baked into the app at build time, so set it as a build variable. Also set the same value as the Worker's runtime variable in wrangler.jsonc: it feeds the discovery descriptor below, and the build fails if the two differ.

5. Add optional settings

GroupVariablesEffect
CookiesCOOKIE_DOMAINShares the session cookie across subdomains, such as .example.com
EmailPOSTMARK_SERVER_TOKEN, EMAIL_FROM, POSTMARK_MESSAGE_STREAMSends password-reset emails through Postmark. Without a token, emails are written to the server log.
Social sign-inGITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET; GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRETEach provider appears only when both of its values are set
Starter contentTREEHOUSE_SEED0 creates new workspaces empty, without the starter README.md and AGENTS.md
LimitsDEFAULT_WORKSPACE_QUOTA_BYTES, DEFAULT_WORKSPACE_FILE_LIMITPer-workspace storage and file-count limits. Unset means unlimited.
LimitsMAX_FILE_BYTESLargest single file, in bytes. Default 104857600 (100 MB). Keep it modest on a small server: uploads are held in memory.
LimitsMCP_MAX_READ_BYTESLargest read_file response over MCP. Default 1048576 (1 MiB).
EncryptionBLOB_KEK_RETIREDComma-separated old keys that still open existing workspaces after a rotation
EncryptionDEVICE_KEY_ENC_KEYEncrypts keys waiting in the device flow. Defaults to BETTER_AUTH_SECRET.
QueueNITRO_REDIS_URLRedis connection, for the worker
AnalyticsPOSTHOG_KEY, POSTHOG_HOSTServer-side error tracking. Off when the key is blank.
BillingBILLING_ENABLED, DEFAULT_PLAN_SLUG, STRIPE_*, FREE_WORKSPACES_PER_USER, INTERNAL_JOB_SECRETPlans and payments. Leave unset to run without billing.

Without billing

With BILLING_ENABLED and DEFAULT_PLAN_SLUG unset and no Stripe keys, billing is off. Workspaces get no plan and are unlimited, apart from any DEFAULT_WORKSPACE_* and MAX_FILE_BYTES limits you set, and GET /api/plans returns available: false so the app shows no plan picker. No Stripe account is needed.

6. Check the discovery descriptor

The web app serves /.well-known/treehouse, which tells clients where your API is:

json
{ "product": "treehouse", "version": 1, "apiUrl": "https://api.example.com" }

The desktop app uses it, so people can connect by entering your app's URL. Because that server isn't the hosted Treehouse, the desktop app asks them to confirm they trust it before connecting. The API must be served over HTTPS for the desktop app to accept it.

The CLI doesn't read the descriptor. Pass your API's URL when connecting a folder:

terminal
treehouse login ~/Acme --api-base https://api.example.com

or set TREEHOUSE_API_BASE=https://api.example.com. See the CLI reference.

7. Connect agents

Agents connect exactly as they do to the hosted service, with your API's URL in place of api.trytree.house. Create a key in your web app (account menu, API keys), then:

terminal
claude mcp add --transport http treehouse https://api.example.com/api/mcp \
  --header "x-api-key: <your key>"

See MCP server and connect other agents.

8. Check it works

  • https://api.example.com/api/health returns { "status": "ok", … }.
  • You can sign up and sign in, and the session cookie is set on your domain.
  • Uploading a file to a new workspace stores it in your bucket or BLOB_DIR.
  • An agent connected over MCP can call list_workspaces.
  • Every BLOB_KEK you have used is backed up outside the deployment.
  • Authentication

    How API keys work, what each kind of key can reach, the device authorisation flow the CLI and desktop app use, and how keys are revoked.

  • MCP server

    Every tool the Treehouse MCP server exposes, with parameters, outputs, limits and the instructions it gives connected agents.

  • Sync CLI reference

    Every treehouse command and flag, the files and environment variables the CLI reads, and the safety rules it follows while syncing.

Last updated