10 Commits

Author SHA1 Message Date
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
Andreas Dueren
f9171c6ca4 Resolve merge conflicts with updated version 0.1.79 2025-08-01 13:46:59 -06:00
Andreas Dueren
8fbf29fc45 Fix API endpoint configuration and domain references
- Change NEXT_PUBLIC_ENTE_ENDPOINT to relative /api for domain flexibility
- Remove runtime JS endpoint replacement (fragile, now unnecessary)
- Fix all domain references to use CLOUDRON_APP_DOMAIN consistently
- Add /ping health check endpoint to Caddy configuration
- Update placeholder server to use dynamic domain

Photos app now working, other apps may need additional fixes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-01 13:46:17 -06:00
Your Name
e95ad5c25f Fix web app endpoint configuration
- Use relative /api endpoint in Dockerfile build
- Remove complex runtime replacement logic
- Simplify start.sh to avoid read-only filesystem issues
- Restore working Caddy configuration

Version 0.1.78 ready for deployment
2025-07-26 20:28:15 -06:00
Your Name
d964d7d264 Remove large ente-source directory to fix build uploads
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-25 19:47:47 -06:00
Your Name
06e0f5075e Implement comprehensive web app API endpoint fix
- Patch origins.ts during Docker build to use window.location.origin + '/api'
- Update version to 0.1.69 to force rebuild
- Add browser compatibility check for server-side rendering
- Fix both API and uploader endpoint redirections

