Support separate auth domain (e.g. auth.cameleer.io) for Logto while
keeping the SaaS app on PUBLIC_HOST (e.g. app.cameleer.io). AUTH_HOST
defaults to PUBLIC_HOST for backward-compatible single-domain setups.
- Logto routing: Host(AUTH_HOST) replaces PathPrefix('/') catch-all
- Root redirect moved from traefik-dynamic.yml to Docker labels with
Host(PUBLIC_HOST) scope so it doesn't intercept auth domain
- Self-signed cert generates SANs for both domains
- Bootstrap Host header uses AUTH_HOST for Logto endpoint validation
- Spring issuer-uri and oidcissueruri use new authhost property
- Both installers (sh + ps1) prompt for AUTH_HOST in expert mode
Local dev: AUTH_HOST=auth.localhost (resolves to 127.0.0.1, no hosts file)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The server now requires a non-empty JWT secret. The installer (bash + ps1)
generates a random value for both SaaS and standalone modes, and the compose
templates map it into the respective containers. Also fixes container names
in generated INSTALL.md docs to use the cameleer- prefix consistently.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CAMELEER_SERVER_RUNTIME_BASEIMAGE was never set on provisioned
per-tenant server containers, causing them to fall back to the
server's hardcoded default. Added CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE
as a configurable property that gets forwarded during provisioning.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Docker compose templates defaulted to admin/admin when .env was missing.
Now uses :? to fail with a clear error instead of silently using weak creds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename Java packages from net.siegeln.cameleer3 to net.siegeln.cameleer,
update all references in workflows, Docker configs, docs, and bootstrap.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Installers now use `--pull always --force-recreate` on `docker compose up`
to ensure fresh images are used on every install/reinstall, preventing
stale containers from missing schema changes like db_password.
Fix VendorTenantServiceTest to expect two repository saves in provisioning
tests (one for dbPassword, one for final status).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use /dev/urandom instead of openssl rand for generating random
passwords. Available on all Linux/macOS systems without requiring
openssl to be installed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The verify_health functions passed short service names (postgres,
clickhouse, server, logto) but the actual compose services are
prefixed with cameleer-. This caused docker compose ps -q to return
empty, so health was never read and checks always timed out.
Also renamed server/server-ui service definitions to
cameleer-server/cameleer-server-ui for consistency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The admin user IS the platform admin — no separate vendor user needed.
The saas-vendor role is now always assigned to the admin user during
bootstrap. Removes VENDOR_ENABLED, VENDOR_USER, VENDOR_PASS from all
config, prompts, compose templates, and bootstrap script.
In multi-tenant mode: admin logs in with saas-admin credentials, gets
platform:admin scope via saas-vendor role, manages tenants directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The cameleer3-server requires CAMELEER_SERVER_SECURITY_BOOTSTRAPTOKEN
at startup. In standalone mode nothing uses it externally, but the
server's SecurityBeanConfig validates it exists. Generate a random
token in the .env and pass it through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single-tenant installations now run the server directly without Logto
or the SaaS management plane. The installer generates a simpler compose
with 5 services: traefik, postgres, clickhouse, cameleer3-server, and
cameleer3-server-ui. Uses local auth (built-in admin), no OIDC.
Multi-tenant (vendor) mode is unchanged — full SaaS stack with Logto.
Changes:
- New DEPLOYMENT_MODE variable (standalone/saas) replaces TENANT_ORG_NAME
- generate_compose_file_standalone() for the 5-service compose
- Standalone traefik-dynamic.yml (no /platform/ redirect)
- Stock postgres:16-alpine (server creates schema via Flyway)
- Standalone health checks (server + UI instead of Logto + SaaS)
- Standalone credentials/docs generation
- Remove Phase 12b from bootstrap (no longer needed)
- Remove setup_single_tenant_record (no longer needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bootstrap script runs before the SaaS app starts, but the tenants
table only exists after Flyway migrations run in the SaaS app. This
circular dependency caused Phase 12b's psql commands to fail under
set -e, crashing the Logto container on first install in single-tenant
mode.
Now the bootstrap only handles Logto-side setup (org, user roles, OIDC
redirect URIs), and the installer creates the tenant DB record after
verify_health confirms the SaaS app is up. Also makes docker_compose_up
tolerant of transient startup errors since verify_health is the real
health gate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TenantProvisionerAutoConfig already hardcodes the socket path via
.withDockerHost("unix:///var/run/docker.sock"). The env var was
redundant and not read by the Java Docker client.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revert env_file approach — only pass the specific env vars the SaaS
app needs for its own database, identity, and tenant provisioning.
Organized into clear groups: Docker, SaaS database, Identity, and
Provisioning (passed to per-tenant servers).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of explicitly listing every env var the SaaS container needs,
use env_file to pass the entire .env. This ensures all installer-
configured values (passwords, hosts, ports, etc.) are available for
current and future use by the SaaS app and its provisioning config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CLICKHOUSE_PASSWORD env var was set on the clickhouse container
but not passed to cameleer-saas. The provisioning properties defaulted
to 'cameleer_ch' instead of the installer-generated password, causing
tenant servers to fail ClickHouse authentication.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The DockerTenantProvisioner hardcoded SPRING_DATASOURCE_USERNAME
and SPRING_DATASOURCE_PASSWORD as "cameleer" / "cameleer_dev".
With the installer generating random passwords, tenant servers
failed to connect to PostgreSQL.
Add datasourceUsername and datasourcePassword to ProvisioningProperties,
pass them from the compose env vars, and use them in the provisioner.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Docker socket group varies by host (e.g., GID 1001 on WSL2).
Hardcoding group_add: ["0"] doesn't work when the socket is owned
by a different group. The installer now detects the socket GID at
install time via stat. The main docker-compose.yml uses a
configurable DOCKER_GID env var (defaults to 0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The cameleer-saas service needs Docker socket access for tenant
provisioning. Add the socket bind mount, group_add for permissions,
and explicit DOCKER_HOST=unix:///var/run/docker.sock to prevent
the Java Docker client from falling back to TCP (which happens on
WSL2 + Docker Desktop when DOCKER_HOST leaks from the host env).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace docker compose exec commands with Docker's built-in health
status checks. The exec-based ClickHouse check hung because
clickhouse-client waits for the server during initialization.
Docker's healthcheck status is already configured in compose and
is more reliable. Logto + Bootstrap merged into one check since
the healthcheck includes the bootstrap.json file test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Installer now asks deployment mode in simple mode:
- Multi-tenant vendor: creates saas-vendor role + assigns to admin
- Single tenant: asks for org name, creates Logto org + tenant record,
assigns admin as org owner
Reverts always-create-vendor-role — role is only created when vendor
mode is selected. TENANT_ORG_NAME env var passed to bootstrap for
single-tenant org creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moves hostname normalization into merge_config() so it applies
regardless of source (CLI flag, env var, config file, prompt,
auto-detect). Logto normalizes hostnames internally — case mismatch
causes JWT issuer validation failure (401).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ClickHouse health check: use $CLICKHOUSE_PASSWORD directly instead
of extracting from .env via grep (nested quoting broke in eval)
- Normalize auto-detected hostname to lowercase (Windows returns
uppercase which causes OIDC issuer case mismatches)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Appends the main() entry point that wires together all installer phases:
arg parsing, config loading, rerun detection, prerequisites, auto-detect,
interactive prompts, config merge/validate, password generation, file
generation, docker pull/up, health verification, and output printing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>