Self-Hosted Deployment
Deploy Ctrl AI on your own infrastructure with Docker.
Prerequisites
- Docker Engine 24+ and Docker Compose v2
- 4 GB RAM minimum (8 GB recommended)
- An LLM API key (Gemini, OpenAI-compatible, or local Ollama)
Quick Start
# 1. Clone the repository
git clone https://github.com/ctrlai/ctrlai.git && cd ctrlai
# 2. Create environment file
cp .env.example .env
# Edit .env — at minimum set AUTH_SECRET and an LLM provider key
# 3. Start all services
docker compose up -dThe app will be available at http://localhost:3000. The first startup takes a few minutes while the image builds.
Database
Docker Compose (default)
The included docker-compose.yml runs PostgreSQL 16 automatically. Data is persisted in the postgres_data volume.
Run migrations after first start:
docker compose exec app npx drizzle-kit migrateBring Your Own PostgreSQL
Set DATABASE_URL in your .env to point at your existing database and remove the postgres service from docker-compose.yml.
DATABASE_URL=postgresql://user:pass@your-host:5432/ctrlaiLLM Configuration
Google Gemini (default)
Set GEMINI_API_KEY in your .env. No other config needed.
Ollama (fully local)
LLM_PROVIDER=ollama
LLM_BASE_URL=http://host.docker.internal:11434/v1
LLM_MODEL=llama3Make sure Ollama is running on the host machine before starting Ctrl AI.
OpenAI-Compatible
LLM_PROVIDER=openai
LLM_BASE_URL=https://api.openai.com/v1
LLM_API_KEY=sk-...
LLM_MODEL=gpt-4oWorks with any OpenAI-compatible API (Together, Groq, Azure OpenAI, etc.).
See LLM Configuration for advanced provider setup.
Email Configuration
Email is optional. Without it, invite and notification features are disabled gracefully.
Resend (cloud)
RESEND_API_KEY=re_...SMTP (self-hosted)
SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASS=secret
SMTP_FROM=Ctrl AI <noreply@example.com>Upgrading
git pull
docker compose build
docker compose up -d
docker compose exec app npx drizzle-kit migrateHealth Check
curl http://localhost:3000/api/health
# {"status":"ok","checks":{"database":"ok","redis":"not_configured"},"version":"0.1.0"}Troubleshooting
| Issue | Solution |
|---|---|
| App exits immediately | Check docker compose logs app — usually a missing AUTH_SECRET or unreachable database |
| Database connection refused | Ensure the postgres service is healthy: docker compose ps |
| Build fails with OOM | Increase Docker memory to 4 GB+ in Docker Desktop settings |
| Ollama not reachable | On macOS/Windows, use host.docker.internal instead of localhost in LLM_BASE_URL |
Logs
# All services
docker compose logs -f
# App only
docker compose logs -f app
# Database
docker compose logs -f postgres