Files
cameleer-saas/HOWTO.md
hsiegeln b78dfa9a7b
All checks were successful
CI / build (push) Successful in 27s
CI / docker (push) Successful in 4s
docs: add HOWTO.md with install, start, and bootstrap instructions
Quick start, full installation guide, Logto setup, first tenant
creation, app deployment walkthrough, API reference, tier limits,
development commands, and troubleshooting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:31:56 +02:00

8.7 KiB

Cameleer SaaS -- How to Install, Start & Bootstrap

Quick Start (Development)

# 1. Clone
git clone https://gitea.siegeln.net/cameleer/cameleer-saas.git
cd cameleer-saas

# 2. Create environment file
cp .env.example .env

# 3. Generate Ed25519 key pair
mkdir -p keys
ssh-keygen -t ed25519 -f keys/ed25519 -N ""
mv keys/ed25519 keys/ed25519.key

# 4. Start the stack
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

# 5. Wait for services to be ready (~30s)
docker compose logs -f cameleer-saas --since 10s
# Look for: "Started CameleerSaasApplication"

# 6. Verify
curl http://localhost:8080/actuator/health
# {"status":"UP"}

Prerequisites

  • Docker Desktop (Windows/Mac) or Docker Engine 24+ (Linux)
  • Git
  • curl or any HTTP client (for testing)

Architecture

The platform runs as a Docker Compose stack with 6 services:

Service Image Port Purpose
traefik traefik:v3 80, 443 Reverse proxy, TLS, routing
postgres postgres:16-alpine 5432* Platform database + Logto database
logto ghcr.io/logto-io/logto 3001*, 3002* Identity provider (OIDC)
cameleer-saas cameleer-saas:latest 8080* SaaS API server
cameleer3-server cameleer3-server:latest 8081 Observability backend
clickhouse clickhouse-server:latest 8123* Trace/metrics/log storage

*Ports exposed to host only with docker-compose.dev.yml overlay.

Installation

1. Environment Configuration

cp .env.example .env

Edit .env and set at minimum:

# Change in production
POSTGRES_PASSWORD=<strong-password>
CAMELEER_AUTH_TOKEN=<random-string-for-agent-bootstrap>

# Logto M2M credentials (get from Logto admin console after first boot)
LOGTO_M2M_CLIENT_ID=
LOGTO_M2M_CLIENT_SECRET=

2. Ed25519 Keys

The platform uses Ed25519 keys for license signing and machine token verification.

mkdir -p keys
ssh-keygen -t ed25519 -f keys/ed25519 -N ""
mv keys/ed25519 keys/ed25519.key

This creates keys/ed25519.key (private) and keys/ed25519.pub (public). The keys directory is mounted read-only into the cameleer-saas container.

If no key files are configured, the platform generates ephemeral keys on startup (suitable for development only -- keys change on every restart).

3. Start the Stack

Development (ports exposed for direct access):

docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Production (traffic routed through Traefik only):

docker compose up -d

4. Verify Services

# Health check
curl http://localhost:8080/actuator/health

# Check all containers are running
docker compose ps

Bootstrapping

First-Time Logto Setup

On first boot, Logto seeds its database automatically. Access the admin console to configure it:

  1. Open http://localhost:3002 (Logto admin console)
  2. Complete the initial setup wizard
  3. Create a Machine-to-Machine application:
    • Go to Applications > Create Application > Machine-to-Machine
    • Note the App ID and App Secret
    • Assign the Logto Management API resource with all scopes
  4. Update .env:
    LOGTO_M2M_CLIENT_ID=<app-id>
    LOGTO_M2M_CLIENT_SECRET=<app-secret>
    
  5. Restart cameleer-saas: docker compose restart cameleer-saas

Create Your First Tenant

With a Logto user token (obtained via OIDC login flow):

TOKEN="<your-logto-jwt>"

# Create tenant
curl -X POST http://localhost:8080/api/tenants \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Company", "slug": "my-company", "tier": "MID"}'

# A "default" environment is auto-created with the tenant

Generate a License

TENANT_ID="<uuid-from-above>"

curl -X POST "http://localhost:8080/api/tenants/$TENANT_ID/license" \
  -H "Authorization: Bearer $TOKEN"

Deploy a Camel Application

# List environments
curl "http://localhost:8080/api/tenants/$TENANT_ID/environments" \
  -H "Authorization: Bearer $TOKEN"

ENV_ID="<default-environment-uuid>"

