8 Commits

Author SHA1 Message Date
Your Name
a8b22a95c8 Bundle Ente CLI for Cloudron console 2025-09-29 21:37:33 -06:00
Your Name
93cdf1f2f1 Remove OTT log highlighter 2025-09-29 21:26:21 -06:00
Your Name
8d6fc6fde0 Document S3 examples and refresh template 2025-09-29 21:18:19 -06:00
Your Name
b1e8df29e7 Allow runtime S3 configuration overrides 2025-09-29 20:59:57 -06:00
Your Name
176d23c086 Fix SPA asset routing for web apps 2025-09-29 20:47:07 -06:00
Andreas Dueren
aba8af9bb4 Force rebuild: Update asset routing with version bump 2025-08-01 14:02:07 -06:00
Andreas Dueren
7fc40ce970 Bump version to 0.1.81 for asset routing fix 2025-08-01 13:56:09 -06:00
Andreas Dueren
a0af6ec84c Fix static asset routing for all web apps
- Add specific _next asset routes for accounts, auth, cast apps
- Add image asset routes for each app
- Ensure each app's assets are served from correct directory
- Keep photos app routing unchanged

Should fix accounts/auth/cast apps loading issues.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-01 13:55:53 -06:00
4 changed files with 424 additions and 126 deletions

View File

@@ -7,7 +7,7 @@
"contactEmail": "contact@ente.io",
"tagline": "Open Source End-to-End Encrypted Photos & Authentication",
"upstreamVersion": "1.0.0",
"version": "0.1.79",
"version": "0.1.123",
"healthCheckPath": "/ping",
"httpPort": 3080,
"memoryLimit": 1073741824,

View File

@@ -120,7 +120,7 @@ WORKDIR /app/code
# Clone the ente repository during build (for the Museum server)
RUN git clone --depth=1 https://github.com/ente-io/ente.git . && \
sed -i 's/go 1.23/go 1.24.1/' server/go.mod && \
sed -i 's/go 1.23/go 1.24/' server/go.mod && \
mkdir -p /app/data/go && \
cp -r server/go.mod server/go.sum /app/data/go/ && \
chmod 777 /app/data/go/go.mod /app/data/go/go.sum
@@ -150,6 +150,12 @@ COPY --from=web-builder /build/web/accounts /app/web/accounts
COPY --from=web-builder /build/web/auth /app/web/auth
COPY --from=web-builder /build/web/cast /app/web/cast
# Build Ente CLI and place binary in /app/code
WORKDIR /app/code/cli
RUN env GOFLAGS= GOMODCACHE=/tmp/cli-go-cache GO111MODULE=on go build -o /app/code/ente . && chmod +x /app/code/ente
WORKDIR /app/code
# Copy Museum server binary from builder stage to app directory (not data volume)
RUN mkdir -p /app/museum-bin
COPY --from=museum-builder /ente/server/museum /app/museum-bin/museum

View File

@@ -7,19 +7,21 @@ Before you can use Ente, you need to configure an S3-compatible storage service:
1. Go to your Cloudron dashboard
2. Click on your Ente app
3. Click on "Terminal"
4. Edit the S3 configuration template:
4. Edit the S3 configuration file:
```
nano /app/data/config/s3.env.template
nano /app/data/config/s3.env
```
5. Fill in your S3 credentials (AWS S3, MinIO, DigitalOcean Spaces, etc.)
6. Save the file and rename it:
```
mv /app/data/config/s3.env.template /app/data/config/s3.env
```
7. Restart your Ente app from the Cloudron dashboard
5. Uncomment the variables you need and fill in your S3 credentials (AWS S3, Cloudflare R2, MinIO, etc.). The file includes commented examples for the previous Wasabi defaults and a generic Cloudflare R2 setup.
6. Save the file and restart your Ente app from the Cloudron dashboard
## Next Steps
1. Once S3 is configured, visit your app URL to create an admin account
2. Configure your mobile apps to use your custom self-hosted server (Settings → Advanced → Custom Server)
3. Enjoy your private, end-to-end encrypted photo storage!
## Ente CLI
- The Ente CLI binary is pre-built at `/app/code/ente` inside the app container.
- Open the Cloudron web terminal (working directory `/app/code`) and run commands with `./ente ...` or add `/app/code` to your `PATH`.
- A writable CLI config template lives at `/app/data/home/.ente/config.yaml` for pointing the CLI to your instance.

