Compare commits
13 Commits
528c6d1980
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
531a17397b | ||
|
|
21ea9515a2 | ||
|
|
0da26160c6 | ||
|
|
b2259328d3 | ||
| 8227483580 | |||
|
|
1ef0016965 | ||
|
|
ec1c1f92d7 | ||
|
|
4037fb9dfb | ||
|
|
35240e0374 | ||
|
|
4885c240e3 | ||
|
|
4380aa790d | ||
|
|
a9aee77077 | ||
|
|
0b092065c5 |
@@ -25,11 +25,9 @@ The installer uses static docker-compose templates in `templates/`. Templates ar
|
||||
|
||||
## SMTP configuration
|
||||
|
||||
The installer prompts for SMTP settings in SaaS mode when the user opts in ("Configure SMTP for email verification?"). SMTP is required for self-service sign-up — without it, only admin-created users can sign in.
|
||||
SMTP / email connector configuration has been moved from the installer to the SaaS vendor admin UI (Email Connector page at `/vendor/email`). The installer no longer prompts for or persists SMTP settings.
|
||||
|
||||
Env vars: `SMTP_HOST`, `SMTP_PORT` (default 587), `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM_EMAIL` (default `noreply@<PUBLIC_HOST>`). Passed to the `cameleer-logto` container. The bootstrap script discovers the SMTP connector factory and creates the connector with Cameleer-branded email templates.
|
||||
|
||||
CLI args: `--smtp-host`, `--smtp-port`, `--smtp-user`, `--smtp-pass`, `--smtp-from-email`. Persisted in `cameleer.conf` for upgrades/reconfigure.
|
||||
Previously, SMTP env vars (`SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASS`, `SMTP_FROM_EMAIL`) were passed to the `cameleer-logto` container and configured via the bootstrap script. This one-shot approach was fragile — email delivery is now configured at runtime through the Logto Management API.
|
||||
|
||||
## Registry configuration
|
||||
|
||||
@@ -45,7 +43,6 @@ For private registries, pass `--registry-user` / `--registry-token`. The install
|
||||
- `CAMELEER_SERVER_*` — server config (consumed by cameleer-server)
|
||||
- `CAMELEER_SAAS_*` — SaaS management plane config
|
||||
- `CAMELEER_SAAS_PROVISIONING_*` — "SaaS forwards this to provisioned tenant servers"
|
||||
- `SMTP_*` — email delivery config for Logto (consumed by bootstrap, SaaS mode only)
|
||||
- No prefix (e.g. `POSTGRES_PASSWORD`, `PUBLIC_HOST`) — shared infrastructure, consumed by multiple components
|
||||
|
||||
## Development
|
||||
|
||||
40
README.md
40
README.md
@@ -7,23 +7,29 @@ One-line installer for the [Cameleer](https://cameleer.io) observability platfor
|
||||
**Linux / macOS:**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw/branch/main/get-cameleer.sh | bash
|
||||
cd installer && ./install.sh
|
||||
bash -c "$(curl -fsSL https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw/branch/main/get-cameleer.sh)"
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
|
||||
```powershell
|
||||
irm https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw/branch/main/get-cameleer.ps1 | iex
|
||||
cd installer; .\install.sh
|
||||
```
|
||||
|
||||
The bootstrap downloads the installer into `./installer/` and launches it immediately. The interactive prompts run in your terminal.
|
||||
|
||||
**Pin a version:**
|
||||
|
||||
```bash
|
||||
curl -fsSL .../get-cameleer.sh | bash -s -- --version=v1.0.0
|
||||
bash -c "$(curl -fsSL .../get-cameleer.sh)" -- --version=v1.0.0
|
||||
```
|
||||
|
||||
```powershell
|
||||
& ([scriptblock]::Create((irm .../get-cameleer.ps1))) -Version v1.0.0
|
||||
```
|
||||
|
||||
Any extra arguments are forwarded to `install.sh` / `install.ps1` (e.g. `--silent`, `--expert`, `--public-host=…`).
|
||||
|
||||
## Deployment Modes
|
||||
|
||||
| | Multi-tenant SaaS | Standalone |
|
||||
@@ -78,9 +84,11 @@ Settings can be provided via CLI flags, environment variables, config file (`cam
|
||||
|
||||
| Setting | CLI Flag | Env Var | Config Key | Default |
|
||||
|---------|----------|---------|------------|---------|
|
||||
| Admin username | `--admin-user` | `SAAS_ADMIN_USER` | `admin_user` | `admin` |
|
||||
| Admin login | `--admin-user` | `SAAS_ADMIN_USER` | `admin_user` | `admin` (standalone) / `admin@<PUBLIC_HOST>` (SaaS) |
|
||||
| Admin password | `--admin-password` | `SAAS_ADMIN_PASS` | `admin_password` | auto-generated |
|
||||
|
||||
In SaaS mode, `SAAS_ADMIN_USER` must be an email address — it is used as both the Logto username and primaryEmail. The installer validates email format in SaaS mode and auto-appends `@<PUBLIC_HOST>` if the `@` is missing. In standalone mode, any username is accepted.
|
||||
|
||||
In standalone mode, the env vars are `SERVER_ADMIN_USER` / `SERVER_ADMIN_PASS`.
|
||||
|
||||
### TLS Certificates
|
||||
@@ -134,17 +142,11 @@ The Docker socket is required for tenant provisioning (SaaS mode) — the platfo
|
||||
|
||||
For private registries, provide credentials and the installer runs `docker login` before pulling. The registry prefix is applied to all container images.
|
||||
|
||||
### SMTP (SaaS Mode)
|
||||
### Email / SMTP
|
||||
|
||||
| Setting | CLI Flag | Env Var | Config Key | Default |
|
||||
|---------|----------|---------|------------|---------|
|
||||
| SMTP host | `--smtp-host` | `SMTP_HOST` | `smtp_host` | — |
|
||||
| SMTP port | `--smtp-port` | `SMTP_PORT` | `smtp_port` | `587` |
|
||||
| SMTP username | `--smtp-user` | `SMTP_USER` | `smtp_user` | — |
|
||||
| SMTP password | `--smtp-pass` | `SMTP_PASS` | `smtp_pass` | — |
|
||||
| From email | `--smtp-from-email` | `SMTP_FROM_EMAIL` | `smtp_from_email` | `noreply@<PUBLIC_HOST>` |
|
||||
Email connector configuration (SMTP, SES, etc.) is managed at runtime via the vendor admin UI at `/vendor/email`. The installer does not configure email delivery.
|
||||
|
||||
SMTP is required for self-service sign-up (email verification codes). Without it, only admin-created users can sign in.
|
||||
Self-service registration is disabled by default and is enabled automatically when the admin configures an email connector.
|
||||
|
||||
### Monitoring
|
||||
|
||||
@@ -216,9 +218,10 @@ All services share a single hostname. Routing:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `get-cameleer.sh` | Bootstrap script (bash) — downloads installer files |
|
||||
| `get-cameleer.ps1` | Bootstrap script (PowerShell) — downloads installer files |
|
||||
| `install.sh` | Main installer — interactive or silent deployment |
|
||||
| `get-cameleer.sh` | Bootstrap script (bash) — downloads installer files and launches `install.sh` |
|
||||
| `get-cameleer.ps1` | Bootstrap script (PowerShell) — downloads installer files and launches `install.ps1` |
|
||||
| `install.sh` | Main installer (Linux / macOS) — interactive or silent deployment |
|
||||
| `install.ps1` | Main installer (Windows PowerShell) — interactive or silent deployment |
|
||||
| `templates/docker-compose.yml` | Base infrastructure (Traefik, PostgreSQL, ClickHouse) |
|
||||
| `templates/docker-compose.saas.yml` | SaaS mode (Logto + management plane) |
|
||||
| `templates/docker-compose.server.yml` | Standalone mode (server + UI) |
|
||||
@@ -239,9 +242,6 @@ All services share a single hostname. Routing:
|
||||
--tls-mode=custom \
|
||||
--cert-file=/etc/ssl/cert.pem \
|
||||
--key-file=/etc/ssl/key.pem \
|
||||
--smtp-host=smtp.example.com \
|
||||
--smtp-user=noreply@example.com \
|
||||
--smtp-pass=mailpass \
|
||||
--registry=registry.example.com/cameleer \
|
||||
--registry-user=deploy \
|
||||
--registry-token=ghp_xxx
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
Bootstrap script — downloads the Cameleer installer and runs it.
|
||||
.EXAMPLE
|
||||
irm https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw/branch/main/get-cameleer.ps1 | iex
|
||||
.\get-cameleer.ps1 -Version v1.2.0
|
||||
& ([scriptblock]::Create((irm https://.../get-cameleer.ps1))) -Version v1.2.0
|
||||
#>
|
||||
param(
|
||||
[string]$Version,
|
||||
[string]$Ref,
|
||||
[switch]$Run
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]]$InstallerArgs
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -23,7 +24,7 @@ $Base = "$Repo/$RefPath"
|
||||
$Dir = '.\installer'
|
||||
|
||||
$Files = @(
|
||||
'install.sh'
|
||||
'install.ps1'
|
||||
'templates/docker-compose.yml'
|
||||
'templates/docker-compose.saas.yml'
|
||||
'templates/docker-compose.server.yml'
|
||||
@@ -47,11 +48,12 @@ foreach ($file in $Files) {
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "Installer ready in $Dir\"
|
||||
Write-Host 'Run: cd installer; .\install.sh'
|
||||
Write-Host "Installer downloaded to $Dir\ — launching..."
|
||||
Write-Host ''
|
||||
|
||||
if ($Run) {
|
||||
Set-Location $Dir
|
||||
& .\install.sh @args
|
||||
$installerPath = Join-Path $Dir 'install.ps1'
|
||||
if ($InstallerArgs) {
|
||||
& $installerPath @InstallerArgs
|
||||
} else {
|
||||
& $installerPath
|
||||
}
|
||||
|
||||
@@ -3,18 +3,20 @@ set -euo pipefail
|
||||
|
||||
# Bootstrap script — downloads the Cameleer installer and runs it.
|
||||
# Usage:
|
||||
# curl -fsSL https://get.cameleer.io/install | bash
|
||||
# curl -fsSL https://get.cameleer.io/install | bash -s -- --version v1.2.0
|
||||
# bash -c "$(curl -fsSL https://get.cameleer.io/install)"
|
||||
# bash -c "$(curl -fsSL https://get.cameleer.io/install)" -- --version v1.2.0
|
||||
|
||||
REPO="https://registry.cameleer.io/cameleer/cameleer-saas-installer/raw"
|
||||
REF="branch/main"
|
||||
DIR="./installer"
|
||||
|
||||
# Parse --version / --ref
|
||||
# Parse --version / --ref (consume them; remaining args are forwarded to install.sh)
|
||||
PASS_ARGS=()
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--version=*) REF="tag/${arg#*=}"; shift ;;
|
||||
--ref=*) REF="branch/${arg#*=}"; shift ;;
|
||||
--version=*) REF="tag/${arg#*=}" ;;
|
||||
--ref=*) REF="branch/${arg#*=}" ;;
|
||||
*) PASS_ARGS+=("$arg") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -43,13 +45,8 @@ done
|
||||
chmod +x "$DIR/install.sh"
|
||||
|
||||
echo ""
|
||||
echo "Installer ready in $DIR/"
|
||||
echo "Run: cd $DIR && ./install.sh"
|
||||
echo "Installer downloaded to $DIR/ — launching..."
|
||||
echo ""
|
||||
|
||||
# Auto-run if not piped with extra args that look like they want manual control
|
||||
if [ "${1:-}" = "--run" ]; then
|
||||
shift
|
||||
cd "$DIR"
|
||||
exec ./install.sh "$@"
|
||||
fi
|
||||
cd "$DIR"
|
||||
exec ./install.sh "${PASS_ARGS[@]}"
|
||||
|
||||
151
install.ps1
151
install.ps1
@@ -37,11 +37,6 @@ param(
|
||||
[string]$DockerSocket,
|
||||
[string]$NodeTlsReject,
|
||||
[string]$DeploymentMode,
|
||||
[string]$SmtpHost,
|
||||
[string]$SmtpPort,
|
||||
[string]$SmtpUser,
|
||||
[string]$SmtpPass,
|
||||
[string]$SmtpFromEmail,
|
||||
[string]$Registry,
|
||||
[string]$RegistryUser,
|
||||
[string]$RegistryToken,
|
||||
@@ -92,11 +87,6 @@ $_ENV_COMPOSE_PROJECT = $env:COMPOSE_PROJECT
|
||||
$_ENV_DOCKER_SOCKET = $env:DOCKER_SOCKET
|
||||
$_ENV_NODE_TLS_REJECT = $env:NODE_TLS_REJECT
|
||||
$_ENV_DEPLOYMENT_MODE = $env:DEPLOYMENT_MODE
|
||||
$_ENV_SMTP_HOST = $env:SMTP_HOST
|
||||
$_ENV_SMTP_PORT = $env:SMTP_PORT
|
||||
$_ENV_SMTP_USER = $env:SMTP_USER
|
||||
$_ENV_SMTP_PASS = $env:SMTP_PASS
|
||||
$_ENV_SMTP_FROM_EMAIL = $env:SMTP_FROM_EMAIL
|
||||
$_ENV_REGISTRY = $env:REGISTRY
|
||||
$_ENV_REGISTRY_USER = $env:REGISTRY_USER
|
||||
$_ENV_REGISTRY_TOKEN = $env:REGISTRY_TOKEN
|
||||
@@ -110,6 +100,7 @@ $script:cfg = @{
|
||||
PublicProtocol = $PublicProtocol
|
||||
AdminUser = $AdminUser
|
||||
AdminPass = $AdminPassword
|
||||
|
||||
TlsMode = $TlsMode
|
||||
CertFile = $CertFile
|
||||
KeyFile = $KeyFile
|
||||
@@ -126,11 +117,6 @@ $script:cfg = @{
|
||||
DockerSocket = $DockerSocket
|
||||
NodeTlsReject = $NodeTlsReject
|
||||
DeploymentMode = $DeploymentMode
|
||||
SmtpHost = $SmtpHost
|
||||
SmtpPort = $SmtpPort
|
||||
SmtpUser = $SmtpUser
|
||||
SmtpPass = $SmtpPass
|
||||
SmtpFromEmail = $SmtpFromEmail
|
||||
Registry = $Registry
|
||||
RegistryUser = $RegistryUser
|
||||
RegistryToken = $RegistryToken
|
||||
@@ -255,7 +241,14 @@ function Write-Utf8File {
|
||||
$enc = New-Object System.Text.UTF8Encoding $false
|
||||
[System.IO.File]::WriteAllText($Path, $Content, $enc)
|
||||
}
|
||||
|
||||
|
||||
# Single-quote a value for .env/.conf files so special characters ($, &, ;, etc.)
|
||||
# are preserved. Embedded single quotes are escaped as '\''.
|
||||
function Format-EnvVal([string]$Key, [string]$Val) {
|
||||
$escaped = $Val -replace "'", "'\\''"
|
||||
return "$Key='$escaped'"
|
||||
}
|
||||
|
||||
# --- Config file ---
|
||||
|
||||
function Load-ConfigFile {
|
||||
@@ -266,6 +259,12 @@ function Load-ConfigFile {
|
||||
if ($line -match '^\s*([^=]+?)\s*=\s*(.*?)\s*$') {
|
||||
$key = $Matches[1].Trim()
|
||||
$val = $Matches[2].Trim()
|
||||
# Strip surrounding quotes and unescape '\''
|
||||
if ($val.Length -ge 2 -and $val[0] -eq "'" -and $val[-1] -eq "'") {
|
||||
$val = $val.Substring(1, $val.Length - 2) -replace "'\\''" , "'"
|
||||
} elseif ($val.Length -ge 2 -and $val[0] -eq '"' -and $val[-1] -eq '"') {
|
||||
$val = $val.Substring(1, $val.Length - 2)
|
||||
}
|
||||
switch ($key) {
|
||||
'install_dir' { if (-not $script:cfg.InstallDir) { $script:cfg.InstallDir = $val } }
|
||||
'public_host' { if (-not $script:cfg.PublicHost) { $script:cfg.PublicHost = $val } }
|
||||
@@ -273,6 +272,7 @@ function Load-ConfigFile {
|
||||
'public_protocol' { if (-not $script:cfg.PublicProtocol) { $script:cfg.PublicProtocol = $val } }
|
||||
'admin_user' { if (-not $script:cfg.AdminUser) { $script:cfg.AdminUser = $val } }
|
||||
'admin_password' { if (-not $script:cfg.AdminPass) { $script:cfg.AdminPass = $val } }
|
||||
|
||||
'tls_mode' { if (-not $script:cfg.TlsMode) { $script:cfg.TlsMode = $val } }
|
||||
'cert_file' { if (-not $script:cfg.CertFile) { $script:cfg.CertFile = $val } }
|
||||
'key_file' { if (-not $script:cfg.KeyFile) { $script:cfg.KeyFile = $val } }
|
||||
@@ -289,11 +289,6 @@ function Load-ConfigFile {
|
||||
'docker_socket' { if (-not $script:cfg.DockerSocket) { $script:cfg.DockerSocket = $val } }
|
||||
'node_tls_reject' { if (-not $script:cfg.NodeTlsReject) { $script:cfg.NodeTlsReject = $val } }
|
||||
'deployment_mode' { if (-not $script:cfg.DeploymentMode) { $script:cfg.DeploymentMode = $val } }
|
||||
'smtp_host' { if (-not $script:cfg.SmtpHost) { $script:cfg.SmtpHost = $val } }
|
||||
'smtp_port' { if (-not $script:cfg.SmtpPort) { $script:cfg.SmtpPort = $val } }
|
||||
'smtp_user' { if (-not $script:cfg.SmtpUser) { $script:cfg.SmtpUser = $val } }
|
||||
'smtp_pass' { if (-not $script:cfg.SmtpPass) { $script:cfg.SmtpPass = $val } }
|
||||
'smtp_from_email' { if (-not $script:cfg.SmtpFromEmail) { $script:cfg.SmtpFromEmail = $val } }
|
||||
'registry' { if (-not $script:cfg.Registry) { $script:cfg.Registry = $val } }
|
||||
'registry_user' { if (-not $script:cfg.RegistryUser) { $script:cfg.RegistryUser = $val } }
|
||||
'registry_token' { if (-not $script:cfg.RegistryToken) { $script:cfg.RegistryToken = $val } }
|
||||
@@ -310,6 +305,7 @@ function Load-EnvOverrides {
|
||||
if (-not $c.PublicProtocol) { $c.PublicProtocol = $_ENV_PUBLIC_PROTOCOL }
|
||||
if (-not $c.AdminUser) { $c.AdminUser = $env:SAAS_ADMIN_USER }
|
||||
if (-not $c.AdminPass) { $c.AdminPass = $env:SAAS_ADMIN_PASS }
|
||||
|
||||
if (-not $c.TlsMode) { $c.TlsMode = $_ENV_TLS_MODE }
|
||||
if (-not $c.CertFile) { $c.CertFile = $_ENV_CERT_FILE }
|
||||
if (-not $c.KeyFile) { $c.KeyFile = $_ENV_KEY_FILE }
|
||||
@@ -326,11 +322,6 @@ function Load-EnvOverrides {
|
||||
if (-not $c.DockerSocket) { $c.DockerSocket = $_ENV_DOCKER_SOCKET }
|
||||
if (-not $c.NodeTlsReject) { $c.NodeTlsReject = $_ENV_NODE_TLS_REJECT }
|
||||
if (-not $c.DeploymentMode) { $c.DeploymentMode = $_ENV_DEPLOYMENT_MODE }
|
||||
if (-not $c.SmtpHost) { $c.SmtpHost = $_ENV_SMTP_HOST }
|
||||
if (-not $c.SmtpPort) { $c.SmtpPort = $_ENV_SMTP_PORT }
|
||||
if (-not $c.SmtpUser) { $c.SmtpUser = $_ENV_SMTP_USER }
|
||||
if (-not $c.SmtpPass) { $c.SmtpPass = $_ENV_SMTP_PASS }
|
||||
if (-not $c.SmtpFromEmail) { $c.SmtpFromEmail = $_ENV_SMTP_FROM_EMAIL }
|
||||
if (-not $c.Registry) { $c.Registry = $_ENV_REGISTRY }
|
||||
if (-not $c.RegistryUser) { $c.RegistryUser = $_ENV_REGISTRY_USER }
|
||||
if (-not $c.RegistryToken) { $c.RegistryToken = $_ENV_REGISTRY_TOKEN }
|
||||
@@ -459,17 +450,41 @@ function Run-SimplePrompts {
|
||||
Write-Host ''
|
||||
Write-Host '--- Simple Installation ---' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
|
||||
|
||||
$c.InstallDir = Prompt-Value 'Install directory' (Coalesce $c.InstallDir $DEFAULT_INSTALL_DIR)
|
||||
$c.PublicHost = Prompt-Value 'Public hostname' (Coalesce $c.PublicHost 'localhost')
|
||||
$c.AdminUser = Prompt-Value 'Admin username' (Coalesce $c.AdminUser $DEFAULT_ADMIN_USER)
|
||||
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ' Deployment mode:'
|
||||
Write-Host ' [1] Multi-tenant SaaS -- manage platform, provision tenants on demand'
|
||||
Write-Host ' [2] Single-tenant -- one server instance, local auth, no identity provider'
|
||||
Write-Host ''
|
||||
$deployChoice = Read-Host ' Select mode [1]'
|
||||
if ($deployChoice -eq '2') { $c.DeploymentMode = 'standalone' } else { $c.DeploymentMode = 'saas' }
|
||||
|
||||
Write-Host ''
|
||||
if ($c.DeploymentMode -eq 'saas') {
|
||||
$defaultEmail = Coalesce $c.AdminUser "admin@$($c.PublicHost)"
|
||||
if ($defaultEmail -and $defaultEmail -notmatch '@.+\..+') {
|
||||
$defaultEmail = "admin@$($c.PublicHost)"
|
||||
}
|
||||
while ($true) {
|
||||
$c.AdminUser = Prompt-Value 'Admin email' $defaultEmail
|
||||
if ($c.AdminUser -match '^[^@]+@[^@]+\.[^@]+$') { break }
|
||||
Write-Host ' Invalid email address. Must be a valid email (e.g. admin@company.com).' -ForegroundColor Red
|
||||
$c.AdminUser = $null
|
||||
$defaultEmail = $null
|
||||
}
|
||||
} else {
|
||||
$c.AdminUser = Prompt-Value 'Admin username' (Coalesce $c.AdminUser $DEFAULT_ADMIN_USER)
|
||||
}
|
||||
|
||||
if (Prompt-YesNo 'Auto-generate admin password?' 'y') {
|
||||
$c.AdminPass = ''
|
||||
} else {
|
||||
$c.AdminPass = Prompt-Password 'Admin password'
|
||||
}
|
||||
|
||||
|
||||
Write-Host ''
|
||||
if (Prompt-YesNo 'Use custom TLS certificates? (no = self-signed)') {
|
||||
$c.TlsMode = 'custom'
|
||||
@@ -481,7 +496,7 @@ function Run-SimplePrompts {
|
||||
} else {
|
||||
$c.TlsMode = 'self-signed'
|
||||
}
|
||||
|
||||
|
||||
Write-Host ''
|
||||
$c.MonitoringNetwork = Prompt-Value 'Monitoring network name (empty = skip)' ''
|
||||
|
||||
@@ -492,25 +507,6 @@ function Run-SimplePrompts {
|
||||
$c.RegistryToken = Prompt-Password 'Registry token/password' (Coalesce $c.RegistryToken '')
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ' Deployment mode:'
|
||||
Write-Host ' [1] Multi-tenant SaaS -- manage platform, provision tenants on demand'
|
||||
Write-Host ' [2] Single-tenant -- one server instance, local auth, no identity provider'
|
||||
Write-Host ''
|
||||
$deployChoice = Read-Host ' Select mode [1]'
|
||||
if ($deployChoice -eq '2') { $c.DeploymentMode = 'standalone' } else { $c.DeploymentMode = 'saas' }
|
||||
|
||||
# SMTP for email verification (SaaS mode only)
|
||||
if ($c.DeploymentMode -eq 'saas') {
|
||||
Write-Host ''
|
||||
if (Prompt-YesNo 'Configure SMTP for email verification? (required for self-service sign-up)') {
|
||||
$c.SmtpHost = Prompt-Value 'SMTP host' (Coalesce $c.SmtpHost '')
|
||||
$c.SmtpPort = Prompt-Value 'SMTP port' (Coalesce $c.SmtpPort '587')
|
||||
$c.SmtpUser = Prompt-Value 'SMTP username' (Coalesce $c.SmtpUser '')
|
||||
$c.SmtpPass = Prompt-Password 'SMTP password' (Coalesce $c.SmtpPass '')
|
||||
$c.SmtpFromEmail = Prompt-Value 'From email address' (Coalesce $c.SmtpFromEmail "noreply@$($c.PublicHost)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Run-ExpertPrompts {
|
||||
@@ -561,7 +557,15 @@ function Merge-Config {
|
||||
if (-not $c.InstallDir) { $c.InstallDir = $DEFAULT_INSTALL_DIR }
|
||||
if (-not $c.PublicHost) { $c.PublicHost = 'localhost' }
|
||||
if (-not $c.PublicProtocol) { $c.PublicProtocol = $DEFAULT_PUBLIC_PROTOCOL }
|
||||
if (-not $c.AdminUser) { $c.AdminUser = $DEFAULT_ADMIN_USER }
|
||||
if ($c.DeploymentMode -eq 'saas') {
|
||||
if (-not $c.AdminUser) { $c.AdminUser = "admin@$($c.PublicHost)" }
|
||||
if ($c.AdminUser -notmatch '^[^@]+@[^@]+\.[^@]+$') {
|
||||
Write-Host "ERROR: SAAS_ADMIN_USER must be a valid email address (e.g. admin@company.com), got: '$($c.AdminUser)'" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
if (-not $c.AdminUser) { $c.AdminUser = $DEFAULT_ADMIN_USER }
|
||||
}
|
||||
if (-not $c.TlsMode) { $c.TlsMode = $DEFAULT_TLS_MODE }
|
||||
if (-not $c.HttpPort) { $c.HttpPort = $DEFAULT_HTTP_PORT }
|
||||
if (-not $c.HttpsPort) { $c.HttpsPort = $DEFAULT_HTTPS_PORT }
|
||||
@@ -669,15 +673,10 @@ HTTPS_PORT=$($c.HttpsPort)
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=cameleer
|
||||
POSTGRES_PASSWORD=$($c.PostgresPassword)
|
||||
POSTGRES_DB=cameleer
|
||||
|
||||
# ClickHouse
|
||||
CLICKHOUSE_PASSWORD=$($c.ClickhousePassword)
|
||||
|
||||
# Server admin
|
||||
SERVER_ADMIN_USER=$($c.AdminUser)
|
||||
SERVER_ADMIN_PASS=$($c.AdminPass)
|
||||
|
||||
# Bootstrap token
|
||||
BOOTSTRAP_TOKEN=$bt
|
||||
@@ -697,6 +696,10 @@ CLICKHOUSE_IMAGE=$($c.Registry)/cameleer-clickhouse
|
||||
SERVER_IMAGE=$($c.Registry)/cameleer-server
|
||||
SERVER_UI_IMAGE=$($c.Registry)/cameleer-server-ui
|
||||
"@
|
||||
# Passwords appended with single-quoting for special character safety
|
||||
$content += "`n$(Format-EnvVal 'POSTGRES_PASSWORD' $c.PostgresPassword)"
|
||||
$content += "`n$(Format-EnvVal 'CLICKHOUSE_PASSWORD' $c.ClickhousePassword)"
|
||||
$content += "`n$(Format-EnvVal 'SERVER_ADMIN_PASS' $c.AdminPass)"
|
||||
if ($c.TlsMode -eq 'custom') {
|
||||
$content += "`nCERT_FILE=/user-certs/cert.pem"
|
||||
$content += "`nKEY_FILE=/user-certs/key.pem"
|
||||
@@ -728,16 +731,11 @@ LOGTO_CONSOLE_BIND=$consoleBind
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=cameleer
|
||||
POSTGRES_PASSWORD=$($c.PostgresPassword)
|
||||
POSTGRES_DB=cameleer_saas
|
||||
|
||||
# ClickHouse
|
||||
CLICKHOUSE_PASSWORD=$($c.ClickhousePassword)
|
||||
|
||||
|
||||
# Admin user
|
||||
SAAS_ADMIN_USER=$($c.AdminUser)
|
||||
SAAS_ADMIN_PASS=$($c.AdminPass)
|
||||
|
||||
|
||||
# TLS
|
||||
NODE_TLS_REJECT=$($c.NodeTlsReject)
|
||||
"@
|
||||
@@ -767,15 +765,12 @@ CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE=$reg/cameleer-runtime-base:$($c.Vers
|
||||
|
||||
# JWT signing secret (forwarded to provisioned tenant servers, must be non-empty)
|
||||
CAMELEER_SERVER_SECURITY_JWTSECRET=$jwtSecret
|
||||
|
||||
# SMTP (for email verification during registration)
|
||||
SMTP_HOST=$($c.SmtpHost)
|
||||
SMTP_PORT=$(if ($c.SmtpPort) { $c.SmtpPort } else { '587' })
|
||||
SMTP_USER=$($c.SmtpUser)
|
||||
SMTP_PASS=$($c.SmtpPass)
|
||||
SMTP_FROM_EMAIL=$(if ($c.SmtpFromEmail) { $c.SmtpFromEmail } else { "noreply@$($c.PublicHost)" })
|
||||
"@
|
||||
$content += $provisioningBlock
|
||||
# Passwords appended with single-quoting for special character safety
|
||||
$content += "`n$(Format-EnvVal 'POSTGRES_PASSWORD' $c.PostgresPassword)"
|
||||
$content += "`n$(Format-EnvVal 'CLICKHOUSE_PASSWORD' $c.ClickhousePassword)"
|
||||
$content += "`n$(Format-EnvVal 'SAAS_ADMIN_PASS' $c.AdminPass)"
|
||||
$composeFile = 'docker-compose.yml;docker-compose.saas.yml'
|
||||
if ($c.TlsMode -eq 'custom') { $composeFile += ';docker-compose.tls.yml' }
|
||||
if ($c.MonitoringNetwork) { $composeFile += ';docker-compose.monitoring.yml' }
|
||||
@@ -1014,15 +1009,11 @@ compose_project=$($c.ComposeProject)
|
||||
docker_socket=$($c.DockerSocket)
|
||||
node_tls_reject=$($c.NodeTlsReject)
|
||||
deployment_mode=$($c.DeploymentMode)
|
||||
smtp_host=$($c.SmtpHost)
|
||||
smtp_port=$($c.SmtpPort)
|
||||
smtp_user=$($c.SmtpUser)
|
||||
smtp_pass=$($c.SmtpPass)
|
||||
smtp_from_email=$($c.SmtpFromEmail)
|
||||
registry=$($c.Registry)
|
||||
registry_user=$($c.RegistryUser)
|
||||
registry_token=$($c.RegistryToken)
|
||||
"@
|
||||
# Passwords appended with single-quoting for special character safety
|
||||
$txt += "`n$(Format-EnvVal 'registry_token' $c.RegistryToken)"
|
||||
Write-Utf8File $f $txt
|
||||
Log-Info 'Saved installer config to cameleer.conf'
|
||||
}
|
||||
@@ -1067,10 +1058,10 @@ ClickHouse: default / $($c.ClickhousePassword)
|
||||
Admin Console: $($c.PublicProtocol)://$($c.PublicHost)/platform/
|
||||
Admin User: $($c.AdminUser)
|
||||
Admin Password: $($c.AdminPass)
|
||||
|
||||
|
||||
PostgreSQL: cameleer / $($c.PostgresPassword)
|
||||
ClickHouse: default / $($c.ClickhousePassword)
|
||||
|
||||
|
||||
$logtoLine
|
||||
"@
|
||||
}
|
||||
@@ -1521,10 +1512,6 @@ function Main {
|
||||
Generate-Passwords
|
||||
|
||||
# Resolve to absolute path NOW.
|
||||
# [System.IO.File]::WriteAllText uses .NET's Environment.CurrentDirectory,
|
||||
# which differs from PowerShell's $PWD on Windows (e.g. resolves ./cameleer
|
||||
# to C:\Users\Hendrik\cameleer instead of the script's working directory).
|
||||
# GetUnresolvedProviderPathFromPSPath always uses PowerShell's current location.
|
||||
$script:cfg.InstallDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(
|
||||
$script:cfg.InstallDir)
|
||||
|
||||
|
||||
147
install.sh
147
install.sh
@@ -46,11 +46,6 @@ _ENV_COMPOSE_PROJECT="${COMPOSE_PROJECT:-}"
|
||||
_ENV_DOCKER_SOCKET="${DOCKER_SOCKET:-}"
|
||||
_ENV_NODE_TLS_REJECT="${NODE_TLS_REJECT:-}"
|
||||
_ENV_DEPLOYMENT_MODE="${DEPLOYMENT_MODE:-}"
|
||||
_ENV_SMTP_HOST="${SMTP_HOST:-}"
|
||||
_ENV_SMTP_PORT="${SMTP_PORT:-}"
|
||||
_ENV_SMTP_USER="${SMTP_USER:-}"
|
||||
_ENV_SMTP_PASS="${SMTP_PASS:-}"
|
||||
_ENV_SMTP_FROM_EMAIL="${SMTP_FROM_EMAIL:-}"
|
||||
_ENV_REGISTRY="${REGISTRY:-}"
|
||||
_ENV_REGISTRY_USER="${REGISTRY_USER:-}"
|
||||
_ENV_REGISTRY_TOKEN="${REGISTRY_TOKEN:-}"
|
||||
@@ -61,6 +56,7 @@ AUTH_HOST=""
|
||||
PUBLIC_PROTOCOL=""
|
||||
ADMIN_USER=""
|
||||
ADMIN_PASS=""
|
||||
|
||||
TLS_MODE=""
|
||||
CERT_FILE=""
|
||||
KEY_FILE=""
|
||||
@@ -77,11 +73,6 @@ COMPOSE_PROJECT=""
|
||||
DOCKER_SOCKET=""
|
||||
NODE_TLS_REJECT=""
|
||||
DEPLOYMENT_MODE=""
|
||||
SMTP_HOST=""
|
||||
SMTP_PORT=""
|
||||
SMTP_USER=""
|
||||
SMTP_PASS=""
|
||||
SMTP_FROM_EMAIL=""
|
||||
REGISTRY=""
|
||||
REGISTRY_USER=""
|
||||
REGISTRY_TOKEN=""
|
||||
@@ -156,6 +147,14 @@ generate_password() {
|
||||
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32 || :
|
||||
}
|
||||
|
||||
# Write KEY='escaped_value' to a file. Single-quotes prevent Docker Compose
|
||||
# from interpreting $, &, ;, etc. Embedded single quotes are escaped as '\''.
|
||||
env_val() {
|
||||
local file="$1" key="$2" val="$3"
|
||||
val="${val//\'/\'\\\'\'}"
|
||||
printf "%s='%s'\n" "$key" "$val" >> "$file"
|
||||
}
|
||||
|
||||
# --- Argument parsing ---
|
||||
|
||||
parse_args() {
|
||||
@@ -170,6 +169,7 @@ parse_args() {
|
||||
--public-protocol) PUBLIC_PROTOCOL="$2"; shift ;;
|
||||
--admin-user) ADMIN_USER="$2"; shift ;;
|
||||
--admin-password) ADMIN_PASS="$2"; shift ;;
|
||||
|
||||
--tls-mode) TLS_MODE="$2"; shift ;;
|
||||
--cert-file) CERT_FILE="$2"; shift ;;
|
||||
--key-file) KEY_FILE="$2"; shift ;;
|
||||
@@ -186,11 +186,6 @@ parse_args() {
|
||||
--docker-socket) DOCKER_SOCKET="$2"; shift ;;
|
||||
--node-tls-reject) NODE_TLS_REJECT="$2"; shift ;;
|
||||
--deployment-mode) DEPLOYMENT_MODE="$2"; shift ;;
|
||||
--smtp-host) SMTP_HOST="$2"; shift ;;
|
||||
--smtp-port) SMTP_PORT="$2"; shift ;;
|
||||
--smtp-user) SMTP_USER="$2"; shift ;;
|
||||
--smtp-pass) SMTP_PASS="$2"; shift ;;
|
||||
--smtp-from-email) SMTP_FROM_EMAIL="$2"; shift ;;
|
||||
--registry) REGISTRY="$2"; shift ;;
|
||||
--registry-user) REGISTRY_USER="$2"; shift ;;
|
||||
--registry-token) REGISTRY_TOKEN="$2"; shift ;;
|
||||
@@ -259,8 +254,9 @@ load_config_file() {
|
||||
case "$key" in
|
||||
\#*|"") continue ;;
|
||||
esac
|
||||
key=$(echo "$key" | tr -d ' ')
|
||||
value=$(echo "$value" | sed 's/^[ ]*//;s/[ ]*$//')
|
||||
key=$(printf '%s' "$key" | tr -d ' ')
|
||||
# Trim whitespace, strip surrounding quotes, unescape '\''
|
||||
value=$(printf '%s' "$value" | sed "s/^[ ]*//;s/[ ]*$//;s/^'\\(.*\\)'$/\\1/;s/^\"\\(.*\\)\"$/\\1/" | sed "s/'\\\\''/'/g")
|
||||
case "$key" in
|
||||
install_dir) [ -z "$INSTALL_DIR" ] && INSTALL_DIR="$value" ;;
|
||||
public_host) [ -z "$PUBLIC_HOST" ] && PUBLIC_HOST="$value" ;;
|
||||
@@ -268,6 +264,7 @@ load_config_file() {
|
||||
public_protocol) [ -z "$PUBLIC_PROTOCOL" ] && PUBLIC_PROTOCOL="$value" ;;
|
||||
admin_user) [ -z "$ADMIN_USER" ] && ADMIN_USER="$value" ;;
|
||||
admin_password) [ -z "$ADMIN_PASS" ] && ADMIN_PASS="$value" ;;
|
||||
|
||||
tls_mode) [ -z "$TLS_MODE" ] && TLS_MODE="$value" ;;
|
||||
cert_file) [ -z "$CERT_FILE" ] && CERT_FILE="$value" ;;
|
||||
key_file) [ -z "$KEY_FILE" ] && KEY_FILE="$value" ;;
|
||||
@@ -284,11 +281,6 @@ load_config_file() {
|
||||
docker_socket) [ -z "$DOCKER_SOCKET" ] && DOCKER_SOCKET="$value" ;;
|
||||
node_tls_reject) [ -z "$NODE_TLS_REJECT" ] && NODE_TLS_REJECT="$value" ;;
|
||||
deployment_mode) [ -z "$DEPLOYMENT_MODE" ] && DEPLOYMENT_MODE="$value" ;;
|
||||
smtp_host) [ -z "$SMTP_HOST" ] && SMTP_HOST="$value" ;;
|
||||
smtp_port) [ -z "$SMTP_PORT" ] && SMTP_PORT="$value" ;;
|
||||
smtp_user) [ -z "$SMTP_USER" ] && SMTP_USER="$value" ;;
|
||||
smtp_pass) [ -z "$SMTP_PASS" ] && SMTP_PASS="$value" ;;
|
||||
smtp_from_email) [ -z "$SMTP_FROM_EMAIL" ] && SMTP_FROM_EMAIL="$value" ;;
|
||||
registry) [ -z "$REGISTRY" ] && REGISTRY="$value" ;;
|
||||
registry_user) [ -z "$REGISTRY_USER" ] && REGISTRY_USER="$value" ;;
|
||||
registry_token) [ -z "$REGISTRY_TOKEN" ] && REGISTRY_TOKEN="$value" ;;
|
||||
@@ -303,6 +295,7 @@ load_env_overrides() {
|
||||
[ -z "$PUBLIC_PROTOCOL" ] && PUBLIC_PROTOCOL="$_ENV_PUBLIC_PROTOCOL"
|
||||
[ -z "$ADMIN_USER" ] && ADMIN_USER="${SAAS_ADMIN_USER:-}"
|
||||
[ -z "$ADMIN_PASS" ] && ADMIN_PASS="${SAAS_ADMIN_PASS:-}"
|
||||
|
||||
[ -z "$TLS_MODE" ] && TLS_MODE="$_ENV_TLS_MODE"
|
||||
[ -z "$CERT_FILE" ] && CERT_FILE="$_ENV_CERT_FILE"
|
||||
[ -z "$KEY_FILE" ] && KEY_FILE="$_ENV_KEY_FILE"
|
||||
@@ -319,11 +312,6 @@ load_env_overrides() {
|
||||
[ -z "$DOCKER_SOCKET" ] && DOCKER_SOCKET="$_ENV_DOCKER_SOCKET"
|
||||
[ -z "$NODE_TLS_REJECT" ] && NODE_TLS_REJECT="$_ENV_NODE_TLS_REJECT"
|
||||
[ -z "$DEPLOYMENT_MODE" ] && DEPLOYMENT_MODE="$_ENV_DEPLOYMENT_MODE"
|
||||
[ -z "$SMTP_HOST" ] && SMTP_HOST="$_ENV_SMTP_HOST"
|
||||
[ -z "$SMTP_PORT" ] && SMTP_PORT="$_ENV_SMTP_PORT"
|
||||
[ -z "$SMTP_USER" ] && SMTP_USER="$_ENV_SMTP_USER"
|
||||
[ -z "$SMTP_PASS" ] && SMTP_PASS="$_ENV_SMTP_PASS"
|
||||
[ -z "$SMTP_FROM_EMAIL" ] && SMTP_FROM_EMAIL="$_ENV_SMTP_FROM_EMAIL"
|
||||
[ -z "$REGISTRY" ] && REGISTRY="$_ENV_REGISTRY"
|
||||
[ -z "$REGISTRY_USER" ] && REGISTRY_USER="$_ENV_REGISTRY_USER"
|
||||
[ -z "$REGISTRY_TOKEN" ] && REGISTRY_TOKEN="$_ENV_REGISTRY_TOKEN"
|
||||
@@ -441,7 +429,37 @@ run_simple_prompts() {
|
||||
|
||||
prompt INSTALL_DIR "Install directory" "${INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
|
||||
prompt PUBLIC_HOST "Public hostname" "${PUBLIC_HOST:-localhost}"
|
||||
prompt ADMIN_USER "Admin username" "${ADMIN_USER:-$DEFAULT_ADMIN_USER}"
|
||||
|
||||
echo ""
|
||||
echo " Deployment mode:"
|
||||
echo " [1] Multi-tenant SaaS — manage platform, provision tenants on demand"
|
||||
echo " [2] Single-tenant — one server instance, local auth, no identity provider"
|
||||
echo ""
|
||||
local deploy_choice
|
||||
read -rp " Select mode [1]: " deploy_choice
|
||||
case "${deploy_choice:-1}" in
|
||||
2)
|
||||
DEPLOYMENT_MODE="standalone"
|
||||
;;
|
||||
*)
|
||||
DEPLOYMENT_MODE="saas"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
||||
while true; do
|
||||
prompt ADMIN_USER "Admin email" "${ADMIN_USER:-admin@${PUBLIC_HOST:-localhost}}"
|
||||
# Validate email: must be user@domain.tld format
|
||||
if echo "$ADMIN_USER" | grep -qE '^[^@]+@[^@]+\.[^@]+$'; then
|
||||
break
|
||||
fi
|
||||
echo -e " ${RED}Invalid email address.${NC} Must be a valid email (e.g. admin@company.com)."
|
||||
ADMIN_USER=""
|
||||
done
|
||||
else
|
||||
prompt ADMIN_USER "Admin username" "${ADMIN_USER:-$DEFAULT_ADMIN_USER}"
|
||||
fi
|
||||
|
||||
if prompt_yesno "Auto-generate admin password?" "y"; then
|
||||
ADMIN_PASS=""
|
||||
@@ -471,33 +489,6 @@ run_simple_prompts() {
|
||||
prompt_password REGISTRY_TOKEN "Registry token/password" "${REGISTRY_TOKEN:-}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " Deployment mode:"
|
||||
echo " [1] Multi-tenant SaaS — manage platform, provision tenants on demand"
|
||||
echo " [2] Single-tenant — one server instance, local auth, no identity provider"
|
||||
echo ""
|
||||
local deploy_choice
|
||||
read -rp " Select mode [1]: " deploy_choice
|
||||
case "${deploy_choice:-1}" in
|
||||
2)
|
||||
DEPLOYMENT_MODE="standalone"
|
||||
;;
|
||||
*)
|
||||
DEPLOYMENT_MODE="saas"
|
||||
;;
|
||||
esac
|
||||
|
||||
# SMTP for email verification (SaaS mode only)
|
||||
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
||||
echo ""
|
||||
if prompt_yesno "Configure SMTP for email verification? (required for self-service sign-up)"; then
|
||||
prompt SMTP_HOST "SMTP host" "${SMTP_HOST:-}"
|
||||
prompt SMTP_PORT "SMTP port" "${SMTP_PORT:-587}"
|
||||
prompt SMTP_USER "SMTP username" "${SMTP_USER:-}"
|
||||
prompt_password SMTP_PASS "SMTP password" "${SMTP_PASS:-}"
|
||||
prompt SMTP_FROM_EMAIL "From email address" "${SMTP_FROM_EMAIL:-noreply@${PUBLIC_HOST}}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run_expert_prompts() {
|
||||
@@ -549,7 +540,16 @@ merge_config() {
|
||||
: "${INSTALL_DIR:=$DEFAULT_INSTALL_DIR}"
|
||||
: "${PUBLIC_HOST:=localhost}"
|
||||
: "${PUBLIC_PROTOCOL:=$DEFAULT_PUBLIC_PROTOCOL}"
|
||||
: "${ADMIN_USER:=$DEFAULT_ADMIN_USER}"
|
||||
if [ "$DEPLOYMENT_MODE" = "saas" ]; then
|
||||
: "${ADMIN_USER:=admin@${PUBLIC_HOST}}"
|
||||
# Validate email format in SaaS mode
|
||||
if ! echo "$ADMIN_USER" | grep -qE '^[^@]+@[^@]+\.[^@]+$'; then
|
||||
echo -e "${RED}ERROR:${NC} SAAS_ADMIN_USER must be a valid email address (e.g. admin@company.com), got: '$ADMIN_USER'" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
: "${ADMIN_USER:=$DEFAULT_ADMIN_USER}"
|
||||
fi
|
||||
: "${TLS_MODE:=$DEFAULT_TLS_MODE}"
|
||||
: "${HTTP_PORT:=$DEFAULT_HTTP_PORT}"
|
||||
: "${HTTPS_PORT:=$DEFAULT_HTTPS_PORT}"
|
||||
@@ -624,6 +624,7 @@ generate_passwords() {
|
||||
ADMIN_PASS=$(generate_password)
|
||||
log_info "Generated admin password."
|
||||
fi
|
||||
|
||||
if [ -z "$POSTGRES_PASSWORD" ]; then
|
||||
POSTGRES_PASSWORD=$(generate_password)
|
||||
log_info "Generated PostgreSQL password."
|
||||
@@ -663,15 +664,10 @@ HTTPS_PORT=${HTTPS_PORT}
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=cameleer
|
||||
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB=cameleer
|
||||
|
||||
# ClickHouse
|
||||
CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
|
||||
|
||||
# Server admin
|
||||
SERVER_ADMIN_USER=${ADMIN_USER}
|
||||
SERVER_ADMIN_PASS=${ADMIN_PASS}
|
||||
|
||||
# Bootstrap token (required by server, not used externally in standalone mode)
|
||||
BOOTSTRAP_TOKEN=$(generate_password)
|
||||
@@ -694,6 +690,10 @@ SERVER_UI_IMAGE=${REGISTRY}/cameleer-server-ui
|
||||
# Compose file assembly
|
||||
COMPOSE_FILE=docker-compose.yml:docker-compose.server.yml$([ "$TLS_MODE" = "custom" ] && echo ":docker-compose.tls.yml")$([ -n "$MONITORING_NETWORK" ] && echo ":docker-compose.monitoring.yml")
|
||||
EOF
|
||||
# Passwords are appended with single-quoting to handle special characters
|
||||
env_val "$f" POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
|
||||
env_val "$f" CLICKHOUSE_PASSWORD "$CLICKHOUSE_PASSWORD"
|
||||
env_val "$f" SERVER_ADMIN_PASS "$ADMIN_PASS"
|
||||
if [ "$TLS_MODE" = "custom" ]; then
|
||||
echo "CERT_FILE=/user-certs/cert.pem" >> "$f"
|
||||
echo "KEY_FILE=/user-certs/key.pem" >> "$f"
|
||||
@@ -729,15 +729,10 @@ LOGTO_CONSOLE_BIND=$([ "$LOGTO_CONSOLE_EXPOSED" = "true" ] && echo "0.0.0.0" ||
|
||||
|
||||
# PostgreSQL
|
||||
POSTGRES_USER=cameleer
|
||||
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
POSTGRES_DB=cameleer_saas
|
||||
|
||||
# ClickHouse
|
||||
CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD}
|
||||
|
||||
# Admin user
|
||||
SAAS_ADMIN_USER=${ADMIN_USER}
|
||||
SAAS_ADMIN_PASS=${ADMIN_PASS}
|
||||
|
||||
# TLS
|
||||
NODE_TLS_REJECT=${NODE_TLS_REJECT}
|
||||
@@ -774,17 +769,15 @@ CAMELEER_SAAS_PROVISIONING_RUNTIMEBASEIMAGE=${REGISTRY}/cameleer-runtime-base:${
|
||||
# JWT signing secret (forwarded to provisioned tenant servers, must be non-empty)
|
||||
CAMELEER_SERVER_SECURITY_JWTSECRET=$(generate_password)
|
||||
|
||||
# SMTP (for email verification during registration)
|
||||
SMTP_HOST=${SMTP_HOST}
|
||||
SMTP_PORT=${SMTP_PORT:-587}
|
||||
SMTP_USER=${SMTP_USER}
|
||||
SMTP_PASS=${SMTP_PASS}
|
||||
SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL:-noreply@${PUBLIC_HOST}}
|
||||
|
||||
# Compose file assembly
|
||||
COMPOSE_FILE=docker-compose.yml:docker-compose.saas.yml$([ "$TLS_MODE" = "custom" ] && echo ":docker-compose.tls.yml")$([ -n "$MONITORING_NETWORK" ] && echo ":docker-compose.monitoring.yml")
|
||||
EOF
|
||||
|
||||
# Passwords are appended with single-quoting to handle special characters
|
||||
env_val "$f" POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
|
||||
env_val "$f" CLICKHOUSE_PASSWORD "$CLICKHOUSE_PASSWORD"
|
||||
env_val "$f" SAAS_ADMIN_PASS "$ADMIN_PASS"
|
||||
|
||||
if [ -n "$MONITORING_NETWORK" ]; then
|
||||
echo "" >> "$f"
|
||||
echo "# Monitoring" >> "$f"
|
||||
@@ -964,15 +957,11 @@ compose_project=${COMPOSE_PROJECT}
|
||||
docker_socket=${DOCKER_SOCKET}
|
||||
node_tls_reject=${NODE_TLS_REJECT}
|
||||
deployment_mode=${DEPLOYMENT_MODE}
|
||||
smtp_host=${SMTP_HOST}
|
||||
smtp_port=${SMTP_PORT}
|
||||
smtp_user=${SMTP_USER}
|
||||
smtp_pass=${SMTP_PASS}
|
||||
smtp_from_email=${SMTP_FROM_EMAIL}
|
||||
registry=${REGISTRY}
|
||||
registry_user=${REGISTRY_USER}
|
||||
registry_token=${REGISTRY_TOKEN}
|
||||
EOF
|
||||
# Passwords appended with single-quoting for special character safety
|
||||
env_val "$f" registry_token "$REGISTRY_TOKEN"
|
||||
log_info "Saved installer config to cameleer.conf"
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,9 @@ CLICKHOUSE_PASSWORD=CHANGE_ME
|
||||
# ============================================================
|
||||
# Admin credentials (SaaS mode)
|
||||
# ============================================================
|
||||
SAAS_ADMIN_USER=admin
|
||||
# In SaaS mode, this must be an email address (primary user identity).
|
||||
# In standalone mode, any username is accepted.
|
||||
SAAS_ADMIN_USER=admin@example.com
|
||||
SAAS_ADMIN_PASS=CHANGE_ME
|
||||
|
||||
# ============================================================
|
||||
@@ -61,14 +63,10 @@ SAAS_ADMIN_PASS=CHANGE_ME
|
||||
# BOOTSTRAP_TOKEN=CHANGE_ME
|
||||
|
||||
# ============================================================
|
||||
# SMTP (for email verification during registration)
|
||||
# Email / SMTP
|
||||
# ============================================================
|
||||
# Required for self-service sign-up. Without SMTP, only admin-created users can sign in.
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=
|
||||
SMTP_PASS=
|
||||
SMTP_FROM_EMAIL=noreply@cameleer.io
|
||||
# Email connector configuration is managed at runtime via the vendor
|
||||
# admin UI (Email Connector page at /vendor/email). No SMTP env vars needed.
|
||||
|
||||
# ============================================================
|
||||
# TLS
|
||||
|
||||
@@ -9,7 +9,8 @@ services:
|
||||
cameleer-postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DB_URL: postgres://${POSTGRES_USER:-cameleer}:${POSTGRES_PASSWORD}@cameleer-postgres:5432/logto
|
||||
# DB_URL is built by the entrypoint from PG_USER/PG_PASSWORD/PG_HOST
|
||||
# to safely handle special characters in the password
|
||||
ENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}
|
||||
ADMIN_ENDPOINT: ${PUBLIC_PROTOCOL:-https}://${AUTH_HOST:-localhost}:${LOGTO_CONSOLE_PORT:-3002}
|
||||
TRUST_PROXY_HEADER: 1
|
||||
@@ -26,12 +27,6 @@ services:
|
||||
PG_DB_SAAS: cameleer_saas
|
||||
SAAS_ADMIN_USER: ${SAAS_ADMIN_USER:-admin}
|
||||
SAAS_ADMIN_PASS: ${SAAS_ADMIN_PASS:?SAAS_ADMIN_PASS must be set in .env}
|
||||
# SMTP (for email verification during registration)
|
||||
SMTP_HOST: ${SMTP_HOST:-}
|
||||
SMTP_PORT: ${SMTP_PORT:-587}
|
||||
SMTP_USER: ${SMTP_USER:-}
|
||||
SMTP_PASS: ${SMTP_PASS:-}
|
||||
SMTP_FROM_EMAIL: ${SMTP_FROM_EMAIL:-noreply@cameleer.io}
|
||||
extra_hosts:
|
||||
# Logto validates M2M tokens by fetching its own JWKS from ENDPOINT.
|
||||
# Route the public hostname back to the Docker host (Traefik on :443)
|
||||
|
||||
Reference in New Issue
Block a user