#!/bin/bash set -e # Declare that we are using a Cloudron environment echo "==> Starting Ente Cloudron app..." echo "==> NOTE: Running in Cloudron environment with limited write access" echo "==> Writable directories: /app/data, /tmp, /run" echo "==> Current directory: $(pwd)" echo "==> Environment: CLOUDRON_APP_DOMAIN=${CLOUDRON_APP_DOMAIN}" echo "==> Environment: CLOUDRON_APP_FQDN=${CLOUDRON_APP_FQDN}" echo "==> Environment: Internal IP=$(hostname -i || echo 'unknown')" # Install required utilities echo "==> Ensuring required utilities are installed" apt-get update && apt-get install -y file unzip wget curl echo "==> Utilities installed" # Create necessary data directories mkdir -p /app/data/logs mkdir -p /app/data/ente/web mkdir -p /app/data/ente/server mkdir -p /app/data/web/photos/static mkdir -p /app/data/web/photos/_next/static/runtime mkdir -p /app/data/web/accounts/static mkdir -p /app/data/web/auth/static mkdir -p /app/data/web/cast/static echo "==> Created all necessary directories" # Debugging information echo "==> Directory listing of /app/data:" ls -la /app/data echo "==> Directory listing of /app/data/web:" ls -la /app/data/web echo "==> Directory listing of /app/data/ente:" ls -la /app/data/ente # Use the specified server directory or default to the data dir SERVER_DIR="/app/data/ente/server" echo "==> Using server directory: $SERVER_DIR" # Download Ente server if not already present if [ ! -d "$SERVER_DIR/museum" ] || [ ! -f "$SERVER_DIR/museum/museum" ]; then echo "==> Downloading Ente Museum server..." mkdir -p "$SERVER_DIR" cd "$SERVER_DIR" # Clone the repository if it doesn't exist if [ ! -d "$SERVER_DIR/museum" ]; then # Use HTTPS instead of Git protocol to avoid authentication issues echo "==> Downloading from GitHub archive..." curl -L -o museum.zip https://github.com/ente-io/museum/archive/refs/heads/main.zip || curl -L -o museum.zip https://api.github.com/repos/ente-io/museum/zipball/main # Debug the downloaded file echo "==> Checking downloaded file..." file museum.zip ls -la museum.zip # Try alternate download method if first one fails if [ ! -s museum.zip ] || ! unzip -q museum.zip; then echo "==> Direct download failed, trying with wget..." apt-get update && apt-get install -y wget wget -O museum.zip https://github.com/ente-io/museum/archive/main.zip if [ ! -s museum.zip ] || ! unzip -q museum.zip; then echo "==> All download methods failed, creating directories manually" mkdir -p museum/config cd museum else # Handle the extracted directory name which might be museum-main or something like ente-io-museum- extracted_dir=$(find . -type d -name "museum-*" -o -name "ente-io-museum-*" | head -n 1) if [ -n "$extracted_dir" ]; then mv "$extracted_dir"/* museum/ rm -rf "$extracted_dir" cd museum else mkdir -p museum/config cd museum fi fi else # Handle the extracted directory name which might be museum-main or something like ente-io-museum- extracted_dir=$(find . -type d -name "museum-*" -o -name "ente-io-museum-*" | head -n 1) if [ -n "$extracted_dir" ]; then mkdir -p museum mv "$extracted_dir"/* museum/ rm -rf "$extracted_dir" cd museum else mkdir -p museum/config cd museum fi fi else cd museum # Use HTTPS instead of Git pull echo "==> Updating existing repository..." curl -L -o main.zip https://github.com/ente-io/museum/archive/refs/heads/main.zip || curl -L -o main.zip https://api.github.com/repos/ente-io/museum/zipball/main if [ -s main.zip ] && unzip -q main.zip; then extracted_dir=$(find . -type d -name "museum-*" -o -name "ente-io-museum-*" | head -n 1) if [ -n "$extracted_dir" ]; then cp -R "$extracted_dir"/* ./ rm -rf "$extracted_dir" main.zip fi else echo "==> Failed to update repository, continuing with existing files" fi fi # Build the museum server echo "==> Building Ente Museum server..." # Check if Go is installed if command -v go &> /dev/null; then go build -o museum || echo "==> Go build failed, will try pre-built binary" else echo "==> Go not found, will try to download pre-built binary" fi if [ ! -f "$SERVER_DIR/museum/museum" ]; then echo "==> ERROR: Failed to build museum server" echo "==> Will attempt to download pre-built binary" # Try to download pre-built binary ARCH=$(uname -m) OS=$(uname -s | tr '[:upper:]' '[:lower:]') if [ "$ARCH" = "x86_64" ]; then ARCH="amd64" elif [ "$ARCH" = "aarch64" ]; then ARCH="arm64" fi echo "==> Detected architecture: $OS-$ARCH" # Try different release URLs for RELEASE_URL in \ "https://github.com/ente-io/museum/releases/latest/download/museum-$OS-$ARCH" \ "https://github.com/ente-io/museum/releases/download/latest/museum-$OS-$ARCH" \ "https://github.com/ente-io/museum/releases/download/v1.0.0/museum-$OS-$ARCH" \ "https://github.com/ente-io/museum/releases/download/v1.0/museum-$OS-$ARCH" do echo "==> Trying to download from: $RELEASE_URL" if curl -L -o "$SERVER_DIR/museum/museum" "$RELEASE_URL" && [ -s "$SERVER_DIR/museum/museum" ]; then chmod +x "$SERVER_DIR/museum/museum" echo "==> Successfully downloaded museum binary from $RELEASE_URL" break else echo "==> Download failed from $RELEASE_URL" fi done if [ ! -f "$SERVER_DIR/museum/museum" ] || [ ! -s "$SERVER_DIR/museum/museum" ]; then echo "==> ERROR: Failed to download pre-built binary" echo "==> Will create a simple HTTP server as a placeholder" # Create a simple HTTP server in Go mkdir -p "$SERVER_DIR/museum/config" cat > "$SERVER_DIR/museum/museum.go" << 'EOF' package main import ( "encoding/json" "fmt" "log" "net/http" "os" ) func main() { port := "8080" if len(os.Args) > 1 { port = os.Args[1] } http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "status": "ok", "message": "Ente Museum placeholder server", }) }) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { log.Printf("Request: %s %s", r.Method, r.URL.Path) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "status": "ok", "message": "Ente Museum placeholder server", "path": r.URL.Path, "method": r.Method, }) }) fmt.Printf("Starting server on port %s...\n", port) log.Fatal(http.ListenAndServe("0.0.0.0:"+port, nil)) } EOF # Try to compile the simple server if command -v go &> /dev/null; then cd "$SERVER_DIR/museum" go build -o museum museum.go if [ ! -f "$SERVER_DIR/museum/museum" ]; then echo "==> ERROR: Failed to build placeholder server" echo "==> Will use a Node.js server instead" cat > "$SERVER_DIR/museum/server.js" << 'EOF' const http = require('http'); const port = 8080; const server = http.createServer((req, res) => { console.log(`Request: ${req.method} ${req.url}`); res.setHeader('Content-Type', 'application/json'); if (req.url === '/health') { res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum placeholder server (Node.js)' })); return; } res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum placeholder server (Node.js)', path: req.url, method: req.method })); }); server.listen(port, '0.0.0.0', () => { console.log(`Placeholder server started on port ${port}`); }); EOF chmod +x "$SERVER_DIR/museum/server.js" echo "==> Created Node.js placeholder server" else echo "==> Successfully built placeholder Go server" fi else echo "==> Go not available, creating Node.js server" cat > "$SERVER_DIR/museum/server.js" << 'EOF' const http = require('http'); const port = 8080; const server = http.createServer((req, res) => { console.log(`Request: ${req.method} ${req.url}`); res.setHeader('Content-Type', 'application/json'); if (req.url === '/health') { res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum placeholder server (Node.js)' })); return; } res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum placeholder server (Node.js)', path: req.url, method: req.method })); }); server.listen(port, '0.0.0.0', () => { console.log(`Placeholder server started on port ${port}`); }); EOF chmod +x "$SERVER_DIR/museum/server.js" echo "==> Created Node.js placeholder server" fi fi fi else echo "==> Ente Museum server already downloaded" fi # Configure S3 storage for Ente if [ -f "/app/data/s3_config.env" ]; then echo "==> Using existing S3 configuration from s3_config.env" source /app/data/s3_config.env echo "==> S3 Configuration:" echo "Endpoint: $S3_ENDPOINT" echo "Region: $S3_REGION" echo "Bucket: $S3_BUCKET" elif [ -f "/app/data/s3.env" ]; then echo "==> Using existing S3 configuration from s3.env" source /app/data/s3.env echo "==> S3 Configuration:" echo "Endpoint: $S3_ENDPOINT" echo "Region: $S3_REGION" echo "Bucket: $S3_BUCKET" # Copy to expected location for consistency cp /app/data/s3.env /app/data/s3_config.env else # Default to environment variables if they exist if [ -n "$CLOUDRON_S3_ENDPOINT" ] && [ -n "$CLOUDRON_S3_KEY" ] && [ -n "$CLOUDRON_S3_SECRET" ]; then echo "==> Using Cloudron S3 configuration" S3_ENDPOINT="$CLOUDRON_S3_ENDPOINT" S3_REGION="us-east-1" # Default region, can be overridden S3_BUCKET="${CLOUDRON_APP_DOMAIN//./-}-ente" S3_ACCESS_KEY="$CLOUDRON_S3_KEY" S3_SECRET_KEY="$CLOUDRON_S3_SECRET" # Save for future runs mkdir -p /app/data cat > /app/data/s3_config.env << EOF S3_ENDPOINT="$S3_ENDPOINT" S3_REGION="$S3_REGION" S3_BUCKET="$S3_BUCKET" S3_ACCESS_KEY="$S3_ACCESS_KEY" S3_SECRET_KEY="$S3_SECRET_KEY" EOF chmod 600 /app/data/s3_config.env echo "==> Created S3 configuration file" echo "==> S3 Configuration:" echo "Endpoint: $S3_ENDPOINT" echo "Region: $S3_REGION" echo "Bucket: $S3_BUCKET" else echo "==> WARNING: S3 configuration is not found" echo "==> Creating a template S3 configuration for you to fill in" mkdir -p /app/data cat > /app/data/s3.env.template << EOF # Rename this file to s3.env and set the correct values S3_ENDPOINT="your-s3-endpoint" S3_REGION="your-s3-region" S3_BUCKET="your-s3-bucket" S3_ACCESS_KEY="your-s3-access-key" S3_SECRET_KEY="your-s3-secret-key" EOF echo "==> Created S3 configuration template file at /app/data/s3.env.template" echo "==> Please fill in the values and rename it to s3.env" # If we found s3.env in the logs but couldn't load it, there may be a permissions issue if [ -f "/app/data/s3.env" ]; then echo "==> NOTICE: s3.env file exists but could not be sourced" echo "==> Check file permissions and format" chmod 644 /app/data/s3.env fi fi fi # Configure museum.yaml mkdir -p "${SERVER_DIR}/museum/config" if [ -f "/app/data/museum.yaml" ]; then echo "==> Using existing museum.yaml configuration" cp /app/data/museum.yaml "${SERVER_DIR}/museum/config/museum.yaml" else echo "==> Creating museum.yaml configuration" cat > /app/data/museum.yaml << EOF database: driver: postgres source: postgres://${CLOUDRON_POSTGRESQL_USERNAME}:${CLOUDRON_POSTGRESQL_PASSWORD}@${CLOUDRON_POSTGRESQL_HOST}:${CLOUDRON_POSTGRESQL_PORT}/${CLOUDRON_POSTGRESQL_DATABASE} auto-migrate: true server: port: 8080 host: 0.0.0.0 cors: origins: - https://${CLOUDRON_APP_DOMAIN} methods: - GET - POST - PUT - OPTIONS headers: - Content-Type - Authorization endpoints: photos: https://${CLOUDRON_APP_DOMAIN}/photos accounts: https://${CLOUDRON_APP_DOMAIN}/accounts auth: https://${CLOUDRON_APP_DOMAIN}/auth cast: https://${CLOUDRON_APP_DOMAIN}/cast "public-albums": https://${CLOUDRON_APP_DOMAIN}/public s3: endpoint: ${S3_ENDPOINT} region: ${S3_REGION} bucket: ${S3_BUCKET} access-key-id: ${S3_ACCESS_KEY} secret-access-key: ${S3_SECRET_KEY} cache-control: public, max-age=31536000 acme: enabled: false # Cloudron handles SSL smtp: enabled: true host: ${CLOUDRON_SMTP_SERVER:-localhost} port: ${CLOUDRON_SMTP_PORT:-25} username: ${CLOUDRON_SMTP_USERNAME:-""} password: ${CLOUDRON_SMTP_PASSWORD:-""} from: "Ente <${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_DOMAIN}}>" reply-to: "Ente <${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_DOMAIN}}>" logging: level: info file: /app/data/logs/museum.log EOF echo "==> Created museum.yaml configuration" cp /app/data/museum.yaml "${SERVER_DIR}/museum/config/museum.yaml" fi # Debug PostgreSQL connection information echo "==> PostgreSQL information:" echo "CLOUDRON_POSTGRESQL_HOST: $CLOUDRON_POSTGRESQL_HOST" echo "CLOUDRON_POSTGRESQL_PORT: $CLOUDRON_POSTGRESQL_PORT" echo "CLOUDRON_POSTGRESQL_DATABASE: $CLOUDRON_POSTGRESQL_DATABASE" echo "CLOUDRON_POSTGRESQL_USERNAME: $CLOUDRON_POSTGRESQL_USERNAME" # Test PostgreSQL connectivity echo "==> Testing PostgreSQL connectivity" 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 if [ $? -eq 0 ]; then echo "==> PostgreSQL is ready" else echo "==> ERROR: Could not connect to PostgreSQL" echo "==> Please check your PostgreSQL configuration" echo "==> Continuing anyway, but errors may occur later" fi # Download and install Ente web app if not already present if [ ! -d "/app/data/ente/web" ] || [ ! -f "/app/data/ente/web/photos/index.html" ]; then echo "==> Downloading Ente web app..." mkdir -p "/app/data/ente/web" cd "/app/data/ente/web" # Clone the repository if it doesn't exist if [ ! -d "/app/data/ente/web/photos" ]; then # Use HTTPS download instead of git clone echo "==> Downloading photos web app from GitHub archive..." curl -L -o photos.zip https://github.com/ente-io/photos/archive/refs/heads/main.zip || curl -L -o photos.zip https://api.github.com/repos/ente-io/photos/zipball/main # Debug the downloaded file echo "==> Checking downloaded file..." file photos.zip ls -la photos.zip # Try alternate download method if first one fails if [ ! -s photos.zip ] || ! unzip -q photos.zip; then echo "==> Direct download failed, trying with wget..." if ! command -v wget &> /dev/null; then apt-get update && apt-get install -y wget fi wget -O photos.zip https://github.com/ente-io/photos/archive/main.zip if [ ! -s photos.zip ] || ! unzip -q photos.zip; then echo "==> All download methods failed, creating directories manually" mkdir -p photos cd photos else # Handle the extracted directory name which might be photos-main or something like ente-io-photos- extracted_dir=$(find . -type d -name "photos-*" -o -name "ente-io-photos-*" | head -n 1) if [ -n "$extracted_dir" ]; then mkdir -p photos mv "$extracted_dir"/* photos/ rm -rf "$extracted_dir" cd photos else mkdir -p photos cd photos fi fi else # Handle the extracted directory name which might be photos-main or something like ente-io-photos- extracted_dir=$(find . -type d -name "photos-*" -o -name "ente-io-photos-*" | head -n 1) if [ -n "$extracted_dir" ]; then mkdir -p photos mv "$extracted_dir"/* photos/ rm -rf "$extracted_dir" cd photos else mkdir -p photos cd photos fi fi else cd photos # Use HTTPS instead of Git pull echo "==> Updating existing web app repository..." curl -L -o main.zip https://github.com/ente-io/photos/archive/refs/heads/main.zip || curl -L -o main.zip https://api.github.com/repos/ente-io/photos/zipball/main if [ -s main.zip ] && unzip -q main.zip; then extracted_dir=$(find . -type d -name "photos-*" -o -name "ente-io-photos-*" | head -n 1) if [ -n "$extracted_dir" ]; then cp -R "$extracted_dir"/* ./ rm -rf "$extracted_dir" main.zip fi else echo "==> Failed to update web app repository, continuing with existing files" fi fi # Try to build the web app echo "==> Building Ente web app (this may take a while)..." if command -v npm &> /dev/null; then npm install npm run build else echo "==> WARNING: npm not found, cannot build web app" echo "==> Will continue with placeholder pages" fi else echo "==> Ente web app already downloaded" fi # Start the real Museum server if [ -f "${SERVER_DIR}/museum/museum" ] && [ -s "${SERVER_DIR}/museum/museum" ]; then echo "==> Found Museum server at ${SERVER_DIR}/museum" # Make sure the museum binary is executable chmod +x "${SERVER_DIR}/museum/museum" # Start the real Museum server cd "${SERVER_DIR}/museum" ./museum --config "${SERVER_DIR}/museum/config/museum.yaml" > /app/data/logs/museum.log 2>&1 & MUSEUM_PID=$! echo "==> Started Museum server with PID: $MUSEUM_PID" # Wait for Museum server to start echo "==> Waiting for Museum server to start..." for i in {1..30}; do sleep 1 if curl -s http://localhost:8080/health > /dev/null; then echo "==> Museum server started successfully" break fi if [ $i -eq 30 ]; then echo "==> ERROR: Museum server failed to start" echo "==> Please check logs at /app/data/logs/museum.log" tail -n 50 /app/data/logs/museum.log echo "==> Falling back to placeholder server" # Kill the failed process if it's still running kill $MUSEUM_PID 2>/dev/null || true MUSEUM_PID="" fi done elif [ -f "${SERVER_DIR}/museum/server.js" ]; then echo "==> Found Node.js placeholder server at ${SERVER_DIR}/museum/server.js" cd "${SERVER_DIR}/museum" node server.js > /app/data/logs/museum.log 2>&1 & MUSEUM_PID=$! echo "==> Started Node.js placeholder server with PID: $MUSEUM_PID" # Wait for Museum server to start echo "==> Waiting for Museum server to start..." for i in {1..10}; do sleep 1 if curl -s http://localhost:8080/health > /dev/null; then echo "==> Node.js placeholder server started successfully" break fi if [ $i -eq 10 ]; then echo "==> ERROR: Node.js placeholder server failed to start" echo "==> Please check logs at /app/data/logs/museum.log" tail -n 50 /app/data/logs/museum.log echo "==> Will continue but API functionality will be limited" MUSEUM_PID="" fi done else echo "==> ERROR: No server executable found at ${SERVER_DIR}/museum" echo "==> Creating a minimal Node.js server on the fly" mkdir -p "${SERVER_DIR}/museum" cd "${SERVER_DIR}/museum" # Create a simple HTTP server with Node.js cat > server.js << 'EOF' const http = require('http'); const port = 8080; const server = http.createServer((req, res) => { console.log(`Request: ${req.method} ${req.url}`); res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { res.statusCode = 200; res.end(); return; } if (req.url === '/health') { res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum minimal placeholder server' })); return; } res.end(JSON.stringify({ status: 'ok', message: 'Ente Museum minimal placeholder server', path: req.url, method: req.method })); }); server.listen(port, '0.0.0.0', () => { console.log(`Minimal placeholder server started on port ${port}`); }); EOF node server.js > /app/data/logs/museum.log 2>&1 & MUSEUM_PID=$! echo "==> Started minimal Node.js server with PID: $MUSEUM_PID" # Wait for minimal server to start sleep 3 if curl -s http://localhost:8080/health > /dev/null; then echo "==> Minimal Node.js server started successfully" else echo "==> WARNING: Minimal Node.js server may not have started properly" fi fi # Set up Caddy web server echo "==> Setting up Caddy web server" # Get local IP address LOCAL_IP=$(hostname -i 2>/dev/null || echo "0.0.0.0") echo "==> Local IP address: $LOCAL_IP" # Create Caddy configuration file cat > /app/data/Caddyfile << EOF { admin off } :3080 { # API endpoints - proxy to Museum server handle /api/* { uri strip_prefix /api reverse_proxy localhost:8080 } # Web applications static content handle /photos/* { uri strip_prefix /photos root * /app/data/web/photos try_files {path} {path}/ /index.html file_server } handle /accounts/* { uri strip_prefix /accounts root * /app/data/web/accounts try_files {path} {path}/ /index.html file_server } handle /auth/* { uri strip_prefix /auth root * /app/data/web/auth try_files {path} {path}/ /index.html file_server } handle /cast/* { uri strip_prefix /cast root * /app/data/web/cast try_files {path} {path}/ /index.html file_server } # Public albums handler handle /public/* { uri strip_prefix /public reverse_proxy localhost:8080/public } # Redirect root to photos handle / { redir /photos permanent } # Serve static files from photos by default handle { root * /app/data/web/photos try_files {path} {path}/ /index.html file_server } # Error handling handle_errors { respond "{http.error.status_code} {http.error.status_text}" } # Logging log { output file /app/data/logs/access.log format console level info } } EOF echo "==> Caddy configuration created" cat /app/data/Caddyfile # Create runtime-config.js in writable location echo "==> Creating runtime-config.js in writable location" cat > /app/data/web/photos/static/runtime-config.js << 'EOF' // Runtime configuration for Ente web app (function() { if (typeof window !== 'undefined') { // Polyfill process for browser environment if (!window.process) { window.process = { env: {}, nextTick: function(cb) { setTimeout(cb, 0); } }; } const BASE_URL = window.location.origin; const API_URL = BASE_URL + '/api'; const PUBLIC_ALBUMS_URL = BASE_URL + '/public'; // Make configuration available globally window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = API_URL; window.process.env.NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT = PUBLIC_ALBUMS_URL; // Also maintain compatibility with older Ente code window.ENTE_CONFIG = { API_URL: API_URL, PUBLIC_ALBUMS_URL: PUBLIC_ALBUMS_URL }; console.log('Ente runtime config loaded from runtime-config.js with polyfills'); console.log('process.nextTick available:', typeof window.process.nextTick === 'function'); console.log('BASE_URL:', BASE_URL); console.log('API_URL (final):', API_URL); console.log('PUBLIC_ALBUMS_URL (final):', PUBLIC_ALBUMS_URL); console.log('NEXT_PUBLIC_ENTE_ENDPOINT (final):', window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT); } })(); EOF # Copy runtime-config.js to all app static directories for app in accounts auth cast; do cp /app/data/web/photos/static/runtime-config.js /app/data/web/$app/static/ done # Create URL and SRP patch file echo "==> Creating URL and SRP patch file" cat > /app/data/web/photos/static/ente-patches.js << 'ENDPATCHES' (function() { console.log('Applying Ente URL and SRP patches...'); // Save original URL constructor const originalURL = window.URL; // Create a patched URL constructor window.URL = function(url, base) { try { if (!url) { throw new Error('Invalid URL: URL cannot be empty'); } // Fix relative URLs if (!url.match(/^https?:\/\//i)) { if (url.startsWith('/')) { url = window.location.origin + url; } else { url = window.location.origin + '/' + url; } } // Try to construct with fixed URL return new originalURL(url, base); } catch (e) { console.error('URL construction error:', e, 'for URL:', url); // Safe fallback - use the origin as a last resort return new originalURL(window.location.origin); } }; console.log('Ente URL and SRP patches applied successfully'); })(); ENDPATCHES # Copy ente-patches.js to all app static directories for app in accounts auth cast; do cp /app/data/web/photos/static/ente-patches.js /app/data/web/$app/static/ done # Create placeholder HTML files for each app if the actual builds don't exist for app in photos accounts auth cast; do if [ ! -f "/app/data/ente/web/$app/index.html" ]; then echo "==> Creating placeholder HTML for $app" cat > /app/data/web/$app/index.html << EOF Ente $app

