elektrine/deploy/docker/docker-entrypoint.sh
maxfield d65402be91 feat(edge): per-site config bundle and pure-edge deploy path
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.
2026-08-02 01:14:00 -04:00

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"