Skip to main content

Docker Compose Setup

Deploy Ovyxa in 5 minutes using Docker Compose. Perfect for single-server deployments up to millions of events per day.

Prerequisites

  • Linux server (Ubuntu 22.04+ recommended)
  • Docker 24+ installed
  • Docker Compose 2.x installed
  • 4GB+ RAM, 20GB+ disk
  • Domain name pointing to your server

Quick Start

1. Clone Repository

git clone https://github.com/ovyxa/ovyxa.git
cd ovyxa/deployments/docker-compose

2. Configure Environment

Copy the example environment file:

cp .env.example .env

Edit .env with your settings:

# Base Configuration
BASE_URL=https://analytics.yourdomain.com
SECRET_KEY_BASE=$(openssl rand -hex 64)

# PostgreSQL
POSTGRES_PASSWORD=$(openssl rand -hex 32)
DATABASE_URL=postgresql://ovyxa:${POSTGRES_PASSWORD}@postgres:5432/ovyxa

# ClickHouse
CLICKHOUSE_HOST=http://clickhouse:8123
CLICKHOUSE_DATABASE=ovyxa

# Redis
REDIS_PASSWORD=$(openssl rand -hex 32)
REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379

# Email (optional, for user invites)
SMTP_HOST=smtp.yourdomain.com
SMTP_PORT=587
SMTP_USER=noreply@yourdomain.com
SMTP_PASSWORD=your-smtp-password

# Admin User (created on first start)
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASSWORD=$(openssl rand -hex 16)

3. Start Services

docker-compose up -d

This starts:

  • PostgreSQL (metadata)
  • ClickHouse (analytics)
  • Redis (cache)
  • API server (ingestion + stats)
  • Web dashboard
  • Caddy (reverse proxy with auto-SSL)

4. Initialize Database

# Run migrations
docker-compose exec api npm run migrate

# Create admin user
docker-compose exec api npm run create-admin

5. Access Dashboard

Visit https://analytics.yourdomain.com and log in with your admin credentials.

Complete docker-compose.yml

version: '3.8'

services:
postgres:
image: postgres:15-alpine
container_name: ovyxa-postgres
environment:
POSTGRES_DB: ovyxa
POSTGRES_USER: ovyxa
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ovyxa"]
interval: 10s
timeout: 5s
retries: 5

clickhouse:
image: clickhouse/clickhouse-server:23-alpine
container_name: ovyxa-clickhouse
environment:
CLICKHOUSE_DB: ovyxa
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
volumes:
- clickhouse_data:/var/lib/clickhouse
- ./clickhouse/config.xml:/etc/clickhouse-server/config.d/ovyxa.xml
restart: unless-stopped
healthcheck:
test: ["CMD", "clickhouse-client", "--query", "SELECT 1"]
interval: 10s
timeout: 5s
retries: 5

redis:
image: redis:7-alpine
container_name: ovyxa-redis
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5

api:
image: ovyxa/api:latest
container_name: ovyxa-api
depends_on:
postgres:
condition: service_healthy
clickhouse:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3000
BASE_URL: ${BASE_URL}
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
DATABASE_URL: ${DATABASE_URL}
CLICKHOUSE_HOST: ${CLICKHOUSE_HOST}
CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE}
REDIS_URL: ${REDIS_URL}
SMTP_HOST: ${SMTP_HOST}
SMTP_PORT: ${SMTP_PORT}
SMTP_USER: ${SMTP_USER}
SMTP_PASSWORD: ${SMTP_PASSWORD}
volumes:
- ./logs:/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3

web:
image: ovyxa/web:latest
container_name: ovyxa-web
depends_on:
- api
environment:
NODE_ENV: production
NEXT_PUBLIC_API_URL: ${BASE_URL}/api
restart: unless-stopped

caddy:
image: caddy:2-alpine
container_name: ovyxa-caddy
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
restart: unless-stopped
depends_on:
- api
- web

volumes:
postgres_data:
clickhouse_data:
redis_data:
caddy_data:
caddy_config:

Caddyfile Configuration

Create Caddyfile:

analytics.yourdomain.com {
# Dashboard
handle /* {
reverse_proxy web:3000
}

# API & Ingestion
handle /api/* {
reverse_proxy api:3000
}

handle /e {
reverse_proxy api:3000
}

# Logs
log {
output file /data/access.log
}

# Security headers
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
Strict-Transport-Security "max-age=31536000;"
}
}

Caddy automatically provisions Let's Encrypt SSL certificates.

Management Commands

View Logs

# All services
docker-compose logs -f

# Specific service
docker-compose logs -f api
docker-compose logs -f clickhouse

Restart Services

# All services
docker-compose restart

# Specific service
docker-compose restart api

Update to Latest Version

docker-compose pull
docker-compose up -d
docker-compose exec api npm run migrate

Stop Services

docker-compose down

Stop and Remove Data

docker-compose down -v  # WARNING: Deletes all data

Configuration

See Configuration Guide for all environment variables.

Monitoring

Health Checks

# Check service health
docker-compose ps

# API health endpoint
curl https://analytics.yourdomain.com/api/health

Database Sizes

# ClickHouse storage
docker-compose exec clickhouse clickhouse-client --query \
"SELECT database, formatReadableSize(sum(bytes)) as size FROM system.parts WHERE active GROUP BY database"

# PostgreSQL size
docker-compose exec postgres psql -U ovyxa -c \
"SELECT pg_size_pretty(pg_database_size('ovyxa'))"

Backups

See Backup Guide for complete backup procedures.

Quick backup:

# Backup all data
./scripts/backup.sh

# Backup files saved to ./backups/

Troubleshooting

Services Won't Start

Check logs:

docker-compose logs postgres
docker-compose logs clickhouse

Common issues:

  • Port conflicts (change ports in docker-compose.yml)
  • Insufficient memory (increase RAM or swap)
  • Permission issues (check volume permissions)

Can't Access Dashboard

  1. Check Caddy logs: docker-compose logs caddy
  2. Verify DNS: dig analytics.yourdomain.com
  3. Check firewall: sudo ufw status
  4. Test local: curl http://localhost

Events Not Being Recorded

  1. Check API logs: docker-compose logs api
  2. Test ingestion: curl -X POST https://analytics.yourdomain.com/e -d '{"site":"test"}'
  3. Check ClickHouse: docker-compose exec clickhouse clickhouse-client --query "SELECT count() FROM ovyxa.events"

Performance Tuning

For high traffic, adjust resources in docker-compose.yml:

services:
clickhouse:
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 2G

api:
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M

Next Steps

Docker Compose is production-ready for most use cases up to 10M+ events/day.