Get started

Deployment

Self-hosted deployment options for Quox.

QuoxCORE is designed for self-hosted deployment, giving you full control over your data and infrastructure. All services build from source using Docker Compose.


System Requirements

ResourceMinimumRecommended
CPU4 cores8 cores
RAM8 GB16 GB
Disk40 GB SSD100 GB SSD
OSLinux (x86_64)Ubuntu 22.04+ / Debian 12+
DockerDocker Engine 24+ with Compose v2Latest stable
Node.js18+ (build only)20 LTS

QuoxCORE runs approximately 12 services. Qdrant (vector DB) and PostgreSQL are the most memory-hungry.


Docker Compose Deployment

1. Clone and configure

bash
git clone [email protected]:quoxai/quox.git quox-dashboard
cd quox-dashboard

# Copy the example environment file
cp .env.example .env

# Auto-generate secrets (JWT, encryption keys, Qdrant API key, etc.)
./scripts/generate-secrets.sh

Edit .env and fill in any API keys you need:

bash
# ============================================
# REQUIRED - Generated by generate-secrets.sh
# ============================================
JWT_SECRET=<generated>
MASTER_ENCRYPTION_KEY=<generated>
QDRANT_API_KEY=<generated>
POSTGRES_PASSWORD=<generated>
INTERNAL_SERVICE_KEY=<generated>

# ============================================
# REQUIRED - Docker host config
# Auto-detected by generate-secrets.sh
# ============================================
# DOCKER_GID=988

# ============================================
# OPTIONAL - API Keys (add for full AI functionality)
# ============================================
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxx
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
ELEVENLABS_API_KEY=

# ============================================
# OPTIONAL - SMTP (for user invitations / password resets)
# ============================================
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
[email protected]

# ============================================
# OPTIONAL - SSL
# ============================================
SSL_MODE=selfsigned
# LETSENCRYPT_DOMAIN=quox.yourdomain.com
# [email protected]

# ============================================
# PORTS (defaults shown)
# ============================================
DASHBOARD_PORT=3000
AUTH_PORT=3101
FILES_PORT=3102
COLLECTOR_PORT=9848
QDRANT_PORT=6333
POSTGRES_PORT=5432

2. Generate SSL certificates

The dashboard serves over HTTPS. Generate a self-signed certificate for local/dev use:

bash
./scripts/generate-certs.sh
cp certs/cert.pem ssl/quox.crt
cp certs/key.pem ssl/quox.key

For production with Let's Encrypt, set SSL_MODE=letsencrypt in .env and use ./scripts/ssl-manager.sh init.

3. Clone QuoxMCP (required for AI tool execution)

The collector service mounts QuoxMCP for MCP protocol tool execution. Without it, AI agents will have no tool capability.

bash
git clone [email protected]:quoxai/quoxmcp.git /home/control/quoxmcp

4. Start services

bash
# Start all core services
docker compose up -d

# Optionally include n8n (legacy workflow engine, 400+ third-party connectors)
docker compose --profile with-n8n up -d

# Verify everything is healthy
docker compose ps

5. Complete setup

Open https://localhost:3000 in your browser and complete the Setup Wizard.

Service overview

QuoxCORE runs the following services (all build from source except Qdrant and PostgreSQL):

ServicePortDescription
dashboard3000 (HTTPS)React frontend served by nginx
auth3101Authentication, RBAC, JWT tokens
files3102File storage service
memory3103Server-side memory persistence (SQLite + FTS5)
tasks3104Background task scheduler
collector9848Chat streaming, fleet management, AI tool execution
orchestrator3100Container orchestration via Docker socket
quoxflow3200Auditable workflow engine (TypeScript)
qdrant6333Vector database for semantic search
postgres5432PostgreSQL database for QuoxFlow
n8n5678Workflow automation (optional, behind with-n8n profile)
screencap3300Headless browser screenshots (optional, behind with-screencap profile)

All internal services bind to 127.0.0.1 only. The collector (9848) is exposed on all interfaces because remote QuoxAgent instances send heartbeats to it.


Reverse Proxy Setup

If you place QuoxCORE behind an external reverse proxy, the dashboard already runs nginx internally. You only need to forward traffic to the dashboard port.

Nginx

