diff --git a/BUILD-INSTRUCTIONS.md b/BUILD-INSTRUCTIONS.md index b59d3bf..a5627dd 100644 --- a/BUILD-INSTRUCTIONS.md +++ b/BUILD-INSTRUCTIONS.md @@ -12,13 +12,13 @@ git clone https://github.com/andreasdueren/ente-cloudron.git cd ente-cloudron ``` -2. Build the image via the Cloudron build service. Adjust `--tag` to match `CloudronManifest.json` (`0.2.1`) and optionally override the Ente git ref: +2. Build the image via the Cloudron build service. Adjust `--tag` to match `CloudronManifest.json` (`0.4.3`) and optionally override the Ente git ref: ```bash cloudron build \ --set-build-service builder.docker.due.ren \ --build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \ --set-repository andreasdueren/ente-cloudron \ - --tag 0.2.1 \ + --tag 0.4.3 \ --build-arg ENTE_GIT_REF=main ``` Use a tagged Ente release for reproducible builds (e.g. `--build-arg ENTE_GIT_REF=v0.9.0`). @@ -28,7 +28,7 @@ Always uninstall the dev instance before reinstalling. ```bash cloudron install \ --location ente.due.ren \ - --image andreasdueren/ente-cloudron:0.2.1 + --image andreasdueren/ente-cloudron:0.4.3 ``` If the install command runs for more than ~30 seconds without feedback, abort and inspect `cloudron logs --app ente.due.ren`. @@ -54,6 +54,7 @@ Optional: set `CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, and `CLOUDR ## Troubleshooting - **S3 errors**: Verify credentials in `/app/data/config/s3.env`; check connectivity using `aws s3 ls --endpoint-url ...` from a trusted host. +- **Startup issues**: Inspect `/app/data/logs/startup.log` (also mirrored to `cloudron logs`) for rendered configuration and error messages. - **Museum not starting**: Inspect `/app/data/museum/configurations/local.yaml` for syntax issues; delete to regenerate. - **Frontend stale after update**: Restart the app—the startup script re-syncs static assets on each boot. - **OIDC issues**: Confirm the callback URL `/api/v1/session/callback` is allowed in the Cloudron SSO client configuration. @@ -63,4 +64,5 @@ Optional: set `CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, and `CLOUDR cloudron exec --app ente.due.ren -- cat /app/data/museum/configurations/local.yaml cloudron exec --app ente.due.ren -- ente --help cloudron logs --app ente.due.ren -f +cloudron exec --app ente.due.ren -- tail -f /app/data/logs/startup.log ``` diff --git a/CHANGELOG.md b/CHANGELOG.md index fa8b488..82f3a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 0.4.3 (2025-10-29) + +* Always regenerate Museum configuration on startup to pick up S3 credential changes +* Enables seamless workflow: add S3 credentials to /app/data/config/s3.env and restart +* Fixes issue where S3 configuration changes required manual intervention + +## 0.4.2 (2025-10-29) + +* Use SMTPS (port 2465) with TLS encryption for email delivery +* Fixes email sending with requiresValidCertificate flag on Cloudron 9 + +## 0.4.1 (2025-10-23) + +* Fix email sending for user registration by enabling TLS certificate validation in sendmail addon +* Add requiresValidCertificate flag to sendmail configuration to ensure proper SMTP authentication with Go applications +* Note: Requires Cloudron 9 or later for requiresValidCertificate support + ## 1.0.0 (2024-06-01) * Initial release of Ente for Cloudron diff --git a/CloudronManifest.json b/CloudronManifest.json index 94f5bff..2a10420 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -7,7 +7,7 @@ "contactEmail": "contact@ente.io", "website": "https://ente.io", "tagline": "Open source, end-to-end encrypted photo backup", - "version": "0.4.0", + "version": "0.4.3", "upstreamVersion": "git-main", "healthCheckPath": "/health", "httpPort": 3080, @@ -17,7 +17,8 @@ "localstorage": {}, "postgresql": {}, "sendmail": { - "supportsDisplayName": true + "supportsDisplayName": true, + "requiresValidCertificate": true } }, "checklist": { diff --git a/config.template.yaml b/config.template.yaml index dbf5f34..e733974 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -18,16 +18,20 @@ database: maxIdleConns: 25 connMaxLifetime: "1h" -storage: - type: "s3" - s3: +s3: + are_local_buckets: false + use_path_style_urls: true + hot_storage: + primary: b2-eu-cen + secondary: b2-eu-cen + derived-storage: b2-eu-cen + b2-eu-cen: endpoint: "%%S3_ENDPOINT%%" region: "%%S3_REGION%%" bucket: "%%S3_BUCKET%%" - accessKey: "%%S3_ACCESS_KEY%%" - secretKey: "%%S3_SECRET_KEY%%" - prefix: "%%S3_PREFIX%%" - forcePathStyle: true + key: "%%S3_ACCESS_KEY%%" + secret: "%%S3_SECRET_KEY%%" + path_prefix: "%%S3_PREFIX%%" email: smtp: @@ -48,19 +52,19 @@ auth: logging: level: "info" format: "text" - + # Additional settings based on Museum requirements keygen: master: "%%MASTER_KEY%%" payments: enabled: false - + metadata: localPath: "/app/data/storage/metadata" - + tempDirectory: "/app/data/storage/temp" memoryCache: enabled: true - size: 100 \ No newline at end of file + size: 100 diff --git a/start.sh b/start.sh index f6926c7..053f2ce 100755 --- a/start.sh +++ b/start.sh @@ -28,7 +28,15 @@ STARTUP_FLAG="$DATA_DIR/startup.lock" mkdir -p "$LOG_DIR" "$CONFIG_DIR" "$TMP_DIR" "$SECRETS_DIR" "$MUSEUM_RUNTIME_DIR" "$WEB_RUNTIME_DIR" "$MUSEUM_CONFIG_DIR" chown -R cloudron:cloudron "$DATA_DIR" +LOG_FILE="$LOG_DIR/startup.log" +touch "$LOG_FILE" +chown cloudron:cloudron "$LOG_FILE" +chmod 640 "$LOG_FILE" +# Mirror all output to a persistent log file while retaining stdout/stderr for Cloudron aggregation +exec > >(tee -a "$LOG_FILE") 2>&1 + log INFO "Starting Ente for Cloudron" +log INFO "Startup logs are mirrored to $LOG_FILE" if ! command -v setpriv >/dev/null 2>&1; then log ERROR "setpriv command not found" @@ -112,19 +120,64 @@ if [ "$S3_NOT_CONFIGURED" = "false" ]; then fi log INFO "Using S3 endpoint $S3_ENDPOINT_HOST (region $S3_REGION, bucket $S3_BUCKET)" + S3_REGION_LOWER="$(printf '%s' "$S3_REGION" | tr '[:upper:]' '[:lower:]')" + if printf '%s' "$S3_ENDPOINT_HOST" | grep -q '\.r2\.cloudflarestorage\.com$' && [ "$S3_REGION_LOWER" != "auto" ]; then + log WARN "Cloudflare R2 endpoints require S3_REGION=auto; current value '$S3_REGION' may cause upload failures" + fi else S3_ENDPOINT_HOST="s3.example.com" log WARN "S3 not configured - using placeholder values" fi +DEFAULT_FORCE_PATH_STYLE="true" +if printf '%s' "$S3_ENDPOINT_HOST" | grep -q '\.r2\.cloudflarestorage\.com$'; then + if [ -z "${S3_FORCE_PATH_STYLE:-}" ] && [ -z "${ENTE_S3_FORCE_PATH_STYLE:-}" ]; then + log INFO "Detected Cloudflare R2 endpoint; defaulting to path-style URLs (required by R2)" + fi +fi + +S3_FORCE_PATH_STYLE_RAW="${S3_FORCE_PATH_STYLE:-${ENTE_S3_FORCE_PATH_STYLE:-$DEFAULT_FORCE_PATH_STYLE}}" +S3_FORCE_PATH_STYLE="$(printf '%s' "$S3_FORCE_PATH_STYLE_RAW" | tr '[:upper:]' '[:lower:]')" +S3_ARE_LOCAL_BUCKETS="$(printf '%s' "${S3_ARE_LOCAL_BUCKETS:-${ENTE_S3_ARE_LOCAL_BUCKETS:-false}}" | tr '[:upper:]' '[:lower:]')" + +S3_PRIMARY_DC="${ENTE_S3_PRIMARY_DC:-b2-eu-cen}" +S3_SECONDARY_DC="${ENTE_S3_SECONDARY_DC:-$S3_PRIMARY_DC}" +S3_DERIVED_DC="${ENTE_S3_DERIVED_DC:-$S3_PRIMARY_DC}" + +S3_DCS=() +add_s3_dc() { + local candidate="$1" + if [ -z "$candidate" ]; then + return + fi + for existing in "${S3_DCS[@]}"; do + if [ "$existing" = "$candidate" ]; then + return + fi + done + S3_DCS+=("$candidate") +} + +add_s3_dc "$S3_PRIMARY_DC" +add_s3_dc "$S3_SECONDARY_DC" +add_s3_dc "$S3_DERIVED_DC" + +S3_PREFIX_DISPLAY="${S3_PREFIX:-}" +log INFO "Resolved S3 configuration: host=$S3_ENDPOINT_HOST region=$S3_REGION pathStyle=$S3_FORCE_PATH_STYLE localBuckets=$S3_ARE_LOCAL_BUCKETS primaryDC=$S3_PRIMARY_DC derivedDC=$S3_DERIVED_DC prefix=$S3_PREFIX_DISPLAY" + +DEFAULT_GIN_TRUSTED_PROXIES="127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" +GIN_TRUSTED_PROXIES="${GIN_TRUSTED_PROXIES:-$DEFAULT_GIN_TRUSTED_PROXIES}" +export GIN_TRUSTED_PROXIES +log INFO "Configured trusted proxy ranges for Museum: $GIN_TRUSTED_PROXIES" + MASTER_KEY_FILE="$SECRETS_DIR/master_key" HASH_KEY_FILE="$SECRETS_DIR/hash_key" JWT_SECRET_FILE="$SECRETS_DIR/jwt_secret" SESSION_SECRET_FILE="$SECRETS_DIR/session_secret" SMTP_HOST="${CLOUDRON_MAIL_SMTP_SERVER:-mail}" -SMTP_PORT="${CLOUDRON_MAIL_SMTP_PORT:-2525}" -SMTP_ENCRYPTION="" +SMTP_PORT="${CLOUDRON_MAIL_SMTPS_PORT:-2465}" +SMTP_ENCRYPTION="tls" SMTP_USERNAME="${CLOUDRON_MAIL_SMTP_USERNAME:-}" SMTP_PASSWORD="${CLOUDRON_MAIL_SMTP_PASSWORD:-}" SMTP_EMAIL="${CLOUDRON_MAIL_FROM:-no-reply@$RP_ID}" @@ -139,7 +192,7 @@ fi normalize_b64() { local value="$1" value="$(printf '%s' "$value" | tr -d '\r\n')" - value="$(printf '%s' "$value" | tr '-_' '+/')" + value="$(printf '%s' "$value" | tr -- '-_' '+/')" local mod=$(( ${#value} % 4 )) if [ $mod -eq 2 ]; then value="${value}==" @@ -154,7 +207,7 @@ normalize_b64() { normalize_b64url() { local value="$1" value="$(printf '%s' "$value" | tr -d '\r\n')" - value="$(printf '%s' "$value" | tr '+/' '-_')" + value="$(printf '%s' "$value" | tr -- '+/' '-_')" local mod=$(( ${#value} % 4 )) if [ $mod -eq 2 ]; then value="${value}==" @@ -173,7 +226,7 @@ generate_b64() { generate_b64url() { local bytes="$1" - openssl rand -base64 "$bytes" | tr '+/' '-_' | tr -d '\n' + openssl rand -base64 "$bytes" | tr -- '+/' '-_' | tr -d '\n' } ensure_secret() { @@ -237,9 +290,9 @@ if [ ! -x "$MUSEUM_BIN" ]; then exit 1 fi -if [ ! -f "$MUSEUM_CONFIG" ]; then - log INFO "Rendering Museum configuration" - cat > "$MUSEUM_CONFIG" < "$MUSEUM_CONFIG" <> "$MUSEUM_CONFIG" <> "$MUSEUM_CONFIG" + fi + printf '\n' >> "$MUSEUM_CONFIG" +done +cat >> "$MUSEUM_CONFIG" < "$CADDY_CONFIG" < "$CADDY_CONFIG" <