#!/bin/bash set -euo pipefail APP_CODE_DIR=${APP_CODE_DIR:-/app/code} APP_DATA_DIR=${APP_DATA_DIR:-/app/data} APP_RUNTIME_DIR=${APP_RUNTIME_DIR:-/run/affine} APP_TMP_DIR=${APP_TMP_DIR:-/tmp/data} APP_BUILD_DIR=${APP_BUILD_DIR:-/app/code/affine} APP_HOME_DIR=${APP_HOME_DIR:-/app/data/home} AFFINE_HOME=${AFFINE_HOME:-$APP_HOME_DIR/.affine} ENV_EXPORT_FILE=${ENV_EXPORT_FILE:-$APP_RUNTIME_DIR/runtime.env} export APP_CODE_DIR APP_DATA_DIR APP_RUNTIME_DIR APP_TMP_DIR APP_BUILD_DIR APP_HOME_DIR AFFINE_HOME ENV_EXPORT_FILE log() { printf '[%s] %s\n' "$(date --iso-8601=seconds)" "$*" } record_env_var() { local name="$1" local value="$2" if [ -n "$value" ]; then printf '%s=%q\n' "$name" "$value" >> "$ENV_EXPORT_FILE" fi } require_env() { local var_name="$1" if [ -z "${!var_name:-}" ]; then echo "Environment variable ${var_name} is not set" >&2 exit 1 fi } prepare_data_dirs() { log "Preparing persistent directories" mkdir -p "$APP_DATA_DIR/config" "$APP_DATA_DIR/storage" "$APP_DATA_DIR/logs" "$APP_RUNTIME_DIR" "$APP_HOME_DIR" "$AFFINE_HOME" mkdir -p /run/nginx/body /run/nginx/proxy /run/nginx/fastcgi : > "$ENV_EXPORT_FILE" if [ ! -f "$APP_DATA_DIR/config/config.json" ]; then log "Seeding default configuration" cp "$APP_TMP_DIR/config/config.json" "$APP_DATA_DIR/config/config.json" fi local storage_contents="" if [ -d "$APP_DATA_DIR/storage" ]; then storage_contents=$(ls -A "$APP_DATA_DIR/storage" 2>/dev/null || true) fi if [ ! -d "$APP_DATA_DIR/storage" ] || [ -z "$storage_contents" ]; then cp -a "$APP_TMP_DIR/storage/." "$APP_DATA_DIR/storage/" 2>/dev/null || true fi rm -rf "$AFFINE_HOME/config" "$AFFINE_HOME/storage" ln -sf "$APP_DATA_DIR/config" "$AFFINE_HOME/config" ln -sf "$APP_DATA_DIR/storage" "$AFFINE_HOME/storage" chown -R cloudron:cloudron "$APP_DATA_DIR" "$APP_RUNTIME_DIR" "$APP_HOME_DIR" } configure_database() { require_env CLOUDRON_POSTGRESQL_URL local db_url="$CLOUDRON_POSTGRESQL_URL" if [[ "$db_url" == postgres://* ]]; then db_url="postgresql://${db_url#postgres://}" fi export DATABASE_URL="$db_url" record_env_var DATABASE_URL "$db_url" log "Configured PostgreSQL endpoint" } configure_redis() { require_env CLOUDRON_REDIS_URL local redis_info redis_info=$(python3 - <<'PY' import os from urllib.parse import urlparse url = os.environ.get('CLOUDRON_REDIS_URL') parsed = urlparse(url) if url else None host = os.environ.get('CLOUDRON_REDIS_HOST') port = os.environ.get('CLOUDRON_REDIS_PORT') password = os.environ.get('CLOUDRON_REDIS_PASSWORD') username = os.environ.get('CLOUDRON_REDIS_USERNAME') db = os.environ.get('CLOUDRON_REDIS_DB') if not host and parsed: host = parsed.hostname or 'localhost' if not port and parsed: port = parsed.port or 6379 if not password and parsed: password = parsed.password or '' if not db and parsed: db = (parsed.path or '/0').lstrip('/') or '0' if username is None: username = parsed.username if parsed and parsed.username else 'default' host = host or 'localhost' port = port or 6379 password = password or '' db = db or '0' print(f"{host}\n{port}\n{password}\n{db}\n{username}") PY ) IFS=$'\n' read -r host port password db username <<<"$redis_info" if [ -n "${CLOUDRON_REDIS_HOST:-}" ]; then host="$CLOUDRON_REDIS_HOST" fi if [ -n "${CLOUDRON_REDIS_PORT:-}" ]; then port="$CLOUDRON_REDIS_PORT" fi if [ -n "${CLOUDRON_REDIS_PASSWORD:-}" ]; then password="$CLOUDRON_REDIS_PASSWORD" fi if [ -n "${CLOUDRON_REDIS_USERNAME:-}" ]; then username="$CLOUDRON_REDIS_USERNAME" elif [ -z "$username" ]; then username="default" fi export REDIS_SERVER_HOST="$host" export REDIS_SERVER_PORT="$port" export REDIS_SERVER_PASSWORD="$password" export REDIS_SERVER_DATABASE="$db" export REDIS_SERVER_USERNAME="$username" export REDIS_URL="$CLOUDRON_REDIS_URL" export REDIS_SERVER_URL="$CLOUDRON_REDIS_URL" record_env_var REDIS_SERVER_HOST "$host" record_env_var REDIS_SERVER_PORT "$port" record_env_var REDIS_SERVER_PASSWORD "$password" record_env_var REDIS_SERVER_DATABASE "$db" record_env_var REDIS_SERVER_USERNAME "$username" record_env_var REDIS_URL "$CLOUDRON_REDIS_URL" record_env_var REDIS_SERVER_URL "$CLOUDRON_REDIS_URL" jq --arg host "$host" \ --arg port "$port" \ --arg password "$password" \ --arg username "$username" \ --arg db "$db" \ '.redis.host = $host | .redis.port = ($port|tonumber) | .redis.password = $password | .redis.username = $username | .redis.db = ($db|tonumber)' \ "$APP_DATA_DIR/config/config.json" > "$APP_DATA_DIR/config/config.json.tmp" mv "$APP_DATA_DIR/config/config.json.tmp" "$APP_DATA_DIR/config/config.json" log "Configured Redis endpoint" } configure_mail() { if [ -z "${CLOUDRON_MAIL_SMTP_SERVER:-}" ]; then log "Cloudron mail addon not configured, skipping SMTP setup" return fi export MAILER_HOST="$CLOUDRON_MAIL_SMTP_SERVER" export MAILER_PORT="${CLOUDRON_MAIL_SMTP_PORT:-587}" export MAILER_USER="${CLOUDRON_MAIL_SMTP_USERNAME:-}" export MAILER_PASSWORD="${CLOUDRON_MAIL_SMTP_PASSWORD:-}" export MAILER_SENDER="${CLOUDRON_MAIL_FROM:-AFFiNE }" export MAILER_SERVERNAME="${MAILER_SERVERNAME:-AFFiNE Server}" record_env_var MAILER_HOST "$MAILER_HOST" record_env_var MAILER_PORT "$MAILER_PORT" record_env_var MAILER_USER "$MAILER_USER" record_env_var MAILER_PASSWORD "$MAILER_PASSWORD" record_env_var MAILER_SENDER "$MAILER_SENDER" record_env_var MAILER_SERVERNAME "$MAILER_SERVERNAME" log "Configured SMTP relay" } configure_server_metadata() { if [ -n "${CLOUDRON_APP_ORIGIN:-}" ]; then export AFFINE_SERVER_EXTERNAL_URL="$CLOUDRON_APP_ORIGIN" local host host=$(python3 - <