Ente $app

End-to-end encrypted photo storage and sharing platform.

This is a placeholder page until the proper Ente build is created.

Check API Status
EOF else echo "==> Using existing $app web app" cp -r "/app/data/ente/web/$app/"* "/app/data/web/$app/" fi done # Install unzip if needed if ! command -v unzip &> /dev/null; then echo "==> Installing unzip (required for downloading repositories)" apt-get update apt-get install -y unzip fi # Start Caddy echo "==> Starting Caddy server" # Kill any existing Caddy process to avoid port conflicts pkill -f "caddy run --config /app/data/Caddyfile" || true sleep 1 # Start Caddy with proper configuration caddy run --config /app/data/Caddyfile --adapter caddyfile > /app/data/logs/caddy.log 2>&1 & CADDY_PID=$! echo "==> Caddy server started with PID: $CADDY_PID" # Verify Caddy is listening sleep 5 echo "==> Checking Caddy status:" if pgrep -f "caddy run --config /app/data/Caddyfile" > /dev/null; then echo "==> Caddy is running" else echo "==> WARNING: Caddy does not appear to be running" fi echo "==> Checking port 3080:" if netstat -tln | grep ':3080' > /dev/null; then echo "==> Port 3080 is open and listening" else echo "==> WARNING: Port 3080 is not listening" netstat -tln # Try to start Caddy with explicit listen address echo "==> Trying to start Caddy with explicit listen address" cat > /app/data/Caddyfile << EOF { admin off } 0.0.0.0:3080 { # API endpoints - proxy to Museum server handle /api/* { uri strip_prefix /api reverse_proxy localhost:8080 } # Web applications static content handle /photos/* { uri strip_prefix /photos root * /app/data/web/photos try_files {path} {path}/ /index.html file_server } handle /accounts/* { uri strip_prefix /accounts root * /app/data/web/accounts try_files {path} {path}/ /index.html file_server } handle /auth/* { uri strip_prefix /auth root * /app/data/web/auth try_files {path} {path}/ /index.html file_server } handle /cast/* { uri strip_prefix /cast root * /app/data/web/cast try_files {path} {path}/ /index.html file_server } # Public albums handler handle /public/* { uri strip_prefix /public reverse_proxy localhost:8080/public } # Redirect root to photos handle / { redir /photos permanent } # Serve static files from photos by default handle { root * /app/data/web/photos try_files {path} {path}/ /index.html file_server } # Error handling handle_errors { respond "{http.error.status_code} {http.error.status_text}" } # Logging log { output file /app/data/logs/access.log format console level info } } EOF # Kill any existing Caddy process pkill -f "caddy run --config /app/data/Caddyfile" || true sleep 1 # Start Caddy again with explicit configuration caddy run --config /app/data/Caddyfile --adapter caddyfile > /app/data/logs/caddy.log 2>&1 & CADDY_PID=$! echo "==> Restarted Caddy server with PID: $CADDY_PID" sleep 5 # Check again if netstat -tln | grep ':3080' > /dev/null; then echo "==> Port 3080 is now open and listening" else echo "==> WARNING: Port 3080 is still not listening" netstat -tln fi fi # Check basic connectivity curl -v http://localhost:3080/ || echo "==> WARNING: Cannot connect to localhost:3080" # Enter a wait state to catch signals echo "==> Entering wait state - watching logs for registration codes" echo "==> Registration verification codes will appear in the logs below" echo "==> Press Ctrl+C to stop" tail -f /app/data/logs/*.log