# Upload JAR and create app
curl -X POST "http://localhost:8080/api/environments/$ENV_ID/apps" \
  -H "Authorization: Bearer $TOKEN" \
  -F 'metadata={"slug":"order-service","displayName":"Order Service"};type=application/json' \
  -F "file=@/path/to/your-camel-app.jar"

APP_ID="<app-uuid-from-response>"

# Deploy (async -- returns 202 with deployment ID)
curl -X POST "http://localhost:8080/api/apps/$APP_ID/deploy" \
  -H "Authorization: Bearer $TOKEN"

DEPLOYMENT_ID="<deployment-uuid>"

# Poll deployment status
curl "http://localhost:8080/api/apps/$APP_ID/deployments/$DEPLOYMENT_ID" \
  -H "Authorization: Bearer $TOKEN"
# Status transitions: BUILDING -> STARTING -> RUNNING (or FAILED)

# View container logs
curl "http://localhost:8080/api/apps/$APP_ID/logs?limit=50" \
  -H "Authorization: Bearer $TOKEN"

# Stop the app
curl -X POST "http://localhost:8080/api/apps/$APP_ID/stop" \
  -H "Authorization: Bearer $TOKEN"

API Reference

Tenants

Method Path Description
POST /api/tenants Create tenant
GET /api/tenants/{id} Get tenant
GET /api/tenants/by-slug/{slug} Get tenant by slug

Licensing

Method Path Description
POST /api/tenants/{tid}/license Generate license
GET /api/tenants/{tid}/license Get active license

Environments

Method Path Description
POST /api/tenants/{tid}/environments Create environment
GET /api/tenants/{tid}/environments List environments
GET /api/tenants/{tid}/environments/{eid} Get environment
PATCH /api/tenants/{tid}/environments/{eid} Rename environment
DELETE /api/tenants/{tid}/environments/{eid} Delete environment

Apps

Method Path Description
POST /api/environments/{eid}/apps Create app + upload JAR
GET /api/environments/{eid}/apps List apps
GET /api/environments/{eid}/apps/{aid} Get app
PUT /api/environments/{eid}/apps/{aid}/jar Re-upload JAR
DELETE /api/environments/{eid}/apps/{aid} Delete app

Deployments

Method Path Description
POST /api/apps/{aid}/deploy Deploy app (async, 202)
GET /api/apps/{aid}/deployments Deployment history
GET /api/apps/{aid}/deployments/{did} Get deployment status
POST /api/apps/{aid}/stop Stop current deployment
POST /api/apps/{aid}/restart Restart app

Logs

Method Path Description
GET /api/apps/{aid}/logs Query container logs

Query params: since, until (ISO timestamps), limit (default 500), stream (stdout/stderr/both)

Health

Method Path Description
GET /actuator/health Health check (public)
GET /api/health/secured Authenticated health check

Tier Limits

Tier Environments Apps Retention Features
LOW 1 3 7 days Topology
MID 2 10 30 days + Lineage, Correlation
HIGH Unlimited 50 90 days + Debugger, Replay
BUSINESS Unlimited Unlimited 365 days All features

Development

Running Tests

# Unit tests only (no Docker required)
mvn test -B -Dsurefire.excludes="**/*ControllerTest.java,**/AuditRepositoryTest.java,**/CameleerSaasApplicationTest.java"

# Integration tests (requires Docker Desktop)
mvn test -B -Dtest="EnvironmentControllerTest,AppControllerTest,DeploymentControllerTest"

# All tests
mvn verify -B

Building Locally

# Build JAR
mvn clean package -DskipTests -B

# Build Docker image
docker build -t cameleer-saas:local .

# Use local image
VERSION=local docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Troubleshooting

Logto fails to start: Check that PostgreSQL is healthy first. Logto needs the logto database created by docker/init-databases.sh. Run docker compose logs logto for details.

cameleer-saas won't start: Check docker compose logs cameleer-saas. Common issues:

  • PostgreSQL not ready (wait for healthcheck)
  • Flyway migration conflict (check for manual schema changes)

Ephemeral key warnings: No Ed25519 key files configured -- generating ephemeral keys (dev mode) is normal in development. For production, generate keys as described above.

Container deployment fails: Check that Docker socket is mounted (/var/run/docker.sock) and the cameleer-runtime-base image is available. Pull it with: docker pull gitea.siegeln.net/cameleer/cameleer-runtime-base:latest