diff --git a/installer/install.sh b/installer/install.sh index e0f17e9..ebc628a 100644 --- a/installer/install.sh +++ b/installer/install.sh @@ -955,3 +955,263 @@ verify_health() { fi log_success "All services healthy." } + +# --- Output file generation --- + +write_config_file() { + local f="$INSTALL_DIR/cameleer.conf" + cat > "$f" << EOF +# Cameleer installation config +# Generated by installer v${CAMELEER_INSTALLER_VERSION} on $(date -u '+%Y-%m-%d %H:%M:%S UTC') + +install_dir=${INSTALL_DIR} +public_host=${PUBLIC_HOST} +public_protocol=${PUBLIC_PROTOCOL} +admin_user=${ADMIN_USER} +tls_mode=${TLS_MODE} +http_port=${HTTP_PORT} +https_port=${HTTPS_PORT} +logto_console_port=${LOGTO_CONSOLE_PORT} +logto_console_exposed=${LOGTO_CONSOLE_EXPOSED} +vendor_enabled=${VENDOR_ENABLED} +vendor_user=${VENDOR_USER} +monitoring_network=${MONITORING_NETWORK} +version=${VERSION} +compose_project=${COMPOSE_PROJECT} +docker_socket=${DOCKER_SOCKET} +node_tls_reject=${NODE_TLS_REJECT} +EOF + log_info "Saved installer config to cameleer.conf" +} + +generate_credentials_file() { + local f="$INSTALL_DIR/credentials.txt" + cat > "$f" << EOF +=========================================== + CAMELEER PLATFORM CREDENTIALS + Generated: $(date -u '+%Y-%m-%d %H:%M:%S UTC') + + SECURE THIS FILE AND DELETE AFTER NOTING + THESE CREDENTIALS CANNOT BE RECOVERED +=========================================== + +Admin Console: ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}/platform/ +Admin User: ${ADMIN_USER} +Admin Password: ${ADMIN_PASS} + +PostgreSQL: cameleer / ${POSTGRES_PASSWORD} +ClickHouse: default / ${CLICKHOUSE_PASSWORD} + +EOF + + if [ "$VENDOR_ENABLED" = "true" ]; then + cat >> "$f" << EOF +Vendor User: ${VENDOR_USER} +Vendor Password: ${VENDOR_PASS} + +EOF + else + echo "Vendor User: (not enabled)" >> "$f" + echo "" >> "$f" + fi + + if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then + echo "Logto Console: ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}" >> "$f" + else + echo "Logto Console: (not exposed)" >> "$f" + fi + + chmod 600 "$f" + log_info "Saved credentials to credentials.txt" +} + +generate_install_doc() { + local f="$INSTALL_DIR/INSTALL.md" + local tls_desc="Self-signed (auto-generated)" + [ "$TLS_MODE" = "custom" ] && tls_desc="Custom certificate" + + cat > "$f" << EOF +# Cameleer SaaS — Installation Documentation + +## Installation Summary + +| | | +|---|---| +| **Version** | ${VERSION} | +| **Date** | $(date -u '+%Y-%m-%d %H:%M:%S UTC') | +| **Installer** | v${CAMELEER_INSTALLER_VERSION} | +| **Install Directory** | ${INSTALL_DIR} | +| **Hostname** | ${PUBLIC_HOST} | +| **TLS** | ${tls_desc} | + +## Service URLs + +- **Platform UI:** ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}/platform/ +- **API Endpoint:** ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}/platform/api/ +EOF + + if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then + echo "- **Logto Admin Console:** ${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}" >> "$f" + fi + + cat >> "$f" << 'EOF' + +## First Steps + +1. Open the Platform UI in your browser +2. Log in with the admin credentials from `credentials.txt` +3. Create your first tenant via the Vendor console +4. The platform will provision a dedicated server instance for the tenant + +## Architecture + +| Container | Purpose | +|---|---| +| `traefik` | Reverse proxy, TLS termination, routing | +| `postgres` | PostgreSQL database (SaaS + Logto + tenant schemas) | +| `clickhouse` | Time-series storage (traces, metrics, logs) | +| `logto` | OIDC identity provider + bootstrap | +| `cameleer-saas` | SaaS platform (Spring Boot + React) | + +Per-tenant `cameleer3-server` and `cameleer3-server-ui` containers are provisioned dynamically when tenants are created. + +## Networking + +EOF + + cat >> "$f" << EOF +| Port | Service | +|---|---| +| ${HTTP_PORT} | HTTP (redirects to HTTPS) | +| ${HTTPS_PORT} | HTTPS (main entry point) | +EOF + + if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then + echo "| ${LOGTO_CONSOLE_PORT} | Logto Admin Console |" >> "$f" + fi + + if [ -n "$MONITORING_NETWORK" ]; then + cat >> "$f" << EOF + +### Monitoring + +Services are connected to the \`${MONITORING_NETWORK}\` Docker network with Prometheus labels for auto-discovery. +EOF + fi + + cat >> "$f" << EOF + +## TLS + +**Mode:** ${tls_desc} +EOF + + if [ "$TLS_MODE" = "self-signed" ]; then + cat >> "$f" << 'EOF' + +The platform generated a self-signed certificate on first boot. To replace it: +1. Log in as admin and navigate to **Certificates** in the vendor console +2. Upload your certificate and key via the UI +3. Activate the new certificate (zero-downtime swap) +EOF + fi + + cat >> "$f" << EOF + +## Data & Backups + +| Docker Volume | Contains | +|---|---| +| \`pgdata\` | PostgreSQL data (tenants, licenses, audit) | +| \`chdata\` | ClickHouse data (traces, metrics, logs) | +| \`certs\` | TLS certificates | +| \`bootstrapdata\` | Logto bootstrap results | + +### Backup Commands + +\`\`\`bash +# PostgreSQL +docker compose -p ${COMPOSE_PROJECT} exec postgres pg_dump -U cameleer cameleer_saas > backup.sql + +# ClickHouse +docker compose -p ${COMPOSE_PROJECT} exec clickhouse clickhouse-client --query "SELECT * FROM cameleer.traces FORMAT Native" > traces.native +\`\`\` + +## Upgrading + +Re-run the installer with a new version: + +\`\`\`bash +curl -sfL https://install.cameleer.io | bash -s -- --install-dir ${INSTALL_DIR} --version NEW_VERSION +\`\`\` + +The installer preserves your \`.env\`, credentials, and data volumes. Only the compose file and images are updated. + +## Troubleshooting + +| Issue | Command | +|---|---| +| Service not starting | \`docker compose -p ${COMPOSE_PROJECT} logs SERVICE_NAME\` | +| Bootstrap failed | \`docker compose -p ${COMPOSE_PROJECT} logs logto\` | +| Routing issues | \`docker compose -p ${COMPOSE_PROJECT} logs traefik\` | +| Database issues | \`docker compose -p ${COMPOSE_PROJECT} exec postgres psql -U cameleer -d cameleer_saas\` | + +## Uninstalling + +\`\`\`bash +# Stop and remove containers +cd ${INSTALL_DIR} && docker compose -p ${COMPOSE_PROJECT} down + +# Remove data volumes (DESTRUCTIVE) +cd ${INSTALL_DIR} && docker compose -p ${COMPOSE_PROJECT} down -v + +# Remove install directory +rm -rf ${INSTALL_DIR} +\`\`\` +EOF + + log_info "Generated INSTALL.md" +} + +print_credentials() { + echo "" + echo -e "${BOLD}==========================================${NC}" + echo -e "${BOLD} CAMELEER PLATFORM CREDENTIALS${NC}" + echo -e "${BOLD}==========================================${NC}" + echo "" + echo -e " Admin Console: ${BLUE}${PUBLIC_PROTOCOL}://${PUBLIC_HOST}/platform/${NC}" + echo -e " Admin User: ${BOLD}${ADMIN_USER}${NC}" + echo -e " Admin Password: ${BOLD}${ADMIN_PASS}${NC}" + echo "" + echo -e " PostgreSQL: cameleer / ${POSTGRES_PASSWORD}" + echo -e " ClickHouse: default / ${CLICKHOUSE_PASSWORD}" + echo "" + if [ "$VENDOR_ENABLED" = "true" ]; then + echo -e " Vendor User: ${BOLD}${VENDOR_USER}${NC}" + echo -e " Vendor Password: ${BOLD}${VENDOR_PASS}${NC}" + echo "" + fi + if [ "$LOGTO_CONSOLE_EXPOSED" = "true" ]; then + echo -e " Logto Console: ${BLUE}${PUBLIC_PROTOCOL}://${PUBLIC_HOST}:${LOGTO_CONSOLE_PORT}${NC}" + echo "" + fi + echo -e " Credentials saved to: ${INSTALL_DIR}/credentials.txt" + echo -e " ${YELLOW}Secure this file and delete after noting credentials.${NC}" + echo "" +} + +print_summary() { + echo -e "${GREEN}==========================================${NC}" + echo -e "${GREEN} Installation complete!${NC}" + echo -e "${GREEN}==========================================${NC}" + echo "" + echo " Install directory: $INSTALL_DIR" + echo " Documentation: $INSTALL_DIR/INSTALL.md" + echo "" + echo " To manage the stack:" + echo " cd $INSTALL_DIR" + echo " docker compose -p $COMPOSE_PROJECT ps # status" + echo " docker compose -p $COMPOSE_PROJECT logs -f # logs" + echo " docker compose -p $COMPOSE_PROJECT down # stop" + echo "" +}