Commit 1c34047f authored by Andreas Düren's avatar Andreas Düren
Browse files

Fix Caddy port configuration and improve connectivity testing

parent 12b486ac
Loading
Loading
Loading
Loading
+199 −268
Original line number Diff line number Diff line
@@ -228,7 +228,173 @@ window.ENTE_CONFIG = {
console.log("Ente config loaded, API_URL =", window.ENTE_CONFIG.API_URL);
EOT

# Set up Caddy server
# Runtime configuration
echo "==> 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 <<EOT
// Direct configuration for Ente
window.ENTE_CONFIG = {
  API_URL: "${API_ENDPOINT}"
};

// Next.js environment variables
window.process = window.process || {};
window.process.env = window.process.env || {};
window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}";
window.process.env.REACT_APP_ENTE_ENDPOINT = "${API_ENDPOINT}";
window.process.env.VUE_APP_ENTE_ENDPOINT = "${API_ENDPOINT}";

console.log("Ente config loaded - API_URL:", window.ENTE_CONFIG.API_URL);
EOT

# First approach: Try to modify index.html files directly
echo "==> 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|</head>|<script src="/config.js"></script></head>|' "/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" <<EOT
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Loading ${app_name}</title>
  <script src="/debug.js"></script>
  <script>
    // Set the global configuration
    window.ENTE_CONFIG = {
      API_URL: "${API_ENDPOINT}"
    };
    
    // Set Next.js environment variables
    window.process = window.process || {};
    window.process.env = window.process.env || {};
    window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}";
    
    // Store in localStorage as a fallback mechanism
    localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG));
    localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}");
    
    // Log the configuration
    console.log("Ente ${app_name} config loaded:", window.ENTE_CONFIG);
    
    // Redirect to the main app after a brief delay
    setTimeout(function() {
      window.location.href = "/${app_name}/";
    }, 100);
  </script>
</head>
<body>
  <h1>Loading ${app_name}...</h1>
  <p>If you are not redirected automatically, <a href="/${app_name}/">click here</a>.</p>
  <p><a href="/debug">Debug Information</a></p>
</body>
</html>
EOT
done

# Create root index.html that loads config and redirects
cat > /app/data/public/index.html <<EOT
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Ente</title>
  <script src="/debug.js"></script>
  <script>
    // Define configuration globally
    window.ENTE_CONFIG = {
      API_URL: "${API_ENDPOINT}"
    };
    
    // Set environment variables for Next.js apps
    window.process = window.process || {};
    window.process.env = window.process.env || {};
    window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}";
    
    // Store in localStorage as a fallback mechanism
    localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG));
    localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}");
    
    // Redirect to photos app after a small delay to let the configuration load
    setTimeout(function() {
      window.location.href = "/photos/";
    }, 100);
  </script>
</head>
<body>
  <h1>Loading Ente...</h1>
  <p>You will be redirected automatically.</p>
  <p><a href="/debug">Debug Information</a></p>
</body>
</html>
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 <<EOT
@@ -246,7 +412,7 @@ cat > /app/data/caddy/Caddyfile <<EOT
    }
}