508
start.sh
View File

@@ -22,6 +22,11 @@ log() {
log "INFO" "Starting Ente Cloudron app"
log "INFO" "Running in Cloudron environment with domain: ${CLOUDRON_APP_DOMAIN}"
# Ensure HOME is writable (needed for CLI usage)
HOME_DIR="/app/data/home"
export HOME="$HOME_DIR"
mkdir -p "$HOME"
# Prevent infinite loops through startup flag
if [ -f "/app/data/startup_in_progress" ]; then
if [ "$(find /app/data/startup_in_progress -mmin +2)" ]; then
@@ -77,32 +82,144 @@ fi
# ===============================================
log "INFO" "Setting up configuration"
# S3 configuration - HARDCODED VALUES
S3_ACCESS_KEY="QZ5M3VMBUHDTIFDFCD8E"
S3_SECRET_KEY="pz1eHYjU1NwAbbruedc7swzCuszd57p1rGSFVzjv"
S3_ENDPOINT="https://s3.eu-central-2.wasabisys.com"
S3_REGION="eu-central-2"
S3_BUCKET="ente-due-ren"
if [ -n "$CLOUDRON_APP_ORIGIN" ]; then
BASE_URL="$CLOUDRON_APP_ORIGIN"
else
BASE_URL="https://${CLOUDRON_APP_DOMAIN:-localhost}"
fi
RP_ID="${CLOUDRON_APP_FQDN:-${CLOUDRON_APP_DOMAIN:-localhost}}"
log "INFO" "Using hardcoded S3 configuration"
# S3 configuration (overridable post-install)
DEFAULT_S3_ACCESS_KEY="QZ5M3VMBUHDTIFDFCD8E"
DEFAULT_S3_SECRET_KEY="pz1eHYjU1NwAbbruedc7swzCuszd57p1rGSFVzjv"
DEFAULT_S3_ENDPOINT="https://s3.eu-central-2.wasabisys.com"
DEFAULT_S3_REGION="eu-central-2"
DEFAULT_S3_BUCKET="ente-due-ren"
S3_CONFIG_DIR="/app/data/config"
S3_CONFIG_FILE="$S3_CONFIG_DIR/s3.env"
write_default_s3_template() {
cat > "$S3_CONFIG_FILE" << 'EOF'
# S3 configuration overrides for Ente on Cloudron.
# Uncomment and set any of the variables below to override the packaged defaults.
# After editing this file, restart the Ente app from the Cloudron dashboard.
#
# Example (previous Wasabi defaults bundled with this package):
#S3_ACCESS_KEY=QZ5M3VMBUHDTIFDFCD8E
#S3_SECRET_KEY=pz1eHYjU1NwAbbruedc7swzCuszd57p1rGSFVzjv
#S3_ENDPOINT=https://s3.eu-central-2.wasabisys.com
#S3_REGION=eu-central-2
#S3_BUCKET=ente-due-ren
#
# Example (Cloudflare R2 — replace placeholders):
#S3_ACCESS_KEY=R2_ACCESS_KEY
#S3_SECRET_KEY=R2_SECRET_KEY
#S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
#S3_REGION=auto
#S3_BUCKET=<bucket-name>
#
#S3_ACCESS_KEY=
#S3_SECRET_KEY=
#S3_ENDPOINT=
#S3_REGION=
#S3_BUCKET=
EOF
chown cloudron:cloudron "$S3_CONFIG_FILE" || true
}
mkdir -p "$S3_CONFIG_DIR"
if [ -f "$S3_CONFIG_FILE" ]; then
if ! grep -q "previous Wasabi defaults" "$S3_CONFIG_FILE" && ! grep -Eq '^[[:space:]]*[^#[:space:]]' "$S3_CONFIG_FILE"; then
log "INFO" "Refreshing S3 configuration template with example values"
write_default_s3_template
fi
log "INFO" "Loading S3 configuration overrides from $S3_CONFIG_FILE"
# shellcheck disable=SC1090
set -a
. "$S3_CONFIG_FILE"
set +a
else
log "INFO" "S3 configuration file not found, writing template to $S3_CONFIG_FILE"
write_default_s3_template
fi
# Seed Ente CLI configuration directory
ENTE_CLI_CONFIG_DIR="$HOME/.ente"
ENTE_CLI_CONFIG_FILE="$ENTE_CLI_CONFIG_DIR/config.yaml"
if [ ! -f "$ENTE_CLI_CONFIG_FILE" ]; then
mkdir -p "$ENTE_CLI_CONFIG_DIR"
cat > "$ENTE_CLI_CONFIG_FILE" << EOF
# Ente CLI configuration
# Uncomment and set the host to point the CLI to this Cloudron deployment.
#host: https://${CLOUDRON_APP_DOMAIN:-localhost}
EOF
chown -R cloudron:cloudron "$HOME_DIR" || true
fi
S3_ACCESS_KEY="${S3_ACCESS_KEY:-$DEFAULT_S3_ACCESS_KEY}"
S3_SECRET_KEY="${S3_SECRET_KEY:-$DEFAULT_S3_SECRET_KEY}"
S3_ENDPOINT="${S3_ENDPOINT:-$DEFAULT_S3_ENDPOINT}"
S3_REGION="${S3_REGION:-$DEFAULT_S3_REGION}"
S3_BUCKET="${S3_BUCKET:-$DEFAULT_S3_BUCKET}"
S3_ENDPOINT_HOST="${S3_ENDPOINT#https://}"
S3_ENDPOINT_HOST="${S3_ENDPOINT_HOST#http://}"
if [ -z "$S3_ACCESS_KEY" ] || [ -z "$S3_SECRET_KEY" ] || [ -z "$S3_ENDPOINT" ] || [ -z "$S3_REGION" ] || [ -z "$S3_BUCKET" ]; then
log "ERROR" "Incomplete S3 configuration detected. Please update $S3_CONFIG_FILE or set environment variables."
exit 1
fi
log "INFO" "Using S3 configuration"
log "INFO" "S3 Endpoint: $S3_ENDPOINT"
log "INFO" "S3 Region: $S3_REGION"
log "INFO" "S3 Bucket: $S3_BUCKET"
ENABLE_SMTP=${ENABLE_SMTP:-false}
SMTP_HOST=""
SMTP_PORT=""
SMTP_ENCRYPTION=""
if [ "$ENABLE_SMTP" = "true" ]; then
SMTP_HOST="${CLOUDRON_MAIL_SMTP_SERVER:-}"
SMTP_PORT="${CLOUDRON_MAIL_SMTP_PORT:-25}"
SMTP_ENCRYPTION="${CLOUDRON_MAIL_SMTP_ENCRYPTION:-}"
if [ -n "${CLOUDRON_MAIL_SMTPS_PORT:-}" ]; then
SMTP_PORT="${CLOUDRON_MAIL_SMTPS_PORT}"
SMTP_ENCRYPTION="tls"
fi
if [ "${SMTP_ENCRYPTION}" = "tls" ] && [ -n "${CLOUDRON_MAIL_DOMAIN:-}" ]; then
SMTP_HOST="mail.${CLOUDRON_MAIL_DOMAIN}"
fi
else
log "INFO" "EMAIL_DISABLED: Skipping SMTP configuration (ENABLE_SMTP=false)"
fi
SMTP_SENDER_NAME="${CLOUDRON_MAIL_FROM_DISPLAY_NAME:-Ente}"
# Museum server configuration - create configurations directory structure
MUSEUM_CONFIG_DIR="/app/data/ente/server/configurations"
MUSEUM_CONFIG="$MUSEUM_CONFIG_DIR/local.yaml"
mkdir -p "$MUSEUM_CONFIG_DIR"
if [ ! -f "$MUSEUM_CONFIG" ]; then
log "INFO" "Creating Museum server configuration"
cat > "$MUSEUM_CONFIG" << EOF
log "INFO" "Rendering Museum server configuration"
cat > "$MUSEUM_CONFIG" << EOF
# Museum server configuration
# Server settings
port: 8080
host: 0.0.0.0
log_level: info
log-file: ""
http:
port: 8080
use-tls: false
apps:
public-albums: "${BASE_URL}/photos"
public-locker: "${BASE_URL}/photos"
accounts: "${BASE_URL}/accounts"
cast: "${BASE_URL}/cast"
family: "${BASE_URL}/photos"
custom-domain:
cname: "${CLOUDRON_APP_DOMAIN:-localhost}"
# Database configuration
db:
@@ -113,48 +230,103 @@ db:
password: ${CLOUDRON_POSTGRESQL_PASSWORD}
sslmode: disable
# CORS settings
cors:
allow_origins:
- "*"
# S3 storage configuration
s3:
endpoint: "${S3_ENDPOINT}"
region: "${S3_REGION}"
access_key: "${S3_ACCESS_KEY}"
secret_key: "${S3_SECRET_KEY}"
bucket: "${S3_BUCKET}"
# For Wasabi, we need path style URLs
use_path_style_urls: true
are_local_buckets: false
use_path_style_urls: true
hot_storage:
primary: wasabi-eu-central-2-v3
secondary: wasabi-eu-central-2-v3
b2-eu-cen:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
wasabi-eu-central-2:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
wasabi-eu-central-2-v3:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
compliance: false
wasabi-eu-central-2-derived:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
scw-eu-fr:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
scw-eu-fr-locked:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
scw-eu-fr-v3:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
b5:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
b6:
key: "${S3_ACCESS_KEY}"
secret: "${S3_SECRET_KEY}"
endpoint: "${S3_ENDPOINT_HOST}"
region: "${S3_REGION}"
bucket: "${S3_BUCKET}"
derived-storage: wasabi-eu-central-2-v3
# Email settings
email:
enabled: true
host: "${CLOUDRON_MAIL_SMTP_SERVER:-localhost}"
port: ${CLOUDRON_MAIL_SMTP_PORT:-25}
smtp:
host: "${SMTP_HOST}"
port: "${SMTP_PORT}"
username: "${CLOUDRON_MAIL_SMTP_USERNAME:-}"
password: "${CLOUDRON_MAIL_SMTP_PASSWORD:-}"
from: "${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_DOMAIN:-localhost}}"
email: "${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_FQDN:-localhost}}"
sender-name: "${SMTP_SENDER_NAME}"
encryption: "${SMTP_ENCRYPTION}"
internal:
silent: true
disable-registration: false
# WebAuthn configuration for passkey support
webauthn:
rpid: "${CLOUDRON_APP_DOMAIN:-localhost}"
rpid: "${RP_ID}"
rporigins:
- "https://${CLOUDRON_APP_DOMAIN:-localhost}"
- "https://${RP_ID}"
# Additional Museum server configuration
http:
allowed_hosts:
- "${CLOUDRON_APP_DOMAIN:-localhost}"
base_url: "https://${CLOUDRON_APP_DOMAIN:-localhost}"
key:
encryption: yvmG/RnzKrbCb9L3mgsmoxXr9H7i2Z4qlbT0mL3ln4w=
hash: KXYiG07wC7GIgvCSdg+WmyWdXDAn6XKYJtp/wkEU7x573+byBRAYtpTP0wwvi8i/4l37uicX1dVTUzwH3sLZyw==
jwt:
secret: i2DecQmfGreG6q1vBj5tCokhlN41gcfS2cjOs9Po-u8=
jobs:
cron:
skip: true
EOF
chmod 600 "$MUSEUM_CONFIG"
log "INFO" "Created Museum configuration at ${MUSEUM_CONFIG}"
else
log "INFO" "Museum configuration already exists"
fi
chmod 600 "$MUSEUM_CONFIG"
log "INFO" "Wrote Museum configuration to ${MUSEUM_CONFIG}"
# ===============================================
# Database check
@@ -180,7 +352,7 @@ fi
# ===============================================
MUSEUM_BIN="/app/data/ente/server/museum"
MUSEUM_LOG="/app/data/logs/museum.log"
USE_PLACEHOLDER=false
USE_PLACEHOLDER=${FORCE_PLACEHOLDER:-false}
log "INFO" "Setting up Museum server binary"
@@ -218,6 +390,17 @@ else
log "INFO" "Web templates already exist or source not available"
fi
# Copy mail templates for transactional emails
MUSEUM_MAIL_TEMPLATES_DIR="/app/data/ente/server/mail-templates"
REPO_MAIL_TEMPLATES_DIR="/app/data/ente/repository/server/mail-templates"
if [ ! -d "$MUSEUM_MAIL_TEMPLATES_DIR" ] && [ -d "$REPO_MAIL_TEMPLATES_DIR" ]; then
log "INFO" "Copying mail templates"
cp -r "$REPO_MAIL_TEMPLATES_DIR" "$MUSEUM_MAIL_TEMPLATES_DIR"
log "INFO" "Copied mail templates to $MUSEUM_MAIL_TEMPLATES_DIR"
else
log "INFO" "Mail templates already exist or source not available"
fi
# Check if Museum binary exists and is valid
log "INFO" "Checking for Museum binary at: $MUSEUM_BIN"
if [ -f "$MUSEUM_BIN" ]; then
@@ -247,7 +430,56 @@ fi
# ===============================================
# Web Application Setup
# ===============================================
log "INFO" "Web applications are pre-built with relative API endpoint /api"
log "INFO" "Setting up web applications with writable directory"
# Copy web apps to writable data directory first
WRITABLE_WEB_DIR="/app/data/web"
if [ ! -d "$WRITABLE_WEB_DIR" ]; then
log "INFO" "Copying web applications to writable directory"
mkdir -p "$WRITABLE_WEB_DIR"
cp -r /app/web/* "$WRITABLE_WEB_DIR/"
chown -R cloudron:cloudron "$WRITABLE_WEB_DIR"
log "INFO" "Web applications copied to $WRITABLE_WEB_DIR"
else
log "INFO" "Web applications already exist in writable directory"
fi
# Fix API endpoint configuration in built JavaScript files
log "INFO" "Updating API endpoint configuration in web apps"
ACTUAL_ENDPOINT="${BASE_URL}/api"
log "INFO" "Setting API endpoint to: $ACTUAL_ENDPOINT"
declare -a PLACEHOLDER_ENDPOINTS=(
"https://example.com/api"
"https://placeholder.invalid/api"
"https://api.ente.io"
"https://api.ente.io/api"
)
declare -A HOST_REWRITES=(
["https://accounts.ente.io"]="${BASE_URL}/accounts"
["https://auth.ente.io"]="${BASE_URL}/auth"
["https://cast.ente.io"]="${BASE_URL}/cast"
["https://photos.ente.io"]="${BASE_URL}/photos"
["https://web.ente.io"]="${BASE_URL}/photos"
)
for webapp in photos accounts auth cast; do
WEB_DIR="$WRITABLE_WEB_DIR/${webapp}"
if [ -d "$WEB_DIR" ]; then
log "INFO" "Processing ${webapp} app for endpoint rewrites"
for placeholder in "${PLACEHOLDER_ENDPOINTS[@]}"; do
find "$WEB_DIR" -name "*.js" -type f -exec sed -i "s|${placeholder}|${ACTUAL_ENDPOINT}|g" {} \;
done
for source in "${!HOST_REWRITES[@]}"; do
target="${HOST_REWRITES[$source]}"
find "$WEB_DIR" -name "*.js" -type f -exec sed -i "s|${source}|${target}|g" {} \;
done
log "INFO" "Endpoint rewrites complete for ${webapp}"
else
log "WARN" "Web directory not found for ${webapp}"
fi
done
# ===============================================
# Node.js Placeholder Server
@@ -349,17 +581,52 @@ const apiHandlers = {
log('Health check request - responded with status OK');
},
// User verification endpoint
'/api/users/verify': (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
log('User verify request - responding with success');
res.end(JSON.stringify({
success: true,
isValidEmail: true,
isAvailable: true,
isVerified: true,
canCreateAccount: true
}));
// User verification endpoint (returns minimal structure expected by UI)
'/api/users/verify-email': (req, res) => {
const buildResponse = (emailAddress) => {
const email = emailAddress || 'unknown@example.com';
const stableId = Math.abs(Buffer.from(email).reduce((acc, byte) => (acc * 31 + byte) % 100000, 17)) || 1;
return {
id: stableId,
token: `placeholder-token-${stableId}`,
encryptedToken: `placeholder-encrypted-token-${stableId}`,
accountsUrl: `${process.env.CLOUDRON_APP_ORIGIN || 'https://example.com'}/accounts`,
twoFactorSessionID: undefined,
twoFactorSessionIDV2: undefined,
passkeySessionID: undefined,
keyAttributes: undefined
};
};
if (req.method !== 'POST') {
res.writeHead(405, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: false, message: 'Method not allowed' }));
return;
}
let rawBody = '';
req.on('data', chunk => { rawBody += chunk.toString(); });
req.on('end', () => {
let email = 'unknown@example.com';
let ott = 'unknown';
try {
const payload = JSON.parse(rawBody || '{}');
if (payload.email) {
email = payload.email;
}
if (payload.ott) {
ott = payload.ott;
}
} catch (err) {
log(`Failed to parse verify-email request body: ${err.message}`);
}
const responsePayload = buildResponse(email);
log(`Verifying OTT ${ott} for ${email}`);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(responsePayload));
});
},
// User login endpoint
@@ -377,7 +644,7 @@ const apiHandlers = {
token: 'placeholder-jwt-token-' + Date.now(),
user: {
id: 1,
email: 'placeholder@' + (process.env.CLOUDRON_APP_DOMAIN || 'localhost'),
email: 'placeholder@example.com',
name: 'Placeholder User'
}
}));
@@ -406,7 +673,7 @@ const apiHandlers = {
token: 'placeholder-jwt-token-' + Date.now(),
user: {
id: 1,
email: 'placeholder@' + (process.env.CLOUDRON_APP_DOMAIN || 'localhost'),
email: 'placeholder@example.com',
name: 'New User'
}
}));
@@ -420,6 +687,52 @@ const apiHandlers = {
}
},
// OTT endpoint
'/users/ott': (req, res) => {
if (req.method !== 'POST') {
res.writeHead(405, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: false, message: 'Method not allowed' }));
return;
}
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
let email = 'unknown@example.com';
try {
const payload = JSON.parse(body || '{}');
if (payload.email) {
email = payload.email;
}
} catch (err) {
log(`Failed to parse OTT request body: ${err.message}`);
}
const ott = ('' + Math.floor(100000 + Math.random() * 900000)).slice(-6);
log(`Generated OTT ${ott} for ${email}`);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: true, ott, email }));
});
},
'/api/users/ott': (req, res) => {
apiHandlers['/users/ott'](req, res);
},
'/users/verify-email': (req, res) => {
apiHandlers['/api/users/verify-email'](req, res);
},
'/api/users/verify': (req, res) => {
apiHandlers['/api/users/verify-email'](req, res);
},
'/users/verify': (req, res) => {
apiHandlers['/api/users/verify-email'](req, res);
},
'/ping': (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
log('Ping request - responding with status OK');
res.end(JSON.stringify({ status: 'OK', server: 'Ente Placeholder', time: new Date().toISOString() }));
},
// Files endpoint
'/api/files': (req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -536,7 +849,7 @@ EOF
SUCCESS=false
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
if curl -s http://localhost:8080/health > /dev/null 2>&1; then
if curl -s http://localhost:8080/ping > /dev/null 2>&1; then
log "INFO" "Node.js placeholder server started successfully"
SUCCESS=true
break
@@ -569,9 +882,10 @@ if [ "$USE_PLACEHOLDER" = true ]; then
else
log "INFO" "Starting actual Museum server"
cd /app/data/ente/server
"$MUSEUM_BIN" > "$MUSEUM_LOG" 2>&1 &
export ENVIRONMENT="${MUSEUM_ENVIRONMENT:-local}"
stdbuf -oL "$MUSEUM_BIN" 2>&1 | tee -a "$MUSEUM_LOG" &
MUSEUM_PID=$!
log "INFO" "Started Museum server with PID: $MUSEUM_PID"
log "INFO" "Started Museum server (pipeline PID: $MUSEUM_PID)"
# Wait for the server to start
MAX_ATTEMPTS=30
@@ -579,7 +893,7 @@ else
SUCCESS=false
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
if curl -s http://localhost:8080/health > /dev/null 2>&1; then
if curl -s http://localhost:8080/ping > /dev/null 2>&1; then
log "INFO" "Museum server started successfully"
SUCCESS=true
break
@@ -591,13 +905,15 @@ else
if [ "$SUCCESS" = false ]; then
log "ERROR" "Museum server failed to start within $MAX_ATTEMPTS seconds"
if ps -p "$MUSEUM_PID" > /dev/null 2>&1; then
log "INFO" "Stopping Museum server pipeline"
kill "$MUSEUM_PID" || true
fi
log "ERROR" "Last 20 lines of museum.log:"
tail -n 20 "$MUSEUM_LOG" | while read -r line; do
log "ERROR" " $line"
done
log "WARN" "Falling back to Node.js placeholder server"
create_nodejs_placeholder
exit 1
fi
fi
@@ -633,7 +949,7 @@ cat > "$CADDY_CONFIG" << EOF
respond 204
}
# API endpoints with CORS - strip /api prefix before forwarding
# API endpoints with CORS
handle_path /api/* {
reverse_proxy localhost:8080 {
header_up Host {http.request.host}
@@ -657,60 +973,34 @@ cat > "$CADDY_CONFIG" << EOF
}
}
# Health check endpoints
# Health check endpoint
handle /health {
reverse_proxy localhost:8080
}
handle /ping {
reverse_proxy localhost:8080
handle /images/* {
rewrite * /photos{path}
root * /app/data/web
file_server
}
# Static files for Next.js assets from all apps
# Static files for Next.js assets shared across apps
handle /_next/* {
@photosNext path /_next/*
handle @photosNext {
root * /app/web/photos
file_server
}
root * /app/data/web
try_files photos{path} accounts{path} auth{path} cast{path} {path}
file_server
header {
Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*"
}
}
# Photos app
handle_path /photos/* {
root * /app/web/photos
try_files {path} /index.html
# Default to serve SPA assets
handle {
root * /app/data/web
try_files {path}/index.html {path} /photos/index.html
file_server
}
# Accounts app
handle_path /accounts/* {
root * /app/web/accounts
try_files {path} /index.html
file_server
}
# Auth app
handle_path /auth/* {
root * /app/web/auth
try_files {path} /index.html
file_server
}
# Cast app
handle_path /cast/* {
root * /app/web/cast
try_files {path} /index.html
file_server
}
# Root redirect
handle / {
redir /photos/ permanent
}
}
EOF
@@ -752,7 +1042,7 @@ cat > /app/data/SETUP-INSTRUCTIONS.md << EOF
## Configuration
1. **S3 Storage**: Edit the configuration file at \`/app/data/s3.env\` with your S3-compatible storage credentials.
1. **S3 Storage**: Edit the configuration file at \`/app/data/config/s3.env\` (uncomment lines and add your values) with your S3-compatible storage credentials.
2. **Museum Server**: The server configuration is at \`/app/data/ente/server/museum.yaml\` if you need to customize settings.
@@ -765,10 +1055,10 @@ cat > /app/data/SETUP-INSTRUCTIONS.md << EOF
The following web applications are available:
- Photos: https://${CLOUDRON_APP_DOMAIN}/photos/
- Accounts: https://${CLOUDRON_APP_DOMAIN}/accounts/
- Auth: https://${CLOUDRON_APP_DOMAIN}/auth/
- Cast: https://${CLOUDRON_APP_DOMAIN}/cast/
- Photos: https://${CLOUDRON_APP_FQDN}/photos/
- Accounts: https://${CLOUDRON_APP_FQDN}/accounts/
- Auth: https://${CLOUDRON_APP_FQDN}/auth/
- Cast: https://${CLOUDRON_APP_FQDN}/cast/
## Support