Self-hosted
Run Tablize on your own box with Docker Compose — same binary as the cloud, your data never leaves your network.
Tablize Cloud is the fast path. But sometimes you need it on your own infrastructure — regulated data, air-gapped networks, lower long-term cost at scale, or simply a preference for owning the stack.
Self-hosted Tablize is the same binary as the cloud. Same features, same Agent, same domains. Different licensing model and a little more ops work up front.
What “self-hosted” means here
You run Tablize in your own Docker environment. We ship a single compose file that stands up:
- Tablize — the main binary (Agent runtime + web server + all domains).
- Postgres (with TimescaleDB extension) — your data.
- MinIO — object storage for Media files.
- EMQX — MQTT broker for IoT.
- Python sandbox — isolated container for the Python tools.
Total resource footprint: 4 cores, 8 GB RAM, 50 GB disk for a small team. Scales up linearly with data and concurrent users.
System requirements
- OS — Linux (Ubuntu 22.04+ or equivalent). macOS works for dev; not recommended for prod.
- Docker — 24.0+ with Compose v2.
- RAM — 8 GB minimum, 16 GB recommended.
- Disk — 50 GB for the system, plus your data and Media storage.
- Network — outbound HTTPS to your LLM provider (Anthropic / OpenAI / OpenRouter / GLM / etc.). Inbound on port 443 if users connect over the internet.
Docker 19.03 on older hosts needs seccomp=unconfined (a tokio clone3 quirk). The deploy script handles this automatically.
Installing
# 1. Clone the deploy bundle
git clone https://github.com/tablize-ai/deploy.git
cd deploy
# 2. Copy the env template and edit
cp .env.example .env
# Edit .env to set:
# - LLM_API_KEY=sk-... (your provider key)
# - LLM_PROVIDER=anthropic (or openai / glm / openrouter)
# - TABLIZE_DOMAIN=tablize.yourco.internal
# - ADMIN_EMAIL=you@yourco.com
# 3. Start everything
./start.sh
First start pulls images, initializes the database schema, and seeds the admin account. Takes 2-5 minutes on a typical host.
Visit https://<TABLIZE_DOMAIN> and sign in with your ADMIN_EMAIL. A magic link arrives via whatever SMTP you configured (see below).
Environment variables
The full list, with defaults where reasonable:
# LLM
LLM_PROVIDER=anthropic # anthropic | openai | glm | openrouter
LLM_API_KEY=sk-... # your provider key
LLM_DEFAULT_MODEL=claude-opus-4-7 # override per-provider default
# Domain
TABLIZE_DOMAIN=tablize.yourco.internal
TABLIZE_PUBLIC_URL=https://tablize.yourco.internal
# Admin
ADMIN_EMAIL=you@yourco.com
# SMTP (for magic links and notifications)
SMTP_HOST=smtp.postmarkapp.com
SMTP_PORT=587
SMTP_USER=...
SMTP_PASS=...
SMTP_FROM="Tablize <no-reply@yourco.com>"
# Database (override to use external PG)
DATABASE_URL=postgres://tablize:...@postgres:5432/tablize
# Media / S3 (override to use external S3)
S3_ENDPOINT=http://minio:9000
S3_BUCKET=tablize
S3_ACCESS_KEY=...
S3_SECRET_KEY=...
# MQTT
MQTT_HOST=emqx
MQTT_PORT=1883
# Secrets
TABLIZE_SECRET=... # 64 random bytes for JWT signing
The start script generates TABLIZE_SECRET and other random credentials on first run — don’t commit these; they live in .env.production.
Connecting to your LLM
Tablize needs an LLM to run the Agent. Four supported providers out of the box:
| Provider | LLM_PROVIDER value | Notes |
|---|---|---|
| Anthropic | anthropic | Claude Opus / Sonnet / Haiku. |
| OpenAI | openai | GPT-4, GPT-4o. |
| GLM | glm | Zhipu AI’s GLM series. |
| OpenRouter | openrouter | Routes to any of the above plus more. |
Your key is used for every Agent request. Cost is paid directly to the provider — there’s no token metering on Tablize’s side for self-hosted.
For air-gapped deployments: bring your own LLM (open-weights model behind vLLM or Ollama). Set LLM_PROVIDER=openai and point LLM_ENDPOINT at your model server — it expects OpenAI-compatible API shape. Works with Llama, Qwen, DeepSeek, Mistral — anything that serves the OpenAI completions protocol.
Reverse proxy / TLS
The Tablize container listens on port 3000 (HTTP). For production, front it with nginx, Caddy, or Traefik for TLS termination. Sample nginx config is in deploy/nginx.conf.example.
For internal deployments, use your internal CA. For internet-facing deployments, Let’s Encrypt via Caddy takes two lines of config.
Upgrading
Upgrades are a pull + restart:
./upgrade.sh
Under the hood:
- Fetches the latest compose file + env template.
- Pulls new images.
- Runs schema migrations (backwards-compatible within a minor version).
- Rolling-restarts Tablize; Postgres, MinIO, EMQX stay up.
Downtime is ~10 seconds during the restart.
Before a major version upgrade (v1.x → v2.x), read the release notes — occasionally a major includes a one-time migration that takes longer.
Backup and restore
Three things to back up:
- Postgres — your data.
pg_dumpworks; the deploy bundle includes abackup.shscript that rotates daily dumps. - MinIO / S3 — Media files. Usually replicated to an external object store (AWS S3, Cloudflare R2) via MinIO’s built-in replication.
.env.production— credentials. Store encrypted in your secret manager.
A full restore:
./stop.sh
./restore.sh path/to/backup.tar.gz
./start.sh
Test the restore flow at least once in staging before you need it.
Monitoring
The Tablize container exposes Prometheus metrics at /metrics:
- Agent tokens consumed per session.
- DB query latency p50/p95/p99.
- WebSocket connection count.
- Background job queue depth.
Standard Grafana dashboards are in deploy/grafana/. Scrape from your existing Prometheus or use the included Prometheus container.
Healthcheck: GET /api/health returns 200 when the service is ready, 503 during startup (domain init), 500 on serious errors. Use as your load balancer’s health probe.
License
Self-hosted Tablize is licensed per-workspace, perpetual. One-time purchase covers the current version and one year of updates; extending updates is optional. You can run as many workspaces, seats, and nodes as you want — the license is on the instance, not the user count.
Pricing: contact enterprise@tablize.com. Typical range: $10K–$50K per instance per year depending on support SLA.
Common gotchas
- “503 Service Unavailable” after startup. Domains are still initializing. Normal — takes 10-30 seconds. If it persists > 2 minutes, check
docker logs tablizefor migration errors. - Agent returns “no LLM configured.” The
LLM_API_KEYis empty or the provider is unreachable from the container. Verify withcurlfrom inside the container. - MQTT connections rejected. EMQX’s default credentials changed between versions. Check
deploy/emqx/passwdfor the current set. - Python tools timing out. The sandbox container is undersized. Increase memory limit in
docker-compose.yml(services.python-sandbox.deploy.resources). - Database slow after months of use. Run
VACUUM ANALYZEon the Tablize database. TimescaleDB chunks for IoT data benefit from periodic compression — enabletimescaledb.enable_compression=on.
Differences from Cloud
Self-hosted and Cloud are the same binary, but:
- No token metering. You pay the LLM provider directly.
- No automatic multi-tenancy. One Tablize instance = one org. For true multi-tenant SaaS, stand up multiple instances (they can share a Postgres if configured).
- Manual upgrades. You upgrade on your schedule, not ours.
- No Federation across instances. Federation works between workspaces on the same instance, not across instances. (If you want cross-instance, use the REST API.)
Next steps
- Troubleshooting — common operational issues.
- Enterprise — if you want commercial support or a custom deployment.
- Integrations — some connectors require additional setup in self-hosted (e.g., webhook URL = your domain, not Tablize’s).