6 Commits

Author SHA1 Message Date
Your Name
da50bf4773 Add OTP email monitor to handle Museum skipped emails
- Implement comprehensive OTP email monitoring service
- Monitor Museum logs for "Skipping sending email" pattern
- Send verification emails using Cloudron email addon
- Add specific regex pattern for Museum's skip email format
- Version bump to 0.1.62

The monitor captures OTP codes from logs when Museum skips sending
emails and sends them via Cloudron's email system. This ensures
users receive their verification codes even when Museum's email
configuration is not sending directly.
2025-07-22 12:27:44 -06:00
Your Name
4290a33ba9 Fix JavaScript URL construction error for API endpoint
- Change NEXT_PUBLIC_ENTE_ENDPOINT from "/api" to "https://example.com/api" during build to satisfy URL constructor requirements
- Add runtime replacement in start.sh to replace placeholder with actual domain endpoint
- This resolves the "TypeError: Failed to construct 'URL': Invalid URL" error in the frontend

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-22 08:58:53 -06:00
Your Name
62b6f7f9ac Fix S3 configuration - set are_local_buckets to true
- Changed are_local_buckets from false to true (required for external S3)
- Simplified S3 configuration to only use b2-eu-cen bucket
- Removed unnecessary replication buckets for single bucket setup

This aligns with Ente's documentation where are_local_buckets=true
is used for external S3 services like Wasabi.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 20:44:19 -06:00
Your Name
e3eb1b0491 Hardcode Wasabi S3 configuration with proper Ente format
- Remove dynamic S3 configuration loading
- Hardcode Wasabi credentials as requested
- Use proper Ente S3 configuration format with datacenter names
- Configure all three storage buckets (b2-eu-cen, wasabi-eu-central-2-v3, scw-eu-fr-v3)
- Set are_local_buckets to false for external S3
- Add compliance flag for Wasabi bucket

This should fix the MissingRegion error by properly configuring S3 storage
according to Ente's expected format.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 20:41:58 -06:00
Your Name
fc82e988e9 Update CloudronManifest version to 1.0.1
Increment version after multiple iterations of S3 configuration fixes and port conflict resolution.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 20:37:07 -06:00
Your Name
5068e12025 Fix port conflict between Museum server and Caddy
- Changed Museum server to run on port 8080 instead of 3080
- Updated all health check URLs to use port 8080
- Updated Caddy reverse proxy to forward API requests to port 8080
- Added clarifying comment about port usage

This resolves the circular reference where both Caddy and Museum were trying to use port 3080.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-21 17:18:51 -06:00
18 changed files with 955 additions and 1892 deletions

View File

