Remote edge nodes pull origins/rules/edge IPs with ess_ site bearers (KD-15) instead of the shared CADDY_EDGE_API_KEY. Bundle supports ETag 304 and since, optional HMAC response sig, and soft-deps empty rules when EdgeRules is absent. First-class edge role enables web with mail and authority off; compose and pure-edge Caddyfile examples included.
127 lines
3.6 KiB
Bash
Executable file
127 lines
3.6 KiB
Bash
Executable file
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
TOR_HS_DIR="/data/tor/elektrine"
|
|
TOR_DATA_DIR="/data/tor/data"
|
|
CERTS_DIR="/data/certs"
|
|
UPLOADS_DATA_DIR="/data/uploads"
|
|
TLS_RUNTIME_DIR="$CERTS_DIR/runtime"
|
|
ROLE="${1:-${ELEKTRINE_RUNTIME_ROLE:-all}}"
|
|
|
|
case "$ROLE" in
|
|
all|app|edge|worker|mail|dns|vpn) ;;
|
|
*)
|
|
echo "Invalid runtime role: $ROLE" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
link_release_uploads_dir() {
|
|
local priv_dir
|
|
|
|
for priv_dir in /app/lib/elektrine-*/priv; do
|
|
[ -d "$priv_dir" ] || continue
|
|
|
|
local static_dir="$priv_dir/static"
|
|
local uploads_path="$static_dir/uploads"
|
|
|
|
mkdir -p "$static_dir" "$UPLOADS_DATA_DIR"
|
|
|
|
if [ -L "$uploads_path" ]; then
|
|
rm -f "$uploads_path"
|
|
elif [ -d "$uploads_path" ]; then
|
|
rm -rf "$uploads_path"
|
|
elif [ -e "$uploads_path" ]; then
|
|
rm -f "$uploads_path"
|
|
fi
|
|
|
|
ln -sfn "$UPLOADS_DATA_DIR" "$uploads_path"
|
|
done
|
|
}
|
|
|
|
decode_b64_to_file() {
|
|
local value="$1"
|
|
local destination="$2"
|
|
local label="$3"
|
|
|
|
[ -z "$value" ] && return 1
|
|
|
|
if printf '%s' "$value" | base64 -d > "${destination}.tmp" 2>/dev/null || \
|
|
printf '%s' "$value" | base64 --decode > "${destination}.tmp" 2>/dev/null; then
|
|
mv "${destination}.tmp" "$destination"
|
|
chmod 600 "$destination"
|
|
echo "Restored ${label} from environment backup."
|
|
return 0
|
|
fi
|
|
|
|
rm -f "${destination}.tmp"
|
|
echo "Warning: failed to decode ${label} from environment backup."
|
|
return 1
|
|
}
|
|
|
|
stage_mail_tls_file() {
|
|
local env_name="$1"
|
|
local source_path="${!env_name:-}"
|
|
|
|
[ -z "$source_path" ] && return 0
|
|
|
|
if [ ! -f "$source_path" ]; then
|
|
echo "Warning: ${env_name} points to a missing file: $source_path"
|
|
return 0
|
|
fi
|
|
|
|
mkdir -p "$TLS_RUNTIME_DIR"
|
|
|
|
local target_path="$TLS_RUNTIME_DIR/${env_name,,}"
|
|
cp "$source_path" "$target_path"
|
|
chmod 600 "$target_path"
|
|
export "$env_name=$target_path"
|
|
}
|
|
|
|
# Create and fix ownership of data directories (volume mount may have wrong perms)
|
|
mkdir -p "$TOR_HS_DIR" "$TOR_DATA_DIR" "$CERTS_DIR" "$UPLOADS_DATA_DIR" 2>/dev/null || true
|
|
chmod 700 "$TOR_HS_DIR" 2>/dev/null || true
|
|
link_release_uploads_dir
|
|
|
|
stage_mail_tls_file MAIL_TLS_CERT_PATH
|
|
stage_mail_tls_file MAIL_TLS_KEY_PATH
|
|
stage_mail_tls_file SMTP_TLS_CERT_PATH
|
|
stage_mail_tls_file SMTP_TLS_KEY_PATH
|
|
stage_mail_tls_file IMAP_TLS_CERT_PATH
|
|
stage_mail_tls_file IMAP_TLS_KEY_PATH
|
|
stage_mail_tls_file POP3_TLS_CERT_PATH
|
|
stage_mail_tls_file POP3_TLS_KEY_PATH
|
|
|
|
# Restore Tor hidden-service identity if /data was replaced and backup secrets are available.
|
|
if [ ! -s "$TOR_HS_DIR/hs_ed25519_secret_key" ] && [ -n "${ONION_HS_SECRET_KEY_B64:-}" ]; then
|
|
echo "No Tor hidden-service key found; attempting restore from environment backup..."
|
|
|
|
decode_b64_to_file "${ONION_HS_SECRET_KEY_B64:-}" "$TOR_HS_DIR/hs_ed25519_secret_key" "Tor secret key" || true
|
|
decode_b64_to_file "${ONION_HS_PUBLIC_KEY_B64:-}" "$TOR_HS_DIR/hs_ed25519_public_key" "Tor public key" || true
|
|
|
|
if [ -n "${ONION_HOST:-}" ]; then
|
|
printf '%s\n' "${ONION_HOST}" > "$TOR_HS_DIR/hostname"
|
|
chmod 600 "$TOR_HS_DIR/hostname"
|
|
echo "Restored Tor hostname from ONION_HOST."
|
|
fi
|
|
fi
|
|
|
|
chown -R nobody:nogroup /data 2>/dev/null || true
|
|
chmod 700 "$TOR_HS_DIR" 2>/dev/null || true
|
|
|
|
# The dedicated vpn role needs root so it can manage the WireGuard interface.
|
|
if [ "$ROLE" = "vpn" ]; then
|
|
if [ "$(id -u)" != "0" ]; then
|
|
echo "The vpn runtime role requires the container to start as root" >&2
|
|
exit 1
|
|
fi
|
|
|
|
exec /app/start.sh "$ROLE"
|
|
fi
|
|
|
|
# Drop to nobody and run the start script when the entrypoint starts as root.
|
|
if [ "$(id -u)" = "0" ]; then
|
|
exec su -s /bin/bash nobody -c "/app/start.sh ${ROLE}"
|
|
fi
|
|
|
|
exec /app/start.sh "$ROLE"
|