Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
61046f1d42 | ||
|
7a5fac90ab | ||
|
b38bd6a249 | ||
|
a8b22a95c8 | ||
|
93cdf1f2f1 | ||
|
8d6fc6fde0 |
@@ -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.119",
|
"version": "0.1.133",
|
||||||
"healthCheckPath": "/ping",
|
"healthCheckPath": "/ping",
|
||||||
"httpPort": 3080,
|
"httpPort": 3080,
|
||||||
"memoryLimit": 1073741824,
|
"memoryLimit": 1073741824,
|
||||||
|
13
Dockerfile
13
Dockerfile
@@ -143,6 +143,7 @@ ENV GOFLAGS="-modfile=/app/data/go/go.mod -mod=mod"
|
|||||||
ENV PATH="/usr/local/go/bin:${PATH}"
|
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||||
ENV GOSUMDB=off
|
ENV GOSUMDB=off
|
||||||
ENV GOMODCACHE="/app/data/go/pkg/mod"
|
ENV GOMODCACHE="/app/data/go/pkg/mod"
|
||||||
|
ENV HOME=/app/data/home
|
||||||
|
|
||||||
# Copy the web app built files from the first stage
|
# 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
|
||||||
@@ -150,6 +151,18 @@ 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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Symlink CLI into PATH for convenience
|
||||||
|
RUN ln -sf /app/code/ente /usr/local/bin/ente
|
||||||
|
|
||||||
|
# Prepare CLI data directory symlink to persistent storage
|
||||||
|
RUN mkdir -p /app/data/cli-data && ln -s /app/data/cli-data /cli-data
|
||||||
|
|
||||||
# Copy Museum server binary from builder stage to app directory (not data volume)
|
# Copy Museum server binary from builder stage to app directory (not data volume)
|
||||||
RUN mkdir -p /app/museum-bin
|
RUN mkdir -p /app/museum-bin
|
||||||
COPY --from=museum-builder /ente/server/museum /app/museum-bin/museum
|
COPY --from=museum-builder /ente/server/museum /app/museum-bin/museum
|
||||||
|
@@ -11,7 +11,7 @@ Before you can use Ente, you need to configure an S3-compatible storage service:
|
|||||||
```
|
```
|
||||||
nano /app/data/config/s3.env
|
nano /app/data/config/s3.env
|
||||||
```
|
```
|
||||||
5. Uncomment the variables you need and fill in your S3 credentials (AWS S3, MinIO, DigitalOcean Spaces, etc.)
|
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
|
6. Save the file and restart your Ente app from the Cloudron dashboard
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
@@ -19,3 +19,16 @@ Before you can use Ente, you need to configure an S3-compatible storage service:
|
|||||||
1. Once S3 is configured, visit your app URL to create an admin account
|
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)
|
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!
|
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 `./ente ...`.
|
||||||
|
- The CLI configuration at `/app/data/home/.ente/config.yaml` already points to your instance (`https://<your-domain>/api`).
|
||||||
|
- CLI state is stored under `/app/data/cli-data/` so re-logins persist.
|
||||||
|
|
||||||
|
## Museum Server Configuration
|
||||||
|
|
||||||
|
- The active configuration lives at `/app/data/ente/server/configurations/local.yaml` and is created the first time the app starts.
|
||||||
|
- Subsequent restarts leave this file untouched, so you can whitelist admin accounts or adjust other settings as documented by Ente.
|
||||||
|
- Delete the file to regenerate the default template (environment values such as database and S3 credentials are rendered during creation).
|
||||||
|
129
start.sh
129
start.sh
@@ -22,6 +22,16 @@ log() {
|
|||||||
log "INFO" "Starting Ente Cloudron app"
|
log "INFO" "Starting Ente Cloudron app"
|
||||||
log "INFO" "Running in Cloudron environment with domain: ${CLOUDRON_APP_DOMAIN}"
|
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"
|
||||||
|
|
||||||
|
# Ensure CLI data directory persists across restarts
|
||||||
|
CLI_DATA_PERSIST="/app/data/cli-data"
|
||||||
|
mkdir -p "$CLI_DATA_PERSIST"
|
||||||
|
|
||||||
|
|
||||||
# Prevent infinite loops through startup flag
|
# Prevent infinite loops through startup flag
|
||||||
if [ -f "/app/data/startup_in_progress" ]; then
|
if [ -f "/app/data/startup_in_progress" ]; then
|
||||||
if [ "$(find /app/data/startup_in_progress -mmin +2)" ]; then
|
if [ "$(find /app/data/startup_in_progress -mmin +2)" ]; then
|
||||||
@@ -94,21 +104,26 @@ DEFAULT_S3_BUCKET="ente-due-ren"
|
|||||||
S3_CONFIG_DIR="/app/data/config"
|
S3_CONFIG_DIR="/app/data/config"
|
||||||
S3_CONFIG_FILE="$S3_CONFIG_DIR/s3.env"
|
S3_CONFIG_FILE="$S3_CONFIG_DIR/s3.env"
|
||||||
|
|
||||||
mkdir -p "$S3_CONFIG_DIR"
|
write_default_s3_template() {
|
||||||
|
|
||||||
if [ -f "$S3_CONFIG_FILE" ]; then
|
|
||||||
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"
|
|
||||||
cat > "$S3_CONFIG_FILE" << 'EOF'
|
cat > "$S3_CONFIG_FILE" << 'EOF'
|
||||||
# S3 configuration overrides for Ente on Cloudron.
|
# S3 configuration overrides for Ente on Cloudron.
|
||||||
# Uncomment and set any of the variables below to override the packaged defaults.
|
# 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.
|
# 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_ACCESS_KEY=
|
||||||
#S3_SECRET_KEY=
|
#S3_SECRET_KEY=
|
||||||
#S3_ENDPOINT=
|
#S3_ENDPOINT=
|
||||||
@@ -116,6 +131,49 @@ else
|
|||||||
#S3_BUCKET=
|
#S3_BUCKET=
|
||||||
EOF
|
EOF
|
||||||
chown cloudron:cloudron "$S3_CONFIG_FILE" || true
|
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" ] && grep -q "^# Ente CLI configuration" "$ENTE_CLI_CONFIG_FILE"; then
|
||||||
|
rm -f "$ENTE_CLI_CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
mkdir -p "$ENTE_CLI_CONFIG_DIR"
|
||||||
|
write_cli_config_if_needed() {
|
||||||
|
cat > "$ENTE_CLI_CONFIG_FILE" << EOF
|
||||||
|
endpoint:
|
||||||
|
api: ${BASE_URL%/}/api
|
||||||
|
log:
|
||||||
|
http: false
|
||||||
|
EOF
|
||||||
|
chown -R cloudron:cloudron "$HOME_DIR" || true
|
||||||
|
}
|
||||||
|
if [ ! -f "$ENTE_CLI_CONFIG_FILE" ]; then
|
||||||
|
write_cli_config_if_needed
|
||||||
|
else
|
||||||
|
if ! grep -q "endpoint:" "$ENTE_CLI_CONFIG_FILE" || grep -q "\\n" "$ENTE_CLI_CONFIG_FILE"; then
|
||||||
|
write_cli_config_if_needed
|
||||||
|
elif ! grep -q "${BASE_URL%/}/api" "$ENTE_CLI_CONFIG_FILE"; then
|
||||||
|
write_cli_config_if_needed
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
S3_ACCESS_KEY="${S3_ACCESS_KEY:-$DEFAULT_S3_ACCESS_KEY}"
|
S3_ACCESS_KEY="${S3_ACCESS_KEY:-$DEFAULT_S3_ACCESS_KEY}"
|
||||||
@@ -162,8 +220,9 @@ MUSEUM_CONFIG_DIR="/app/data/ente/server/configurations"
|
|||||||
MUSEUM_CONFIG="$MUSEUM_CONFIG_DIR/local.yaml"
|
MUSEUM_CONFIG="$MUSEUM_CONFIG_DIR/local.yaml"
|
||||||
mkdir -p "$MUSEUM_CONFIG_DIR"
|
mkdir -p "$MUSEUM_CONFIG_DIR"
|
||||||
|
|
||||||
log "INFO" "Rendering Museum server configuration"
|
if [ ! -f "$MUSEUM_CONFIG" ]; then
|
||||||
cat > "$MUSEUM_CONFIG" << EOF
|
log "INFO" "Rendering Museum server configuration"
|
||||||
|
cat > "$MUSEUM_CONFIG" << EOF
|
||||||
# Museum server configuration
|
# Museum server configuration
|
||||||
|
|
||||||
# Server settings
|
# Server settings
|
||||||
@@ -285,8 +344,11 @@ jobs:
|
|||||||
cron:
|
cron:
|
||||||
skip: true
|
skip: true
|
||||||
EOF
|
EOF
|
||||||
chmod 600 "$MUSEUM_CONFIG"
|
chmod 600 "$MUSEUM_CONFIG"
|
||||||
log "INFO" "Wrote Museum configuration to ${MUSEUM_CONFIG}"
|
log "INFO" "Wrote Museum configuration to ${MUSEUM_CONFIG}"
|
||||||
|
else
|
||||||
|
log "INFO" "Museum configuration already present at ${MUSEUM_CONFIG}; preserving existing file"
|
||||||
|
fi
|
||||||
|
|
||||||
# ===============================================
|
# ===============================================
|
||||||
# Database check
|
# Database check
|
||||||
@@ -441,34 +503,6 @@ for webapp in photos accounts auth cast; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# ===============================================
|
|
||||||
# Museum log highlighter (extract OTTs from logs)
|
|
||||||
# ===============================================
|
|
||||||
prepare_ott_highlighter() {
|
|
||||||
cat > "/app/data/ente/server/ott-log-highlight.js" << 'EOF'
|
|
||||||
const readline = require('readline');
|
|
||||||
const rl = readline.createInterface({ input: process.stdin });
|
|
||||||
|
|
||||||
const shouldHighlight = (line) => {
|
|
||||||
if (!line) return false;
|
|
||||||
const lower = line.toLowerCase();
|
|
||||||
if (lower.includes('added ott')) return true;
|
|
||||||
if (lower.includes('ott"') || lower.includes(' ott ')) return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
rl.on('line', (line) => {
|
|
||||||
process.stdout.write(line + '\n');
|
|
||||||
if (shouldHighlight(line)) {
|
|
||||||
const trimmed = line.trim();
|
|
||||||
process.stdout.write('============================================================\n');
|
|
||||||
process.stdout.write(`HIGHLIGHT: ${trimmed}\n`);
|
|
||||||
process.stdout.write('============================================================\n');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
# ===============================================
|
# ===============================================
|
||||||
# Node.js Placeholder Server
|
# Node.js Placeholder Server
|
||||||
# ===============================================
|
# ===============================================
|
||||||
@@ -610,9 +644,7 @@ const apiHandlers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const responsePayload = buildResponse(email);
|
const responsePayload = buildResponse(email);
|
||||||
log('============================================================');
|
log(`Verifying OTT ${ott} for ${email}`);
|
||||||
log(`HIGHLIGHT: Verifying OTT ${ott} for ${email}`);
|
|
||||||
log('============================================================');
|
|
||||||
|
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify(responsePayload));
|
res.end(JSON.stringify(responsePayload));
|
||||||
@@ -699,9 +731,7 @@ const apiHandlers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ott = ('' + Math.floor(100000 + Math.random() * 900000)).slice(-6);
|
const ott = ('' + Math.floor(100000 + Math.random() * 900000)).slice(-6);
|
||||||
log('============================================================');
|
log(`Generated OTT ${ott} for ${email}`);
|
||||||
log(`HIGHLIGHT: Generated OTT ${ott} for ${email}`);
|
|
||||||
log('============================================================');
|
|
||||||
|
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify({ success: true, ott, email }));
|
res.end(JSON.stringify({ success: true, ott, email }));
|
||||||
@@ -873,10 +903,9 @@ if [ "$USE_PLACEHOLDER" = true ]; then
|
|||||||
create_nodejs_placeholder
|
create_nodejs_placeholder
|
||||||
else
|
else
|
||||||
log "INFO" "Starting actual Museum server"
|
log "INFO" "Starting actual Museum server"
|
||||||
prepare_ott_highlighter
|
|
||||||
cd /app/data/ente/server
|
cd /app/data/ente/server
|
||||||
export ENVIRONMENT="${MUSEUM_ENVIRONMENT:-local}"
|
export ENVIRONMENT="${MUSEUM_ENVIRONMENT:-local}"
|
||||||
stdbuf -oL "$MUSEUM_BIN" 2>&1 | node ott-log-highlight.js | tee -a "$MUSEUM_LOG" &
|
stdbuf -oL "$MUSEUM_BIN" 2>&1 | tee -a "$MUSEUM_LOG" &
|
||||||
MUSEUM_PID=$!
|
MUSEUM_PID=$!
|
||||||
log "INFO" "Started Museum server (pipeline PID: $MUSEUM_PID)"
|
log "INFO" "Started Museum server (pipeline PID: $MUSEUM_PID)"
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user