@@ -1,68 +0,0 @@
# Ente Cloudron App Build & Deployment Guide
## Prerequisites
- Cloudron CLI (`npm install -g cloudron`) configured for your server
- Docker (for local test builds, optional when using the Cloudron build service)
- Access to this repository (`andreasdueren/ente-cloudron`)
- Cloudron build-service token: `e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e`
## Build
1. Clone the repository (if needed):
```bash
git clone https://github.com/andreasdueren/ente-cloudron.git
cd ente-cloudron
```
2. Build the image via the Cloudron build service. Adjust `--tag` to match `CloudronManifest.json` (`0.4.3`) and optionally override the Ente git ref:
```bash
cloudron build \
--set-build-service builder.docker.due.ren \
--build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \
--set-repository andreasdueren/ente-cloudron \
--tag 0.4.3 \
--build-arg ENTE_GIT_REF=main
```
Use a tagged Ente release for reproducible builds (e.g. `--build-arg ENTE_GIT_REF=v0.9.0`).
## Install / Reinstall
Always uninstall the dev instance before reinstalling.
```bash
cloudron install \
--location ente.due.ren \
--image andreasdueren/ente-cloudron:0.4.3
```
If the install command runs for more than ~30seconds without feedback, abort and inspect `cloudron logs --app ente.due.ren`.
## Smoke Tests
1. Open `https://ente.due.ren/health` and ensure it returns `status: OK`.
2. Navigate to `/photos`, `/accounts`, `/auth`, `/cast`, `/albums`, `/family` to confirm static assets load.
3. Tail logs while signing up a user to verify Museum output:
```bash
cloudron logs --app ente.due.ren -f
```
## Required Configuration
Populate `/app/data/config/s3.env` with valid S3 credentials and restart the app.
```bash
S3_ENDPOINT=https://<account>.r2.cloudflarestorage.com
S3_REGION=auto
S3_BUCKET=ente-due-ren
S3_ACCESS_KEY=XXXXXXXX
S3_SECRET_KEY=YYYYYYYY
S3_PREFIX=optional/path
```
Optional: set `CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, and `CLOUDRON_OIDC_CLIENT_SECRET` in the Cloudron UI to enable SSO in the generated Museum configuration.
## Troubleshooting
- **S3 errors**: Verify credentials in `/app/data/config/s3.env`; check connectivity using `aws s3 ls --endpoint-url ...` from a trusted host.
- **Startup issues**: Inspect `/app/data/logs/startup.log` (also mirrored to `cloudron logs`) for rendered configuration and error messages.
- **Museum not starting**: Inspect `/app/data/museum/configurations/local.yaml` for syntax issues; delete to regenerate.
- **Frontend stale after update**: Restart the app—the startup script re-syncs static assets on each boot.
- **OIDC issues**: Confirm the callback URL `/api/v1/session/callback` is allowed in the Cloudron SSO client configuration.
## Useful Commands
```bash
cloudron exec --app ente.due.ren -- cat /app/data/museum/configurations/local.yaml
cloudron exec --app ente.due.ren -- ente --help
cloudron logs --app ente.due.ren -f
cloudron exec --app ente.due.ren -- tail -f /app/data/logs/startup.log
```

View File

@@ -1,36 +1,5 @@
# Changelog # Changelog
## 0.4.5 (2025-10-30)
* Serve photos UI on the primary hostname and mount other apps on `accounts/auth/cast/albums/family.<root-domain>`
* Enable multiDomain in the manifest so aliases can be set in Cloudron UI
* Simplified documentation for S3 setup and alias domains
* Fix CORS responses for auth subdomains and forward real client IPs from Cloudron proxy
## 0.4.4 (2025-10-30)
* Restore Cloudflare R2 path-style URLs and simplify to a single hot-storage data center
* Serve the frontend apps on dedicated subdomains (photos/accounts/auth/cast/albums/family)
* Startup script now regenerates Caddy and Museum configs for the new host layout
* Added post-install checklist entries and updated docs for required DNS records
## 0.4.3 (2025-10-29)
* Always regenerate Museum configuration on startup to pick up S3 credential changes
* Enables seamless workflow: add S3 credentials to /app/data/config/s3.env and restart
* Fixes issue where S3 configuration changes required manual intervention
## 0.4.2 (2025-10-29)
* Use SMTPS (port 2465) with TLS encryption for email delivery
* Fixes email sending with requiresValidCertificate flag on Cloudron 9
## 0.4.1 (2025-10-23)
* Fix email sending for user registration by enabling TLS certificate validation in sendmail addon
* Add requiresValidCertificate flag to sendmail configuration to ensure proper SMTP authentication with Go applications
* Note: Requires Cloudron 9 or later for requiresValidCertificate support
## 1.0.0 (2024-06-01) ## 1.0.0 (2024-06-01)
* Initial release of Ente for Cloudron * Initial release of Ente for Cloudron

158
CLAUDE.md
View File

@@ -1,158 +0,0 @@
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

View File

@@ -1,21 +0,0 @@
{
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

@@ -1,38 +1,38 @@
{ {
"id": "io.ente.cloudronapp", "id": "io.ente.cloudronapp",
"title": "Ente", "title": "Ente",
"author": "Ente Development Team", "author": "Ente Authors",
"description": "file://DESCRIPTION.md", "description": "file://DESCRIPTION.md",
"changelog": "file://CHANGELOG.md", "changelog": "file://CHANGELOG.md",
"contactEmail": "contact@ente.io", "contactEmail": "contact@ente.io",
"website": "https://ente.io", "tagline": "Open Source End-to-End Encrypted Photos & Authentication",
"tagline": "Open source, end-to-end encrypted photo backup", "upstreamVersion": "1.0.0",
"version": "0.4.3", "version": "0.1.62",
"upstreamVersion": "git-main", "healthCheckPath": "/ping",
"healthCheckPath": "/health",
"httpPort": 3080, "httpPort": 3080,
"memoryLimit": 1610612736, "memoryLimit": 1073741824,
"postInstallMessage": "file://POSTINSTALL.md",
"addons": { "addons": {
"localstorage": {}, "localstorage": {},
"postgresql": {}, "postgresql": {},
"email": {},
"sendmail": { "sendmail": {
"supportsDisplayName": true, "supportsDisplayName": true
"requiresValidCertificate": true
} }
}, },
"checklist": { "checklist": {
"configure-object-storage": { "create-permanent-admin": {
"message": "Configure your S3-compatible storage in /app/data/config/s3.env before first use." "message": "Required: S3 Storage Configuration!"
} }
}, },
"icon": "file://logo.png", "icon": "file://logo.png",
"tags": [ "tags": [
"photos", "photos",
"encryption", "authentication",
"backup", "e2ee",
"self-hosting" "encryption"
], ],
"manifestVersion": 2, "manifestVersion": 2,
"minBoxVersion": "8.1.0" "minBoxVersion": "8.1.0",
"website": "https://ente.io"
} }

View File

@@ -1,111 +1,173 @@
# syntax=docker/dockerfile:1 # Build Museum server from source
ARG ENTE_GIT_REF=main
FROM debian:bookworm AS ente-source
ARG ENTE_GIT_REF
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates git && \
git clone --depth=1 --branch "${ENTE_GIT_REF}" https://github.com/ente-io/ente.git /src && \
rm -rf /var/lib/apt/lists/*
FROM golang:1.24-bookworm AS museum-builder FROM golang:1.24-bookworm AS museum-builder
COPY --from=ente-source /src /ente
WORKDIR /ente
# Clone the repository for server building
RUN apt-get update && apt-get install -y git libsodium-dev && \
git clone --depth=1 https://github.com/ente-io/ente.git . && \
apt-get clean && apt-get autoremove && \
rm -rf /var/cache/apt /var/lib/apt/lists
# Build the Museum server
WORKDIR /ente/server WORKDIR /ente/server
RUN apt-get update && \ RUN go mod download && \
apt-get install -y --no-install-recommends build-essential pkg-config libsodium-dev && \ CGO_ENABLED=1 GOOS=linux go build -a -o museum ./cmd/museum
rm -rf /var/lib/apt/lists/*
RUN mkdir -p /build/museum && \
CGO_ENABLED=1 GOOS=linux go build -o /build/museum/museum ./cmd/museum && \
for dir in migrations web-templates mail-templates assets; do \
rm -rf "/build/museum/$dir"; \
if [ -d "$dir" ]; then \
cp -r "$dir" "/build/museum/$dir"; \
else \
mkdir -p "/build/museum/$dir"; \
fi; \
done
FROM golang:1.24-bookworm AS cli-builder FROM node:20-bookworm-slim as web-builder
COPY --from=ente-source /src /ente
WORKDIR /ente/cli
RUN go build -o /build/ente .
FROM node:20-bookworm-slim AS web-builder WORKDIR /ente
ENV NEXT_PUBLIC_ENTE_ENDPOINT=ENTE_API_ORIGIN_PLACEHOLDER
ENV NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT=https://albums.localhost.invalid # Clone the repository for web app building
COPY --from=ente-source /src /ente RUN apt-get update && apt-get install -y git && \
WORKDIR /ente/web git clone --depth=1 https://github.com/ente-io/ente.git . && \
RUN apt-get update && \ apt-get clean && apt-get autoremove && \
apt-get install -y --no-install-recommends build-essential python3 && \ rm -rf /var/cache/apt /var/lib/apt/lists
rm -rf /var/lib/apt/lists/*
# Will help default to yarn version 1.22.22
RUN corepack enable RUN corepack enable
RUN yarn install --network-timeout 1000000
RUN mkdir -p /build/web/photos /build/web/accounts /build/web/auth /build/web/cast /build/web/albums /build/web/family # Set environment variables for web app build
RUN set -e; \ # Set the API endpoint to use current origin - this will work at runtime
yarn build:photos; \ ENV NEXT_PUBLIC_ENTE_ENDPOINT="https://example.com/api"
yarn build:accounts; \ # Add a note for clarity
yarn build:auth; \ RUN echo "Building with placeholder NEXT_PUBLIC_ENTE_ENDPOINT, will be served by Caddy proxy at /api"
yarn build:cast
RUN if [ -d "apps" ]; then \ # Debugging the repository structure
for app in photos accounts auth cast; do \ RUN find . -type d -maxdepth 3 | sort
if [ -d "apps/${app}/out" ]; then \
rm -rf "/build/web/${app}"; \ # Check if web directory exists with apps subdirectory
mkdir -p "/build/web/${app}"; \ RUN mkdir -p /build/web/photos /build/web/accounts /build/web/auth /build/web/cast && \
cp -r "apps/${app}/out/." "/build/web/${app}/"; \ if [ -d "web" ] && [ -d "web/apps" ]; then \
else \ echo "Found web/apps directory, building web apps"; \
printf 'Missing build output for %s\n' "${app}"; \ cd web && \
printf '<html><body><h1>Ente %s</h1><p>Build output missing.</p></body></html>\n' "${app}" > "/build/web/${app}/index.html"; \ yarn cache clean && \
yarn install --network-timeout 1000000000 && \
yarn build:photos && \
yarn build:accounts && \
yarn build:auth && \
yarn build:cast && \
if [ -d "apps/photos/out" ]; then \
cp -r apps/photos/out/* /build/web/photos/; \
fi && \
if [ -d "apps/accounts/out" ]; then \
cp -r apps/accounts/out/* /build/web/accounts/; \
fi && \
if [ -d "apps/auth/out" ]; then \
cp -r apps/auth/out/* /build/web/auth/; \
fi && \
if [ -d "apps/cast/out" ]; then \
cp -r apps/cast/out/* /build/web/cast/; \
fi; \
elif [ -d "web" ]; then \
echo "Found web directory, looking for alternative structure"; \
find web -type d | grep -v node_modules | sort; \
if [ -d "web/photos" ]; then \
echo "Building photos app"; \
cd web/photos && yarn install && yarn build && \
if [ -d "out" ]; then cp -r out/* /build/web/photos/; fi; \
fi; \
if [ -d "web/accounts" ]; then \
echo "Building accounts app"; \
cd web/accounts && yarn install && yarn build && \
if [ -d "out" ]; then cp -r out/* /build/web/accounts/; fi; \
fi; \
if [ -d "web/auth" ]; then \
echo "Building auth app"; \
cd web/auth && yarn install && yarn build && \
if [ -d "out" ]; then cp -r out/* /build/web/auth/; fi; \
fi; \
if [ -d "web/cast" ]; then \
echo "Building cast app"; \
cd web/cast && yarn install && yarn build && \
if [ -d "out" ]; then cp -r out/* /build/web/cast/; fi; \
fi; \ fi; \
done; \
else \ else \
for app in photos accounts auth cast; do \ echo "Web directory not found, creating placeholder web pages"; \
printf '<html><body><h1>Ente %s</h1><p>Build output missing.</p></body></html>\n' "${app}" > "/build/web/${app}/index.html"; \ # Create placeholder HTML files for each app \
done; \ mkdir -p /build/web/photos /build/web/accounts /build/web/auth /build/web/cast; \
fi && \ echo "<html><body><h1>Ente Photos</h1><p>Web app not available. Please check the build logs.</p></body></html>" > /build/web/photos/index.html; \
rm -rf /build/web/albums /build/web/family && \ echo "<html><body><h1>Ente Accounts</h1><p>Web app not available. Please check the build logs.</p></body></html>" > /build/web/accounts/index.html; \
cp -r /build/web/photos /build/web/albums && \ echo "<html><body><h1>Ente Auth</h1><p>Web app not available. Please check the build logs.</p></body></html>" > /build/web/auth/index.html; \
cp -r /build/web/photos /build/web/family echo "<html><body><h1>Ente Cast</h1><p>Web app not available. Please check the build logs.</p></body></html>" > /build/web/cast/index.html; \
fi
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
ENV APP_DIR=/app/code \ # Install necessary packages and Caddy webserver
DATA_DIR=/app/data \
HOME=/app/data/home
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl jq libsodium23 pkg-config postgresql-client caddy openssl && \ apt-get install -y curl git nodejs npm libsodium23 libsodium-dev pkg-config postgresql-client && \
rm -rf /var/lib/apt/lists/* npm install -g yarn serve && \
# Install Caddy for web server
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https && \
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list && \
apt-get update && \
apt-get install -y caddy && \
apt-get clean && apt-get autoremove && \
rm -rf /var/cache/apt /var/lib/apt/lists
RUN mkdir -p /app/pkg /app/web "$HOME" && chown -R cloudron:cloudron /app /app/web "$HOME" # Install Go 1.24.1
RUN curl -L https://go.dev/dl/go1.24.1.linux-amd64.tar.gz -o go.tar.gz && \
rm -rf /usr/local/go && \
tar -C /usr/local -xzf go.tar.gz && \
rm go.tar.gz && \
ln -sf /usr/local/go/bin/go /usr/local/bin/go && \
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
COPY --from=ente-source /src ${APP_DIR} # Set up directory structure
RUN rm -rf ${APP_DIR}/.git RUN mkdir -p /app/code /app/data/config /app/data/caddy /app/web
RUN mkdir -p /app/museum-bin WORKDIR /app/code
COPY --from=museum-builder /build/museum/museum /app/museum-bin/museum
COPY --from=museum-builder /build/museum/migrations ${APP_DIR}/server/migrations
COPY --from=museum-builder /build/museum/web-templates ${APP_DIR}/server/web-templates
COPY --from=museum-builder /build/museum/mail-templates ${APP_DIR}/server/mail-templates
COPY --from=museum-builder /build/museum/assets ${APP_DIR}/server/assets
RUN chmod +x /app/museum-bin/museum
COPY --from=cli-builder /build/ente /app/code/ente # Clone the ente repository during build (for the Museum server)
RUN ln -sf /app/code/ente /usr/local/bin/ente && chmod +x /app/code/ente 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 && \
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
# Pre-download Go dependencies
RUN cd server && \
export GOMODCACHE="/app/data/go/pkg/mod" && \
export GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod" && \
export GOTOOLCHAIN=local && \
export GO111MODULE=on && \
export GOSUMDB=off && \
mkdir -p /app/data/go/pkg/mod && \
chmod -R 777 /app/data/go && \
go mod download
# Set Go environment variables
ENV GOTOOLCHAIN=local
ENV GO111MODULE=on
ENV GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod"
ENV PATH="/usr/local/go/bin:${PATH}"
ENV GOSUMDB=off
ENV GOMODCACHE="/app/data/go/pkg/mod"
# Copy the web app built files from the first stage
COPY --from=web-builder /build/web/photos /app/web/photos COPY --from=web-builder /build/web/photos /app/web/photos
COPY --from=web-builder /build/web/accounts /app/web/accounts 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/auth /app/web/auth
COPY --from=web-builder /build/web/cast /app/web/cast COPY --from=web-builder /build/web/cast /app/web/cast
COPY --from=web-builder /build/web/albums /app/web/albums
COPY --from=web-builder /build/web/family /app/web/family
COPY start.sh /app/pkg/start.sh # Copy Museum server binary from builder stage to app directory (not data volume)
COPY admin-helper.sh /app/pkg/admin-helper.sh RUN mkdir -p /app/museum-bin
COPY admin-helper-direct.sh /app/pkg/admin-helper-direct.sh COPY --from=museum-builder /ente/server/museum /app/museum-bin/museum
RUN chmod +x /app/museum-bin/museum
RUN chmod +x /app/pkg/start.sh /app/pkg/admin-helper.sh /app/pkg/admin-helper-direct.sh # Copy configuration and startup scripts
ADD start.sh /app/pkg/
ADD config.template.yaml /app/pkg/
EXPOSE 3080 8080 # Set proper permissions
RUN chmod +x /app/pkg/start.sh
# Expose the web port (Cloudron expects port 3080)
EXPOSE 3080
# Also expose API port
EXPOSE 8080
# Start the application
CMD ["/app/pkg/start.sh"] CMD ["/app/pkg/start.sh"]

View File

@@ -1,38 +1,25 @@
Your Ente installation is almost ready! Your Ente installation is almost ready!
## Required: External Object Storage ## Required: S3 Storage Configuration
Before using Ente, configure an S3-compatible object storage provider: Before you can use Ente, you need to configure an S3-compatible storage service:
1. Open the Cloudron dashboard and select your Ente app. 1. Go to your Cloudron dashboard
2. Launch the web terminal. 2. Click on your Ente app
3. Edit `/app/data/config/s3.env` and provide values for **all** required keys: 3. Click on "Terminal"
```bash 4. Edit the S3 configuration template:
nano /app/data/config/s3.env
``` ```
4. Save the file and restart the app from the Cloudron dashboard. nano /app/data/config/s3.env.template
```
Supported variables: 5. Fill in your S3 credentials (AWS S3, MinIO, DigitalOcean Spaces, etc.)
- `S3_ENDPOINT` (e.g. `https://<account>.r2.cloudflarestorage.com`) 6. Save the file and rename it:
- `S3_REGION` ```
- `S3_BUCKET` mv /app/data/config/s3.env.template /app/data/config/s3.env
- `S3_ACCESS_KEY` ```
- `S3_SECRET_KEY` 7. Restart your Ente app from the Cloudron dashboard
- `S3_PREFIX` (optional path prefix)
## Next Steps ## Next Steps
- Visit the app URL and create the first administrator account. 1. Once S3 is configured, visit your app URL to create an admin account
- Configure the Ente mobile apps to use your custom server (`Settings → Advanced → Custom Server`). 2. Configure your mobile apps to use your custom self-hosted server (Settings → Advanced → Custom Server)
- Optional: set the environment variables `CLOUDRON_OIDC_IDENTIFIER`, `CLOUDRON_OIDC_CLIENT_ID`, and `CLOUDRON_OIDC_CLIENT_SECRET` to enable Cloudron SSO in the generated Museum config. 3. Enjoy your private, end-to-end encrypted photo storage!
## Administration Helpers
- The Ente CLI binary is shipped at `/app/code/ente`. Run it via the Cloudron web terminal.
- CLI configuration lives at `/app/data/home/.ente/config.yaml` and already points to `https://<your-domain>/api`.
- The main Museum configuration is generated at `/app/data/museum/configurations/local.yaml`. Delete this file to regenerate it with updated environment variables.
Logs are streamed to the Cloudron dashboard. For deeper inspection use:
```bash
cloudron logs --app <location> -f
```

