Self-Hosting
Run your own tela. It's a Go + PostgreSQL + React stack shipped as a Docker Compose deployment behind a Caddy proxy — you need only Docker (the marketing landing builds inside the image, so no Node toolchain).
tela is AGPL-3.0; the "tela" name and logo are reserved trademarks.
Quick start
git clone https://github.com/zcag/tela && cd tela
make setup # writes deploy/.env from the example with generated secrets
$EDITOR deploy/.env # set TELA_PUBLIC_BASE_URL, admin creds, SMTP
make up # build + start
make logs # the bootstrap admin password prints here once
The stack publishes host port 8780 (Caddy → app). The first admin comes from TELA_ADMIN_USERNAME/PASSWORD/EMAIL on first boot — or, if you leave TELA_ADMIN_PASSWORD unset, from the /setup web wizard the fresh instance lands on.
Configuration
Everything is env-driven (deploy/.env; every variable is documented in .env.example). The ones that matter:
| Variable | Notes |
|---|---|
TELA_PG_PASSWORD |
No default — required. make setup generates it. |
TELA_PUBLIC_BASE_URL |
Must match how users reach the instance — it drives emailed links and the cookie Secure flag. |
TELA_SHARE_SECRET, TELA_API_KEY_SECRET |
HMAC keys. Unset → generated and persisted on first boot (stable across restarts); set them to pin/rotate from the environment. Rotating them invalidates outstanding share cookies / PATs. |
TELA_SMTP_* |
Required for a usable multi-user instance (see Email). |
TELA_DATABASE_URL |
Auto-built from TELA_PG_* in this compose stack — set it only when pointing at an external Postgres. |
The backend logs its effective config at boot (config: …) — check those lines first when something's off.
TLS
The proxy defaults to plain HTTP on :80 (published as 8780), correct behind an external terminator (Cloudflare, a load balancer) — point it at :8780 and set an https:// base URL. For direct TLS, set TELA_SITE_ADDRESS=your.domain, publish 80+443 on the proxy, and Caddy auto-provisions a certificate. Direct TLS is also the prerequisite for org [[Custom domains]] (on-demand cert issuance can't fire behind an external terminator).
[!WARNING] The login cookie is
Secureonly whenTELA_PUBLIC_BASE_URLishttps://. If it'shttpsbut you serve plain HTTP, browsers drop the cookie and login silently fails. Keep the scheme matched to how users connect.
With TELA_SMTP_HOST unset, tela logs verify/reset links instead of sending them — fine for a single admin, but open self-registration is unusable without SMTP (confirmation links only hit the log). Configure TELA_SMTP_* for any multi-user instance; it works with any SMTP relay (e.g. Resend).
Registration policy
By default anyone can register. For a private or internal instance, close self-registration after the initial admin setup: go to Settings → Instance (as an instance admin) or call the admin API:
curl -s -X PATCH https://your.host/api/admin/settings \
-H 'Authorization: Bearer tela_pat_…' \
-H 'content-type: application/json' \
-d '{"settings":{"registration_open":"false"}}'
File sync (WebDAV)
tela exposes a WebDAV surface at /dav/ so you can sync pages from rclone, Obsidian, or any WebDAV client using a Personal Access Token. See [[Sync your vault (WebDAV)]] for setup steps.
[!NOTE] If you run behind Cloudflare: CF's default WAF rules block non-standard HTTP methods (PROPFIND, MKCOL, MOVE, COPY, etc.). You need to add a WAF skip rule for
/dav/*on your zone, or WebDAV will fail with 403 errors from CF's edge — not from tela.
WebDAV is on by default; disable it with TELA_WEBDAV_ENABLED=0 in deploy/.env.
Semantic search & AI
Full-text search works out of the box. Semantic search ("ask your docs") needs an embedder and an LLM — both ship dark (return 503) until configured.
- Self-host the embedder:
docker compose --profile embed up -d, setTELA_RAG_EMBED_URL=http://ollama:11434, and… exec ollama ollama pull qwen3-embedding:0.6b(the model must be 1024-d). - Or use tela cloud's managed endpoints (no GPU to run): point
TELA_RAG_EMBED_URL/TELA_LLM_URLat the managed proxy with a telawiki.com PAT — see.env.example.
[!NOTE] Changing the embed model means re-embedding everything: after editing
TELA_RAG_EMBED_MODEL, run… exec backend /tela reindex-all(resumable).
Reliability & failover
AI endpoints are external — if one clogs (rate-limited, slow, or down), the features that depend on it degrade. To keep them up, run the optional relief proxy: make up-relief starts a LiteLLM proxy in front of chat and embeddings, each with a primary and a relief endpoint, so traffic fails over automatically when the primary clogs. Set the endpoints in deploy/.env (the AI relief proxy block in .env.example); a relief embedder must output the same dimension (1024) as the primary.
Either way, Settings → Insights → AI endpoints & reliability (instance admin) shows each service's live status, probe latency, and whether it's behind a relief pool — the at-a-glance view of what's happening. Set TELA_GRAFANA_AI_URL to deep-link the card to a Grafana dashboard for the deeper per-endpoint failover metrics.
AI agents (MCP)
tela has a built-in MCP server at /api/mcp. Connect Claude, Claude Code, or any MCP client to https://your.host/api/mcp with a PAT as the bearer token. See [[Using the MCP server]] for tool reference and client setup.
Backups & upgrades
make backup # → ./backups/tela-<timestamp>.sql
make restore FILE=backups/... # restore a dump
Upgrade with git pull && make up — migrations run automatically on boot (forward-only). Back up before upgrading.
Operations
- CLI:
docker compose … exec backend /tela create-admin <user> <email> <pw>(admin recovery),set-plan,list-users,reindex-all(after an embedder model change). - Health:
GET /api/health(db + rag status);GET /api/version. - Metrics: Prometheus at
/metrics(instance-admin only; scrape with an admin PAT) — includes AI service health + token volume. - Admin: instance settings live under Settings as an instance admin.