nginx
server {
    listen 443 ssl http2;
    server_name quox.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/quox.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/quox.yourdomain.com/privkey.pem;

    # Dashboard (handles all routing internally)
    location / {
        proxy_pass https://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Traefik

yaml
# docker-compose.override.yml
services:
  dashboard:
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.quox.rule=Host(`quox.yourdomain.com`)"
      - "traefik.http.routers.quox.tls.certresolver=letsencrypt"
      - "traefik.http.services.quox.loadbalancer.server.scheme=https"
      - "traefik.http.services.quox.loadbalancer.server.port=443"

Production Checklist

Security

  • TLS certificates -- Use Let's Encrypt or your own CA, not self-signed
  • Secrets generated -- All keys in .env are unique random values (run generate-secrets.sh)
  • .env not in version control -- Confirm .gitignore includes .env
  • Cookie security -- Set COOKIE_SECURE=true for HTTPS deployments
  • Firewall rules -- Only expose required ports
bash
# External ports (must be reachable)
3000/tcp   # Dashboard (HTTPS, behind reverse proxy)
9848/tcp   # Collector (QuoxAgent heartbeats from remote hosts)

# Internal only (bind to 127.0.0.1 by default)
3100/tcp   # Orchestrator
3101/tcp   # Auth
3102/tcp   # Files
3103/tcp   # Memory
3104/tcp   # Tasks
5432/tcp   # PostgreSQL
5678/tcp   # n8n (if enabled)
6333/tcp   # Qdrant
  • RBAC configured -- Users have appropriate roles
  • Audit logging enabled -- All actions logged via AEE protocol

Data Persistence

All service data is stored in named Docker volumes. Verify they are created:

bash
docker volume ls | grep quox

Key volumes to back up:

VolumeContents
quox-auth-dataUser accounts, sessions, credentials (SQLite)
quox-collector-dataAEE envelope database, chat history
quox-memory-dataLearned memories (SQLite + FTS5)
quox-qdrant-dataVector embeddings
quox-postgres-dataQuoxFlow workflow data
quox-files-dataUploaded files and metadata
quox-tasks-dataScheduled task database
bash
# Example backup script
#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR="./backups/$DATE"
mkdir -p "$BACKUP_DIR"

# Stop services for consistent backup
docker compose stop

# Back up each volume
for vol in quox-auth-data quox-collector-data quox-memory-data quox-qdrant-data quox-postgres-data quox-files-data quox-tasks-data; do
  docker run --rm -v "$vol":/data -v "$(pwd)/$BACKUP_DIR":/backup alpine \
    tar czf "/backup/$vol.tar.gz" -C /data .
done

# Restart services
docker compose up -d
echo "Backup complete: $BACKUP_DIR"
  • Backup strategy tested -- Run a backup and verify you can restore
  • Restore tested -- Practice restoring from backup to a fresh environment

Monitoring

  • Health checks -- All services have built-in health checks (visible via docker compose ps)
  • Log rotation -- Configure Docker log limits
yaml
# Add to docker-compose.override.yml for log rotation
services:
  dashboard:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
  • Alerting -- Monitor docker compose ps for unhealthy containers
  • Disk usage -- Watch Qdrant and PostgreSQL volume growth

Performance

  • Resource limits -- Set memory limits for heavy services
yaml
# docker-compose.override.yml
services:
  qdrant:
    mem_limit: 4G
  postgres:
    mem_limit: 1G
  collector:
    mem_limit: 2G

Scaling

Vertical Scaling

For larger fleets and more concurrent users, increase resources on the host machine. The collector service handles QuoxAgent heartbeats and AI chat streaming -- it benefits most from additional CPU and RAM.

QuoxAgent Fleet

The collector can handle hundreds of QuoxAgent instances reporting in. Each agent connects over HTTPS to port 9848. For geographically distributed fleets, consider deploying multiple QuoxCORE instances per region.


Upgrading

Standard Upgrade

QuoxCORE services build from source, so upgrading means pulling the latest code and rebuilding:

bash
cd quox-dashboard

# Pull latest code
git pull

# Rebuild all services
docker compose build

# Restart with new images
docker compose up -d

# Verify health
docker compose ps

Rebuilding Individual Services

If you only changed one service (e.g., the collector):

bash
docker compose build collector
docker compose up -d collector

Note: The dashboard bakes the React frontend into its Docker image during build. After any frontend code change, you must rebuild the dashboard image.

Database Migrations

SQLite-based services (auth, memory, collector, tasks) run migrations automatically on startup. PostgreSQL migrations for QuoxFlow also run on boot. No manual migration step is needed.


Troubleshooting

Container won't start

bash
# Check logs for the failing service
docker compose logs auth
docker compose logs collector

# Common causes:
# - Missing required env vars (JWT_SECRET, QDRANT_API_KEY, POSTGRES_PASSWORD)
# - Port conflicts with other services on the host
# - DOCKER_GID mismatch (re-run generate-secrets.sh)

QuoxAgent can't connect

bash
# On the agent host, check QuoxAgent status
quoxagent status

# Verify the collector is reachable from the agent host
curl -s http://<quoxcore-ip>:9848/health

# On the QuoxCORE host, check collector logs
docker compose logs collector | grep heartbeat

Services unhealthy

bash
# See which services are unhealthy
docker compose ps

# Restart a specific service
docker compose restart auth

# Full restart of all services
docker compose down && docker compose up -d

Qdrant memory issues

bash
# Check Qdrant resource usage
docker stats quox-qdrant

# If OOM, increase the memory limit
# In docker-compose.override.yml:
#   qdrant:
#     mem_limit: 4G

SSL certificate issues

bash
# Regenerate self-signed certs
./scripts/generate-certs.sh
cp certs/cert.pem ssl/quox.crt
cp certs/key.pem ssl/quox.key
docker compose restart dashboard

Next Steps