:8000 {
:3080 {
    log {
        output file /app/data/caddy/access.log {
            roll_size 10MB
@@ -284,6 +450,11 @@ cat > /app/data/caddy/Caddyfile <<EOT
        respond "OK" 200
    }
    
    # Cloudron health check endpoint
    handle /healthcheck {
        respond "OK" 200
    }
    
    # Serve our custom config-injected landing pages
    handle /photos-config {
        root * /app/data/public
@@ -356,285 +527,45 @@ EOT

echo "==> Caddy configuration created at /app/data/caddy/Caddyfile"

# Create HTML transformer script to modify all index.html files on load
mkdir -p /app/data/scripts
cat > /app/data/scripts/insert-config.sh <<EOT
#!/bin/bash
# This script injects our configuration into all index.html files

# List of web app directories
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 writable copy
        cp "\$app_dir/index.html" "/app/data/temp.html"
        
        # Insert our config script right before the closing head tag
        sed -i 's|</head>|<script>window.ENTE_CONFIG = { API_URL: "${API_ENDPOINT}" };</script></head>|' "/app/data/temp.html"
        
        # Create a symlink from the modified file to the original
        # Only if the temp file was created and modified successfully
        if [ -f "/app/data/temp.html" ]; then
            mkdir -p "/app/data/transformed/\$(basename \$app_dir)"
            cp "/app/data/temp.html" "/app/data/transformed/\$(basename \$app_dir)/index.html"
        fi
    fi
done

echo "All index.html files processed"
EOT
chmod +x /app/data/scripts/insert-config.sh

# Run the transformer script to create modified index.html files
mkdir -p /app/data/transformed
echo "==> Creating modified index.html files with injected configuration"
/app/data/scripts/insert-config.sh

# Create direct configuration files for different frameworks
mkdir -p /app/data/public
echo "==> Creating framework-specific configuration files"

# Create a Next.js public runtime configuration
cat > /app/data/public/env.js <<EOT
// Next.js runtime configuration
window.ENV = {
  NEXT_PUBLIC_ENTE_ENDPOINT: "${API_ENDPOINT}"
};
window.process = window.process || {};
window.process.env = window.process.env || {};
window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}";
EOT

# Create a simple JSON config
cat > /app/data/public/config.json <<EOT
{
  "API_URL": "${API_ENDPOINT}"
}
EOT

# Create additional HTML files with the config directly embedded
for app_name in "photos" "accounts" "auth" "cast"; do
  cat > "/app/data/public/${app_name}-config.html" <<EOT
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Loading ${app_name}</title>
  <script src="/debug.js"></script>
  <script>
    // Set the global configuration
    window.ENTE_CONFIG = {
      API_URL: "${API_ENDPOINT}"
    };
    
    // Set Next.js environment variables
    window.process = window.process || {};
    window.process.env = window.process.env || {};
    window.process.env.NEXT_PUBLIC_ENTE_ENDPOINT = "${API_ENDPOINT}";
    
    // Store in localStorage as a fallback mechanism
    localStorage.setItem('ENTE_CONFIG', JSON.stringify(window.ENTE_CONFIG));
    localStorage.setItem('NEXT_PUBLIC_ENTE_ENDPOINT', "${API_ENDPOINT}");
    
    // Log the configuration
    console.log("Ente ${app_name} config loaded:", window.ENTE_CONFIG);
    
    // Redirect to the main app after a brief delay
    setTimeout(function() {
      window.location.href = "/${app_name}/";
    }, 100);
  </script>
</head>
<body>
  <h1>Loading ${app_name}...</h1>
  <p>If you are not redirected automatically, <a href="/${app_name}/">click here</a>.</p>
  <p><a href="/debug">Debug Information</a></p>
</body>
</html>
EOT
done

echo "==> Created app-specific config loading pages with debug info"

# Looking for Museum (Go server component)
echo "==> Looking for Museum (Go server component)"

# Find the server directory - expanded search
SERVER_DIR=""

# Look in all the most likely places
if [ -d "/app/code/server" ]; then
    echo "==> Found server directory at /app/code/server"
    SERVER_DIR="/app/code/server"
elif [ -d "/app/code/museum" ]; then
    echo "==> Found server directory at /app/code/museum"
    SERVER_DIR="/app/code/museum"
fi

# If not found yet, try to find it based on Go files
if [ -z "$SERVER_DIR" ]; then
    echo "==> Searching for Go server files in the repository"
    
    # Look for cmd/museum path which is mentioned in docs
    if find /app/code -path "*/cmd/museum" -type d | grep -q .; then
        MUSEUM_DIR=$(find /app/code -path "*/cmd/museum" -type d | head -1)
        echo "==> Found Museum command directory at $MUSEUM_DIR"
        SERVER_DIR=$(dirname $(dirname "$MUSEUM_DIR"))
        echo "==> Setting server directory to $SERVER_DIR"
    # Look for main.go files in areas that might be server-related
    elif find /app/code -name "main.go" -path "*/server*" | grep -q .; then
        MAIN_GO=$(find /app/code -name "main.go" -path "*/server*" | head -1)
        SERVER_DIR=$(dirname "$MAIN_GO")
        echo "==> Found main.go in $SERVER_DIR"
    # Look for any Go files with "museum" in the path
    elif find /app/code -name "*.go" -path "*/museum*" | grep -q .; then
        MUSEUM_GO=$(find /app/code -name "*.go" -path "*/museum*" | head -1)
        SERVER_DIR=$(dirname "$MUSEUM_GO")
        echo "==> Found Go file in museum directory: $SERVER_DIR"
    # Last resort - look for any main.go file
    elif find /app/code -name "main.go" | grep -v "test" | grep -q .; then
        MAIN_GO=$(find /app/code -name "main.go" | grep -v "test" | head -1)
        SERVER_DIR=$(dirname "$MAIN_GO")
        echo "==> Found main.go as fallback: $SERVER_DIR"
    fi
fi

# If still not found, check the 'cli' directory as it might be a client for the Museum
if [ -z "$SERVER_DIR" ] && [ -d "/app/code/cli" ]; then
    echo "==> Checking CLI directory for Museum server code"
    if find /app/code/cli -name "*.go" | grep -q .; then
        SERVER_DIR="/app/code/cli"
        echo "==> Using CLI directory as fallback for server: $SERVER_DIR"
    fi
fi

# If all else fails, just use the root
if [ -z "$SERVER_DIR" ]; then
    echo "==> WARNING: Could not find server directory with Go files"
    echo "==> Using repository root as fallback"
    SERVER_DIR="/app/code"
fi

echo "==> Selected server directory: $SERVER_DIR"
echo "==> Contents of $SERVER_DIR:"
ls -la "$SERVER_DIR"

# Check for server dependencies
echo "==> Installing Go dependencies"
if [ -x "$(command -v go)" ]; then
    echo "==> Go is installed, version: $(go version)"
    # Check go.mod version requirement and modify if needed
    GO_VERSION=$(go version | cut -d " " -f 3 | sed 's/go//')
    echo "==> Current Go version: $GO_VERSION"
    if [ -f "$SERVER_DIR/go.mod" ]; then
        REQUIRED_VERSION=$(grep -o "go [0-9]\+\.[0-9]\+" "$SERVER_DIR/go.mod" | cut -d " " -f 2)
        echo "==> Required Go version: $REQUIRED_VERSION"
        
        # Don't try to modify the go.mod file since filesystem is read-only
        # Instead, use environment variables to override version requirements
        echo "==> Setting Go flags to override version requirements"
        export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod"
        export GO111MODULE=on
        export GOTOOLCHAIN=local
    fi
else
    echo "==> Installing Go"
    apt-get update && apt-get install -y golang
fi

# Skip trying to install specific Go versions since we can't modify /app/code
echo "==> Using existing Go toolchain with compatibility flags"

# Check for libsodium
if dpkg -l | grep -q libsodium; then
    echo "==> libsodium is installed"
else
    echo "==> Installing libsodium"
    apt-get update && apt-get install -y libsodium23 libsodium-dev
fi

# Check for pkg-config
if [ -x "$(command -v pkg-config)" ]; then
    echo "==> pkg-config is installed"
else
    echo "==> Installing pkg-config"
    apt-get update && apt-get install -y pkg-config
fi

# Change to server directory
cd "$SERVER_DIR"

# Set Go module cache to a writable location
export GOPATH=/app/data/go
export GO111MODULE=on
# Use local toolchain to avoid downloading required version
export GOTOOLCHAIN=local

# Ensure go.mod is in the writable directory
if [ ! -f "/app/data/go/go.mod" ] && [ -f "$SERVER_DIR/go.mod" ]; then
    echo "==> Copying go.mod and go.sum to writable location"
    mkdir -p /app/data/go
    cp -f "$SERVER_DIR/go.mod" "$SERVER_DIR/go.sum" /app/data/go/ || echo "==> Warning: Could not copy go.mod/go.sum"
    chmod 666 /app/data/go/go.mod /app/data/go/go.sum || echo "==> Warning: Could not set permissions"
fi

# Create proper directories with correct permissions
mkdir -p /app/data/go/cache /app/data/go/pkg/mod /app/data/go/bin
chmod -R 777 /app/data/go
chown -R cloudron:cloudron /app/data/go

# Override version requirements and force module mode
export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod -modcacherw"

# Create a temporary directory for Go module cache and build in writable area
export GOCACHE=/app/data/go/cache
export GOMODCACHE=/app/data/go/pkg/mod
mkdir -p $GOCACHE $GOMODCACHE
echo "==> Set up Go environment in writable directories"

# Set up more verbose logging for API debugging
export ENTE_LOG_LEVEL=debug

# 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 3080"
echo "==> Testing if port 3080 is already in use"
if netstat -tuln | grep -q ":3080 "; then
    echo "==> WARNING: Port 3080 is already in use, Caddy may fail to start"
    netstat -tuln | grep ":3080 "
else
    echo "==> Port 3080 is available"
fi
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/logs
chmod -R 755 /app/data/caddy
mkdir -p /app/data/caddy
chmod -R 777 /app/data/caddy
chown -R cloudron:cloudron /app/data/caddy

# Start Caddy
echo "==> Starting 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"

# Check if Caddy started successfully
# Wait a moment for Caddy to start
sleep 2
if ! ps -p $CADDY_PID > /dev/null; then
    echo "==> ERROR: Caddy failed to start"
    echo "==> Any logs available:"
    if [ -f "/app/data/caddy/caddy.log" ]; then
        cat /app/data/caddy/caddy.log

# 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
        echo "No Caddy logs available yet"
    fi
        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 "==> Caddy is running properly on port 3080"
    echo "==> Testing Caddy connectivity"
    curl -v http://localhost:3080/healthcheck || echo "==> Failed to connect to Caddy"
            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