Self-hosted

Run Tablize on your own box with Docker Compose — same binary as the cloud, your data never leaves your network.

Updated 2026-04-17

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:

ProviderLLM_PROVIDER valueNotes
AnthropicanthropicClaude Opus / Sonnet / Haiku.
OpenAIopenaiGPT-4, GPT-4o.
GLMglmZhipu AI’s GLM series.
OpenRouteropenrouterRoutes 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_dump works; the deploy bundle includes a backup.sh script 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 tablize for migration errors.
  • Agent returns “no LLM configured.” The LLM_API_KEY is empty or the provider is unreachable from the container. Verify with curl from inside the container.
  • MQTT connections rejected. EMQX’s default credentials changed between versions. Check deploy/emqx/passwd for 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 ANALYZE on the Tablize database. TimescaleDB chunks for IoT data benefit from periodic compression — enable timescaledb.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).