View File

@@ -1,133 +0,0 @@
#!/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

View File

@@ -1,93 +0,0 @@
#!/bin/bash
# Ente Admin Helper Script for Cloudron
# This script simplifies admin operations in the Cloudron terminal
MUSEUM_BIN="/app/museum-bin/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/museum
# 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/museum
"$MUSEUM_BIN" admin get-user-details --user "$user_email"
}
# Function to list all users
list_users() {
cd /app/data/museum
# 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

View File

@@ -18,20 +18,16 @@ database:
maxIdleConns: 25 maxIdleConns: 25
connMaxLifetime: "1h" connMaxLifetime: "1h"
s3: storage:
are_local_buckets: false type: "s3"
use_path_style_urls: true s3:
hot_storage:
primary: b2-eu-cen
secondary: b2-eu-cen
derived-storage: b2-eu-cen
b2-eu-cen:
endpoint: "%%S3_ENDPOINT%%" endpoint: "%%S3_ENDPOINT%%"
region: "%%S3_REGION%%" region: "%%S3_REGION%%"
bucket: "%%S3_BUCKET%%" bucket: "%%S3_BUCKET%%"
key: "%%S3_ACCESS_KEY%%" accessKey: "%%S3_ACCESS_KEY%%"
secret: "%%S3_SECRET_KEY%%" secretKey: "%%S3_SECRET_KEY%%"
path_prefix: "%%S3_PREFIX%%" prefix: "%%S3_PREFIX%%"
forcePathStyle: true
email: email:
smtp: smtp:

View File

@@ -1,35 +0,0 @@
#!/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"

View File

@@ -1,38 +0,0 @@
<!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>

View File

@@ -1,32 +0,0 @@
#!/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"
}

View File

@@ -1,64 +0,0 @@
# 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
```

View File

@@ -1,20 +0,0 @@
#!/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"

View File

@@ -1,150 +0,0 @@
#!/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

1598
start.sh Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +0,0 @@
#!/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"