This addresses the root cause where web apps were hardcoded to use
https://api.ente.io instead of the local Museum server.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-25 19:27:11 -06:00
Your Name
c7b9ab18bb Fix static asset routing and path handling for auth/accounts/cast apps
- Fixed Next.js static asset (_next/*) routing for each app separately
- Updated app path handling to work with both /app and /app/* patterns
- Resolved 404 errors for static assets from auth, accounts, and cast apps
- Updated to version 0.1.66
2025-07-25 11:12:27 -06:00
Your Name
b7fcf5c01d Add comprehensive API documentation to Cloudron setup instructions
- Added detailed API endpoint information in SETUP-INSTRUCTIONS.md
- Documented API usage with Ente CLI
- Enhanced routing configuration for auth/cast/accounts apps
- Updated to version 0.1.64
2025-07-25 11:02:06 -06:00
15 changed files with 1023 additions and 45 deletions

110
BUILD-INSTRUCTIONS.md Normal file
View File

@@ -0,0 +1,110 @@
# Ente Cloudron App Build and Installation Instructions
This document provides detailed instructions for building and installing the Ente Cloudron app, an open-source, end-to-end encrypted photo storage and authentication solution.
## Prerequisites
- **Cloudron CLI**: Ensure the Cloudron CLI is installed and configured on your system. Refer to [Cloudron CLI Documentation](https://docs.cloudron.io/packaging/cli/) for setup instructions.
- **Docker**: Required for local testing or custom builds if needed.
- **Git**: To clone or manage the repository.
- **Repository Access**: Ensure you have access to the Ente Cloudron repository at `andreasdueren/ente-cloudron`.
- **Build Service Token**: A token for the Cloudron build service is required (provided in the command below).
## Build Commands
1. **Clone the Repository** (if not already done):
```bash
git clone https://github.com/andreasdueren/ente-cloudron.git
cd ente-cloudron
```
2. **Build the App Using Cloudron Build Service**:
Use the provided build service and token to build the app. Replace `<version>` with the desired version tag (e.g., `0.1.0` or as per `CloudronManifest.json`).
```bash
cloudron build --set-build-service builder.docker.due.ren --build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e --set-repository andreasdueren/ente-cloudron --tag 1.0.1
```
**Note**: The build process should complete within a reasonable time. Monitor the output for any errors.
## Installation Commands
1. **Install the App on Cloudron**:
After a successful build, install the app on your Cloudron instance at the desired location (e.g., `ente.due.ren`).
```bash
cloudron install --location ente.due.ren --image andreasdueren/ente-cloudron:1.0.1
```
**Important**: Do not wait more than 30 seconds for feedback after running the install command. If there's an error, the process may hang, and you should terminate it to troubleshoot.
**Note**: Always uninstall and reinstall during development rather than updating an existing app to ensure a clean setup.
## Testing Procedures
1. **Verify Installation**:
- Access the app at `https://ente.due.ren` (or your configured domain).
- Ensure the Ente web interfaces (Photos, Accounts, Auth, Cast) load correctly.
2. **Check S3 Configuration**:
- Confirm that S3 environment variables are set in Cloudron app settings under the 'Environment Variables' section.
- Variables to check: `APP_S3_ENABLED`, `APP_S3_ENDPOINT`, `APP_S3_ACCESS_KEY_ID`, `APP_S3_SECRET_ACCESS_KEY`, `APP_S3_BUCKET`.
3. **Monitor Logs for Errors**:
- Use the Cloudron CLI to view logs:
```bash
cloudron logs --app ente.due.ren -f
```
- Alternatively, shell into the app for detailed log inspection:
```bash
cloudron exec --app ente.due.ren
tail -f /app/data/logs/*
```
- Look for S3 connection errors or other issues.
## Deployment Steps
1. **Post-Installation Configuration**:
- If S3 is not working, update the environment variables in Cloudron app settings and restart the app:
```bash
cloudron restart --app ente.due.ren
```
2. **User Authentication**:
- Ente uses its own authentication system. Ensure user registration and login work as expected.
- If OIDC integration is desired in the future, it can be configured using Cloudron's OIDC variables (`CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, `CLOUDRON_OIDC_CLIENT_SECRET`).
## Troubleshooting Common Issues
- **S3 Configuration Errors**:
- **Symptom**: App falls back to local storage or logs show S3 connection failures.
- **Solution**: Verify S3 environment variables in Cloudron settings. Test connectivity manually using AWS CLI (`aws s3 ls s3://<bucket> --endpoint-url <endpoint>`).
- **Build Failures**:
- **Symptom**: Build command errors out or hangs.
- **Solution**: Check network connectivity to the build service, ensure the token is correct, and review build logs for specific errors.
- **Installation Hangs**:
- **Symptom**: Install command does not complete within 30 seconds.
- **Solution**: Terminate the command and check Cloudron logs for errors (`cloudron logs --app ente.due.ren`). Reinstall if necessary.
- **App Not Starting**:
- **Symptom**: App shows as 'Stopped' or inaccessible after install.
- **Solution**: Check logs for startup errors (`cloudron logs --app ente.due.ren`). Ensure database connectivity and correct configuration.
## Configuration Examples
- **S3 Environment Variables** in Cloudron settings:
```
APP_S3_ENABLED=true
APP_S3_ENDPOINT=s3.amazonaws.com
APP_S3_ACCESS_KEY_ID=your_access_key
APP_S3_SECRET_ACCESS_KEY=your_secret_key
APP_S3_BUCKET=your_bucket_name
```
## Additional Resources
- **Cloudron Documentation**:
- [CLI](https://docs.cloudron.io/packaging/cli/)
- [Packaging Tutorial](https://docs.cloudron.io/packaging/tutorial/)
- [Manifest Reference](https://docs.cloudron.io/packaging/manifest/)
- [Addons Guide](https://docs.cloudron.io/packaging/addons/)
- [Cheat Sheet](https://docs.cloudron.io/packaging/cheat-sheet/)
For further assistance, contact the Ente team at `contact@ente.io` or refer to the GitHub repository at [https://github.com/ente-io/ente](https://github.com/ente-io/ente).

158
CLAUDE.md Normal file
View File

@@ -0,0 +1,158 @@
Cloudron Application Packaging System Prompt
You are a Cloudron packaging expert specializing in creating complete, production-ready Cloudron packages. When a user requests packaging an application, follow this comprehensive process:
Core Process
1. Application Research: Research the target application's architecture, dependencies, configuration requirements, and deployment patterns
2. Package Generation: Create all required Cloudron packaging files
3. Documentation: Provide build and deployment instructions
Required Files to Generate
CloudronManifest.json
- Use reverse-domain notation for app ID (e.g., io.example.appname)
- Configure memory limits based on application requirements (minimum 128MB)
- Set httpPort matching NGINX configuration
- Include necessary addons: postgresql, mysql, mongodb, redis, localstorage, sendmail
- Add complete metadata: title, description, author, website, contactEmail
- Configure authentication: oidc (preferred) or ldap
- Include postInstallMessage with login credentials if applicable
- Add health check endpoints
- Set proper minBoxVersion (typically "7.0.0")
Dockerfile
- Base image: FROM cloudron/base:5.0.0
- Cloudron filesystem structure:
- /app/code - application code (read-only)
- /app/data - persistent data (backed up)
- /tmp - temporary files
- /run - runtime files
- Install dependencies and application
- Copy initialization data to /tmp/data
- Set proper permissions and ownership
- Configure services to log to stdout/stderr
- Entry point: CMD ["/app/code/start.sh"]
start.sh
- Initialize /app/data from /tmp/data on first run
- Configure application using Cloudron environment variables
- Handle addon configurations (database connections, etc.)
- Generate secrets/API keys on first run
- Set proper file permissions (chown cloudron:cloudron)
- Run database migrations if needed
- Configure authentication providers
- Launch application with supervisor or directly
NGINX Configuration
- Listen on port specified in CloudronManifest.json
- Handle proxy headers properly:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
- Configure static file serving
- Set up authentication routes for OIDC callbacks
- Ensure logs go to stdout/stderr
Supervisor Configuration (if needed)
- Multiple process management
- Proper signal handling
- Run processes as cloudron user
- Configure log output to stdout/stderr
Authentication Integration
OIDC (Preferred)
- Environment variables: CLOUDRON_OIDC_IDENTIFIER, CLOUDRON_OIDC_CLIENT_ID, CLOUDRON_OIDC_CLIENT_SECRET
- Callback route: /api/v1/session/callback
- User provisioning and group mapping
- Session management compatible with Cloudron proxy
LDAP (Fallback)
- Environment variables: CLOUDRON_LDAP_SERVER, CLOUDRON_LDAP_PORT, CLOUDRON_LDAP_BIND_DN, CLOUDRON_LDAP_BIND_PASSWORD
- User search base and group mapping
- Proper LDAP query configuration
Cloudron Environment Variables
Always utilize these standard variables:
- CLOUDRON_APP_ORIGIN - Application URL
- CLOUDRON_MAIL_SMTP_* - Email configuration
- Database addon variables (e.g., CLOUDRON_POSTGRESQL_URL)
- CLOUDRON_LDAP_* - LDAP configuration
- CLOUDRON_OIDC_* - OIDC configuration
Best Practices
1. Security: Never expose secrets, use environment variables
2. Persistence: Store data in /app/data, initialize from /tmp/data
3. Updates: Handle schema migrations and configuration updates
4. Logging: All logs to stdout/stderr for Cloudron log aggregation
5. Health Checks: Implement endpoints for monitoring
6. Process Management: Use supervisor for multi-process applications
7. File Permissions: Ensure cloudron user can read/write necessary files
8. Building: use the cloudron build service under builder.docker.due.ren
9. Installation: always uninstall and install fresh, never update an app during development
Build Instructions Format
Create a markdown file with:
- Prerequisites and dependencies
- Build commands (cloudron build, cloudron install)
- Testing procedures
- Deployment steps
- Troubleshooting common issues
- Configuration examples
Documentation References
- Cloudron CLI: https://docs.cloudron.io/packaging/cli/
- Packaging Tutorial: https://docs.cloudron.io/packaging/tutorial/
- Manifest Reference: https://docs.cloudron.io/packaging/manifest/
- Addons Guide: https://docs.cloudron.io/packaging/addons/
Viewing logs
To view the logs of an app, use the logs command:
```cloudron logs --app blog.example.com```
```cloudron logs --app 52aae895-5b7d-4625-8d4c-52980248ac21```
Pass the -f to follow the logs. Note that not all apps log to stdout/stderr. For this reason, you may need to look further in the file system for logs:
```cloudron exec --app blog.example.com # shell into the app's file system```
``# tail -f /run/wordpress/wp-debug.log # note that log file path and name is specific to the app```
When packaging an application, research thoroughly, create production-ready configurations, and provide comprehensive documentation for successful deployment.
Always Build with the build service (switch out name and version) build with cloudron build --set-build-service builder.docker.due.ren --build-service-token
e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e --set-repository andreasdueren/ente-cloudron --tag 0.1.0
cloudron install --location ente.due.ren --image andreasdueren/ente-cloudron:0.1.0
After install and build, dont wait more than 30 seconds for feedback. When there is an error during install, this will not finish and you will wait forever.
Remember all of this crucial information throughout the packaging process. Create a file for persistency if necessary to poll from later. Fix this packaging of ente for cloudron:
https://github.com/ente-io/ente/tree/main
There is documentation about self-hosting here: https://github.com/ente-io/ente/tree/main/docs/docs/self-hosting and here https://github.com/ente-io/ente/tree/main/server
Use Caddy as a reverse proxy. More info on setting it up: https://help.ente.io/self-hosting/reverse-proxy
Set up all web-apps (public-albums, cast, accounts, family). Use a path (/albums, /cast…) and not sub domains.: https://help.ente.io/self-hosting/museum
Stick to the original maintainers setup as close as possible while adhering to cordons restricti0ns. Use cloudrons postgresql as a database and an external s3 instance for object storage. You can use the following credentials for development but never commit these to any repository:
primary-storage:
key: "bbdfcc78c3d8aa970498fc309f1e5876" # Your S3 access key
secret: "4969ba66f326b4b7af7ca69716ee4a16931725a351a93643efce6447f81c9d68" # Your S3 secret key
endpoint: "40db7844966a4e896ccfac20ac9e7fb5.r2.cloudflarestorage.com" # S3 endpoint URL
region: "wnam" # S3 region (e.g. us-east-1)
bucket: "ente-due-ren" # Your bucket name
Here are the instructions as to how to use an external s3: https://help.ente.io/self-hosting/guides/external-s3

21
Caddyfile.simple Normal file
View File

@@ -0,0 +1,21 @@
{
admin off
auto_https off
}
:3080 {
log {
output stdout
level DEBUG
}
# Simple health check that always works
handle /health {
respond "{\"status\": \"OK\"}" 200
}
# Catch-all for debugging
handle {
respond "Caddy is running on port 3080" 200
}
}

View File

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

View File

@@ -27,11 +27,9 @@ RUN apt-get update && apt-get install -y git && \
# Will help default to yarn version 1.22.22 # Will help default to yarn version 1.22.22
RUN corepack enable RUN corepack enable
# Set environment variables for web app build # Set environment variables for web app build - use relative endpoint
# Set the API endpoint to use current origin - this will work at runtime ENV NEXT_PUBLIC_ENTE_ENDPOINT="/api"
ENV NEXT_PUBLIC_ENTE_ENDPOINT="https://example.com/api" RUN echo "Building with relative NEXT_PUBLIC_ENTE_ENDPOINT=/api for self-hosted deployment"
# Add a note for clarity
RUN echo "Building with placeholder NEXT_PUBLIC_ENTE_ENDPOINT, will be served by Caddy proxy at /api"
# Debugging the repository structure # Debugging the repository structure
RUN find . -type d -maxdepth 3 | sort RUN find . -type d -maxdepth 3 | sort
@@ -160,9 +158,13 @@ RUN chmod +x /app/museum-bin/museum
# Copy configuration and startup scripts # Copy configuration and startup scripts
ADD start.sh /app/pkg/ ADD start.sh /app/pkg/
ADD config.template.yaml /app/pkg/ ADD config.template.yaml /app/pkg/
ADD otp-email-monitor.js /app/pkg/
ADD package.json /app/pkg/
ADD admin-helper.sh /app/pkg/
ADD admin-helper-direct.sh /app/pkg/
# Set proper permissions # Set proper permissions
RUN chmod +x /app/pkg/start.sh RUN chmod +x /app/pkg/start.sh /app/pkg/admin-helper.sh /app/pkg/admin-helper-direct.sh
# Expose the web port (Cloudron expects port 3080) # Expose the web port (Cloudron expects port 3080)
EXPOSE 3080 EXPOSE 3080

133
admin-helper-direct.sh Normal file
View File

@@ -0,0 +1,133 @@
#!/bin/bash
# Direct Database Admin Helper for Ente Cloudron
# This script directly updates the database for admin operations
# Function to update user subscription directly in database
update_subscription() {
local user_email="$1"
local storage_gb="$2"
local valid_days="$3"
if [ -z "$user_email" ] || [ -z "$storage_gb" ] || [ -z "$valid_days" ]; then
echo "Usage: $0 update-subscription <user-email> <storage-gb> <valid-days>"
echo "Example: $0 update-subscription user@example.com 100 365"
return 1
fi
echo "Updating subscription for: $user_email"
echo "Storage: ${storage_gb}GB"
echo "Valid for: ${valid_days} days"
# Convert GB to bytes (1 GB = 1073741824 bytes)
local storage_bytes=$((storage_gb * 1073741824))
# Calculate expiry timestamp (current time + valid_days)
local current_timestamp=$(date +%s)
local expiry_timestamp=$((current_timestamp + (valid_days * 86400)))
# Convert to microseconds for the database
local expiry_microseconds="${expiry_timestamp}000000"
# Update the database directly
PGPASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD" psql \
-h "$CLOUDRON_POSTGRESQL_HOST" \
-p "$CLOUDRON_POSTGRESQL_PORT" \
-U "$CLOUDRON_POSTGRESQL_USERNAME" \
-d "$CLOUDRON_POSTGRESQL_DATABASE" << EOF
-- Update user's storage and subscription
UPDATE users
SET
storage_bonus = $storage_bytes,
subscription_expiry = $expiry_microseconds
WHERE email = '$user_email';
-- Show the updated values
SELECT
email,
storage_bonus / 1073741824.0 as storage_gb,
to_timestamp(subscription_expiry / 1000000) as subscription_expires
FROM users
WHERE email = '$user_email';
EOF
if [ $? -eq 0 ]; then
echo "✓ Subscription updated successfully"
else
echo "✗ Failed to update subscription"
return 1
fi
}
# Function to get user details
get_user_details() {
local user_email="$1"
if [ -z "$user_email" ]; then
echo "Usage: $0 get-user <user-email>"
return 1
fi
PGPASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD" psql \
-h "$CLOUDRON_POSTGRESQL_HOST" \
-p "$CLOUDRON_POSTGRESQL_PORT" \
-U "$CLOUDRON_POSTGRESQL_USERNAME" \
-d "$CLOUDRON_POSTGRESQL_DATABASE" << EOF
SELECT
email,
storage_bonus / 1073741824.0 as storage_gb,
storage_consumed / 1073741824.0 as used_gb,
to_timestamp(subscription_expiry / 1000000) as subscription_expires,
CASE
WHEN subscription_expiry > (EXTRACT(EPOCH FROM NOW()) * 1000000) THEN 'Active'
ELSE 'Expired'
END as status
FROM users
WHERE email = '$user_email';
EOF
}
# Function to list all users
list_users() {
PGPASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD" psql \
-h "$CLOUDRON_POSTGRESQL_HOST" \
-p "$CLOUDRON_POSTGRESQL_PORT" \
-U "$CLOUDRON_POSTGRESQL_USERNAME" \
-d "$CLOUDRON_POSTGRESQL_DATABASE" << EOF
SELECT
email,
storage_bonus / 1073741824.0 as storage_gb,
storage_consumed / 1073741824.0 as used_gb,
to_timestamp(subscription_expiry / 1000000) as expires,
CASE
WHEN subscription_expiry > (EXTRACT(EPOCH FROM NOW()) * 1000000) THEN 'Active'
ELSE 'Expired'
END as status
FROM users
ORDER BY email;
EOF
}
# Main command handler
case "$1" in
"update-subscription")
update_subscription "$2" "$3" "$4"
;;
"get-user")
get_user_details "$2"
;;
"list-users")
list_users
;;
*)
echo "Ente Direct Admin Helper"
echo ""
echo "Usage:"
echo " $0 update-subscription <user-email> <storage-gb> <valid-days>"
echo " $0 get-user <user-email>"
echo " $0 list-users"
echo ""
echo "Examples:"
echo " $0 update-subscription user@example.com 100 365"
echo " $0 get-user user@example.com"
echo " $0 list-users"
;;
esac

93
admin-helper.sh Normal file
View File

@@ -0,0 +1,93 @@
#!/bin/bash
# Ente Admin Helper Script for Cloudron
# This script simplifies admin operations in the Cloudron terminal
MUSEUM_BIN="/app/data/ente/server/museum"
# Check if museum binary exists
if [ ! -f "$MUSEUM_BIN" ]; then
echo "Error: Museum binary not found at $MUSEUM_BIN"
exit 1
fi
# Function to update user subscription
update_subscription() {
local user_email="$1"
local storage_gb="$2"
local valid_days="$3"
if [ -z "$user_email" ] || [ -z "$storage_gb" ] || [ -z "$valid_days" ]; then
echo "Usage: $0 update-subscription <user-email> <storage-gb> <valid-days>"
echo "Example: $0 update-subscription user@example.com 100 365"
return 1
fi
echo "Updating subscription for: $user_email"
echo "Storage: ${storage_gb}GB"
echo "Valid for: ${valid_days} days"
cd /app/data/ente/server
# Use environment variables for database connection
export DB_HOST="$CLOUDRON_POSTGRESQL_HOST"
export DB_PORT="$CLOUDRON_POSTGRESQL_PORT"
export DB_NAME="$CLOUDRON_POSTGRESQL_DATABASE"
export DB_USERNAME="$CLOUDRON_POSTGRESQL_USERNAME"
export DB_PASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD"
# Museum admin commands need specific syntax
"$MUSEUM_BIN" admin update-subscription "$user_email" "$storage_gb" "$valid_days"
}
# Function to get user details
get_user_details() {
local user_email="$1"
if [ -z "$user_email" ]; then
echo "Usage: $0 get-user <user-email>"
return 1
fi
cd /app/data/ente/server
"$MUSEUM_BIN" admin get-user-details --user "$user_email"
}
# Function to list all users
list_users() {
cd /app/data/ente/server
# Connect to PostgreSQL and list users
PGPASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD" psql \
-h "$CLOUDRON_POSTGRESQL_HOST" \
-p "$CLOUDRON_POSTGRESQL_PORT" \
-U "$CLOUDRON_POSTGRESQL_USERNAME" \
-d "$CLOUDRON_POSTGRESQL_DATABASE" \
-c "SELECT email, storage_bonus, subscription_expiry FROM users ORDER BY email;"
}
# Main command handler
case "$1" in
"update-subscription")
update_subscription "$2" "$3" "$4"
;;
"get-user")
get_user_details "$2"
;;
"list-users")
list_users
;;
*)
echo "Ente Admin Helper"
echo ""
echo "Usage:"
echo " $0 update-subscription <user-email> <storage-gb> <valid-days>"
echo " $0 get-user <user-email>"
echo " $0 list-users"
echo ""
echo "Examples:"
echo " $0 update-subscription user@example.com 100 365"
echo " $0 get-user user@example.com"
echo " $0 list-users"
;;
esac

35
debug-headers.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
echo "==> Debugging Caddy MIME type headers"
echo "==> Testing various file types..."
BASE_URL="${1:-https://ente.due.ren}"
echo
echo "Testing HTML files:"
curl -I "$BASE_URL/" 2>/dev/null | grep -i content-type || echo "No Content-Type header found"
curl -I "$BASE_URL/index.html" 2>/dev/null | grep -i content-type || echo "No Content-Type header found"
echo
echo "Testing JavaScript files:"
curl -I "$BASE_URL/config.js" 2>/dev/null | grep -i content-type || echo "No Content-Type header found"
echo
echo "Testing CSS files (if any):"
curl -I "$BASE_URL/styles.css" 2>/dev/null | grep -i content-type || echo "File not found or no Content-Type header"
echo
echo "Testing JSON files (if any):"
curl -I "$BASE_URL/manifest.json" 2>/dev/null | grep -i content-type || echo "File not found or no Content-Type header"
echo
echo "==> Full response headers for main page:"
curl -I "$BASE_URL/" 2>/dev/null || echo "Failed to connect to $BASE_URL"
echo
echo "==> To test from inside a container:"
echo "docker exec -it <container-name> curl -I http://localhost:3080/"
echo
echo "==> To view Caddy logs:"
echo "docker exec -it <container-name> tail -f /app/data/logs/caddy.log"

38
debug-network.html Normal file
View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>Debug Ente Auth Network Calls</title>
</head>
<body>
<h1>Debug Ente Auth Network Calls</h1>
<div id="output"></div>
<script>
// Override fetch to log all network requests
const originalFetch = window.fetch;
window.fetch = function(...args) {
console.log('FETCH REQUEST:', args[0], args[1]);
const output = document.getElementById('output');
output.innerHTML += '<p>FETCH: ' + args[0] + '</p>';
return originalFetch.apply(this, args)
.then(response => {
console.log('FETCH RESPONSE:', response.status, response.url);
output.innerHTML += '<p>RESPONSE: ' + response.status + ' ' + response.url + '</p>';
return response;
})
.catch(error => {
console.log('FETCH ERROR:', error);
output.innerHTML += '<p>ERROR: ' + error.message + '</p>';
throw error;
});
};
// Load the Ente Auth app in an iframe to see what happens
const iframe = document.createElement('iframe');
iframe.src = 'https://ente.due.ren/auth/';
iframe.style.width = '100%';
iframe.style.height = '400px';
document.body.appendChild(iframe);
</script>
</body>
</html>

32
debug-start.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
# Add this debugging section to your start.sh after line 350
# Start Caddy with more verbose logging
echo "==> Starting Caddy web server with debug logging"
echo "==> Validating Caddyfile first..."
caddy validate --config /app/data/Caddyfile --adapter caddyfile || {
echo "==> ERROR: Caddyfile validation failed!"
cat /app/data/Caddyfile
exit 1
}
echo "==> Starting Caddy..."
# Run Caddy in foreground first to see errors
timeout 10 caddy run --config /app/data/Caddyfile --adapter caddyfile 2>&1 | tee /app/data/logs/caddy-debug.log || {
echo "==> ERROR: Caddy failed to start"
echo "==> Last 50 lines of Caddy debug log:"
tail -50 /app/data/logs/caddy-debug.log
}
# Check if port is actually listening
echo "==> Checking if port 3080 is listening..."
netstat -tlnp | grep 3080 || lsof -i :3080 || {
echo "==> ERROR: Nothing listening on port 3080"
}
# Test the health endpoint
echo "==> Testing health endpoint..."
curl -v http://localhost:3080/health || {
echo "==> ERROR: Health check failed"
}

64
ente-cli-config.md Normal file
View File

@@ -0,0 +1,64 @@
# Ente CLI Configuration for Custom Server
The Ente CLI expects configuration in `~/.ente/config.yaml`. Here's how to set it up:
## Method 1: Direct Configuration
1. Create the config file:
```bash
mkdir -p ~/.ente
cat > ~/.ente/config.yaml << EOF
api:
url: https://ente.due.ren
EOF
```
2. Add your account interactively:
```bash
ente account add
# It will ask for:
# - Export directory: /tmp/ente-export (or any directory)
# - Email: your-admin@email.com
# - Password: your-password
```
## Method 2: Using the Admin Commands Directly
If the interactive setup is problematic, you can use the admin commands with explicit parameters:
```bash
# Set the API endpoint
export ENTE_API_URL="https://ente.due.ren"
# Or pass it directly in the command
ente admin update-subscription \
--api-url https://ente.due.ren \
--admin-user admin@due.ren \
--user user@example.com \
--storage 1000 \
--valid-for 365
```
## Method 3: Direct Database Update (Fallback)
Since the CLI setup seems problematic, you can update the database directly in the Cloudron terminal:
```bash
# In Cloudron terminal
PGPASSWORD="$CLOUDRON_POSTGRESQL_PASSWORD" psql \
-h "$CLOUDRON_POSTGRESQL_HOST" \
-U "$CLOUDRON_POSTGRESQL_USERNAME" \
-d "$CLOUDRON_POSTGRESQL_DATABASE" << EOF
-- Update user to 1TB for 1 year
UPDATE users
SET storage_bonus = 1073741824000, -- 1000 GB in bytes
subscription_expiry = EXTRACT(EPOCH FROM NOW() + INTERVAL '365 days') * 1000000
WHERE email = 'andreas@due.ren';
-- Show the result
SELECT email,
storage_bonus / 1073741824.0 as storage_gb,
to_timestamp(subscription_expiry / 1000000) as expires
FROM users WHERE email = 'andreas@due.ren';
EOF
```

20
setup-ente-cli.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
# Setup Ente CLI for custom server
echo "Setting up Ente CLI for custom server..."
# Create config directory
mkdir -p ~/.ente
# Create the CLI config with custom endpoint
cat > ~/.ente/config.yaml << EOF
host: https://ente.due.ren
EOF
echo "Configuration created at ~/.ente/config.yaml"
echo ""
echo "Now you can add your account:"
echo " ente account add"
echo ""
echo "Then use admin commands:"
echo " ente admin update-subscription --admin-user admin@due.ren --user user@example.com --storage 1000 --valid-for 365"

150
start-debug.sh Executable file
View File

@@ -0,0 +1,150 @@
#!/bin/bash
# Better signal handling - forward signals to child processes
trap 'kill -TERM $SERVER_PID; kill -TERM $CADDY_PID; exit' TERM INT
set -eu
echo "==> Starting Ente Cloudron app (DEBUG MODE)..."
# Create necessary directories
mkdir -p /app/data/config /app/data/logs /app/data/caddy
# Check if web directories exist
echo "==> Checking web app directories:"
for app in photos accounts auth cast; do
if [ -d "/app/web/$app" ]; then
echo "==> Found: /app/web/$app"
ls -la "/app/web/$app" | head -5
else
echo "==> WARNING: Missing /app/web/$app - creating placeholder"
mkdir -p "/app/web/$app"
echo "<html><body><h1>$app app placeholder</h1></body></html>" > "/app/web/$app/index.html"
fi
done
# Create a simple test Caddyfile first
echo "==> Creating simple test Caddyfile"
cat > /app/data/Caddyfile <<'EOT'
{
admin off
auto_https off
}
:3080 {
log {
output stdout
format console
level DEBUG
}
# Health check endpoint
handle /health {
header Content-Type "application/json"
respond "{\"status\": \"OK\", \"timestamp\": \"{{now | date \"2006-01-02T15:04:05Z07:00\"}}\"}" 200
}
# Test endpoint
handle /test {
respond "Caddy is working on port 3080!" 200
}
# API proxy to Museum server
handle /api/* {
uri strip_prefix /api
reverse_proxy localhost:8080 {
transport http {
read_timeout 60s
write_timeout 60s
}
# Add error handling
handle_errors {
respond "{\"error\": \"Museum server not available\"}" 503
}
}
}
# Serve web apps with fallback
handle {
root * /app/web/photos
try_files {path} {path}/ /index.html
file_server {
browse
}
}
}
EOT
# Start a simple Museum mock server for testing
echo "==> Starting mock Museum server on port 8080"
cat > /tmp/museum-mock.js <<'EOF'
const http = require('http');
const server = http.createServer((req, res) => {
console.log(`Museum mock: ${req.method} ${req.url}`);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ status: 'ok', path: req.url, timestamp: new Date().toISOString() }));
});
server.listen(8080, '127.0.0.1', () => {
console.log('Museum mock server running on http://127.0.0.1:8080');
});
EOF
node /tmp/museum-mock.js > /app/data/logs/museum-mock.log 2>&1 &
SERVER_PID=$!
echo "==> Mock Museum server started (PID: $SERVER_PID)"
# Wait for Museum mock to be ready
sleep 2
# Test Museum mock
echo "==> Testing Museum mock server..."
curl -s http://localhost:8080/test || echo "WARNING: Museum mock not responding"
# Validate Caddyfile
echo "==> Validating Caddyfile..."
caddy validate --config /app/data/Caddyfile --adapter caddyfile || {
echo "==> ERROR: Caddyfile validation failed!"
exit 1
}
# Start Caddy with explicit environment
echo "==> Starting Caddy web server..."
CADDY_FORMAT=console caddy run --config /app/data/Caddyfile --adapter caddyfile 2>&1 | tee /app/data/logs/caddy-combined.log &
CADDY_PID=$!
echo "==> Caddy started (PID: $CADDY_PID)"
# Wait for Caddy to start
echo "==> Waiting for Caddy to start..."
for i in {1..30}; do
if curl -s http://localhost:3080/health > /dev/null; then
echo "==> Caddy is responding!"
break
fi
echo -n "."
sleep 1
done
echo
# Check process status
echo "==> Process status:"
ps aux | grep -E "(caddy|node)" | grep -v grep || echo "No processes found"
# Check port status
echo "==> Port status:"
netstat -tlnp 2>/dev/null | grep -E "(3080|8080)" || lsof -i :3080 -i :8080 2>/dev/null || echo "Cannot check port status"
# Test endpoints
echo "==> Testing endpoints:"
echo "Health check:"
curl -s http://localhost:3080/health | jq . || echo "Failed"
echo -e "\nTest endpoint:"
curl -s http://localhost:3080/test || echo "Failed"
echo -e "\nAPI proxy:"
curl -s http://localhost:3080/api/status | jq . || echo "Failed"
echo "==> Startup complete. Services:"
echo " - Caddy PID: $CADDY_PID"
echo " - Museum Mock PID: $SERVER_PID"
echo "==> Logs: /app/data/logs/"
# Keep running
wait $SERVER_PID $CADDY_PID

139
start.sh
View File

@@ -136,13 +136,19 @@ email:
port: ${CLOUDRON_MAIL_SMTP_PORT:-25} port: ${CLOUDRON_MAIL_SMTP_PORT:-25}
username: "${CLOUDRON_MAIL_SMTP_USERNAME:-}" username: "${CLOUDRON_MAIL_SMTP_USERNAME:-}"
password: "${CLOUDRON_MAIL_SMTP_PASSWORD:-}" password: "${CLOUDRON_MAIL_SMTP_PASSWORD:-}"
from: "${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_FQDN:-localhost}}" from: "${CLOUDRON_MAIL_FROM:-no-reply@${CLOUDRON_APP_DOMAIN:-localhost}}"
# WebAuthn configuration for passkey support # WebAuthn configuration for passkey support
webauthn: webauthn:
rpid: "${CLOUDRON_APP_FQDN:-localhost}" rpid: "${CLOUDRON_APP_DOMAIN:-localhost}"
rporigins: rporigins:
- "https://${CLOUDRON_APP_FQDN:-localhost}" - "https://${CLOUDRON_APP_DOMAIN:-localhost}"
# Additional Museum server configuration
http:
allowed_hosts:
- "${CLOUDRON_APP_DOMAIN:-localhost}"
base_url: "https://${CLOUDRON_APP_DOMAIN:-localhost}"
EOF EOF
chmod 600 "$MUSEUM_CONFIG" chmod 600 "$MUSEUM_CONFIG"
log "INFO" "Created Museum configuration at ${MUSEUM_CONFIG}" log "INFO" "Created Museum configuration at ${MUSEUM_CONFIG}"
@@ -241,25 +247,7 @@ fi
# =============================================== # ===============================================
# Web Application Setup # Web Application Setup
# =============================================== # ===============================================
log "INFO" "Web applications are pre-built and available in /app/web/" log "INFO" "Web applications are pre-built with relative API endpoint /api"
# Fix API endpoint configuration in built JavaScript files
log "INFO" "Updating API endpoint configuration in web apps"
ACTUAL_ENDPOINT="https://${CLOUDRON_APP_DOMAIN}/api"
log "INFO" "Setting API endpoint to: $ACTUAL_ENDPOINT"
# Replace placeholder endpoint in all JavaScript files
for webapp in photos accounts auth cast; do
WEB_DIR="/app/web/${webapp}"
if [ -d "$WEB_DIR" ]; then
log "INFO" "Processing ${webapp} app"
# Find and replace the placeholder endpoint in all JS files
find "$WEB_DIR" -name "*.js" -type f -exec sed -i "s|https://example.com/api|${ACTUAL_ENDPOINT}|g" {} \;
log "INFO" "Updated endpoint configuration for ${webapp}"
else
log "WARN" "Web directory not found for ${webapp}"
fi
done
# =============================================== # ===============================================
# Node.js Placeholder Server # Node.js Placeholder Server
@@ -389,7 +377,7 @@ const apiHandlers = {
token: 'placeholder-jwt-token-' + Date.now(), token: 'placeholder-jwt-token-' + Date.now(),
user: { user: {
id: 1, id: 1,
email: 'placeholder@example.com', email: 'placeholder@' + (process.env.CLOUDRON_APP_DOMAIN || 'localhost'),
name: 'Placeholder User' name: 'Placeholder User'
} }
})); }));
@@ -418,7 +406,7 @@ const apiHandlers = {
token: 'placeholder-jwt-token-' + Date.now(), token: 'placeholder-jwt-token-' + Date.now(),
user: { user: {
id: 1, id: 1,
email: 'placeholder@example.com', email: 'placeholder@' + (process.env.CLOUDRON_APP_DOMAIN || 'localhost'),
name: 'New User' name: 'New User'
} }
})); }));
@@ -645,8 +633,8 @@ cat > "$CADDY_CONFIG" << EOF
respond 204 respond 204
} }
# API endpoints with CORS # API endpoints with CORS - strip /api prefix before forwarding
handle /api/* { handle_path /api/* {
reverse_proxy localhost:8080 { reverse_proxy localhost:8080 {
header_up Host {http.request.host} header_up Host {http.request.host}
header_up X-Real-IP {http.request.remote} header_up X-Real-IP {http.request.remote}
@@ -669,24 +657,101 @@ cat > "$CADDY_CONFIG" << EOF
} }
} }
# Health check endpoint # Health check endpoints
handle /health { handle /health {
reverse_proxy localhost:8080 reverse_proxy localhost:8080
} }
# Static files for Next.js assets from all apps handle /ping {
handle /_next/* { reverse_proxy localhost:8080
@photosNext path /_next/*
handle @photosNext {
root * /app/web/photos
file_server
} }
# Next.js assets for cast app - Fixed routing v2
handle_path /cast/_next/* {
root * /app/web/cast
file_server
header { header {
Cache-Control "public, max-age=31536000" Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*" Access-Control-Allow-Origin "*"
} }
} }
# Next.js assets for accounts app
handle_path /accounts/_next/* {
root * /app/web/accounts
file_server
header {
Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*"
}
}
# Next.js assets for auth app
handle_path /auth/_next/* {
root * /app/web/auth
file_server
header {
Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*"
}
}
# Next.js assets for photos app
handle_path /photos/_next/* {
root * /app/web/photos
file_server
header {
Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*"
}
}
# Generic _next assets (fallback to photos)
handle /_next/* {
root * /app/web/photos
file_server
header {
Cache-Control "public, max-age=31536000"
Access-Control-Allow-Origin "*"
}
}
# Images for cast app
handle_path /cast/images/* {
root * /app/web/cast
file_server
header {
Cache-Control "public, max-age=86400"
}
}
# Images for accounts app
handle_path /accounts/images/* {
root * /app/web/accounts
file_server
header {
Cache-Control "public, max-age=86400"
}
}
# Images for auth app
handle_path /auth/images/* {
root * /app/web/auth
file_server
header {
Cache-Control "public, max-age=86400"
}
}
# Images for photos app
handle_path /photos/images/* {
root * /app/web/photos
file_server
header {
Cache-Control "public, max-age=86400"
}
}
# Photos app # Photos app
handle_path /photos/* { handle_path /photos/* {
root * /app/web/photos root * /app/web/photos
@@ -773,10 +838,10 @@ cat > /app/data/SETUP-INSTRUCTIONS.md << EOF
The following web applications are available: The following web applications are available:
- Photos: https://${CLOUDRON_APP_FQDN}/photos/ - Photos: https://${CLOUDRON_APP_DOMAIN}/photos/
- Accounts: https://${CLOUDRON_APP_FQDN}/accounts/ - Accounts: https://${CLOUDRON_APP_DOMAIN}/accounts/
- Auth: https://${CLOUDRON_APP_FQDN}/auth/ - Auth: https://${CLOUDRON_APP_DOMAIN}/auth/
- Cast: https://${CLOUDRON_APP_FQDN}/cast/ - Cast: https://${CLOUDRON_APP_DOMAIN}/cast/
## Support ## Support

57
update-storage.sh Executable file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
# Script to update Ente user storage using the Ente CLI
# Run this from your local machine (not inside Cloudron)
# Check if ente CLI is installed
if ! command -v ente &> /dev/null; then
echo "Ente CLI is not installed. Please install it first:"
echo ""
echo "For macOS:"
echo " brew tap ente-io/ente"
echo " brew install ente-cli"
echo ""
echo "For other systems, download from:"
echo " https://github.com/ente-io/ente/releases"
exit 1
fi
# Your Ente instance
ENTE_ENDPOINT="https://ente.due.ren"
# Function to update subscription
update_subscription() {
local admin_email="$1"
local user_email="$2"
local storage_gb="$3"
local valid_days="$4"
echo "Updating subscription for: $user_email"
echo "Storage: ${storage_gb}GB"
echo "Valid for: ${valid_days} days"
echo "Using admin account: $admin_email"
echo ""
# Run the ente CLI command
ente admin update-subscription \
--host "$ENTE_ENDPOINT" \
--admin-user "$admin_email" \
--user "$user_email" \
--storage "$storage_gb" \
--valid-for "$valid_days"
}
# Check arguments
if [ $# -lt 4 ]; then
echo "Usage: $0 <admin-email> <user-email> <storage-gb> <valid-days>"
echo ""
echo "Example:"
echo " $0 admin@due.ren andreas@due.ren 1000 365"
echo ""
echo "Make sure you're logged in to the Ente CLI first:"
echo " ente account add"
echo " API endpoint: $ENTE_ENDPOINT"
exit 1
fi
# Run the update
update_subscription "$1" "$2" "$3" "$4"