From 956d39fca5e733d4ccd84d13203893dc5ad17a07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20D=C3=BCren?=
Date: Sun, 16 Mar 2025 23:11:53 +0100
Subject: [PATCH] Complete rewrite of Ente Cloudron app startup script with
proper SERVER_DIR detection
---
start.sh | 1185 +++++++++++++++++++++---------------------------------
1 file changed, 450 insertions(+), 735 deletions(-)
diff --git a/start.sh b/start.sh
index 90b754e..9d48d2d 100644
--- a/start.sh
+++ b/start.sh
@@ -14,6 +14,22 @@ mkdir -p /app/data/config /app/data/storage /app/data/caddy /app/data/go /app/da
echo "==> NOTE: Running in Cloudron environment with limited write access"
echo "==> Writable directories: /app/data, /tmp, /run"
+# Define the server directory
+SERVER_DIR="/app/code/server"
+if [ ! -d "$SERVER_DIR" ]; then
+ if [ -d "/app/code/museum" ]; then
+ SERVER_DIR="/app/code/museum"
+ else
+ # Look for main.go in likely places
+ SERVER_DIR=$(dirname $(find /app/code -name "main.go" -path "*/server*" -o -path "*/museum*" | head -1))
+ if [ ! -d "$SERVER_DIR" ]; then
+ echo "==> WARNING: Could not find server directory, using /app/code as fallback"
+ SERVER_DIR="/app/code"
+ fi
+ fi
+fi
+echo "==> Using server directory: $SERVER_DIR"
+
# One-time initialization tracking
if [[ ! -f /app/data/.initialized ]]; then
echo "==> Fresh installation, setting up data directory..."
@@ -216,728 +232,11 @@ export REACT_APP_ENTE_ENDPOINT=$API_ENDPOINT
export VUE_APP_ENTE_ENDPOINT=$API_ENDPOINT
echo "==> Set environment variables for web apps"
-# Create directory for direct modifications
+# Create directory for configuration files
+mkdir -p /app/data/public
mkdir -p /app/data/scripts
-# Create a script that will directly define the ENTE_CONFIG global in window
-cat > /app/data/scripts/ente-config.js < Setting up direct runtime configuration"
-
-# Global API endpoint
-API_ENDPOINT="${CLOUDRON_APP_ORIGIN}/api"
-echo "==> Setting API endpoint to $API_ENDPOINT"
-
-# Create runtime configuration files
-mkdir -p /app/data/runtime
-echo "==> Creating runtime configuration files"
-
-# Create a config script
-cat > /app/data/runtime/config.js < Attempting to directly modify web app HTML files"
-WEB_APPS=("/app/web/photos" "/app/web/accounts" "/app/web/auth" "/app/web/cast")
-
-for app_dir in "${WEB_APPS[@]}"; do
- if [ -f "$app_dir/index.html" ]; then
- echo "==> Processing $app_dir/index.html"
-
- # Create a backup copy in our data directory
- mkdir -p "/app/data/original/$(basename $app_dir)"
- cp "$app_dir/index.html" "/app/data/original/$(basename $app_dir)/index.html"
-
- # Create a modified version of the file in our data directory
- mkdir -p "/app/data/modified/$(basename $app_dir)"
- cp "$app_dir/index.html" "/app/data/modified/$(basename $app_dir)/index.html"
-
- # Insert our configuration script into the head section
- sed -i 's|||' "/app/data/modified/$(basename $app_dir)/index.html"
-
- # Try to replace the original file (may fail if read-only)
- if cp "/app/data/modified/$(basename $app_dir)/index.html" "$app_dir/index.html" 2>/dev/null; then
- echo "==> Successfully modified $app_dir/index.html"
- else
- echo "==> Could not modify $app_dir/index.html (read-only filesystem)"
- fi
- else
- echo "==> Skipping $app_dir - index.html not found"
- fi
-done
-
-# Second approach: Create a modified copy that Caddy will serve
-mkdir -p /app/data/public
-cp /app/data/runtime/config.js /app/data/public/
-echo "==> Created public configuration script"
-
-# Create a loading page for each app with configuration
-for app_name in "photos" "accounts" "auth" "cast"; do
- cat > "/app/data/public/${app_name}-config.html" <
-
-
-
- Loading ${app_name}
-
-
-
-
- Loading ${app_name}...
- If you are not redirected automatically, click here.
- Debug Information
-
-
-EOT
-done
-
-# Create root index.html that loads config and redirects
-cat > /app/data/public/index.html <
-
-
-
- Ente
-
-
-
-
- Loading Ente...
- You will be redirected automatically.
- Debug Information
-
-
-EOT
-
-echo "==> Created special root index.html with configuration"
-
-# Check port availability before starting services
-echo "==> Checking port availability"
-CADDY_PORT=3080
-API_PORT=8080
-
-# Check if ports are already in use
-if lsof -i:$CADDY_PORT > /dev/null 2>&1; then
- echo "==> WARNING: Port $CADDY_PORT is already in use"
- echo "===> Process using port $CADDY_PORT:"
- lsof -i:$CADDY_PORT
-else
- echo "==> Port $CADDY_PORT is available for Caddy"
-fi
-
-if lsof -i:$API_PORT > /dev/null 2>&1; then
- echo "==> WARNING: Port $API_PORT is already in use"
- echo "===> Process using port $API_PORT:"
- lsof -i:$API_PORT
-else
- echo "==> Port $API_PORT is available for API server"
-fi
-
-# Set up Caddy
-echo "==> Setting up Caddy server for web apps"
-mkdir -p /app/data/caddy/public
-cat > /app/data/caddy/Caddyfile < Caddy configuration created at /app/data/caddy/Caddyfile"
-
-# Start Caddy first before the Museum server to ensure port 3080 is available for health checks
-echo "==> Setting up Caddy before starting the Museum server"
-echo "==> Caddy will be listening on port $CADDY_PORT"
-
-# Only set permissions on the Caddy directory, not the web directory which is read-only
-mkdir -p /app/data/caddy
-chmod -R 777 /app/data/caddy
-chown -R cloudron:cloudron /app/data/caddy
-
-# Start Caddy server
-echo "==> Starting Caddy server..."
-caddy run --config /app/data/caddy/Caddyfile --adapter caddyfile &
-CADDY_PID=$!
-echo "==> Caddy started with PID $CADDY_PID"
-
-# Wait a moment for Caddy to start
-sleep 2
-
-# Test Caddy connectivity
-echo "==> Testing Caddy connectivity on port $CADDY_PORT"
-for i in {1..5}; do
- if curl -s --max-time 2 --head --fail http://localhost:$CADDY_PORT/health > /dev/null; then
- echo "==> Caddy is running properly on port $CADDY_PORT"
- break
- else
- if [ $i -eq 5 ]; then
- echo "==> Failed to connect to Caddy on port $CADDY_PORT after multiple attempts"
- echo "==> Last 20 lines of Caddy log:"
- tail -20 /app/data/caddy/caddy.log || echo "==> No Caddy log available"
- echo "==> Network ports in use:"
- netstat -tuln || echo "==> netstat command not available"
- echo "==> Processes listening on ports:"
- lsof -i -P -n | grep LISTEN || echo "==> lsof command not available"
- else
- echo "==> Attempt $i: Waiting for Caddy to start... (1 second)"
- sleep 1
- fi
- fi
-done
-
-# Determine available memory and set limits accordingly
-if [[ -f /sys/fs/cgroup/cgroup.controllers ]]; then # cgroup v2
- memory_limit=$(cat /sys/fs/cgroup/memory.max)
- [[ "${memory_limit}" == "max" ]] && memory_limit=$(( 2 * 1024 * 1024 * 1024 )) # "max" really means unlimited
-else
- memory_limit=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes) # this is the RAM. we have equal amount of swap
-fi
-memory_mb=$((memory_limit/1024/1024))
-echo "==> Available memory: ${memory_mb}MB"
-
-# Set up database environment variables and ensure proper SSL config
-export ENTE_DB_USER="${CLOUDRON_POSTGRESQL_USERNAME}"
-export ENTE_DB_PASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}"
-export ENTE_DB_HOST="${CLOUDRON_POSTGRESQL_HOST}"
-export ENTE_DB_PORT="${CLOUDRON_POSTGRESQL_PORT}"
-export ENTE_DB_NAME="${CLOUDRON_POSTGRESQL_DATABASE}"
-export ENTE_DB_SSLMODE="disable"
-export CONFIG_PATH="/app/data/config/config.yaml"
-
-# Check database connectivity
-echo "==> Checking database connectivity"
-MAX_RETRIES=5
-RETRY_COUNT=0
-while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
- if PGPASSWORD="${CLOUDRON_POSTGRESQL_PASSWORD}" psql -h "${CLOUDRON_POSTGRESQL_HOST}" -p "${CLOUDRON_POSTGRESQL_PORT}" \
- -U "${CLOUDRON_POSTGRESQL_USERNAME}" -d "${CLOUDRON_POSTGRESQL_DATABASE}" -c "SELECT 1" > /dev/null 2>&1; then
- echo "==> Successfully connected to database"
- break
- else
- echo "==> Failed to connect to database (attempt $((RETRY_COUNT+1))/$MAX_RETRIES)"
- RETRY_COUNT=$((RETRY_COUNT+1))
- sleep 5
- fi
-done
-
-if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
- echo "==> ERROR: Could not connect to database after $MAX_RETRIES attempts"
- echo "==> Database connection details:"
- echo "Host: ${CLOUDRON_POSTGRESQL_HOST}"
- echo "Port: ${CLOUDRON_POSTGRESQL_PORT}"
- echo "User: ${CLOUDRON_POSTGRESQL_USERNAME}"
- echo "Database: ${CLOUDRON_POSTGRESQL_DATABASE}"
- exit 1
-fi
-
-# Fix database migration state if needed
-echo "==> Checking database migration state"
-if [ -d "$SERVER_DIR/cmd/museum" ]; then
- echo "==> Attempting to fix dirty migration state"
- cd "$SERVER_DIR"
-
- # Create migrations log directory
- mkdir -p /app/data/logs/migrations
-
- echo "==> Forcing migration version to 25"
- if /usr/local/bin/gosu cloudron:cloudron env GOCACHE=/app/data/go/cache GOMODCACHE=/app/data/go/pkg/mod \
- go run -modfile=/app/data/go/go.mod -mod=mod cmd/museum/main.go migrate force 25 \
- > /app/data/logs/migrations/force.log 2>&1; then
- echo "==> Successfully forced migration version"
- else
- echo "==> Failed to force migration version. Check /app/data/logs/migrations/force.log for details"
- cat /app/data/logs/migrations/force.log
- fi
-
- echo "==> Running clean migrations"
- if /usr/local/bin/gosu cloudron:cloudron env GOCACHE=/app/data/go/cache GOMODCACHE=/app/data/go/pkg/mod \
- go run -modfile=/app/data/go/go.mod -mod=mod cmd/museum/main.go migrate up \
- > /app/data/logs/migrations/up.log 2>&1; then
- echo "==> Successfully ran migrations"
- else
- echo "==> Failed to run migrations. Check /app/data/logs/migrations/up.log for details"
- cat /app/data/logs/migrations/up.log
- echo "==> WARNING: Database migrations failed. The application may not work correctly."
- fi
-fi
-
-# Additional environment variables
-export REMOTE_STORAGE_ENDPOINT="${S3_ENDPOINT}"
-export REMOTE_STORAGE_REGION="${S3_REGION}"
-export REMOTE_STORAGE_BUCKET="${S3_BUCKET}"
-export REMOTE_STORAGE_ACCESS_KEY="${S3_ACCESS_KEY}"
-export REMOTE_STORAGE_SECRET_KEY="${S3_SECRET_KEY}"
-export REMOTE_STORAGE_PREFIX="${S3_PREFIX:-}"
-
-# Change ownership to cloudron user
-chown -R cloudron:cloudron /app/data
-
-# Start Museum server on port 8080 for compatibility with the Caddy configuration
-echo "==> Starting Museum server"
-
-# Modify environment variables for frontend
-echo "==> Setting up environment variables for frontend"
-# Set frontend endpoint to the proper origin
-export NEXT_PUBLIC_ENTE_ENDPOINT="${CLOUDRON_APP_ORIGIN}/api"
-echo "==> NEXT_PUBLIC_ENTE_ENDPOINT set to ${NEXT_PUBLIC_ENTE_ENDPOINT}"
-
-# Also create a direct config in multiple formats to ensure it's properly loaded
-echo "==> Creating runtime configuration for the web apps in multiple formats"
-mkdir -p /app/data/runtime
-
-# 1. Standard config.js
-cat > /app/data/runtime/config.js < /app/data/runtime/config.json < /app/data/runtime/env.js < Generated config.js content:"
-cat /app/data/runtime/config.js
-
-# First check for pre-built Museum binary
-if find "$SERVER_DIR" -name "museum" -type f -executable | grep -q .; then
- MUSEUM_BIN=$(find "$SERVER_DIR" -name "museum" -type f -executable | head -1)
- echo "==> Found Museum binary at $MUSEUM_BIN"
- /usr/local/bin/gosu cloudron:cloudron "$MUSEUM_BIN" --port 8080 \
- --storage.s3.endpoint="${S3_ENDPOINT}" \
- --storage.s3.region="${S3_REGION}" \
- --storage.s3.bucket="${S3_BUCKET}" \
- --storage.s3.accessKey="${S3_ACCESS_KEY}" \
- --storage.s3.secretKey="${S3_SECRET_KEY}" \
- --storage.s3.prefix="${S3_PREFIX:-}" \
- --storage.s3.forcePathStyle=true \
- --storage.s3.areLocalBuckets=false \
- --storage.type="s3" \
- --config.path="/app/data/config/museum.yaml" \
- --database.sslmode="disable" > /app/data/logs/museum-server.log 2>&1 &
- SERVER_PID=$!
- echo "==> Museum server started with PID $SERVER_PID"
-# Next check for cmd/museum directory pattern
-elif [ -d "$SERVER_DIR/cmd/museum" ]; then
- echo "==> Found Museum source in cmd/museum, running with go run"
- cd "$SERVER_DIR"
-
- # Set environment variables for compatibility
- echo "==> Setting Go environment variables for compatibility"
- export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod -modcacherw"
- # Use local toolchain to avoid downloading required version
- export GOTOOLCHAIN=local
-
- # Launch the server with S3 configuration
- echo "==> Starting Museum server with S3 configuration"
- cd "$SERVER_DIR" && \
- /usr/local/bin/gosu cloudron:cloudron env GOCACHE=/app/data/go/cache GOMODCACHE=/app/data/go/pkg/mod PORT=8080 GIN_MODE=release go run -modfile=/app/data/go/go.mod -mod=mod cmd/museum/main.go --port 8080 \
- --storage.s3.endpoint="${S3_ENDPOINT}" \
- --storage.s3.region="${S3_REGION}" \
- --storage.s3.bucket="${S3_BUCKET}" \
- --storage.s3.accessKey="${S3_ACCESS_KEY}" \
- --storage.s3.secretKey="${S3_SECRET_KEY}" \
- --storage.s3.prefix="${S3_PREFIX:-}" \
- --storage.s3.forcePathStyle=true \
- --storage.s3.areLocalBuckets=false \
- --storage.type="s3" \
- --config.path="/app/data/config/museum.yaml" \
- --database.sslmode="disable" \
- --log.level=debug > /app/data/logs/museum-server.log 2>&1 &
- SERVER_PID=$!
- echo "==> Museum server started with PID $SERVER_PID"
-
- # Wait for the server to start
- echo "==> Waiting for Museum server to start..."
- sleep 5
-
- # Test if API is responding
- MAX_RETRIES=5
- RETRY_COUNT=0
- while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
- echo "==> Testing API connection (attempt $((RETRY_COUNT+1))/$MAX_RETRIES)"
- if curl -s http://localhost:8080/api/health > /dev/null; then
- echo "==> API is now responding"
- break
- else
- echo "==> API not responding yet, waiting..."
- RETRY_COUNT=$((RETRY_COUNT+1))
- sleep 5
- # Print recent log output
- echo "==> Recent server log output:"
- tail -n 20 /app/data/logs/museum-server.log || echo "==> No logs available yet"
- fi
- done
-
- if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
- echo "==> WARNING: API server did not respond after multiple attempts"
- echo "==> Checking server logs:"
- ps -p $SERVER_PID >/dev/null || echo "==> ERROR: Server process is not running!"
- tail -n 50 /app/data/logs/museum-server.log || echo "==> No logs available"
- fi
-
-# Next try to find any main.go for the Museum
-else
- # Fallback approach - find main.go files
- MAIN_FILES=$(find "$SERVER_DIR" -name "main.go" | grep -v "test" || echo "")
- if [ -n "$MAIN_FILES" ]; then
- MAIN_FILE=$(echo "$MAIN_FILES" | head -1)
- MAIN_DIR=$(dirname "$MAIN_FILE")
- echo "==> Using main.go file at $MAIN_FILE"
- cd "$MAIN_DIR"
-
- # Instead of trying to modify go.mod, set environment variables for compatibility
- echo "==> Setting Go environment variables for compatibility"
- export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod -modcacherw"
- export GOTOOLCHAIN=local
-
- echo "==> Running main.go with Go"
- cd "$MAIN_DIR" && \
- /usr/local/bin/gosu cloudron:cloudron env GOCACHE=/app/data/go/cache GOMODCACHE=/app/data/go/pkg/mod PORT=8080 GIN_MODE=release go run -modfile=/app/data/go/go.mod -mod=mod main.go --port 8080 \
- --storage.s3.endpoint="${S3_ENDPOINT}" \
- --storage.s3.region="${S3_REGION}" \
- --storage.s3.bucket="${S3_BUCKET}" \
- --storage.s3.accessKey="${S3_ACCESS_KEY}" \
- --storage.s3.secretKey="${S3_SECRET_KEY}" \
- --storage.s3.prefix="${S3_PREFIX:-}" \
- --storage.s3.forcePathStyle=true \
- --storage.s3.areLocalBuckets=false \
- --storage.type="s3" \
- --config.path="/app/data/config/museum.yaml" \
- --database.sslmode="disable" \
- --log.level=debug > /app/data/logs/museum-server.log 2>&1 &
- SERVER_PID=$!
- echo "==> Museum server started with PID $SERVER_PID"
-
- # Check if the server process is actually running after a brief pause
- sleep 2
- if ! ps -p $SERVER_PID > /dev/null; then
- echo "==> WARNING: Server process exited immediately"
- echo "==> Recent server log output:"
- tail -n 50 /app/data/logs/museum-server.log || echo "==> No logs available yet"
- echo "==> Falling back to mock server"
- SERVER_PID=""
- fi
- else
- echo "==> ERROR: Could not find Museum binary or main.go source file"
- echo "==> Available Go files:"
- find "$SERVER_DIR" -name "*.go" | sort
-
- SERVER_PID=""
- fi
-fi
-
-# If server didn't start successfully, use mock server
-if [ -z "$SERVER_PID" ] || ! ps -p $SERVER_PID > /dev/null; then
- echo "==> Starting mock server as fallback"
- # Last resort - create a temporary Go HTTP server that returns a meaningful error
- mkdir -p /tmp/mock-server
- cat > /tmp/mock-server/main.go <The Ente Museum server could not be started due to compatibility issues.
"
- html += "Please check the application logs for more information.
"
- html += "